Merge "Fix screenshot buffer leaks" into udc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
3a4bf0e510
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user