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.WindowContentFrameStats;
import android.view.WindowAnimationFrameStats; import android.view.WindowAnimationFrameStats;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.window.ScreenCapture.ScreenCaptureListener;
import android.window.ScreenCapture.LayerCaptureArgs;
import java.util.List; import java.util.List;
@@ -43,8 +45,8 @@ interface IUiAutomationConnection {
void injectInputEventToInputFilter(in InputEvent event); void injectInputEventToInputFilter(in InputEvent event);
void syncInputTransactions(boolean waitForAnimations); void syncInputTransactions(boolean waitForAnimations);
boolean setRotation(int rotation); boolean setRotation(int rotation);
Bitmap takeScreenshot(in Rect crop); boolean takeScreenshot(in Rect crop, in ScreenCaptureListener listener);
Bitmap takeSurfaceControlScreenshot(in SurfaceControl surfaceControl); boolean takeSurfaceControlScreenshot(in SurfaceControl surfaceControl, in ScreenCaptureListener listener);
boolean clearWindowContentFrameStats(int windowId); boolean clearWindowContentFrameStats(int windowId);
WindowContentFrameStats getWindowContentFrameStats(int windowId); WindowContentFrameStats getWindowContentFrameStats(int windowId);
void clearWindowAnimationFrameStats(); void clearWindowAnimationFrameStats();

View File

@@ -37,6 +37,7 @@ import android.graphics.Bitmap;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Region; import android.graphics.Region;
import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.DisplayManagerGlobal;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
@@ -71,6 +72,8 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityInteractionConnection;
import android.view.inputmethod.EditorInfo; 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.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
@@ -1160,17 +1163,12 @@ public final class UiAutomation {
Point displaySize = new Point(); Point displaySize = new Point();
display.getRealSize(displaySize); display.getRealSize(displaySize);
int rotation = display.getRotation();
// Take the screenshot // Take the screenshot
Bitmap screenShot = null; ScreenCapture.SynchronousScreenCaptureListener syncScreenCapture =
ScreenCapture.createSyncCaptureListener();
try { try {
// Calling out without a lock held. if (!mUiAutomationConnection.takeScreenshot(
screenShot = mUiAutomationConnection.takeScreenshot( new Rect(0, 0, displaySize.x, displaySize.y), syncScreenCapture)) {
new Rect(0, 0, displaySize.x, displaySize.y));
if (screenShot == null) {
Log.e(LOG_TAG, "mUiAutomationConnection.takeScreenshot() returned null for display "
+ mDisplayId);
return null; return null;
} }
} catch (RemoteException re) { } catch (RemoteException re) {
@@ -1178,10 +1176,23 @@ public final class UiAutomation {
return null; return null;
} }
// Optimization final ScreenshotHardwareBuffer screenshotBuffer =
screenShot.setHasAlpha(false); 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 // Apply a sync transaction to ensure SurfaceFlinger is flushed before capturing a
// screenshot. // screenshot.
new SurfaceControl.Transaction().apply(true); new SurfaceControl.Transaction().apply(true);
ScreenCapture.SynchronousScreenCaptureListener syncScreenCapture =
ScreenCapture.createSyncCaptureListener();
try { try {
return mUiAutomationConnection.takeSurfaceControlScreenshot(sc); if (!mUiAutomationConnection.takeSurfaceControlScreenshot(sc, syncScreenCapture)) {
return null;
}
} catch (RemoteException re) { } catch (RemoteException re) {
Log.e(LOG_TAG, "Error while taking screenshot!", re); Log.e(LOG_TAG, "Error while taking screenshot!", re);
return null; 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.annotation.UserIdInt;
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect; import android.graphics.Rect;
import android.hardware.input.InputManager; import android.hardware.input.InputManager;
import android.hardware.input.InputManagerGlobal; import android.hardware.input.InputManagerGlobal;
@@ -51,8 +50,6 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.IAccessibilityManager; import android.view.accessibility.IAccessibilityManager;
import android.window.ScreenCapture; import android.window.ScreenCapture;
import android.window.ScreenCapture.CaptureArgs; import android.window.ScreenCapture.CaptureArgs;
import android.window.ScreenCapture.ScreenshotHardwareBuffer;
import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import libcore.io.IoUtils; import libcore.io.IoUtils;
@@ -224,56 +221,54 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
} }
@Override @Override
public Bitmap takeScreenshot(Rect crop) { public boolean takeScreenshot(Rect crop, ScreenCapture.ScreenCaptureListener listener) {
synchronized (mLock) { synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked(); throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked(); throwIfShutdownLocked();
throwIfNotConnectedLocked(); throwIfNotConnectedLocked();
} }
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
final CaptureArgs captureArgs = new CaptureArgs.Builder<>() final CaptureArgs captureArgs = new CaptureArgs.Builder<>()
.setSourceCrop(crop) .setSourceCrop(crop)
.build(); .build();
SynchronousScreenCaptureListener syncScreenCapture = mWindowManager.captureDisplay(DEFAULT_DISPLAY, captureArgs, listener);
ScreenCapture.createSyncCaptureListener();
mWindowManager.captureDisplay(DEFAULT_DISPLAY, captureArgs,
syncScreenCapture);
final ScreenshotHardwareBuffer screenshotBuffer =
syncScreenCapture.getBuffer();
return screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
} catch (RemoteException re) { } catch (RemoteException re) {
re.rethrowAsRuntimeException(); re.rethrowAsRuntimeException();
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
} }
return null;
return true;
} }
@Nullable @Nullable
@Override @Override
public Bitmap takeSurfaceControlScreenshot(@NonNull SurfaceControl surfaceControl) { public boolean takeSurfaceControlScreenshot(@NonNull SurfaceControl surfaceControl,
ScreenCapture.ScreenCaptureListener listener) {
synchronized (mLock) { synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked(); throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked(); throwIfShutdownLocked();
throwIfNotConnectedLocked(); throwIfNotConnectedLocked();
} }
ScreenCapture.ScreenshotHardwareBuffer captureBuffer;
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
captureBuffer = ScreenCapture.captureLayers( ScreenCapture.LayerCaptureArgs args =
new ScreenCapture.LayerCaptureArgs.Builder(surfaceControl) new ScreenCapture.LayerCaptureArgs.Builder(surfaceControl)
.setChildrenOnly(false) .setChildrenOnly(false)
.build()); .build();
int status = ScreenCapture.captureLayers(args, listener);
if (status != 0) {
return false;
}
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
} }
if (captureBuffer == null) { return true;
return null;
}
return captureBuffer.asBitmap();
} }
@Override @Override