Use screenshotToBuffer
To avoid copying buffers. Yay!
Test: Open app, go to recents, make sure screenshot is showing.
Bug: 31339431
Change-Id: I62736b8ba9ca45155d602286de8280304160bbd6
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 66267bd..73bf3dc 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -94,6 +94,7 @@
import android.app.ActivityManager.StackId;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -2105,12 +2106,55 @@
* @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot
* @param includeDecor whether to include window decors, like the status or navigation bar
* background of the window
- * @param toAshmem whether to convert the resulting bitmap to ashmem; this should be set to
- * true if the Bitmap is sent over binder, and false otherwise
*/
Bitmap screenshotApplications(IBinder appToken, int width, int height,
boolean includeFullDisplay, float frameScale, Bitmap.Config config,
- boolean wallpaperOnly, boolean includeDecor, boolean toAshmem) {
+ boolean wallpaperOnly, boolean includeDecor) {
+ Bitmap bitmap = screenshotApplications(appToken, width, height, includeFullDisplay,
+ frameScale, wallpaperOnly, includeDecor, SurfaceControl::screenshot);
+
+ if (DEBUG_SCREENSHOT) {
+ // TEST IF IT's ALL BLACK
+ int[] buffer = new int[bitmap.getWidth() * bitmap.getHeight()];
+ bitmap.getPixels(buffer, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(),
+ bitmap.getHeight());
+ boolean allBlack = true;
+ final int firstColor = buffer[0];
+ for (int i = 0; i < buffer.length; i++) {
+ if (buffer[i] != firstColor) {
+ allBlack = false;
+ break;
+ }
+ }
+ if (allBlack) {
+ final WindowState appWin = mScreenshotApplicationState.appWin;
+ final int maxLayer = mScreenshotApplicationState.maxLayer;
+ final int minLayer = mScreenshotApplicationState.minLayer;
+ Slog.i(TAG_WM, "Screenshot " + appWin + " was monochrome(" +
+ Integer.toHexString(firstColor) + ")! mSurfaceLayer=" +
+ (appWin != null ?
+ appWin.mWinAnimator.mSurfaceController.getLayer() : "null") +
+ " minLayer=" + minLayer + " maxLayer=" + maxLayer);
+ }
+ }
+
+ // Create a copy of the screenshot that is immutable and backed in ashmem.
+ // This greatly reduces the overhead of passing the bitmap between processes.
+ Bitmap ret = bitmap.createAshmemBitmap(config);
+ bitmap.recycle();
+ return ret;
+ }
+
+ GraphicBuffer screenshotApplicationsToBuffer(IBinder appToken, int width, int height,
+ boolean includeFullDisplay, float frameScale, boolean wallpaperOnly,
+ boolean includeDecor) {
+ return screenshotApplications(appToken, width, height, includeFullDisplay, frameScale,
+ wallpaperOnly, includeDecor, SurfaceControl::screenshotToBuffer);
+ }
+
+ private <E> E screenshotApplications(IBinder appToken, int width, int height,
+ boolean includeFullDisplay, float frameScale, boolean wallpaperOnly,
+ boolean includeDecor, Screenshoter<E> screenshoter) {
int dw = mDisplayInfo.logicalWidth;
int dh = mDisplayInfo.logicalHeight;
if (dw == 0 || dh == 0) {
@@ -2119,7 +2163,7 @@
return null;
}
- Bitmap bm = null;
+ E bitmap;
mScreenshotApplicationState.reset(appToken == null && !wallpaperOnly);
final Rect frame = new Rect();
@@ -2327,48 +2371,15 @@
SurfaceControl.openTransaction();
SurfaceControl.closeTransactionSync();
- bm = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer,
+ bitmap = screenshoter.screenshot(crop, width, height, minLayer, maxLayer,
inRotation, rot);
- if (bm == null) {
+ if (bitmap == null) {
Slog.w(TAG_WM, "Screenshot failure taking screenshot for (" + dw + "x" + dh
+ ") to layer " + maxLayer);
return null;
}
}
-
- if (DEBUG_SCREENSHOT) {
- // TEST IF IT's ALL BLACK
- int[] buffer = new int[bm.getWidth() * bm.getHeight()];
- bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
- boolean allBlack = true;
- final int firstColor = buffer[0];
- for (int i = 0; i < buffer.length; i++) {
- if (buffer[i] != firstColor) {
- allBlack = false;
- break;
- }
- }
- if (allBlack) {
- final WindowState appWin = mScreenshotApplicationState.appWin;
- final int maxLayer = mScreenshotApplicationState.maxLayer;
- final int minLayer = mScreenshotApplicationState.minLayer;
- Slog.i(TAG_WM, "Screenshot " + appWin + " was monochrome(" +
- Integer.toHexString(firstColor) + ")! mSurfaceLayer=" +
- (appWin != null ?
- appWin.mWinAnimator.mSurfaceController.getLayer() : "null") +
- " minLayer=" + minLayer + " maxLayer=" + maxLayer);
- }
- }
-
- // Create a copy of the screenshot that is immutable and backed in ashmem.
- // This greatly reduces the overhead of passing the bitmap between processes.
- if (toAshmem) {
- Bitmap ret = bm.createAshmemBitmap(config);
- bm.recycle();
- return ret;
- } else {
- return bm;
- }
+ return bitmap;
}
// TODO: Can this use createRotationMatrix()?
@@ -2721,4 +2732,13 @@
return mName;
}
}
+
+ /**
+ * Interface to screenshot into various types, i.e. {@link Bitmap} and {@link GraphicBuffer}.
+ */
+ @FunctionalInterface
+ private interface Screenshoter<E> {
+ E screenshot(Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
+ boolean useIdentityTransform, int rotation);
+ }
}