diff options
11 files changed, 90 insertions, 25 deletions
diff --git a/core/java/android/window/TaskSnapshot.java b/core/java/android/window/TaskSnapshot.java index b7bb6082296e..41b6d31661ce 100644 --- a/core/java/android/window/TaskSnapshot.java +++ b/core/java/android/window/TaskSnapshot.java @@ -28,6 +28,7 @@ import android.hardware.HardwareBuffer; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.os.SystemClock; import android.view.Surface; import android.view.WindowInsetsController; @@ -38,6 +39,9 @@ import android.view.WindowInsetsController; public class TaskSnapshot implements Parcelable { // Identifier of this snapshot private final long mId; + // The elapsed real time (in nanoseconds) when this snapshot was captured, not intended for use outside the + // process in which the snapshot was taken (ie. this is not parceled) + private final long mCaptureTime; // Top activity in task when snapshot was taken private final ComponentName mTopActivityComponent; private final HardwareBuffer mSnapshot; @@ -65,7 +69,7 @@ public class TaskSnapshot implements Parcelable { // Must be one of the named color spaces, otherwise, always use SRGB color space. private final ColorSpace mColorSpace; - public TaskSnapshot(long id, + public TaskSnapshot(long id, long captureTime, @NonNull ComponentName topActivityComponent, HardwareBuffer snapshot, @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize, Rect contentInsets, Rect letterboxInsets, boolean isLowResolution, @@ -73,6 +77,7 @@ public class TaskSnapshot implements Parcelable { @WindowInsetsController.Appearance int appearance, boolean isTranslucent, boolean hasImeSurface) { mId = id; + mCaptureTime = captureTime; mTopActivityComponent = topActivityComponent; mSnapshot = snapshot; mColorSpace = colorSpace.getId() < 0 @@ -92,6 +97,7 @@ public class TaskSnapshot implements Parcelable { private TaskSnapshot(Parcel source) { mId = source.readLong(); + mCaptureTime = SystemClock.elapsedRealtimeNanos(); mTopActivityComponent = ComponentName.readFromParcel(source); mSnapshot = source.readTypedObject(HardwareBuffer.CREATOR); int colorSpaceId = source.readInt(); @@ -119,6 +125,14 @@ public class TaskSnapshot implements Parcelable { } /** + * @return The elapsed real time (in nanoseconds) when this snapshot was captured. This time is + * only valid in the process where this snapshot was taken. + */ + public long getCaptureTime() { + return mCaptureTime; + } + + /** * @return The top activity component for the task at the point this snapshot was taken. */ public ComponentName getTopActivityComponent() { @@ -268,6 +282,7 @@ public class TaskSnapshot implements Parcelable { final int height = mSnapshot != null ? mSnapshot.getHeight() : 0; return "TaskSnapshot{" + " mId=" + mId + + " mCaptureTime=" + mCaptureTime + " mTopActivityComponent=" + mTopActivityComponent.flattenToShortString() + " mSnapshot=" + mSnapshot + " (" + width + "x" + height + ")" + " mColorSpace=" + mColorSpace.toString() @@ -296,6 +311,7 @@ public class TaskSnapshot implements Parcelable { /** Builder for a {@link TaskSnapshot} object */ public static final class Builder { private long mId; + private long mCaptureTime; private ComponentName mTopActivity; private HardwareBuffer mSnapshot; private ColorSpace mColorSpace; @@ -317,6 +333,11 @@ public class TaskSnapshot implements Parcelable { return this; } + public Builder setCaptureTime(long captureTime) { + mCaptureTime = captureTime; + return this; + } + public Builder setTopActivityComponent(ComponentName name) { mTopActivity = name; return this; @@ -400,6 +421,7 @@ public class TaskSnapshot implements Parcelable { public TaskSnapshot build() { return new TaskSnapshot( mId, + mCaptureTime, mTopActivity, mSnapshot, mColorSpace, diff --git a/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java index 281d677dccb0..6764ac85dcef 100644 --- a/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java +++ b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java @@ -88,6 +88,7 @@ public class SnapshotDrawerUtilsTest { 1, HardwareBuffer.USAGE_CPU_READ_RARELY); return new TaskSnapshot( System.currentTimeMillis(), + 0 /* captureTime */, new ComponentName("", ""), buffer, ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, Surface.ROTATION_0, taskSize, contentInsets, new Rect() /* letterboxInsets */, diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 4b4e7220cb29..e4defcfa359f 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1135,6 +1135,12 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, + "-1060529098": { + "message": " Skipping post-transition snapshot for task %d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" + }, "-1060365734": { "message": "Attempted to add QS dialog window with bad token %s. Aborting.", "level": "WARN", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index a9ad3c90949f..c2869592dbb6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -264,21 +264,18 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { void cancel(String reason) { // restoring (to-home = false) involves submitting more WM changes, so by default, use // toHome = true when canceling. - cancel(true /* toHome */, reason); + cancel(true /* toHome */, false /* withScreenshots */, reason); } - void cancel(boolean toHome, String reason) { + void cancel(boolean toHome, boolean withScreenshots, String reason) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.cancel: toHome=%b reason=%s", mInstanceId, toHome, reason); if (mListener != null) { - try { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, - "[%d] RecentsController.cancel: calling onAnimationCanceled", - mInstanceId); - mListener.onAnimationCanceled(null, null); - } catch (RemoteException e) { - Slog.e(TAG, "Error canceling recents animation", e); + if (withScreenshots) { + sendCancelWithSnapshots(); + } else { + sendCancel(null, null); } } if (mFinishCB != null) { @@ -300,24 +297,34 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { snapshots = new TaskSnapshot[mPausingTasks.size()]; try { for (int i = 0; i < mPausingTasks.size(); ++i) { + TaskState state = mPausingTasks.get(0); snapshots[i] = ActivityTaskManager.getService().takeTaskSnapshot( - mPausingTasks.get(0).mTaskInfo.taskId, false /* updateCache */); + state.mTaskInfo.taskId, true /* updateCache */); } } catch (RemoteException e) { taskIds = null; snapshots = null; } } + return sendCancel(taskIds, snapshots); + } + + /** + * Sends a cancel message to the recents animation. + */ + private boolean sendCancel(@Nullable int[] taskIds, + @Nullable TaskSnapshot[] taskSnapshots) { try { + final String cancelDetails = taskSnapshots != null ? " with snapshots" : ""; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, - "[%d] RecentsController.cancel: calling onAnimationCanceled with snapshots", - mInstanceId); - mListener.onAnimationCanceled(taskIds, snapshots); + "[%d] RecentsController.cancel: calling onAnimationCanceled %s", + mInstanceId, cancelDetails); + mListener.onAnimationCanceled(taskIds, taskSnapshots); + return true; } catch (RemoteException e) { Slog.e(TAG, "Error canceling recents animation", e); return false; } - return true; } void cleanUp() { @@ -519,7 +526,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { // Finish recents animation if the display is changed, so the default // transition handler can play the animation such as rotation effect. if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)) { - cancel(mWillFinishToHome, "display change"); + cancel(mWillFinishToHome, true /* withScreenshots */, "display change"); return; } // Don't consider order-only changes as changing apps. @@ -633,7 +640,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { + foundRecentsClosing); if (foundRecentsClosing) { mWillFinishToHome = false; - cancel(false /* toHome */, "didn't merge"); + cancel(false /* toHome */, false /* withScreenshots */, "didn't merge"); } return; } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java index 8115a5d4e89c..ee9f88663326 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java @@ -364,6 +364,7 @@ public class StartingSurfaceDrawerTests extends ShellTestCase { 1, HardwareBuffer.USAGE_CPU_READ_RARELY); return new TaskSnapshot( System.currentTimeMillis(), + 0 /* captureTime */, new ComponentName("", ""), buffer, ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, Surface.ROTATION_0, taskSize, contentInsets, new Rect() /* letterboxInsets */, diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java index 5c929a93bf12..bd07622ee5ca 100644 --- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java +++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java @@ -30,6 +30,7 @@ import android.graphics.RecordingCanvas; import android.graphics.Rect; import android.graphics.RenderNode; import android.hardware.HardwareBuffer; +import android.os.SystemClock; import android.os.Trace; import android.util.Pair; import android.util.Slog; @@ -213,6 +214,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, // Failed to acquire image. Has been logged. return null; } + builder.setCaptureTime(SystemClock.elapsedRealtimeNanos()); builder.setSnapshot(screenshotBuffer.getHardwareBuffer()); builder.setColorSpace(screenshotBuffer.getColorSpace()); return builder.build(); @@ -432,6 +434,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, // color above return new TaskSnapshot( System.currentTimeMillis() /* id */, + SystemClock.elapsedRealtimeNanos() /* captureTime */, topActivity.mActivityComponent, hwBitmap.getHardwareBuffer(), hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation, mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight), diff --git a/services/core/java/com/android/server/wm/AppSnapshotLoader.java b/services/core/java/com/android/server/wm/AppSnapshotLoader.java index 88c47526869f..ed65a2b2f8e6 100644 --- a/services/core/java/com/android/server/wm/AppSnapshotLoader.java +++ b/services/core/java/com/android/server/wm/AppSnapshotLoader.java @@ -28,6 +28,7 @@ import android.graphics.BitmapFactory.Options; import android.graphics.Point; import android.graphics.Rect; import android.hardware.HardwareBuffer; +import android.os.SystemClock; import android.util.Slog; import android.window.TaskSnapshot; @@ -195,8 +196,9 @@ class AppSnapshotLoader { taskSize = new Point(proto.taskWidth, proto.taskHeight); } - return new TaskSnapshot(proto.id, topActivityComponent, buffer, - hwBitmap.getColorSpace(), proto.orientation, proto.rotation, taskSize, + return new TaskSnapshot(proto.id, SystemClock.elapsedRealtimeNanos(), + topActivityComponent, buffer, hwBitmap.getColorSpace(), + proto.orientation, proto.rotation, taskSize, new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom), new Rect(proto.letterboxInsetLeft, proto.letterboxInsetTop, proto.letterboxInsetRight, proto.letterboxInsetBottom), diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 7e20b3bbe396..c747c09a6872 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -180,6 +180,18 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot } /** + * Returns the elapsed real time (in nanoseconds) at which a snapshot for the given task was + * last taken, or -1 if no such snapshot exists for that task. + */ + long getSnapshotCaptureTime(int taskId) { + final TaskSnapshot snapshot = mCache.getSnapshot(taskId); + if (snapshot != null) { + return snapshot.getCaptureTime(); + } + return -1; + } + + /** * @see WindowManagerInternal#clearSnapshotCache */ public void clearSnapshotCache() { diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 0ce794fdb2ba..663db861b79e 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1086,12 +1086,23 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (commitVisibility) { ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Commit activity becoming invisible: %s", ar); + final SnapshotController snapController = mController.mSnapshotController; if (mTransientLaunches != null && !task.isVisibleRequested()) { + final long startTimeNs = mLogger.mSendTimeNs; + final long lastSnapshotTimeNs = snapController.mTaskSnapshotController + .getSnapshotCaptureTime(task.mTaskId); // If transition is transient, then snapshots are taken at end of - // transition. - mController.mSnapshotController.mTaskSnapshotController - .recordSnapshot(task, false /* allowSnapshotHome */); - mController.mSnapshotController.mActivitySnapshotController + // transition only if a snapshot was not already captured by request + // during the transition + if (lastSnapshotTimeNs < startTimeNs) { + snapController.mTaskSnapshotController + .recordSnapshot(task, false /* allowSnapshotHome */); + } else { + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, + " Skipping post-transition snapshot for task %d", + task.mTaskId); + } + snapController.mActivitySnapshotController .notifyAppVisibilityChanged(ar, false /* visible */); } ar.commitVisibility(false /* visible */, false /* performLayout */, diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 10f4158205e6..0ccb0d0b2ef5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -1286,7 +1286,7 @@ public class RecentTasksTest extends WindowTestsBase { doReturn(bufferSize.x).when(buffer).getWidth(); doReturn(bufferSize.y).when(buffer).getHeight(); } - return new TaskSnapshot(1, new ComponentName("", ""), buffer, + return new TaskSnapshot(1, 0 /* captureTime */, new ComponentName("", ""), buffer, ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, Surface.ROTATION_0, taskSize, new Rect() /* contentInsets */, new Rect() /* letterboxInsets*/, false /* isLowResolution */, diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java index b69874a97132..84c069691e04 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -218,7 +218,7 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { Canvas c = buffer.lockCanvas(); c.drawColor(Color.RED); buffer.unlockCanvasAndPost(c); - return new TaskSnapshot(MOCK_SNAPSHOT_ID, mTopActivityComponent, + return new TaskSnapshot(MOCK_SNAPSHOT_ID, 0 /* captureTime */, mTopActivityComponent, HardwareBuffer.createFromGraphicBuffer(buffer), ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, mRotation, taskSize, TEST_CONTENT_INSETS, TEST_LETTERBOX_INSETS, |