ART: Add GetAllThreads

Add support for GetAllThreads. Add a test.

Bug: 31684593
Test: m test-art-host-run-test-924-threads
Change-Id: I7068dd4d3700a32a87a44d38590e53df0bd238c7
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 4334ca3..e41f074 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -127,7 +127,7 @@
   }
 
   static jvmtiError GetAllThreads(jvmtiEnv* env, jint* threads_count_ptr, jthread** threads_ptr) {
-    return ERR(NOT_IMPLEMENTED);
+    return ThreadUtil::GetAllThreads(env, threads_count_ptr, threads_ptr);
   }
 
   static jvmtiError SuspendThread(jvmtiEnv* env, jthread thread) {
diff --git a/runtime/openjdkjvmti/ti_thread.cc b/runtime/openjdkjvmti/ti_thread.cc
index e20f560..f7f63bd 100644
--- a/runtime/openjdkjvmti/ti_thread.cc
+++ b/runtime/openjdkjvmti/ti_thread.cc
@@ -42,6 +42,7 @@
 #include "obj_ptr.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
+#include "thread_list.h"
 #include "well_known_classes.h"
 
 namespace openjdkjvmti {
@@ -354,4 +355,53 @@
   return ERR(NONE);
 }
 
+jvmtiError ThreadUtil::GetAllThreads(jvmtiEnv* env,
+                                     jint* threads_count_ptr,
+                                     jthread** threads_ptr) {
+  if (threads_count_ptr == nullptr || threads_ptr == nullptr) {
+    return ERR(NULL_POINTER);
+  }
+
+  art::Thread* current = art::Thread::Current();
+
+  art::ScopedObjectAccess soa(current);
+
+  art::MutexLock mu(current, *art::Locks::thread_list_lock_);
+  std::list<art::Thread*> thread_list = art::Runtime::Current()->GetThreadList()->GetList();
+
+  std::vector<art::ObjPtr<art::mirror::Object>> peers;
+
+  for (art::Thread* thread : thread_list) {
+    // Skip threads that are still starting.
+    if (thread->IsStillStarting()) {
+      continue;
+    }
+
+    art::ObjPtr<art::mirror::Object> peer = thread->GetPeer();
+    if (peer != nullptr) {
+      peers.push_back(peer);
+    }
+  }
+
+  if (peers.empty()) {
+    *threads_count_ptr = 0;
+    *threads_ptr = nullptr;
+  } else {
+    unsigned char* data;
+    jvmtiError data_result = env->Allocate(peers.size() * sizeof(jthread), &data);
+    if (data_result != ERR(NONE)) {
+      return data_result;
+    }
+    jthread* threads = reinterpret_cast<jthread*>(data);
+    for (size_t i = 0; i != peers.size(); ++i) {
+      threads[i] = soa.AddLocalReference<jthread>(peers[i]);
+    }
+
+    *threads_count_ptr = static_cast<jint>(peers.size());
+    *threads_ptr = threads;
+  }
+
+  return ERR(NONE);
+}
+
 }  // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_thread.h b/runtime/openjdkjvmti/ti_thread.h
index b6ffbb5..fca42ad 100644
--- a/runtime/openjdkjvmti/ti_thread.h
+++ b/runtime/openjdkjvmti/ti_thread.h
@@ -39,6 +39,8 @@
 
 class ThreadUtil {
  public:
+  static jvmtiError GetAllThreads(jvmtiEnv* env, jint* threads_count_ptr, jthread** threads_ptr);
+
   static jvmtiError GetCurrentThread(jvmtiEnv* env, jthread* thread_ptr);
 
   static jvmtiError GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr);