Fix mutex issue
We were having some issues with mutex locking order related to
upgrading local to global references when recording non-debuggable
classes. We refactored this code so there is no longer this issue.
Bug: 35838746
Test: Build and boot a marlin with libartd.so
Change-Id: I093b433d921478307130c49a07d0c7ec34dd070d
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 100f476..bb92ca7 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -74,12 +74,35 @@
}
}
-static void DoCollectNonDebuggableCallback(Thread* thread, void* data ATTRIBUTE_UNUSED)
+class ClassSet {
+ public:
+ explicit ClassSet(Thread* const self) : hs_(self) {}
+
+ void AddClass(ObjPtr<mirror::Class> klass) REQUIRES(Locks::mutator_lock_) {
+ for (Handle<mirror::Class> k : class_set_) {
+ if (k.Get() == klass.Ptr()) {
+ return;
+ }
+ }
+ class_set_.push_back(hs_.NewHandle<mirror::Class>(klass));
+ }
+
+ const std::vector<Handle<mirror::Class>>& GetClasses() const {
+ return class_set_;
+ }
+
+ private:
+ VariableSizedHandleScope hs_;
+ std::vector<Handle<mirror::Class>> class_set_;
+};
+
+static void DoCollectNonDebuggableCallback(Thread* thread, void* data)
REQUIRES(Locks::mutator_lock_) {
class NonDebuggableStacksVisitor : public StackVisitor {
public:
- explicit NonDebuggableStacksVisitor(Thread* t)
- : StackVisitor(t, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {}
+ NonDebuggableStacksVisitor(Thread* t, ClassSet* class_set)
+ : StackVisitor(t, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+ class_set_(class_set) {}
~NonDebuggableStacksVisitor() OVERRIDE {}
@@ -87,7 +110,7 @@
if (GetMethod()->IsRuntimeMethod()) {
return true;
}
- NonDebuggableClasses::AddNonDebuggableClass(GetMethod()->GetDeclaringClass());
+ class_set_->AddClass(GetMethod()->GetDeclaringClass());
if (kIsDebugBuild) {
LOG(INFO) << GetMethod()->GetDeclaringClass()->PrettyClass()
<< " might not be fully debuggable/deoptimizable due to "
@@ -95,16 +118,36 @@
}
return true;
}
+
+ private:
+ ClassSet* class_set_;
};
- NonDebuggableStacksVisitor visitor(thread);
+ NonDebuggableStacksVisitor visitor(thread, reinterpret_cast<ClassSet*>(data));
visitor.WalkStack();
}
-static void CollectNonDebuggableClasses() {
+static void CollectNonDebuggableClasses() REQUIRES(!Locks::mutator_lock_) {
Runtime* const runtime = Runtime::Current();
- ScopedSuspendAll suspend("Checking stacks for non-obsoletable methods!", /*long_suspend*/false);
- MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
- runtime->GetThreadList()->ForEach(DoCollectNonDebuggableCallback, nullptr);
+ Thread* const self = Thread::Current();
+ // Get the mutator lock.
+ ScopedObjectAccess soa(self);
+ ClassSet classes(self);
+ {
+ // Drop the mutator lock.
+ self->TransitionFromRunnableToSuspended(art::ThreadState::kNative);
+ {
+ // Get it back with a suspend all.
+ ScopedSuspendAll suspend("Checking stacks for non-obsoletable methods!",
+ /*long_suspend*/false);
+ MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
+ runtime->GetThreadList()->ForEach(DoCollectNonDebuggableCallback, &classes);
+ }
+ // Recover the shared lock before we leave this scope.
+ self->TransitionFromSuspendedToRunnable();
+ }
+ for (Handle<mirror::Class> klass : classes.GetClasses()) {
+ NonDebuggableClasses::AddNonDebuggableClass(klass.Get());
+ }
}
static void EnableDebugFeatures(uint32_t debug_flags) {
diff --git a/runtime/non_debuggable_classes.h b/runtime/non_debuggable_classes.h
index b72afd8..0c94dc0 100644
--- a/runtime/non_debuggable_classes.h
+++ b/runtime/non_debuggable_classes.h
@@ -35,7 +35,8 @@
return non_debuggable_classes;
}
- static void AddNonDebuggableClass(ObjPtr<mirror::Class> klass) REQUIRES(Locks::mutator_lock_);
+ static void AddNonDebuggableClass(ObjPtr<mirror::Class> klass)
+ REQUIRES_SHARED(Locks::mutator_lock_);
private:
static std::vector<jclass> non_debuggable_classes;