Hold heap bitmap lock in Heap::GetObjectsAllocated

Fixes a race condition where add and remove space could cause a crash
when we iterated over the spaces.

TODO: Add a spaces lock or something to guard against this.

(cherry picked from commit a395c0a492079d86b312c9edc796d63001576954)

Bug: 21031927

Change-Id: I7f0d558316f8e9d9f22ffd182e8666355bf50d47
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 811d15a..4bc9f98 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2143,6 +2143,7 @@
     case kWaitingForDebuggerToAttach:
     case kWaitingForDeoptimization:
     case kWaitingForGcToComplete:
+    case kWaitingForGetObjectsAllocated:
     case kWaitingForJniOnLoad:
     case kWaitingForMethodTracingStart:
     case kWaitingForSignalCatcherOutput:
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 4129d75..11a0e3c 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1612,10 +1612,19 @@
 }
 
 size_t Heap::GetObjectsAllocated() const {
+  Thread* self = Thread::Current();
+  ScopedThreadStateChange tsc(self, kWaitingForGetObjectsAllocated);
+  auto* tl = Runtime::Current()->GetThreadList();
+  // Need SuspendAll here to prevent lock violation if RosAlloc does it during InspectAll.
+  tl->SuspendAll(__FUNCTION__);
   size_t total = 0;
-  for (space::AllocSpace* space : alloc_spaces_) {
-    total += space->GetObjectsAllocated();
+  {
+    ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    for (space::AllocSpace* space : alloc_spaces_) {
+      total += space->GetObjectsAllocated();
+    }
   }
+  tl->ResumeAll();
   return total;
 }
 
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index be7022e..6569d83 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -84,6 +84,7 @@
     case kWaitingInMainDebuggerLoop:      return kJavaWaiting;
     case kWaitingForDebuggerSuspension:   return kJavaWaiting;
     case kWaitingForDeoptimization:       return kJavaWaiting;
+    case kWaitingForGetObjectsAllocated:  return kJavaWaiting;
     case kWaitingForJniOnLoad:            return kJavaWaiting;
     case kWaitingForSignalCatcherOutput:  return kJavaWaiting;
     case kWaitingInMainSignalCatcherLoop: return kJavaWaiting;
diff --git a/runtime/thread_state.h b/runtime/thread_state.h
index b5479ed..c7ea7f4 100644
--- a/runtime/thread_state.h
+++ b/runtime/thread_state.h
@@ -42,6 +42,7 @@
   kWaitingForDeoptimization,        // WAITING        TS_WAIT      waiting for deoptimization suspend all
   kWaitingForMethodTracingStart,    // WAITING        TS_WAIT      waiting for method tracing to start
   kWaitingForVisitObjects,          // WAITING        TS_WAIT      waiting for visiting objects
+  kWaitingForGetObjectsAllocated,   // WAITING        TS_WAIT      waiting for getting the number of allocated objects
   kStarting,                        // NEW            TS_WAIT      native thread started, not yet ready to run managed code
   kNative,                          // RUNNABLE       TS_RUNNING   running in a JNI native method
   kSuspended,                       // RUNNABLE       TS_RUNNING   suspended by GC or debugger