Camera: improve Image allocation in camera CTS

Reduce the chance where CTS rely on GC to clean up
image buffers.
Also reduce ZSL buffer number in PerformanceTest further.

Bug: 24506101
Change-Id: Ice11fd564c392b652a557ce441f054a64e092b64
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
index 75de9c0..41e2045 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
@@ -714,6 +714,7 @@
 
                     // clear out the surface and camera session
                     stopPreviewAndClearSurface(previewBuilder, rawBurstBuilder);
+                    rawReaderListener.drain();
                     closeImageReader();
                 }
             } finally {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
index c5eb27b..d78b3b5 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -337,7 +337,7 @@
          *
          */
         public void drain() {
-            for (int i = 0; i < mQueue.size(); i++) {
+            while (!mQueue.isEmpty()) {
                 Image image = mQueue.poll();
                 assertNotNull("Unable to get an image", image);
                 image.close();
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
index dc499ba..2ae29c3 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -316,18 +316,24 @@
                         session, previewBuilder.build(), mHandler);
 
                 // Check if all timestamps are the same
+                Image prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
                 validateTimestamps("Result 1", result.first,
-                        prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result.second);
+                        prevImage, result.second);
+                prevImage.close();
 
                 // Capture targeting both jpeg and preview
                 Pair<TotalCaptureResult, Long> result2 = captureAndVerifyResult(mockCaptureCallback,
                         session, multiBuilder.build(), mHandler);
 
                 // Check if all timestamps are the same
+                prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+                Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
                 validateTimestamps("Result 2 Preview", result2.first,
-                        prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result2.second);
+                        prevImage, result2.second);
                 validateTimestamps("Result 2 Jpeg", result2.first,
-                        jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result2.second);
+                        jpegImage, result2.second);
+                prevImage.close();
+                jpegImage.close();
 
                 // Check if timestamps are increasing
                 mCollector.expectGreater("Timestamps must be increasing.", result.second,
@@ -343,10 +349,14 @@
                 long resultDiff = result4.second - result3.second;
 
                 // Check if all timestamps are the same
+                prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
                 validateTimestamps("Result 3", result3.first,
-                        prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result3.second);
+                        prevImage, result3.second);
+                prevImage.close();
+                prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
                 validateTimestamps("Result 4", result4.first,
-                        prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result4.second);
+                        prevImage, result4.second);
+                prevImage.close();
 
                 // Check that the timestamps monotonically increase at a reasonable rate
                 mCollector.expectGreaterOrEqual("Timestamps increase faster than system clock.",
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
index 7c80c7d..155f9dd 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -460,6 +460,10 @@
 
                             // Stop capture, delete the streams.
                             stopCapture(/*fast*/false);
+                            yuvImage.close();
+                            jpegImage.close();
+                            yuvListener.drain();
+                            jpegListener.drain();
                         } finally {
                             closeImageReader(jpegReader);
                             jpegReader = null;
@@ -645,6 +649,8 @@
                             maxYuvSz.getHeight(), ImageFormat.YUV_420_888, /*filePath*/null);
                     CameraTestUtils.validateImage(captureImage, captureSz.getWidth(),
                             captureSz.getHeight(), format, /*filePath*/null);
+                    yuvImage.close();
+                    captureImage.close();
                 }
 
                 // Stop capture, delete the streams.
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
index dfba587..2795bde 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
@@ -78,7 +78,7 @@
             Exception prior = null;
 
             ImageVerifierListener yuvListener;
-            ImageReader yuvReader;
+            ImageReader yuvReader = null;
 
             try {
                 openCamera(cameraId);
@@ -102,6 +102,9 @@
                 prior = e;
             } finally {
                 try {
+                    if (yuvReader != null) {
+                        yuvReader.close();
+                    }
                     closeCamera(cameraId);
                 } catch (Exception e) {
                     if (prior != null) {
@@ -151,7 +154,7 @@
             Exception prior = null;
 
             ImageVerifierListener yuvListener;
-            ImageReader yuvReader;
+            ImageReader yuvReader = null;
 
             try {
                 openCamera(cameraId);
@@ -175,6 +178,9 @@
                 prior = e;
             } finally {
                 try {
+                    if (yuvReader != null) {
+                        yuvReader.close();
+                    }
                     closeCamera(cameraId);
                 } catch (Exception e) {
                     if (prior != null) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
index 4af88ca..b14c551 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -71,8 +71,7 @@
     private final int MAX_INPUT_IMAGES = MAX_REPROCESS_IMAGES;
     // ZSL queue depth should be bigger than the max simultaneous reprocessing capture request
     // count to maintain reasonable number of candidate image for the worse-case.
-    // Here we want to make sure we at most dequeue half of the queue max images for the worst-case.
-    private final int MAX_ZSL_IMAGES = MAX_REPROCESS_IMAGES * 2;
+    private final int MAX_ZSL_IMAGES = MAX_REPROCESS_IMAGES * 3 / 2;
     private final double REPROCESS_STALL_MARGIN = 0.1;
 
     private DeviceReportLog mReportLog;
@@ -434,7 +433,7 @@
             // Wait for reprocess output jpeg and result come back.
             reprocessResultListener.getCaptureResultForRequest(reprocessRequest,
                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
-            mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+            mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS).close();
             long numFramesMaybeStalled = mZslResultListener.getTotalNumFrames();
             assertTrue("Reprocess capture result should be returned in "
                     + MAX_REPROCESS_RETURN_FRAME_COUNT + " frames",
@@ -475,6 +474,8 @@
             maxCaptureGapsMs[i] = maxTimestampGapMs;
         }
 
+        stopZslStreaming();
+
         String reprocessType = " YUV reprocessing ";
         if (reprocessInputFormat == ImageFormat.PRIVATE) {
             reprocessType = " opaque reprocessing ";
@@ -539,24 +540,34 @@
 
             // Get images
             startTimeMs = SystemClock.elapsedRealtime();
+            Image jpegImages[] = new Image[MAX_REPROCESS_IMAGES];
             for (int i = 0; i < MAX_REPROCESS_IMAGES; i++) {
-                mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+                jpegImages[i] = mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
                 getImageLatenciesMs[i] = SystemClock.elapsedRealtime() - startTimeMs;
                 startTimeMs = SystemClock.elapsedRealtime();
             }
+            for (Image i : jpegImages) {
+                i.close();
+            }
         } else {
             // sync capture: issue reprocess request one by one, only submit next one when
             // the previous capture image is returned. This is to test the back to back capture
             // performance.
+            Image jpegImages[] = new Image[MAX_REPROCESS_IMAGES];
             for (int i = 0; i < MAX_REPROCESS_IMAGES; i++) {
                 startTimeMs = SystemClock.elapsedRealtime();
                 mWriter.queueInputImage(inputImages[i]);
                 mSession.capture(reprocessReqs[i].build(), null, null);
-                mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+                jpegImages[i] = mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
                 getImageLatenciesMs[i] = SystemClock.elapsedRealtime() - startTimeMs;
             }
+            for (Image i : jpegImages) {
+                i.close();
+            }
         }
 
+        stopZslStreaming();
+
         String reprocessType = " YUV reprocessing ";
         if (reprocessInputFormat == ImageFormat.PRIVATE) {
             reprocessType = " opaque reprocessing ";
@@ -591,6 +602,12 @@
         mSession.setRepeatingRequest(zslBuilder.build(), mZslResultListener, mHandler);
     }
 
+    private void stopZslStreaming() throws Exception {
+        mSession.stopRepeating();
+        mSessionListener.getStateWaiter().waitForState(
+            BlockingSessionCallback.SESSION_READY, CameraTestUtils.CAMERA_IDLE_TIMEOUT_MS);
+    }
+
     /**
      * Wait for a certain number of frames, the images and results will be drained from the
      * listeners to make sure that next reprocessing can get matched results and images.
@@ -598,24 +615,22 @@
      * @param numFrameWait The number of frames to wait before return, 0 means that
      *      this call returns immediately after streaming on.
      */
-    private void waitForFrames(int numFrameWait) {
+    private void waitForFrames(int numFrameWait) throws Exception {
         if (numFrameWait < 0) {
             throw new IllegalArgumentException("numFrameWait " + numFrameWait +
                     " should be non-negative");
         }
 
-        if (numFrameWait == 0) {
-            // Let is stream out for a while
-            waitForNumResults(mZslResultListener, numFrameWait);
-            // Drain the pending images, to ensure that all future images have an associated
-            // capture result available.
-            mCameraZslImageListener.drain();
+        for (int i = 0; i < numFrameWait; i++) {
+            mCameraZslImageListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS).close();
         }
     }
 
     private void closeReaderWriters() {
+        mCameraZslImageListener.drain();
         CameraTestUtils.closeImageReader(mCameraZslReader);
         mCameraZslReader = null;
+        mJpegListener.drain();
         CameraTestUtils.closeImageReader(mJpegReader);
         mJpegReader = null;
         CameraTestUtils.closeImageWriter(mWriter);