Merge "Fix screenshot buffer leaks" into udc-qpr-dev am: 3a4bf0e510 am: fe9ad73543
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23770899
Change-Id: I8f852fd2dc43df04416181829dd52d41de61b992
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index fbb0748..63cae63 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -24,6 +24,8 @@
import android.view.WindowContentFrameStats;
import android.view.WindowAnimationFrameStats;
import android.os.ParcelFileDescriptor;
+import android.window.ScreenCapture.ScreenCaptureListener;
+import android.window.ScreenCapture.LayerCaptureArgs;
import java.util.List;
@@ -43,8 +45,8 @@
void injectInputEventToInputFilter(in InputEvent event);
void syncInputTransactions(boolean waitForAnimations);
boolean setRotation(int rotation);
- Bitmap takeScreenshot(in Rect crop);
- Bitmap takeSurfaceControlScreenshot(in SurfaceControl surfaceControl);
+ boolean takeScreenshot(in Rect crop, in ScreenCaptureListener listener);
+ boolean takeSurfaceControlScreenshot(in SurfaceControl surfaceControl, in ScreenCaptureListener listener);
boolean clearWindowContentFrameStats(int windowId);
WindowContentFrameStats getWindowContentFrameStats(int windowId);
void clearWindowAnimationFrameStats();
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index b613fae..b0180c1 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -37,6 +37,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Build;
import android.os.Handler;
@@ -71,6 +72,8 @@
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
import android.view.inputmethod.EditorInfo;
+import android.window.ScreenCapture;
+import android.window.ScreenCapture.ScreenshotHardwareBuffer;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -1190,17 +1193,12 @@
Point displaySize = new Point();
display.getRealSize(displaySize);
- int rotation = display.getRotation();
-
// Take the screenshot
- Bitmap screenShot = null;
+ ScreenCapture.SynchronousScreenCaptureListener syncScreenCapture =
+ ScreenCapture.createSyncCaptureListener();
try {
- // Calling out without a lock held.
- screenShot = mUiAutomationConnection.takeScreenshot(
- new Rect(0, 0, displaySize.x, displaySize.y));
- if (screenShot == null) {
- Log.e(LOG_TAG, "mUiAutomationConnection.takeScreenshot() returned null for display "
- + mDisplayId);
+ if (!mUiAutomationConnection.takeScreenshot(
+ new Rect(0, 0, displaySize.x, displaySize.y), syncScreenCapture)) {
return null;
}
} catch (RemoteException re) {
@@ -1208,10 +1206,23 @@
return null;
}
- // Optimization
- screenShot.setHasAlpha(false);
+ final ScreenshotHardwareBuffer screenshotBuffer =
+ syncScreenCapture.getBuffer();
+ Bitmap screenShot = screenshotBuffer.asBitmap();
+ if (screenShot == null) {
+ Log.e(LOG_TAG, "mUiAutomationConnection.takeScreenshot() returned null for display "
+ + mDisplayId);
+ return null;
+ }
+ Bitmap swBitmap;
+ try (HardwareBuffer buffer = screenshotBuffer.getHardwareBuffer()) {
+ swBitmap = screenShot.copy(Bitmap.Config.ARGB_8888, false);
+ }
+ screenShot.recycle();
- return screenShot;
+ // Optimization
+ swBitmap.setHasAlpha(false);
+ return swBitmap;
}
/**
@@ -1248,12 +1259,27 @@
// Apply a sync transaction to ensure SurfaceFlinger is flushed before capturing a
// screenshot.
new SurfaceControl.Transaction().apply(true);
+ ScreenCapture.SynchronousScreenCaptureListener syncScreenCapture =
+ ScreenCapture.createSyncCaptureListener();
try {
- return mUiAutomationConnection.takeSurfaceControlScreenshot(sc);
+ if (!mUiAutomationConnection.takeSurfaceControlScreenshot(sc, syncScreenCapture)) {
+ return null;
+ }
+
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while taking screenshot!", re);
return null;
}
+ ScreenCapture.ScreenshotHardwareBuffer captureBuffer =
+ syncScreenCapture.getBuffer();
+ Bitmap screenShot = captureBuffer.asBitmap();
+ Bitmap swBitmap;
+ try (HardwareBuffer buffer = captureBuffer.getHardwareBuffer()) {
+ swBitmap = screenShot.copy(Bitmap.Config.ARGB_8888, false);
+ }
+
+ screenShot.recycle();
+ return swBitmap;
}
/**
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 34f0964..52949d6 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -25,7 +25,6 @@
import android.annotation.UserIdInt;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.graphics.Bitmap;
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerGlobal;
@@ -51,8 +50,6 @@
import android.view.accessibility.IAccessibilityManager;
import android.window.ScreenCapture;
import android.window.ScreenCapture.CaptureArgs;
-import android.window.ScreenCapture.ScreenshotHardwareBuffer;
-import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import libcore.io.IoUtils;
@@ -224,56 +221,54 @@
}
@Override
- public Bitmap takeScreenshot(Rect crop) {
+ public boolean takeScreenshot(Rect crop, ScreenCapture.ScreenCaptureListener listener) {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
+
final long identity = Binder.clearCallingIdentity();
try {
final CaptureArgs captureArgs = new CaptureArgs.Builder<>()
.setSourceCrop(crop)
.build();
- SynchronousScreenCaptureListener syncScreenCapture =
- ScreenCapture.createSyncCaptureListener();
- mWindowManager.captureDisplay(DEFAULT_DISPLAY, captureArgs,
- syncScreenCapture);
- final ScreenshotHardwareBuffer screenshotBuffer =
- syncScreenCapture.getBuffer();
- return screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
+ mWindowManager.captureDisplay(DEFAULT_DISPLAY, captureArgs, listener);
} catch (RemoteException re) {
re.rethrowAsRuntimeException();
} finally {
Binder.restoreCallingIdentity(identity);
}
- return null;
+
+ return true;
}
@Nullable
@Override
- public Bitmap takeSurfaceControlScreenshot(@NonNull SurfaceControl surfaceControl) {
+ public boolean takeSurfaceControlScreenshot(@NonNull SurfaceControl surfaceControl,
+ ScreenCapture.ScreenCaptureListener listener) {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
- ScreenCapture.ScreenshotHardwareBuffer captureBuffer;
final long identity = Binder.clearCallingIdentity();
try {
- captureBuffer = ScreenCapture.captureLayers(
+ ScreenCapture.LayerCaptureArgs args =
new ScreenCapture.LayerCaptureArgs.Builder(surfaceControl)
- .setChildrenOnly(false)
- .build());
+ .setChildrenOnly(false)
+ .build();
+ int status = ScreenCapture.captureLayers(args, listener);
+
+ if (status != 0) {
+ return false;
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
- if (captureBuffer == null) {
- return null;
- }
- return captureBuffer.asBitmap();
+ return true;
}
@Override