Mark threads started by Daemons.java as systemDaemon

The threads started by Daemons.java are special daemon threads that
provide important GC related functionality to the runtime. As such the
runtime sometimes needs to keep track of which threads these are. This
adds support for keeping track of that data.

Also give a way for the runtime to wait for all Daemon threads to come
up.

Test: while atest CtsJdwpTestCases; do; done;
Exempt-From-Owner-Approval: Previous version approved by nfuller@ with
                            only minor nit changes. Bypassing further
                            owner review since all owners are currently
                            in LON.
Bug: 123696564
Change-Id: Ia70da0b4d11409930bef47e4d06359b0d612c8fa
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index a04bee8..c827532 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -25,6 +25,7 @@
 import java.lang.ref.ReferenceQueue;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeoutException;
 import libcore.util.EmptyArray;
 
@@ -40,28 +41,44 @@
     private static final int NANOS_PER_SECOND = NANOS_PER_MILLI * 1000;
     @UnsupportedAppUsage
     private static final long MAX_FINALIZE_NANOS = 10L * NANOS_PER_SECOND;
+    private static final Daemon[] DAEMONS = new Daemon[] {
+            HeapTaskDaemon.INSTANCE,
+            ReferenceQueueDaemon.INSTANCE,
+            FinalizerDaemon.INSTANCE,
+            FinalizerWatchdogDaemon.INSTANCE,
+    };
+    private static final CountDownLatch POST_ZYGOTE_START_LATCH = new CountDownLatch(DAEMONS.length);
+    private static final CountDownLatch PRE_ZYGOTE_START_LATCH = new CountDownLatch(DAEMONS.length);
+
+    private static boolean postZygoteFork = false;
 
     @UnsupportedAppUsage
     public static void start() {
-        ReferenceQueueDaemon.INSTANCE.start();
-        FinalizerDaemon.INSTANCE.start();
-        FinalizerWatchdogDaemon.INSTANCE.start();
-        HeapTaskDaemon.INSTANCE.start();
+        for (Daemon daemon : DAEMONS) {
+            daemon.start();
+        }
     }
 
     public static void startPostZygoteFork() {
-        ReferenceQueueDaemon.INSTANCE.startPostZygoteFork();
-        FinalizerDaemon.INSTANCE.startPostZygoteFork();
-        FinalizerWatchdogDaemon.INSTANCE.startPostZygoteFork();
-        HeapTaskDaemon.INSTANCE.startPostZygoteFork();
+        postZygoteFork = true;
+        for (Daemon daemon : DAEMONS) {
+            daemon.startPostZygoteFork();
+        }
     }
 
     @UnsupportedAppUsage
     public static void stop() {
-        HeapTaskDaemon.INSTANCE.stop();
-        ReferenceQueueDaemon.INSTANCE.stop();
-        FinalizerDaemon.INSTANCE.stop();
-        FinalizerWatchdogDaemon.INSTANCE.stop();
+        for (Daemon daemon : DAEMONS) {
+            daemon.stop();
+        }
+    }
+
+    private static void waitForDaemonStart() throws Exception {
+        if (postZygoteFork) {
+            POST_ZYGOTE_START_LATCH.await();
+        } else {
+            PRE_ZYGOTE_START_LATCH.await();
+        }
     }
 
     /**
@@ -95,16 +112,20 @@
             }
             thread = new Thread(ThreadGroup.systemThreadGroup, this, name);
             thread.setDaemon(true);
+            thread.setSystemDaemon(true);
             thread.start();
         }
 
-        public void run() {
+        public final void run() {
             if (postZygoteFork) {
                 // We don't set the priority before the Thread.start() call above because
                 // Thread.start() will call SetNativePriority and overwrite the desired native
                 // priority. We (may) use a native priority that doesn't have a corresponding
                 // java.lang.Thread-level priority (native priorities are more coarse-grained.)
                 VMRuntime.getRuntime().setSystemDaemonThreadPriority();
+                POST_ZYGOTE_START_LATCH.countDown();
+            } else {
+                PRE_ZYGOTE_START_LATCH.countDown();
             }
             runInternal();
         }
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index 591d14a..0ca9074 100644
--- a/ojluni/src/main/java/java/lang/Thread.java
+++ b/ojluni/src/main/java/java/lang/Thread.java
@@ -236,6 +236,11 @@
     /* For generating thread ID */
     private static long threadSeqNumber;
 
+
+    // Android-added: The concept of "system-daemon" threads. See java.lang.Daemons.
+    /** True if this thread is managed by {@link Daemons}. */
+    private boolean systemDaemon = false;
+
     /* Java thread status for tools,
      * initialized to indicate thread 'not yet started'
      */
@@ -2182,6 +2187,43 @@
         getUncaughtExceptionHandler().uncaughtException(this, e);
     }
 
+    // BEGIN Android-added: The concept of "system-daemon" threads. See java.lang.Daemons.
+    /**
+     * Marks this thread as either a special runtime-managed ("system daemon")
+     * thread or a normal (i.e. app code created) daemon thread.)
+     *
+     * <p>System daemon threads get special handling when starting up in some
+     * cases.
+     *
+     * <p>This method must be invoked before the thread is started.
+     *
+     * <p>This method must only be invoked on Thread instances that have already
+     * had {@code setDaemon(true)} called on them.
+     *
+     * <p>Package-private since only {@link java.lang.Daemons} needs to call
+     * this.
+     *
+     * @param  on if {@code true}, marks this thread as a system daemon thread
+     *
+     * @throws  IllegalThreadStateException
+     *          if this thread is {@linkplain #isAlive alive} or not a
+     *          {@linkplain #isDaemon daemon}
+     *
+     * @throws  SecurityException
+     *          if {@link #checkAccess} determines that the current
+     *          thread cannot modify this thread
+     *
+     * @hide For use by Daemons.java only.
+     */
+    final void setSystemDaemon(boolean on) {
+        checkAccess();
+        if (isAlive() || !isDaemon()) {
+            throw new IllegalThreadStateException();
+        }
+        systemDaemon = on;
+    }
+    // END Android-added: The concept of "system-daemon" threads. See java.lang.Daemons.
+
     /**
      * Removes from the specified map any keys that have been enqueued
      * on the specified reference queue.