Loading core/java/android/window/flags/windowing_frontend.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -431,3 +431,14 @@ flag { bug: "277292497" is_fixed_read_only: true } flag { name: "exclude_drawing_app_theme_snapshot_from_lock" namespace: "windowing_frontend" description: "Do not hold wm lock when drawing app theme snapshot." is_fixed_read_only: true bug: "373502791" metadata { purpose: PURPOSE_BUGFIX } } No newline at end of file services/core/java/com/android/server/wm/AbsAppSnapshotController.java +119 −38 Original line number Diff line number Diff line Loading @@ -51,8 +51,11 @@ import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.server.wm.utils.InsetUtils; import com.android.window.flags.Flags; import java.io.PrintWriter; import java.util.function.Consumer; import java.util.function.Supplier; /** * Base class for a Snapshot controller Loading Loading @@ -148,43 +151,60 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, protected abstract Rect getLetterboxInsets(ActivityRecord topActivity); /** * This is different than {@link #recordSnapshotInner(TYPE)} because it doesn't store * the snapshot to the cache and returns the TaskSnapshot immediately. * * This is only used for testing so the snapshot content can be verified. * This is different than {@link #recordSnapshotInner(TYPE, boolean, Consumer)} because it * doesn't store the snapshot to the cache and returns the TaskSnapshot immediately. */ @VisibleForTesting TaskSnapshot captureSnapshot(TYPE source) { final TaskSnapshot snapshot; SnapshotSupplier captureSnapshot(TYPE source, boolean allowAppTheme) { final SnapshotSupplier supplier = new SnapshotSupplier(); switch (getSnapshotMode(source)) { case SNAPSHOT_MODE_NONE: return null; case SNAPSHOT_MODE_APP_THEME: snapshot = drawAppThemeSnapshot(source); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "drawAppThemeSnapshot"); if (Flags.excludeDrawingAppThemeSnapshotFromLock()) { if (allowAppTheme) { supplier.setSupplier(drawAppThemeSnapshot(source)); } } else { final Supplier<TaskSnapshot> original = drawAppThemeSnapshot(source); final TaskSnapshot snapshot = original != null ? original.get() : null; supplier.setSnapshot(snapshot); } Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); break; case SNAPSHOT_MODE_REAL: snapshot = snapshot(source); supplier.setSnapshot(snapshot(source)); break; default: snapshot = null; break; } return snapshot; return supplier; } final TaskSnapshot recordSnapshotInner(TYPE source) { /** * @param allowAppTheme If true, allows to draw app theme snapshot when it's not allowed to take * a real screenshot, but create a fake representation of the app. * @param inLockConsumer Extra task to do in WM lock when first get the snapshot object. */ final SnapshotSupplier recordSnapshotInner(TYPE source, boolean allowAppTheme, @Nullable Consumer<TaskSnapshot> inLockConsumer) { if (shouldDisableSnapshots()) { return null; } final TaskSnapshot snapshot = captureSnapshot(source); if (snapshot == null) { return null; final SnapshotSupplier supplier = captureSnapshot(source, allowAppTheme); supplier.setConsumer(t -> { synchronized (mService.mGlobalLock) { if (!source.isAttached()) { return; } mCache.putSnapshot(source, snapshot); return snapshot; mCache.putSnapshot(source, t); if (inLockConsumer != null) { inLockConsumer.accept(t); } } }); return supplier; } @VisibleForTesting int getSnapshotMode(TYPE source) { final int type = source.getActivityType(); if (type == ACTIVITY_TYPE_RECENTS || type == ACTIVITY_TYPE_DREAM) { Loading Loading @@ -400,7 +420,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, * If we are not allowed to take a real screenshot, this attempts to represent the app as best * as possible by using the theme's window background. */ private TaskSnapshot drawAppThemeSnapshot(TYPE source) { private Supplier<TaskSnapshot> drawAppThemeSnapshot(TYPE source) { final ActivityRecord topActivity = getTopActivity(source); if (topActivity == null) { return null; Loading Loading @@ -432,26 +452,46 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, decorPainter.setInsets(systemBarInsets); decorPainter.drawDecors(c /* statusBarExcludeFrame */, null /* alreadyDrawFrame */); node.end(c); final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height); if (hwBitmap == null) { return null; } final Rect contentInsets = new Rect(systemBarInsets); final Rect letterboxInsets = getLetterboxInsets(topActivity); InsetUtils.addInsets(contentInsets, letterboxInsets); // Note, the app theme snapshot is never translucent because we enforce a non-translucent // color above final TaskSnapshot taskSnapshot = new TaskSnapshot( System.currentTimeMillis() /* id */, SystemClock.elapsedRealtimeNanos() /* captureTime */, topActivity.mActivityComponent, hwBitmap.getHardwareBuffer(), hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation, mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight), contentInsets, letterboxInsets, false /* isLowResolution */, false /* isRealSnapshot */, source.getWindowingMode(), attrs.insetsFlags.appearance, false /* isTranslucent */, false /* hasImeSurface */, topActivity.getConfiguration().uiMode /* uiMode */); return validateSnapshot(taskSnapshot); final TaskSnapshot.Builder builder = new TaskSnapshot.Builder(); builder.setIsRealSnapshot(false); builder.setId(System.currentTimeMillis()); builder.setContentInsets(contentInsets); builder.setLetterboxInsets(letterboxInsets); builder.setTopActivityComponent(topActivity.mActivityComponent); // Note, the app theme snapshot is never translucent because we enforce a // non-translucent color above. builder.setIsTranslucent(false); builder.setWindowingMode(source.getWindowingMode()); builder.setAppearance(attrs.insetsFlags.appearance); builder.setUiMode(topActivity.getConfiguration().uiMode); builder.setRotation(mainWindow.getWindowConfiguration().getRotation()); builder.setOrientation(mainWindow.getConfiguration().orientation); builder.setTaskSize(new Point(taskWidth, taskHeight)); builder.setCaptureTime(SystemClock.elapsedRealtimeNanos()); return () -> { try { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "drawAppThemeSnapshot_acquire"); // Do not hold WM lock when calling to render thread. final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height); if (hwBitmap == null) { return null; } builder.setSnapshot(hwBitmap.getHardwareBuffer()); builder.setColorSpace(hwBitmap.getColorSpace()); return validateSnapshot(builder.build()); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } }; } static Rect getSystemBarInsets(Rect frame, InsetsState state) { Loading Loading @@ -482,4 +522,45 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, pw.println(prefix + "mSnapshotEnabled=" + mSnapshotEnabled); mCache.dump(pw, prefix); } static class SnapshotSupplier implements Supplier<TaskSnapshot> { private TaskSnapshot mSnapshot; private boolean mHasSet; private Consumer<TaskSnapshot> mConsumer; private Supplier<TaskSnapshot> mSupplier; /** Callback when the snapshot is get for the first time. */ void setConsumer(@NonNull Consumer<TaskSnapshot> consumer) { mConsumer = consumer; } void setSupplier(@NonNull Supplier<TaskSnapshot> createSupplier) { mSupplier = createSupplier; } void setSnapshot(TaskSnapshot snapshot) { mSnapshot = snapshot; } void handleSnapshot() { if (mHasSet) { return; } mHasSet = true; if (mSnapshot == null) { mSnapshot = mSupplier != null ? mSupplier.get() : null; } if (mConsumer != null && mSnapshot != null) { mConsumer.accept(mSnapshot); } } @Override @Nullable public TaskSnapshot get() { handleSnapshot(); return mSnapshot; } } } services/core/java/com/android/server/wm/ActivitySnapshotController.java +4 −1 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; import java.util.function.Supplier; /** * When an app token becomes invisible, we take a snapshot (bitmap) and put it into our cache. Loading Loading @@ -355,7 +356,9 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord final int[] mixedCode = new int[size]; if (size == 1) { final ActivityRecord singleActivity = activity.get(0); final TaskSnapshot snapshot = recordSnapshotInner(singleActivity); final Supplier<TaskSnapshot> supplier = recordSnapshotInner(singleActivity, false /* allowAppTheme */, null /* inLockConsumer */); final TaskSnapshot snapshot = supplier != null ? supplier.get() : null; if (snapshot != null) { mixedCode[0] = getSystemHashCode(singleActivity); addUserSavedFile(singleActivity.mUserId, snapshot, mixedCode); Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +6 −1 Original line number Diff line number Diff line Loading @@ -314,6 +314,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Supplier; /** * System service for managing activities and their containers (task, displays,... ). Loading Loading @@ -4038,6 +4039,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mAmInternal.enforceCallingPermission(READ_FRAME_BUFFER, "takeTaskSnapshot()"); final long ident = Binder.clearCallingIdentity(); try { final Supplier<TaskSnapshot> supplier; synchronized (mGlobalLock) { final Task task = mRootWindowContainer.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS); Loading @@ -4050,11 +4052,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // be retrieved by recents. While if updateCache is false, the real snapshot will // always be taken and the snapshot won't be put into SnapshotPersister. if (updateCache) { return mWindowManager.mTaskSnapshotController.recordSnapshot(task); supplier = mWindowManager.mTaskSnapshotController .getRecordSnapshotSupplier(task); } else { return mWindowManager.mTaskSnapshotController.snapshot(task); } } return supplier != null ? supplier.get() : null; } finally { Binder.restoreCallingIdentity(ident); } Loading Loading @@ -6403,6 +6407,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public boolean shuttingDown(boolean booted, int timeout) { mShuttingDown = true; mWindowManager.mSnapshotController.mTaskSnapshotController.prepareShutdown(); synchronized (mGlobalLock) { mRootWindowContainer.prepareForShutdown(); updateEventDispatchingLocked(booted); Loading services/core/java/com/android/server/wm/RootWindowContainer.java +0 −1 Original line number Diff line number Diff line Loading @@ -2926,7 +2926,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } void prepareForShutdown() { mWindowManager.mSnapshotController.mTaskSnapshotController.prepareShutdown(); for (int i = 0; i < getChildCount(); i++) { createSleepToken("shutdown", getChildAt(i).mDisplayId); } Loading Loading
core/java/android/window/flags/windowing_frontend.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -431,3 +431,14 @@ flag { bug: "277292497" is_fixed_read_only: true } flag { name: "exclude_drawing_app_theme_snapshot_from_lock" namespace: "windowing_frontend" description: "Do not hold wm lock when drawing app theme snapshot." is_fixed_read_only: true bug: "373502791" metadata { purpose: PURPOSE_BUGFIX } } No newline at end of file
services/core/java/com/android/server/wm/AbsAppSnapshotController.java +119 −38 Original line number Diff line number Diff line Loading @@ -51,8 +51,11 @@ import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.server.wm.utils.InsetUtils; import com.android.window.flags.Flags; import java.io.PrintWriter; import java.util.function.Consumer; import java.util.function.Supplier; /** * Base class for a Snapshot controller Loading Loading @@ -148,43 +151,60 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, protected abstract Rect getLetterboxInsets(ActivityRecord topActivity); /** * This is different than {@link #recordSnapshotInner(TYPE)} because it doesn't store * the snapshot to the cache and returns the TaskSnapshot immediately. * * This is only used for testing so the snapshot content can be verified. * This is different than {@link #recordSnapshotInner(TYPE, boolean, Consumer)} because it * doesn't store the snapshot to the cache and returns the TaskSnapshot immediately. */ @VisibleForTesting TaskSnapshot captureSnapshot(TYPE source) { final TaskSnapshot snapshot; SnapshotSupplier captureSnapshot(TYPE source, boolean allowAppTheme) { final SnapshotSupplier supplier = new SnapshotSupplier(); switch (getSnapshotMode(source)) { case SNAPSHOT_MODE_NONE: return null; case SNAPSHOT_MODE_APP_THEME: snapshot = drawAppThemeSnapshot(source); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "drawAppThemeSnapshot"); if (Flags.excludeDrawingAppThemeSnapshotFromLock()) { if (allowAppTheme) { supplier.setSupplier(drawAppThemeSnapshot(source)); } } else { final Supplier<TaskSnapshot> original = drawAppThemeSnapshot(source); final TaskSnapshot snapshot = original != null ? original.get() : null; supplier.setSnapshot(snapshot); } Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); break; case SNAPSHOT_MODE_REAL: snapshot = snapshot(source); supplier.setSnapshot(snapshot(source)); break; default: snapshot = null; break; } return snapshot; return supplier; } final TaskSnapshot recordSnapshotInner(TYPE source) { /** * @param allowAppTheme If true, allows to draw app theme snapshot when it's not allowed to take * a real screenshot, but create a fake representation of the app. * @param inLockConsumer Extra task to do in WM lock when first get the snapshot object. */ final SnapshotSupplier recordSnapshotInner(TYPE source, boolean allowAppTheme, @Nullable Consumer<TaskSnapshot> inLockConsumer) { if (shouldDisableSnapshots()) { return null; } final TaskSnapshot snapshot = captureSnapshot(source); if (snapshot == null) { return null; final SnapshotSupplier supplier = captureSnapshot(source, allowAppTheme); supplier.setConsumer(t -> { synchronized (mService.mGlobalLock) { if (!source.isAttached()) { return; } mCache.putSnapshot(source, snapshot); return snapshot; mCache.putSnapshot(source, t); if (inLockConsumer != null) { inLockConsumer.accept(t); } } }); return supplier; } @VisibleForTesting int getSnapshotMode(TYPE source) { final int type = source.getActivityType(); if (type == ACTIVITY_TYPE_RECENTS || type == ACTIVITY_TYPE_DREAM) { Loading Loading @@ -400,7 +420,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, * If we are not allowed to take a real screenshot, this attempts to represent the app as best * as possible by using the theme's window background. */ private TaskSnapshot drawAppThemeSnapshot(TYPE source) { private Supplier<TaskSnapshot> drawAppThemeSnapshot(TYPE source) { final ActivityRecord topActivity = getTopActivity(source); if (topActivity == null) { return null; Loading Loading @@ -432,26 +452,46 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, decorPainter.setInsets(systemBarInsets); decorPainter.drawDecors(c /* statusBarExcludeFrame */, null /* alreadyDrawFrame */); node.end(c); final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height); if (hwBitmap == null) { return null; } final Rect contentInsets = new Rect(systemBarInsets); final Rect letterboxInsets = getLetterboxInsets(topActivity); InsetUtils.addInsets(contentInsets, letterboxInsets); // Note, the app theme snapshot is never translucent because we enforce a non-translucent // color above final TaskSnapshot taskSnapshot = new TaskSnapshot( System.currentTimeMillis() /* id */, SystemClock.elapsedRealtimeNanos() /* captureTime */, topActivity.mActivityComponent, hwBitmap.getHardwareBuffer(), hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation, mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight), contentInsets, letterboxInsets, false /* isLowResolution */, false /* isRealSnapshot */, source.getWindowingMode(), attrs.insetsFlags.appearance, false /* isTranslucent */, false /* hasImeSurface */, topActivity.getConfiguration().uiMode /* uiMode */); return validateSnapshot(taskSnapshot); final TaskSnapshot.Builder builder = new TaskSnapshot.Builder(); builder.setIsRealSnapshot(false); builder.setId(System.currentTimeMillis()); builder.setContentInsets(contentInsets); builder.setLetterboxInsets(letterboxInsets); builder.setTopActivityComponent(topActivity.mActivityComponent); // Note, the app theme snapshot is never translucent because we enforce a // non-translucent color above. builder.setIsTranslucent(false); builder.setWindowingMode(source.getWindowingMode()); builder.setAppearance(attrs.insetsFlags.appearance); builder.setUiMode(topActivity.getConfiguration().uiMode); builder.setRotation(mainWindow.getWindowConfiguration().getRotation()); builder.setOrientation(mainWindow.getConfiguration().orientation); builder.setTaskSize(new Point(taskWidth, taskHeight)); builder.setCaptureTime(SystemClock.elapsedRealtimeNanos()); return () -> { try { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "drawAppThemeSnapshot_acquire"); // Do not hold WM lock when calling to render thread. final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height); if (hwBitmap == null) { return null; } builder.setSnapshot(hwBitmap.getHardwareBuffer()); builder.setColorSpace(hwBitmap.getColorSpace()); return validateSnapshot(builder.build()); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } }; } static Rect getSystemBarInsets(Rect frame, InsetsState state) { Loading Loading @@ -482,4 +522,45 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, pw.println(prefix + "mSnapshotEnabled=" + mSnapshotEnabled); mCache.dump(pw, prefix); } static class SnapshotSupplier implements Supplier<TaskSnapshot> { private TaskSnapshot mSnapshot; private boolean mHasSet; private Consumer<TaskSnapshot> mConsumer; private Supplier<TaskSnapshot> mSupplier; /** Callback when the snapshot is get for the first time. */ void setConsumer(@NonNull Consumer<TaskSnapshot> consumer) { mConsumer = consumer; } void setSupplier(@NonNull Supplier<TaskSnapshot> createSupplier) { mSupplier = createSupplier; } void setSnapshot(TaskSnapshot snapshot) { mSnapshot = snapshot; } void handleSnapshot() { if (mHasSet) { return; } mHasSet = true; if (mSnapshot == null) { mSnapshot = mSupplier != null ? mSupplier.get() : null; } if (mConsumer != null && mSnapshot != null) { mConsumer.accept(mSnapshot); } } @Override @Nullable public TaskSnapshot get() { handleSnapshot(); return mSnapshot; } } }
services/core/java/com/android/server/wm/ActivitySnapshotController.java +4 −1 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; import java.util.function.Supplier; /** * When an app token becomes invisible, we take a snapshot (bitmap) and put it into our cache. Loading Loading @@ -355,7 +356,9 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord final int[] mixedCode = new int[size]; if (size == 1) { final ActivityRecord singleActivity = activity.get(0); final TaskSnapshot snapshot = recordSnapshotInner(singleActivity); final Supplier<TaskSnapshot> supplier = recordSnapshotInner(singleActivity, false /* allowAppTheme */, null /* inLockConsumer */); final TaskSnapshot snapshot = supplier != null ? supplier.get() : null; if (snapshot != null) { mixedCode[0] = getSystemHashCode(singleActivity); addUserSavedFile(singleActivity.mUserId, snapshot, mixedCode); Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +6 −1 Original line number Diff line number Diff line Loading @@ -314,6 +314,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Supplier; /** * System service for managing activities and their containers (task, displays,... ). Loading Loading @@ -4038,6 +4039,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mAmInternal.enforceCallingPermission(READ_FRAME_BUFFER, "takeTaskSnapshot()"); final long ident = Binder.clearCallingIdentity(); try { final Supplier<TaskSnapshot> supplier; synchronized (mGlobalLock) { final Task task = mRootWindowContainer.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS); Loading @@ -4050,11 +4052,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // be retrieved by recents. While if updateCache is false, the real snapshot will // always be taken and the snapshot won't be put into SnapshotPersister. if (updateCache) { return mWindowManager.mTaskSnapshotController.recordSnapshot(task); supplier = mWindowManager.mTaskSnapshotController .getRecordSnapshotSupplier(task); } else { return mWindowManager.mTaskSnapshotController.snapshot(task); } } return supplier != null ? supplier.get() : null; } finally { Binder.restoreCallingIdentity(ident); } Loading Loading @@ -6403,6 +6407,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public boolean shuttingDown(boolean booted, int timeout) { mShuttingDown = true; mWindowManager.mSnapshotController.mTaskSnapshotController.prepareShutdown(); synchronized (mGlobalLock) { mRootWindowContainer.prepareForShutdown(); updateEventDispatchingLocked(booted); Loading
services/core/java/com/android/server/wm/RootWindowContainer.java +0 −1 Original line number Diff line number Diff line Loading @@ -2926,7 +2926,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } void prepareForShutdown() { mWindowManager.mSnapshotController.mTaskSnapshotController.prepareShutdown(); for (int i = 0; i < getChildCount(); i++) { createSleepToken("shutdown", getChildAt(i).mDisplayId); } Loading