Try to de-flake & improve the not-leaking tests

* Double the amount that we allow memory to differ by.
* Run GC before creating the sentinel. Should maybe
  ensure all double-GC objects are fully cleaned up
  in the same pass the sentinel is finalized?
* Monitor FD count as it's less likely to be as variable,
  but will still catch any leaked gralloc buffers as
  those are backed by FDs.

Bug: 111308777
Test: this
Merged-In: I0caee10237e43ac945c47b08c80f96fa4f3bf989
Change-Id: I0caee10237e43ac945c47b08c80f96fa4f3bf989
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
index a0c09f1..1ef7c87 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
@@ -17,6 +17,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -51,6 +52,7 @@
 import org.junit.runner.RunWith;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.IntBuffer;
@@ -1458,7 +1460,10 @@
         nValidateNdkAccessAfterRecycle(bitmap);
     }
 
-    private void runGcAndFinalizersSync() {
+    private static void runGcAndFinalizersSync() {
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+
         final CountDownLatch fence = new CountDownLatch(1);
         new Object() {
             @Override
@@ -1478,33 +1483,35 @@
         } catch (InterruptedException ex) {
             throw new RuntimeException(ex);
         }
-        Runtime.getRuntime().gc();
     }
 
-    private void assertNotLeaking(int iteration, Debug.MemoryInfo start, Debug.MemoryInfo end) {
+    private static File sProcSelfFd = new File("/proc/self/fd");
+    private static int getFdCount() {
+        return sProcSelfFd.listFiles().length;
+    }
+
+    private static void assertNotLeaking(int iteration,
+            Debug.MemoryInfo start, Debug.MemoryInfo end) {
         Debug.getMemoryInfo(end);
+        assertNotEquals(0, start.getTotalPss());
+        assertNotEquals(0, end.getTotalPss());
         if (end.getTotalPss() - start.getTotalPss() > 2000 /* kB */) {
             runGcAndFinalizersSync();
             Debug.getMemoryInfo(end);
-            if (end.getTotalPss() - start.getTotalPss() > 2000 /* kB */) {
+            if (end.getTotalPss() - start.getTotalPss() > 4000 /* kB */) {
                 // Guarded by if so we don't continually generate garbage for the
                 // assertion string.
                 assertEquals("Memory leaked, iteration=" + iteration,
                         start.getTotalPss(), end.getTotalPss(),
-                        2000 /* kb */);
+                        4000 /* kb */);
             }
         }
     }
 
-    @Test
-    @LargeTest
-    public void testHardwareBitmapNotLeaking() {
+    private static void runNotLeakingTest(Runnable test) {
         Debug.MemoryInfo meminfoStart = new Debug.MemoryInfo();
         Debug.MemoryInfo meminfoEnd = new Debug.MemoryInfo();
-        BitmapFactory.Options opts = new BitmapFactory.Options();
-        opts.inPreferredConfig = Config.HARDWARE;
-        opts.inScaled = false;
-
+        int fdCount = -1;
         for (int i = 0; i < 2000; i++) {
             if (i == 2) {
                 // Not really the "start" but by having done a couple
@@ -1512,10 +1519,26 @@
                 // so memory usage should be stable now
                 runGcAndFinalizersSync();
                 Debug.getMemoryInfo(meminfoStart);
+                fdCount = getFdCount();
             }
             if (i % 100 == 5) {
                 assertNotLeaking(i, meminfoStart, meminfoEnd);
+                assertEquals(fdCount, getFdCount());
             }
+            test.run();
+        }
+        assertNotLeaking(2000, meminfoStart, meminfoEnd);
+        assertEquals(fdCount, getFdCount());
+    }
+
+    @Test
+    @LargeTest
+    public void testHardwareBitmapNotLeaking() {
+        BitmapFactory.Options opts = new BitmapFactory.Options();
+        opts.inPreferredConfig = Config.HARDWARE;
+        opts.inScaled = false;
+
+        runNotLeakingTest(() -> {
             Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, opts);
             assertNotNull(bitmap);
             // Make sure nothing messed with the bitmap
@@ -1523,16 +1546,12 @@
             assertEquals(128, bitmap.getHeight());
             assertEquals(Config.HARDWARE, bitmap.getConfig());
             bitmap.recycle();
-        }
-
-        assertNotLeaking(2000, meminfoStart, meminfoEnd);
+        });
     }
 
     @Test
     @LargeTest
     public void testDrawingHardwareBitmapNotLeaking() {
-        Debug.MemoryInfo meminfoStart = new Debug.MemoryInfo();
-        Debug.MemoryInfo meminfoEnd = new Debug.MemoryInfo();
         BitmapFactory.Options opts = new BitmapFactory.Options();
         opts.inPreferredConfig = Config.HARDWARE;
         opts.inScaled = false;
@@ -1540,17 +1559,7 @@
         renderTarget.setDefaultSize(128, 128);
         final Surface surface = renderTarget.getSurface();
 
-        for (int i = 0; i < 2000; i++) {
-            if (i == 2) {
-                // Not really the "start" but by having done a couple
-                // we've fully initialized any state that may be required,
-                // so memory usage should be stable now
-                runGcAndFinalizersSync();
-                Debug.getMemoryInfo(meminfoStart);
-            }
-            if (i % 100 == 5) {
-                assertNotLeaking(i, meminfoStart, meminfoEnd);
-            }
+        runNotLeakingTest(() -> {
             Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, opts);
             assertNotNull(bitmap);
             // Make sure nothing messed with the bitmap
@@ -1561,9 +1570,7 @@
             canvas.drawBitmap(bitmap, 0, 0, null);
             surface.unlockCanvasAndPost(canvas);
             bitmap.recycle();
-        }
-
-        assertNotLeaking(2000, meminfoStart, meminfoEnd);
+        });
     }
 
     private void strictModeTest(Runnable runnable) {