ART: Refactor run-test 924

Move testing to a dedicated thread to have a known thread name.
Change event reporting to be Java-side. Use Java-side thread list
(from Thread.getAllStackTraces) as comparison for minimal expected
set of threads.

Bug: 32072923
Test: art/test/testrunner/testrunner.py -b --host -t 924
Change-Id: I238ffc202e42eea8d1788137715188d3dfbcc8fb
diff --git a/test/924-threads/expected.txt b/test/924-threads/expected.txt
index 4c0f4ea..1eb2e1b 100644
--- a/test/924-threads/expected.txt
+++ b/test/924-threads/expected.txt
@@ -1,10 +1,10 @@
 currentThread OK
-main
+TestThread
 5
 false
 java.lang.ThreadGroup[name=main,maxpri=10]
 class dalvik.system.PathClassLoader
-main
+TestThread
 5
 false
 java.lang.ThreadGroup[name=main,maxpri=10]
@@ -33,10 +33,11 @@
 e1 = ALIVE|WAITING_WITH_TIMEOUT|SLEEPING|WAITING
 5 = ALIVE|RUNNABLE
 2 = TERMINATED
-[Thread[FinalizerDaemon,5,system], Thread[FinalizerWatchdogDaemon,5,system], Thread[HeapTaskDaemon,5,system], Thread[ReferenceQueueDaemon,5,system], Thread[Signal Catcher,5,system], Thread[main,5,main]]
+[Thread[FinalizerDaemon,5,system], Thread[FinalizerWatchdogDaemon,5,system], Thread[HeapTaskDaemon,5,system], Thread[ReferenceQueueDaemon,5,system], Thread[TestThread,5,main], Thread[main,5,main]]
 JVMTI_ERROR_THREAD_NOT_ALIVE
 JVMTI_ERROR_THREAD_NOT_ALIVE
 Constructed thread
-Thread(EventTestThread): start
-Thread(EventTestThread): end
+[]
+[Thread(EventTestThread): start]
+[Thread(EventTestThread): end]
 Thread joined
diff --git a/test/924-threads/src/art/Test924.java b/test/924-threads/src/art/Test924.java
index 160bf8e..5445939 100644
--- a/test/924-threads/src/art/Test924.java
+++ b/test/924-threads/src/art/Test924.java
@@ -25,17 +25,35 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 public class Test924 {
   public static void run() throws Exception {
     Main.bindAgentJNIForClass(Test924.class);
-    doTest();
+
+    // Run the test on its own thread, so we have a known state for the "current" thread.
+    Thread t = new Thread("TestThread") {
+      @Override
+      public void run() {
+        try {
+          doTest();
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+    t.start();
+    t.join();
   }
 
   private static void doTest() throws Exception {
     Thread t1 = Thread.currentThread();
     Thread t2 = getCurrentThread();
 
+    // Need to adjust priority, as on-device this may be unexpected (and we prefer not
+    // to special-case this.)
+    t1.setPriority(5);
+
     if (t1 != t2) {
       throw new RuntimeException("Expected " + t1 + " but got " + t2);
     }
@@ -188,7 +206,32 @@
     }
 
     Collections.sort(threadList, THREAD_COMP);
-    System.out.println(threadList);
+
+    List<Thread> expectedList = new ArrayList<>();
+    Set<Thread> threadsFromTraces = Thread.getAllStackTraces().keySet();
+
+    expectedList.add(findThreadByName(threadsFromTraces, "FinalizerDaemon"));
+    expectedList.add(findThreadByName(threadsFromTraces, "FinalizerWatchdogDaemon"));
+    expectedList.add(findThreadByName(threadsFromTraces, "HeapTaskDaemon"));
+    expectedList.add(findThreadByName(threadsFromTraces, "ReferenceQueueDaemon"));
+    // We can't get the signal catcher through getAllStackTraces. So ignore it.
+    // expectedList.add(findThreadByName(threadsFromTraces, "Signal Catcher"));
+    expectedList.add(findThreadByName(threadsFromTraces, "TestThread"));
+    expectedList.add(findThreadByName(threadsFromTraces, "main"));
+
+    if (!threadList.containsAll(expectedList)) {
+      throw new RuntimeException("Expected " + expectedList + " as subset, got " + threadList);
+    }
+    System.out.println(expectedList);
+  }
+
+  private static Thread findThreadByName(Set<Thread> threads, String name) {
+    for (Thread t : threads) {
+        if (t.getName().equals(name)) {
+            return t;
+        }
+    }
+    throw new RuntimeException("Did not find thread " + name + ": " + threads);
   }
 
   private static void doTLSTests() throws Exception {
@@ -256,13 +299,35 @@
   private static void doTestEvents() throws Exception {
     enableThreadEvents(true);
 
-    Thread t = new Thread("EventTestThread");
+    final CountDownLatch cdl1 = new CountDownLatch(1);
+    final CountDownLatch cdl2 = new CountDownLatch(1);
+
+    Runnable r = new Runnable() {
+      @Override
+      public void run() {
+        try {
+          cdl1.countDown();
+          cdl2.await();
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+    Thread t = new Thread(r, "EventTestThread");
 
     System.out.println("Constructed thread");
     Thread.yield();
+    Thread.sleep(100);
+    System.out.println(Arrays.toString(getThreadEventMessages()));
 
     t.start();
+    cdl1.await();
+
+    System.out.println(Arrays.toString(getThreadEventMessages()));
+
+    cdl2.countDown();
     t.join();
+    System.out.println(Arrays.toString(getThreadEventMessages()));
 
     System.out.println("Thread joined");
 
@@ -337,4 +402,5 @@
   private static native void setTLS(Thread t, long l);
   private static native long getTLS(Thread t);
   private static native void enableThreadEvents(boolean b);
+  private static native String[] getThreadEventMessages();
 }
diff --git a/test/924-threads/threads.cc b/test/924-threads/threads.cc
index 701ab1d..e21dcc2 100644
--- a/test/924-threads/threads.cc
+++ b/test/924-threads/threads.cc
@@ -16,6 +16,10 @@
 
 #include <stdio.h>
 
+#include <mutex>
+#include <string>
+#include <vector>
+
 #include "android-base/logging.h"
 #include "android-base/stringprintf.h"
 #include "jni.h"
@@ -139,17 +143,27 @@
   JvmtiErrorToException(env, jvmti_env, result);
 }
 
+static std::mutex gEventsMutex;
+static std::vector<std::string> gEvents;
+
 static void JNICALL ThreadEvent(jvmtiEnv* jvmti_env,
                                 JNIEnv* jni_env,
                                 jthread thread,
                                 bool is_start) {
   jvmtiThreadInfo info;
-  jvmtiError result = jvmti_env->GetThreadInfo(thread, &info);
-  if (result != JVMTI_ERROR_NONE) {
-    printf("Error getting thread info");
-    return;
+  {
+    std::lock_guard<std::mutex> guard(gEventsMutex);
+
+    jvmtiError result = jvmti_env->GetThreadInfo(thread, &info);
+    if (result != JVMTI_ERROR_NONE) {
+      gEvents.push_back("Error getting thread info");
+      return;
+    }
+
+    gEvents.push_back(android::base::StringPrintf("Thread(%s): %s",
+                                                  info.name,
+                                                  is_start ? "start" : "end"));
   }
-  printf("Thread(%s): %s\n", info.name, is_start ? "start" : "end");
 
   jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(info.name));
   jni_env->DeleteLocalRef(info.thread_group);
@@ -205,5 +219,18 @@
   JvmtiErrorToException(env, jvmti_env, ret);
 }
 
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test924_getThreadEventMessages(
+    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
+  std::lock_guard<std::mutex> guard(gEventsMutex);
+  jobjectArray ret = CreateObjectArray(env,
+                                       static_cast<jint>(gEvents.size()),
+                                       "java/lang/String",
+                                       [&](jint i) {
+    return env->NewStringUTF(gEvents[i].c_str());
+  });
+  gEvents.clear();
+  return ret;
+}
+
 }  // namespace Test924Threads
 }  // namespace art