Reduce risk of flakes in memory leak detection tests.

Now performing jreck@-style garbage collection prior to getting Launcher
PSS. The reduces PSS noise from ~700KB to ~250KB (std dev).

The tests (MemoryTests) run outside of Launcher process and
communicate with Launcher via RPC.

The change is in the RPC handler that lives in Launcher and returns
Launcher PSS to the test.

Bug: 139137636
Change-Id: I457e590b005dac53345f4223d972c7961754938c
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 619293b..7931c96 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -36,7 +36,9 @@
 import com.android.launcher3.util.ResourceBasedOverride;
 
 import java.util.LinkedList;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 
 public class TestInformationHandler implements ResourceBasedOverride {
 
@@ -137,6 +139,7 @@
             }
 
             case TestProtocol.REQUEST_TOTAL_PSS_KB: {
+                runGcAndFinalizersSync();
                 Debug.MemoryInfo mem = new Debug.MemoryInfo();
                 Debug.getMemoryInfo(mem);
                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, mem.getTotalPss());
@@ -173,4 +176,29 @@
         final LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
         return model.getCallback() == null || model.isModelLoaded();
     }
+
+    private static void runGcAndFinalizersSync() {
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+
+        final CountDownLatch fence = new CountDownLatch(1);
+        new Object() {
+            @Override
+            protected void finalize() throws Throwable {
+                try {
+                    fence.countDown();
+                } finally {
+                    super.finalize();
+                }
+            }
+        };
+        try {
+            do {
+                Runtime.getRuntime().gc();
+                Runtime.getRuntime().runFinalization();
+            } while (!fence.await(100, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
 }