diff options
-rw-r--r-- | core/java/android/view/SurfaceControl.java | 26 | ||||
-rw-r--r-- | core/jni/android_view_SurfaceControl.cpp | 9 | ||||
-rw-r--r-- | core/res/res/values/config.xml | 3 | ||||
-rw-r--r-- | core/res/res/values/symbols.xml | 1 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/TaskSnapshotController.java | 23 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/TaskSnapshotLoader.java | 18 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/TaskSnapshotPersister.java | 12 |
7 files changed, 77 insertions, 15 deletions
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index b815c641ff25..3251127397b6 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -90,7 +90,8 @@ public final class SurfaceControl implements Parcelable { Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation, boolean captureSecureLayers); private static native ScreenshotGraphicBuffer nativeCaptureLayers(IBinder displayToken, - long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects); + long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects, + int format); private static native long nativeMirrorSurface(long mirrorOfObject); private static native long nativeCreateTransaction(); private static native long nativeGetNativeTransactionFinalizer(); @@ -1869,8 +1870,27 @@ public final class SurfaceControl implements Parcelable { */ public static ScreenshotGraphicBuffer captureLayers(SurfaceControl layer, Rect sourceCrop, float frameScale) { + return captureLayers(layer, sourceCrop, frameScale, PixelFormat.RGBA_8888); + } + + /** + * Captures a layer and its children and returns a {@link GraphicBuffer} with the content. + * + * @param layer The root layer to capture. + * @param sourceCrop The portion of the root surface to capture; caller may pass in 'new + * Rect()' or null if no cropping is desired. + * @param frameScale The desired scale of the returned buffer; the raw + * screen will be scaled up/down. + * @param format The desired pixel format of the returned buffer. + * + * @return Returns a GraphicBuffer that contains the layer capture. + * @hide + */ + public static ScreenshotGraphicBuffer captureLayers(SurfaceControl layer, Rect sourceCrop, + float frameScale, int format) { final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); - return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale, null); + return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale, null, + format); } /** @@ -1885,7 +1905,7 @@ public final class SurfaceControl implements Parcelable { nativeExcludeObjects[i] = exclude[i].mNativeObject; } return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale, - nativeExcludeObjects); + nativeExcludeObjects, PixelFormat.RGBA_8888); } /** diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index c807e90d5ad4..f8a2744fdcb0 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -274,7 +274,7 @@ static jobject nativeScreenshot(JNIEnv* env, jclass clazz, static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject displayTokenObj, jlong layerObject, jobject sourceCropObj, jfloat frameScale, - jlongArray excludeObjectArray) { + jlongArray excludeObjectArray, jint format) { auto layer = reinterpret_cast<SurfaceControl *>(layerObject); if (layer == NULL) { @@ -311,8 +311,9 @@ static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject displayTok dataspace = pickDataspaceFromColorMode(colorMode); } status_t res = ScreenshotClient::captureChildLayers(layer->getHandle(), dataspace, - ui::PixelFormat::RGBA_8888, sourceCrop, - excludeHandles, frameScale, &buffer); + static_cast<ui::PixelFormat>(format), + sourceCrop, excludeHandles, frameScale, + &buffer); if (res != NO_ERROR) { return NULL; } @@ -1386,7 +1387,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeScreenshot }, {"nativeCaptureLayers", "(Landroid/os/IBinder;JLandroid/graphics/Rect;" - "F[J)" + "F[JI)" "Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;", (void*)nativeCaptureLayers }, {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V", diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index efa42e5735e1..cb0b5993c420 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2652,6 +2652,9 @@ <!-- The amount to scale fullscreen snapshots for Overview and snapshot starting windows. --> <item name="config_fullTaskSnapshotScale" format="float" type="dimen">1.0</item> + <!-- Feature flag to store TaskSnapshot in 16 bit pixel format to save memory. --> + <bool name="config_use16BitTaskSnapshotPixelFormat">false</bool> + <!-- Determines whether recent tasks are provided to the user. Default device has recents property. If this is false, then the following recents config flags are ignored. --> <bool name="config_hasRecents">true</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 91a8ba4ca3d2..28809daeaad8 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -356,6 +356,7 @@ <java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/> <java-symbol type="bool" name="config_disableUsbPermissionDialogs"/> <java-symbol type="dimen" name="config_fullTaskSnapshotScale" /> + <java-symbol type="bool" name="config_use16BitTaskSnapshotPixelFormat" /> <java-symbol type="bool" name="config_lowRamTaskSnapshotsAndRecents" /> <java-symbol type="bool" name="config_hasRecents" /> <java-symbol type="string" name="config_recentsComponentName" /> diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 0d4ec652f3bb..35f61a88522b 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + import static com.android.server.wm.TaskSnapshotPersister.DISABLE_FULL_SIZED_BITMAPS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -248,6 +250,12 @@ class TaskSnapshotController { @Nullable SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task, float scaleFraction) { + return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888); + } + + @Nullable + SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task, + float scaleFraction, int pixelFormat) { if (task.getSurfaceControl() == null) { if (DEBUG_SCREENSHOT) { Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + task); @@ -258,7 +266,7 @@ class TaskSnapshotController { mTmpRect.offsetTo(0, 0); final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer = SurfaceControl.captureLayers( - task.getSurfaceControl(), mTmpRect, scaleFraction); + task.getSurfaceControl(), mTmpRect, scaleFraction, pixelFormat); final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer() : null; if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) { @@ -299,8 +307,14 @@ class TaskSnapshotController { Slog.w(TAG_WM, "Failed to take screenshot. No main window for " + task); return null; } + final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE; + final boolean isShowWallpaper = (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) != 0; + final int pixelFormat = mPersister.use16BitFormat() && activity.fillsParent() + && !(isWindowTranslucent && isShowWallpaper) + ? PixelFormat.RGB_565 + : PixelFormat.RGBA_8888; final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer = - createTaskSnapshot(task, scaleFraction); + createTaskSnapshot(task, scaleFraction, pixelFormat); if (screenshotBuffer == null) { if (DEBUG_SCREENSHOT) { @@ -308,7 +322,8 @@ class TaskSnapshotController { } return null; } - final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE; + final boolean isTranslucent = PixelFormat.formatHasAlpha(pixelFormat) + && (!activity.fillsParent() || isWindowTranslucent); return new TaskSnapshot( System.currentTimeMillis() /* id */, activity.mActivityComponent, screenshotBuffer.getGraphicBuffer(), @@ -316,7 +331,7 @@ class TaskSnapshotController { activity.getTask().getConfiguration().orientation, getInsets(mainWindow), isLowRamDevice /* reduced */, scaleFraction /* scale */, true /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task), - !activity.fillsParent() || isWindowTranslucent); + isTranslucent); } private boolean shouldDisableSnapshots() { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java index 696e1c3a2602..22c1ea59d176 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java @@ -75,25 +75,35 @@ class TaskSnapshotLoader { final byte[] bytes = Files.readAllBytes(protoFile.toPath()); final TaskSnapshotProto proto = TaskSnapshotProto.parseFrom(bytes); final Options options = new Options(); - options.inPreferredConfig = Config.HARDWARE; + options.inPreferredConfig = mPersister.use16BitFormat() && !proto.isTranslucent + ? Config.RGB_565 + : Config.ARGB_8888; final Bitmap bitmap = BitmapFactory.decodeFile(bitmapFile.getPath(), options); if (bitmap == null) { Slog.w(TAG, "Failed to load bitmap: " + bitmapFile.getPath()); return null; } - final GraphicBuffer buffer = bitmap.createGraphicBufferHandle(); + + final Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false); + bitmap.recycle(); + if (hwBitmap == null) { + Slog.w(TAG, "Failed to create hardware bitmap: " + bitmapFile.getPath()); + return null; + } + final GraphicBuffer buffer = hwBitmap.createGraphicBufferHandle(); if (buffer == null) { Slog.w(TAG, "Failed to retrieve gralloc buffer for bitmap: " + bitmapFile.getPath()); return null; } + final ComponentName topActivityComponent = ComponentName.unflattenFromString( proto.topActivityComponent); // For legacy snapshots, restore the scale based on the reduced resolution state final float legacyScale = reducedResolution ? mPersister.getReducedScale() : 1f; final float scale = Float.compare(proto.scale, 0f) != 0 ? proto.scale : legacyScale; - return new TaskSnapshot(proto.id, topActivityComponent, buffer, bitmap.getColorSpace(), - proto.orientation, + return new TaskSnapshot(proto.id, topActivityComponent, buffer, + hwBitmap.getColorSpace(), proto.orientation, new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom), reducedResolution, scale, proto.isRealSnapshot, proto.windowingMode, proto.systemUiVisibility, proto.isTranslucent); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java index a156f5c240a8..59155907823b 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java @@ -74,6 +74,7 @@ class TaskSnapshotPersister { private final Object mLock = new Object(); private final DirectoryResolver mDirectoryResolver; private final float mReducedScale; + private final boolean mUse16BitFormat; /** * The list of ids of the tasks that have been persisted since {@link #removeObsoleteFiles} was @@ -92,6 +93,8 @@ class TaskSnapshotPersister { mReducedScale = ActivityManager.isLowRamDeviceStatic() ? LOW_RAM_REDUCED_SCALE : REDUCED_SCALE; } + mUse16BitFormat = service.mContext.getResources().getBoolean( + com.android.internal.R.bool.config_use16BitTaskSnapshotPixelFormat); } /** @@ -164,6 +167,15 @@ class TaskSnapshotPersister { return mReducedScale; } + /** + * Return if task snapshots are stored in 16 bit pixel format. + * + * @return true if task snapshots are stored in 16 bit pixel format. + */ + boolean use16BitFormat() { + return mUse16BitFormat; + } + @TestApi void waitForQueueEmpty() { while (true) { |