1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.view.cts.surfacevalidator; 17 18 import static android.server.wm.BuildUtils.HW_TIMEOUT_MULTIPLIER; 19 20 import static org.junit.Assert.assertTrue; 21 22 import android.graphics.Bitmap; 23 import android.graphics.Point; 24 import android.graphics.Rect; 25 import android.hardware.HardwareBuffer; 26 import android.media.Image; 27 import android.media.ImageReader; 28 import android.os.Handler; 29 import android.os.HandlerThread; 30 import android.os.Trace; 31 import android.util.Log; 32 import android.util.SparseArray; 33 import android.view.Surface; 34 35 36 import java.util.concurrent.CountDownLatch; 37 import java.util.concurrent.TimeUnit; 38 39 public class SurfacePixelValidator2 { 40 private static final String TAG = "SurfacePixelValidator"; 41 42 private static final boolean DEBUG = false; 43 44 private static final int MAX_CAPTURED_FAILURES = 5; 45 private static final int PIXEL_STRIDE = 4; 46 47 private final int mWidth; 48 private final int mHeight; 49 50 private final HandlerThread mWorkerThread; 51 52 private final PixelChecker mPixelChecker; 53 private final Rect mBoundsToCheck; 54 private ImageReader mImageReader; 55 56 private int mResultSuccessFrames; 57 private int mResultFailureFrames; 58 private final SparseArray<Bitmap> mFirstFailures = new SparseArray<>(MAX_CAPTURED_FAILURES); 59 private long mFrameNumber = 0; 60 61 private final int mRequiredNumFrames; 62 63 private final CountDownLatch mRequiredNumFramesDrawnLatch = new CountDownLatch(1); 64 65 private final Handler mHandler; 66 67 private final ImageReader.OnImageAvailableListener mOnImageAvailable = 68 new ImageReader.OnImageAvailableListener() { 69 @Override 70 public void onImageAvailable(ImageReader reader) { 71 if (mImageReader == null) { 72 return; 73 } 74 75 Trace.beginSection("Read buffer"); 76 Image image = reader.acquireNextImage(); 77 78 Image.Plane plane = image.getPlanes()[0]; 79 if (plane.getPixelStride() != PIXEL_STRIDE) { 80 throw new IllegalStateException("pixel stride != " + PIXEL_STRIDE + "? " 81 + plane.getPixelStride()); 82 } 83 Trace.endSection(); 84 85 int totalFramesSeen; 86 boolean success = mPixelChecker.validatePlane(plane, mFrameNumber++, 87 mBoundsToCheck, 88 mWidth, mHeight); 89 if (success) { 90 mResultSuccessFrames++; 91 } else { 92 mResultFailureFrames++; 93 } 94 95 totalFramesSeen = mResultSuccessFrames + mResultFailureFrames; 96 if (DEBUG) { 97 Log.d(TAG, "Received image " + success + " numSuccess=" 98 + mResultSuccessFrames + " numFail=" + mResultFailureFrames 99 + " total=" + totalFramesSeen); 100 } 101 102 if (!success) { 103 Log.d(TAG, "Failure (" + mPixelChecker.getLastError() 104 + ") occurred on frame " + totalFramesSeen); 105 106 if (mFirstFailures.size() < MAX_CAPTURED_FAILURES) { 107 Log.d(TAG, "Capturing bitmap #" + mFirstFailures.size()); 108 // error, worth looking at... 109 Bitmap capture = Bitmap.wrapHardwareBuffer( 110 image.getHardwareBuffer(), null) 111 .copy(Bitmap.Config.ARGB_8888, false); 112 mFirstFailures.put(totalFramesSeen, capture); 113 } 114 } 115 116 image.close(); 117 if (totalFramesSeen >= mRequiredNumFrames) { 118 mRequiredNumFramesDrawnLatch.countDown(); 119 } 120 } 121 }; 122 SurfacePixelValidator2(Point size, Rect boundsToCheck, PixelChecker pixelChecker, int requiredNumFrames)123 public SurfacePixelValidator2(Point size, Rect boundsToCheck, PixelChecker pixelChecker, 124 int requiredNumFrames) { 125 mWidth = size.x; 126 mHeight = size.y; 127 128 mWorkerThread = new HandlerThread("SurfacePixelValidator"); 129 mWorkerThread.start(); 130 131 mPixelChecker = pixelChecker; 132 mBoundsToCheck = new Rect(boundsToCheck); 133 mRequiredNumFrames = requiredNumFrames; 134 mHandler = new Handler(mWorkerThread.getLooper()); 135 136 mImageReader = ImageReader.newInstance(mWidth, mHeight, HardwareBuffer.RGBA_8888, 1, 137 HardwareBuffer.USAGE_GPU_COLOR_OUTPUT | HardwareBuffer.USAGE_CPU_READ_OFTEN 138 | HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE); 139 mImageReader.setOnImageAvailableListener(mOnImageAvailable, mHandler); 140 } 141 getSurface()142 public Surface getSurface() { 143 return mImageReader.getSurface(); 144 } 145 146 /** 147 * Shuts down processing pipeline, and returns current pass/fail counts. 148 * 149 * Wait for pipeline to flush before calling this method. If not, frames that are still in 150 * flight may be lost. 151 */ finish(CapturedActivity.TestResult testResult)152 public void finish(CapturedActivity.TestResult testResult) { 153 CountDownLatch countDownLatch = new CountDownLatch(1); 154 // Post the imageReader close on the same thread it's processing data to avoid shutting down 155 // while still in the middle of processing an image. 156 mHandler.post(() -> { 157 testResult.failFrames = mResultFailureFrames; 158 testResult.passFrames = mResultSuccessFrames; 159 160 for (int i = 0; i < mFirstFailures.size(); i++) { 161 testResult.failures.put(mFirstFailures.keyAt(i), mFirstFailures.valueAt(i)); 162 } 163 mImageReader.close(); 164 mImageReader = null; 165 mWorkerThread.quitSafely(); 166 countDownLatch.countDown(); 167 }); 168 169 try { 170 assertTrue("Failed to wait for results", 171 countDownLatch.await(5L * HW_TIMEOUT_MULTIPLIER, TimeUnit.SECONDS)); 172 } catch (InterruptedException e) { 173 } 174 } 175 waitForAllFrames(long timeoutMs)176 public boolean waitForAllFrames(long timeoutMs) { 177 try { 178 return mRequiredNumFramesDrawnLatch.await(timeoutMs, TimeUnit.MILLISECONDS); 179 } catch (InterruptedException e) { 180 return false; 181 } 182 } 183 } 184