Offer `TestLooperManager` on Ravenwood.

Common test utilities like `TestableLooper` rely on being able to
drive `Looper` interactions via `TestLooperManager` which can only
be obtained via `Instrumentation`.

This change integrates with the common `InstrumentationRegistry`
library which is how most tests obtain their `Instrumentation`
instance.  We play an odd dance with `java_host_for_device` and
`java_device_for_host` to get a version of `androidx.test.monitor`
that we can link against our runtime.  (The build system otherwise
gets excited that we're trying to compile an Android-linked library
into what appears to be a Java-linked library, but we know that we're
offering the Android runtime.)

Fix subtle bug in `MessageQueue_host` where a requested wake might
race with the `for (;;)` loop in `MessageQueue.next()`; if a wake is
pending, it's a valid reason to return from `nativePollOnce()`.

Add timeout logic to `RavenwoodRuleImpl` which can be enabled to
dump all our stack traces just before Tradefed times out, to aid in
debugging deadlocks; disabled by default.

Bug: 319647875
Test: atest SystemUiRoboTests
Test: atest SystemUiRavenTests
Test: atest FrameworksCoreTestsRavenwood:TestLooperManagerTest
Change-Id: I13605d32df0c3e6758f541d5e75a6bdaf44368db
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index e013a3e..1ac69f6 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -30,6 +30,9 @@
         "junit-src/**/*.java",
         "junit-impl-src/**/*.java",
     ],
+    static_libs: [
+        "androidx.test.monitor-for-device",
+    ],
     libs: [
         "framework-minus-apex.ravenwood",
         "junit",
@@ -61,3 +64,17 @@
         "core-xml-for-host",
     ],
 }
+
+java_host_for_device {
+    name: "androidx.test.monitor-for-device",
+    libs: [
+        "androidx.test.monitor-for-host",
+    ],
+}
+
+java_device_for_host {
+    name: "androidx.test.monitor-for-host",
+    libs: [
+        "androidx.test.monitor",
+    ],
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index b3dbcde..a797b1d 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -16,12 +16,35 @@
 
 package android.platform.test.ravenwood;
 
+import android.app.Instrumentation;
+import android.os.Bundle;
 import android.os.HandlerThread;
 import android.os.Looper;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.io.PrintStream;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
 public class RavenwoodRuleImpl {
     private static final String MAIN_THREAD_NAME = "RavenwoodMain";
 
+    /**
+     * When enabled, attempt to dump all thread stacks just before we hit the
+     * overall Tradefed timeout, to aid in debugging deadlocks.
+     */
+    private static final boolean ENABLE_TIMEOUT_STACKS = false;
+    private static final int TIMEOUT_MILLIS = 9_000;
+
+    private static final ScheduledExecutorService sTimeoutExecutor =
+            Executors.newScheduledThreadPool(1);
+
+    private static ScheduledFuture<?> sPendingTimeout;
+
     public static boolean isOnRavenwood() {
         return true;
     }
@@ -41,9 +64,22 @@
             main.start();
             Looper.setMainLooperForTest(main.getLooper());
         }
+
+        InstrumentationRegistry.registerInstance(new Instrumentation(), Bundle.EMPTY);
+
+        if (ENABLE_TIMEOUT_STACKS) {
+            sPendingTimeout = sTimeoutExecutor.schedule(RavenwoodRuleImpl::dumpStacks,
+                    TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        }
     }
 
     public static void reset(RavenwoodRule rule) {
+        if (ENABLE_TIMEOUT_STACKS) {
+            sPendingTimeout.cancel(false);
+        }
+
+        InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
+
         if (rule.mProvideMainThread) {
             Looper.getMainLooper().quit();
             Looper.clearMainLooperForTest();
@@ -55,4 +91,19 @@
         android.os.Binder.reset$ravenwood();
         android.os.Process.reset$ravenwood();
     }
+
+    private static void dumpStacks() {
+        final PrintStream out = System.err;
+        out.println("-----BEGIN ALL THREAD STACKS-----");
+        final Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();
+        for (Map.Entry<Thread, StackTraceElement[]> stack : stacks.entrySet()) {
+            out.println();
+            Thread t = stack.getKey();
+            out.println(t.toString() + " ID=" + t.getId());
+            for (StackTraceElement e : stack.getValue()) {
+                out.println("\tat " + e);
+            }
+        }
+        out.println("-----END ALL THREAD STACKS-----");
+    }
 }
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index eaf01a3..b775f9a 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -72,6 +72,7 @@
 android.os.ServiceSpecificException
 android.os.SystemClock
 android.os.SystemProperties
+android.os.TestLooperManager
 android.os.ThreadLocalWorkSource
 android.os.TimestampedValue
 android.os.Trace
@@ -141,6 +142,8 @@
 
 android.content.ContentProvider
 
+android.app.Instrumentation
+
 android.metrics.LogMaker
 
 android.view.Display$HdrCapabilities