Move heap trimming daemon and GC deamon into a single daemon

Bug: 18739541
Change-Id: Icf309cd8981372f24caa7c8b98a2e0591b1d90ea
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 58094d8..b054fb3 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -295,10 +295,13 @@
      */
     public native void registerNativeFree(int bytes);
 
-    public native void trimHeap();
-    public native void concurrentGC();
     public native void requestConcurrentGC();
-    public native void waitForConcurrentGCRequest();
+    public native void concurrentGC();
+    public native void requestHeapTrim();
+    public native void trimHeap();
+    public native void startHeapTaskProcessor();
+    public native void stopHeapTaskProcessor();
+    public native void runHeapTasks();
 
     /**
      * Let the heap know of the new process state. This can change allocation and garbage collection
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index d3f62c2..76f4ea9 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -40,16 +40,14 @@
         ReferenceQueueDaemon.INSTANCE.start();
         FinalizerDaemon.INSTANCE.start();
         FinalizerWatchdogDaemon.INSTANCE.start();
-        HeapTrimmerDaemon.INSTANCE.start();
-        GCDaemon.INSTANCE.start();
+        HeapTaskDaemon.INSTANCE.start();
     }
 
     public static void stop() {
+        HeapTaskDaemon.INSTANCE.stop();
         ReferenceQueueDaemon.INSTANCE.stop();
         FinalizerDaemon.INSTANCE.stop();
         FinalizerWatchdogDaemon.INSTANCE.stop();
-        HeapTrimmerDaemon.INSTANCE.stop();
-        GCDaemon.INSTANCE.stop();
     }
 
     /**
@@ -292,45 +290,38 @@
         }
     }
 
-    // Invoked by the GC to request that the HeapTrimmerDaemon thread attempt to trim the heap.
+    // Adds a heap trim task ot the heap event processor, not called from java. Left for
+    // compatibility purposes due to reflection.
     public static void requestHeapTrim() {
-        synchronized (HeapTrimmerDaemon.INSTANCE) {
-            HeapTrimmerDaemon.INSTANCE.notify();
-        }
+        VMRuntime.getRuntime().requestHeapTrim();
     }
 
-    private static class HeapTrimmerDaemon extends Daemon {
-        private static final HeapTrimmerDaemon INSTANCE = new HeapTrimmerDaemon();
-
-        @Override public void run() {
-            while (isRunning()) {
-                try {
-                    synchronized (this) {
-                        wait();
-                    }
-                    VMRuntime.getRuntime().trimHeap();
-                } catch (InterruptedException ignored) {
-                }
-            }
-        }
+    // Adds a concurrent GC request task ot the heap event processor, not called from java. Left
+    // for compatibility purposes due to reflection.
+    public static void requestGC() {
+        VMRuntime.getRuntime().requestConcurrentGC();
     }
 
-    private static class GCDaemon extends Daemon {
-        private static final GCDaemon INSTANCE = new GCDaemon();
+    private static class HeapTaskDaemon extends Daemon {
+        private static final HeapTaskDaemon INSTANCE = new HeapTaskDaemon();
 
         // Overrides the Daemon.interupt method which is called from Daemons.stop.
-        public void interrupt(Thread thread) {
-            // Notifies the daemon thread.
-            VMRuntime.getRuntime().requestConcurrentGC();
+        public synchronized void interrupt(Thread thread) {
+            VMRuntime.getRuntime().stopHeapTaskProcessor();
         }
 
         @Override public void run() {
-            while (isRunning()) {
-                VMRuntime.getRuntime().waitForConcurrentGCRequest();
+            synchronized (this) {
                 if (isRunning()) {
-                    VMRuntime.getRuntime().concurrentGC();
+                  // Needs to be synchronized or else we there is a race condition where we start
+                  // the thread, call stopHeapTaskProcessor before we start the heap task
+                  // processor, resulting in a deadlock since startHeapTaskProcessor restarts it
+                  // while the other thread is waiting in Daemons.stop().
+                  VMRuntime.getRuntime().startHeapTaskProcessor();
                 }
             }
+            // This runs tasks until we are stopped and there is no more pending task.
+            VMRuntime.getRuntime().runHeapTasks();
         }
     }
 }