Merge "Fix screenshot buffer leaks" into udc-qpr-dev

This commit is contained in:
Jeimy Santiago Morales
2023-06-28 14:20:55 +00:00
committed by Android (Google) Code Review
3 changed files with 59 additions and 36 deletions

View File

@@ -24,6 +24,8 @@ import android.view.SurfaceControl;
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 @@ interface IUiAutomationConnection {
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();

View File

@@ -37,6 +37,7 @@ import android.graphics.Bitmap;
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.AccessibilityNodeInfo;
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;
@@ -1160,17 +1163,12 @@ public final class UiAutomation {
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) {
@@ -1178,10 +1176,23 @@ public final class UiAutomation {
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;
}
/**
@@ -1218,12 +1229,27 @@ public final class UiAutomation {
// 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;
}
/**

View File

@@ -25,7 +25,6 @@ import android.annotation.Nullable;
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.AccessibilityEvent;
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 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
}
@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