Loading services/core/java/com/android/server/wm/ActivitySnapshotController.java +194 −95 Original line number Diff line number Diff line Loading @@ -16,16 +16,14 @@ package com.android.server.wm; import static com.android.server.wm.SnapshotController.ACTIVITY_CLOSE; import static com.android.server.wm.SnapshotController.ACTIVITY_OPEN; import static com.android.server.wm.SnapshotController.TASK_CLOSE; import static com.android.server.wm.SnapshotController.TASK_OPEN; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.os.Environment; import android.os.SystemProperties; import android.os.Trace; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; Loading @@ -35,7 +33,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; import com.android.server.wm.SnapshotController.TransitionState; import java.io.File; import java.util.ArrayList; Loading @@ -61,12 +58,6 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord static final String SNAPSHOTS_DIRNAME = "activity_snapshots"; /** * The pending activities which should capture snapshot when process transition finish. */ @VisibleForTesting final ArraySet<ActivityRecord> mPendingCaptureActivity = new ArraySet<>(); /** * The pending activities which should remove snapshot from memory when process transition * finish. Loading @@ -86,6 +77,10 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord @VisibleForTesting final ArraySet<ActivityRecord> mPendingLoadActivity = new ArraySet<>(); private final ArraySet<ActivityRecord> mOnBackPressedActivities = new ArraySet<>(); private final ArrayList<ActivityRecord> mTmpBelowActivities = new ArrayList<>(); private final ArrayList<WindowContainer> mTmpTransitionParticipants = new ArrayList<>(); private final SnapshotPersistQueue mSnapshotPersistQueue; private final PersistInfoProvider mPersistInfoProvider; private final AppSnapshotLoader mSnapshotLoader; Loading Loading @@ -117,20 +112,6 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord setSnapshotEnabled(snapshotEnabled); } void systemReady() { if (shouldDisableSnapshots()) { return; } mService.mSnapshotController.registerTransitionStateConsumer( ACTIVITY_OPEN, this::handleOpenActivityTransition); mService.mSnapshotController.registerTransitionStateConsumer( ACTIVITY_CLOSE, this::handleCloseActivityTransition); mService.mSnapshotController.registerTransitionStateConsumer( TASK_OPEN, this::handleOpenTaskTransition); mService.mSnapshotController.registerTransitionStateConsumer( TASK_CLOSE, this::handleCloseTaskTransition); } @Override protected float initSnapshotScale() { final float config = mService.mContext.getResources().getFloat( Loading Loading @@ -173,6 +154,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord @Override void write() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "cleanUpUserFiles"); final File file = mPersistInfoProvider.getDirectory(userId); if (file.exists()) { final File[] contents = file.listFiles(); Loading @@ -182,15 +164,30 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord } } } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } }); } } void addOnBackPressedActivity(ActivityRecord ar) { if (shouldDisableSnapshots()) { return; } mOnBackPressedActivities.add(ar); } void clearOnBackPressedActivities() { if (shouldDisableSnapshots()) { return; } mOnBackPressedActivities.clear(); } /** * Prepare to handle on transition start. Clear all temporary fields. * Prepare to collect any change for snapshots processing. Clear all temporary fields. */ void preTransitionStart() { void beginSnapshotProcess() { if (shouldDisableSnapshots()) { return; } Loading @@ -198,18 +195,22 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord } /** * on transition start has notified, start process data. * End collect any change for snapshots processing, start process data. */ void postTransitionStart() { void endSnapshotProcess() { if (shouldDisableSnapshots()) { return; } onCommitTransition(); for (int i = mOnBackPressedActivities.size() - 1; i >= 0; --i) { handleActivityTransition(mOnBackPressedActivities.valueAt(i)); } mOnBackPressedActivities.clear(); mTmpTransitionParticipants.clear(); postProcess(); } @VisibleForTesting void resetTmpFields() { mPendingCaptureActivity.clear(); mPendingRemoveActivity.clear(); mPendingDeleteActivity.clear(); mPendingLoadActivity.clear(); Loading @@ -218,31 +219,13 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord /** * Start process all pending activities for a transition. */ private void onCommitTransition() { private void postProcess() { if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#onCommitTransition result:" + " capture " + mPendingCaptureActivity Slog.d(TAG, "ActivitySnapshotController#postProcess result:" + " remove " + mPendingRemoveActivity + " delete " + mPendingDeleteActivity + " load " + mPendingLoadActivity); } // task snapshots for (int i = mPendingCaptureActivity.size() - 1; i >= 0; i--) { recordSnapshot(mPendingCaptureActivity.valueAt(i)); } // clear mTmpRemoveActivity from cache for (int i = mPendingRemoveActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingRemoveActivity.valueAt(i); final int code = getSystemHashCode(ar); mCache.onIdRemoved(code); } // clear snapshot on cache and delete files for (int i = mPendingDeleteActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingDeleteActivity.valueAt(i); final int code = getSystemHashCode(ar); mCache.onIdRemoved(code); removeIfUserSavedFileExist(code, ar.mUserId); } // load snapshot to cache for (int i = mPendingLoadActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingLoadActivity.valueAt(i); Loading @@ -258,6 +241,8 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider) { @Override void write() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "load_activity_snapshot"); final TaskSnapshot snapshot = mSnapshotLoader.loadTask(code, userId, false /* loadLowResolutionBitmap */); synchronized (mService.getWindowManagerLock()) { Loading @@ -265,16 +250,36 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord mCache.putSnapshot(ar, snapshot); } } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } }); } } } // clear mTmpRemoveActivity from cache for (int i = mPendingRemoveActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingRemoveActivity.valueAt(i); final int code = getSystemHashCode(ar); mCache.onIdRemoved(code); } // clear snapshot on cache and delete files for (int i = mPendingDeleteActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingDeleteActivity.valueAt(i); final int code = getSystemHashCode(ar); mCache.onIdRemoved(code); removeIfUserSavedFileExist(code, ar.mUserId); } // don't keep any reference resetTmpFields(); } private void recordSnapshot(ActivityRecord activity) { void recordSnapshot(ActivityRecord activity) { if (shouldDisableSnapshots()) { return; } if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#recordSnapshot " + activity); } final TaskSnapshot snapshot = recordSnapshotInner(activity, false /* allowSnapshotHome */); if (snapshot != null) { final int code = getSystemHashCode(activity); Loading @@ -285,15 +290,20 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord /** * Called when the visibility of an app changes outside the regular app transition flow. */ void notifyAppVisibilityChanged(ActivityRecord appWindowToken, boolean visible) { void notifyAppVisibilityChanged(ActivityRecord ar, boolean visible) { if (shouldDisableSnapshots()) { return; } final Task task = ar.getTask(); if (task == null) { return; } // Doesn't need to capture activity snapshot when it converts from translucent. if (!visible) { resetTmpFields(); addBelowTopActivityIfExist(appWindowToken.getTask(), mPendingRemoveActivity, addBelowActivityIfExist(ar, mPendingRemoveActivity, false, "remove-snapshot"); onCommitTransition(); postProcess(); } } Loading @@ -301,65 +311,146 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord return System.identityHashCode(activity); } void handleOpenActivityTransition(TransitionState<ActivityRecord> transitionState) { ArraySet<ActivityRecord> participant = transitionState.getParticipant(false /* open */); for (ActivityRecord ar : participant) { mPendingCaptureActivity.add(ar); // remove the snapshot for the one below close final ActivityRecord below = ar.getTask().getActivityBelow(ar); if (below != null) { mPendingRemoveActivity.add(below); @VisibleForTesting void handleTransitionFinish(@NonNull ArrayList<WindowContainer> windows) { mTmpTransitionParticipants.clear(); mTmpTransitionParticipants.addAll(windows); for (int i = mTmpTransitionParticipants.size() - 1; i >= 0; --i) { final WindowContainer next = mTmpTransitionParticipants.get(i); if (next.asTask() != null) { handleTaskTransition(next.asTask()); } else if (next.asTaskFragment() != null) { final TaskFragment tf = next.asTaskFragment(); final ActivityRecord ar = tf.getTopMostActivity(); if (ar != null) { handleActivityTransition(ar); } } else if (next.asActivityRecord() != null) { handleActivityTransition(next.asActivityRecord()); } } } void handleCloseActivityTransition(TransitionState<ActivityRecord> transitionState) { ArraySet<ActivityRecord> participant = transitionState.getParticipant(true /* open */); for (ActivityRecord ar : participant) { private void handleActivityTransition(@NonNull ActivityRecord ar) { if (shouldDisableSnapshots()) { return; } if (ar.isVisibleRequested()) { mPendingDeleteActivity.add(ar); // load next one if exists. final ActivityRecord below = ar.getTask().getActivityBelow(ar); if (below != null) { mPendingLoadActivity.add(below); } addBelowActivityIfExist(ar, mPendingLoadActivity, true, "load-snapshot"); } else { // remove the snapshot for the one below close addBelowActivityIfExist(ar, mPendingRemoveActivity, true, "remove-snapshot"); } } void handleCloseTaskTransition(TransitionState<Task> closeTaskTransitionRecord) { ArraySet<Task> participant = closeTaskTransitionRecord.getParticipant(false /* open */); for (Task close : participant) { // this is close task transition // remove the N - 1 from cache addBelowTopActivityIfExist(close, mPendingRemoveActivity, "remove-snapshot"); private void handleTaskTransition(Task task) { if (shouldDisableSnapshots()) { return; } final ActivityRecord topActivity = task.getTopMostActivity(); if (topActivity == null) { return; } void handleOpenTaskTransition(TransitionState<Task> openTaskTransitionRecord) { ArraySet<Task> participant = openTaskTransitionRecord.getParticipant(true /* open */); for (Task open : participant) { // this is close task transition // remove the N - 1 from cache addBelowTopActivityIfExist(open, mPendingLoadActivity, "load-snapshot"); if (task.isVisibleRequested()) { // this is open task transition // load the N - 1 to cache addBelowActivityIfExist(topActivity, mPendingLoadActivity, true, "load-snapshot"); // Move the activities to top of mSavedFilesInOrder, so when purge happen, there // will trim the persisted files from the most non-accessed. adjustSavedFileOrder(open); adjustSavedFileOrder(task); } else { // this is close task transition // remove the N - 1 from cache addBelowActivityIfExist(topActivity, mPendingRemoveActivity, true, "remove-snapshot"); } } // Add the top -1 activity to a set if it exists. private void addBelowTopActivityIfExist(Task task, ArraySet<ActivityRecord> set, String debugMessage) { final ActivityRecord topActivity = task.getTopMostActivity(); if (topActivity != null) { final ActivityRecord below = task.getActivityBelow(topActivity); if (below != null) { set.add(below); /** * Add the top -1 activity to a set if it exists. * @param inTransition true if the activity must participant in transition. */ private void addBelowActivityIfExist(ActivityRecord currentActivity, ArraySet<ActivityRecord> set, boolean inTransition, String debugMessage) { getActivityBelow(currentActivity, inTransition, mTmpBelowActivities); for (int i = mTmpBelowActivities.size() - 1; i >= 0; --i) { set.add(mTmpBelowActivities.get(i)); if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#addBelowTopActivityIfExist " + below + " from " + debugMessage); + mTmpBelowActivities.get(i) + " from " + debugMessage); } } mTmpBelowActivities.clear(); } private void getActivityBelow(ActivityRecord currentActivity, boolean inTransition, ArrayList<ActivityRecord> result) { final Task currentTask = currentActivity.getTask(); if (currentTask == null) { return; } final ActivityRecord initPrev = currentTask.getActivityBelow(currentActivity); if (initPrev == null) { return; } final TaskFragment currTF = currentActivity.getTaskFragment(); final TaskFragment prevTF = initPrev.getTaskFragment(); final TaskFragment prevAdjacentTF = prevTF != null ? prevTF.getAdjacentTaskFragment() : null; if (currTF == prevTF && currTF != null || prevAdjacentTF == null) { // Current activity and previous one is in the same task fragment, or // previous activity is not in a task fragment, or // previous activity's task fragment doesn't adjacent to any others. if (!inTransition || isInParticipant(initPrev, mTmpTransitionParticipants)) { result.add(initPrev); } return; } if (prevAdjacentTF == currTF) { // previous activity A is adjacent to current activity B. // Try to find anyone below previous activityA, which are C and D if exists. // A | B // C (| D) getActivityBelow(initPrev, inTransition, result); } else { // previous activity C isn't adjacent to current activity A. // A // B | C final Task prevAdjacentTask = prevAdjacentTF.getTask(); if (prevAdjacentTask == currentTask) { final int currentIndex = currTF != null ? currentTask.mChildren.indexOf(currTF) : currentTask.mChildren.indexOf(currentActivity); final int prevAdjacentIndex = prevAdjacentTask.mChildren.indexOf(prevAdjacentTF); // prevAdjacentTF already above currentActivity if (prevAdjacentIndex > currentIndex) { return; } } if (!inTransition || isInParticipant(initPrev, mTmpTransitionParticipants)) { result.add(initPrev); } // prevAdjacentTF is adjacent to another one final ActivityRecord prevAdjacentActivity = prevAdjacentTF.getTopMostActivity(); if (prevAdjacentActivity != null && (!inTransition || isInParticipant(prevAdjacentActivity, mTmpTransitionParticipants))) { result.add(prevAdjacentActivity); } } } static boolean isInParticipant(ActivityRecord ar, ArrayList<WindowContainer> transitionParticipants) { for (int i = transitionParticipants.size() - 1; i >= 0; --i) { final WindowContainer wc = transitionParticipants.get(i); if (ar == wc || ar.isDescendantOf(wc)) { return true; } } return false; } private void adjustSavedFileOrder(Task nextTopTask) { Loading @@ -376,6 +467,9 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord @Override void onAppRemoved(ActivityRecord activity) { if (shouldDisableSnapshots()) { return; } super.onAppRemoved(activity); final int code = getSystemHashCode(activity); removeIfUserSavedFileExist(code, activity.mUserId); Loading @@ -386,6 +480,9 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord @Override void onAppDied(ActivityRecord activity) { if (shouldDisableSnapshots()) { return; } super.onAppDied(activity); final int code = getSystemHashCode(activity); removeIfUserSavedFileExist(code, activity.mUserId); Loading Loading @@ -440,7 +537,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord private void removeIfUserSavedFileExist(int code, int userId) { final UserSavedFile usf = getUserFiles(userId).get(code); if (usf != null) { mUserSavedFiles.remove(code); mUserSavedFiles.get(userId).remove(code); mSavedFilesInOrder.remove(usf); mPersister.removeSnap(code, userId); } Loading Loading @@ -490,11 +587,13 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider) { @Override void write() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activity_remove_files"); for (int i = files.size() - 1; i >= 0; --i) { final UserSavedFile usf = files.get(i); mSnapshotPersistQueue.deleteSnapshot( usf.mFileId, usf.mUserId, mPersistInfoProvider); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } }); } Loading services/core/java/com/android/server/wm/BackNavigationController.java +7 −0 Original line number Diff line number Diff line Loading @@ -1177,6 +1177,8 @@ class BackNavigationController { if (!composeAnimations(mCloseTarget, mOpenTarget, openActivity)) { return null; } mCloseTarget.mTransitionController.mSnapshotController .mActivitySnapshotController.clearOnBackPressedActivities(); applyPreviewStrategy(mOpenAdaptor, openActivity); final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback(); Loading Loading @@ -1222,6 +1224,8 @@ class BackNavigationController { // Call it again to make sure the activity could be visible while handling the pending // animation. activity.commitVisibility(true, true); activity.mTransitionController.mSnapshotController .mActivitySnapshotController.addOnBackPressedActivity(activity); } activity.mLaunchTaskBehind = true; Loading @@ -1248,6 +1252,9 @@ class BackNavigationController { // Restore the launch-behind state. activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token); activity.mLaunchTaskBehind = false; // Ignore all change activity.mTransitionController.mSnapshotController .mActivitySnapshotController.clearOnBackPressedActivities(); ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Setting Activity.mLauncherTaskBehind to false. Activity=%s", activity); Loading services/core/java/com/android/server/wm/SnapshotController.java +54 −253 File changed.Preview size limit exceeded, changes collapsed. Show changes services/core/java/com/android/server/wm/SnapshotPersistQueue.java +6 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.graphics.Bitmap.CompressFormat.JPEG; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; Loading @@ -26,6 +27,7 @@ import android.annotation.TestApi; import android.graphics.Bitmap; import android.os.Process; import android.os.SystemClock; import android.os.Trace; import android.util.AtomicFile; import android.util.Slog; import android.window.TaskSnapshot; Loading Loading @@ -249,6 +251,7 @@ class SnapshotPersistQueue { @Override void write() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "StoreWriteQueueItem"); if (!mPersistInfoProvider.createDirectory(mUserId)) { Slog.e(TAG, "Unable to create snapshot directory for user dir=" + mPersistInfoProvider.getDirectory(mUserId)); Loading @@ -263,6 +266,7 @@ class SnapshotPersistQueue { if (failed) { deleteSnapshot(mId, mUserId, mPersistInfoProvider); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } boolean writeProto() { Loading Loading @@ -373,7 +377,9 @@ class SnapshotPersistQueue { @Override void write() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "DeleteWriteQueueItem"); deleteSnapshot(mId, mUserId, mPersistInfoProvider); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } } services/core/java/com/android/server/wm/TaskSnapshotController.java +11 −16 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.server.wm; import static com.android.server.wm.SnapshotController.TASK_CLOSE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; Loading Loading @@ -77,13 +76,6 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot setSnapshotEnabled(snapshotEnabled); } void systemReady() { if (!shouldDisableSnapshots()) { mService.mSnapshotController.registerTransitionStateConsumer(TASK_CLOSE, this::handleTaskClose); } } static PersistInfoProvider createPersistInfoProvider(WindowManagerService service, BaseAppSnapshotPersister.DirectoryResolver resolver) { final float highResTaskSnapshotScale = service.mContext.getResources().getFloat( Loading Loading @@ -116,20 +108,23 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot enableLowResSnapshots, lowResScaleFactor, use16BitFormat); } void handleTaskClose(SnapshotController.TransitionState<Task> closeTaskTransitionRecord) { // Still needed for legacy transition.(AppTransitionControllerTest) void handleClosingApps(ArraySet<ActivityRecord> closingApps) { if (shouldDisableSnapshots()) { return; } // We need to take a snapshot of the task if and only if all activities of the task are // either closing or hidden. mTmpTasks.clear(); final ArraySet<Task> tasks = closeTaskTransitionRecord.getParticipant(false /* open */); if (mService.mAtmService.getTransitionController().isShellTransitionsEnabled()) { mTmpTasks.addAll(tasks); } else { for (Task task : tasks) { for (int i = closingApps.size() - 1; i >= 0; i--) { final ActivityRecord activity = closingApps.valueAt(i); final Task task = activity.getTask(); if (task == null) continue; getClosingTasksInner(task, mTmpTasks); } } snapshotTasks(mTmpTasks); mTmpTasks.clear(); mSkipClosingAppSnapshotTasks.clear(); } Loading Loading
services/core/java/com/android/server/wm/ActivitySnapshotController.java +194 −95 Original line number Diff line number Diff line Loading @@ -16,16 +16,14 @@ package com.android.server.wm; import static com.android.server.wm.SnapshotController.ACTIVITY_CLOSE; import static com.android.server.wm.SnapshotController.ACTIVITY_OPEN; import static com.android.server.wm.SnapshotController.TASK_CLOSE; import static com.android.server.wm.SnapshotController.TASK_OPEN; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.os.Environment; import android.os.SystemProperties; import android.os.Trace; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; Loading @@ -35,7 +33,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; import com.android.server.wm.SnapshotController.TransitionState; import java.io.File; import java.util.ArrayList; Loading @@ -61,12 +58,6 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord static final String SNAPSHOTS_DIRNAME = "activity_snapshots"; /** * The pending activities which should capture snapshot when process transition finish. */ @VisibleForTesting final ArraySet<ActivityRecord> mPendingCaptureActivity = new ArraySet<>(); /** * The pending activities which should remove snapshot from memory when process transition * finish. Loading @@ -86,6 +77,10 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord @VisibleForTesting final ArraySet<ActivityRecord> mPendingLoadActivity = new ArraySet<>(); private final ArraySet<ActivityRecord> mOnBackPressedActivities = new ArraySet<>(); private final ArrayList<ActivityRecord> mTmpBelowActivities = new ArrayList<>(); private final ArrayList<WindowContainer> mTmpTransitionParticipants = new ArrayList<>(); private final SnapshotPersistQueue mSnapshotPersistQueue; private final PersistInfoProvider mPersistInfoProvider; private final AppSnapshotLoader mSnapshotLoader; Loading Loading @@ -117,20 +112,6 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord setSnapshotEnabled(snapshotEnabled); } void systemReady() { if (shouldDisableSnapshots()) { return; } mService.mSnapshotController.registerTransitionStateConsumer( ACTIVITY_OPEN, this::handleOpenActivityTransition); mService.mSnapshotController.registerTransitionStateConsumer( ACTIVITY_CLOSE, this::handleCloseActivityTransition); mService.mSnapshotController.registerTransitionStateConsumer( TASK_OPEN, this::handleOpenTaskTransition); mService.mSnapshotController.registerTransitionStateConsumer( TASK_CLOSE, this::handleCloseTaskTransition); } @Override protected float initSnapshotScale() { final float config = mService.mContext.getResources().getFloat( Loading Loading @@ -173,6 +154,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord @Override void write() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "cleanUpUserFiles"); final File file = mPersistInfoProvider.getDirectory(userId); if (file.exists()) { final File[] contents = file.listFiles(); Loading @@ -182,15 +164,30 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord } } } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } }); } } void addOnBackPressedActivity(ActivityRecord ar) { if (shouldDisableSnapshots()) { return; } mOnBackPressedActivities.add(ar); } void clearOnBackPressedActivities() { if (shouldDisableSnapshots()) { return; } mOnBackPressedActivities.clear(); } /** * Prepare to handle on transition start. Clear all temporary fields. * Prepare to collect any change for snapshots processing. Clear all temporary fields. */ void preTransitionStart() { void beginSnapshotProcess() { if (shouldDisableSnapshots()) { return; } Loading @@ -198,18 +195,22 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord } /** * on transition start has notified, start process data. * End collect any change for snapshots processing, start process data. */ void postTransitionStart() { void endSnapshotProcess() { if (shouldDisableSnapshots()) { return; } onCommitTransition(); for (int i = mOnBackPressedActivities.size() - 1; i >= 0; --i) { handleActivityTransition(mOnBackPressedActivities.valueAt(i)); } mOnBackPressedActivities.clear(); mTmpTransitionParticipants.clear(); postProcess(); } @VisibleForTesting void resetTmpFields() { mPendingCaptureActivity.clear(); mPendingRemoveActivity.clear(); mPendingDeleteActivity.clear(); mPendingLoadActivity.clear(); Loading @@ -218,31 +219,13 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord /** * Start process all pending activities for a transition. */ private void onCommitTransition() { private void postProcess() { if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#onCommitTransition result:" + " capture " + mPendingCaptureActivity Slog.d(TAG, "ActivitySnapshotController#postProcess result:" + " remove " + mPendingRemoveActivity + " delete " + mPendingDeleteActivity + " load " + mPendingLoadActivity); } // task snapshots for (int i = mPendingCaptureActivity.size() - 1; i >= 0; i--) { recordSnapshot(mPendingCaptureActivity.valueAt(i)); } // clear mTmpRemoveActivity from cache for (int i = mPendingRemoveActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingRemoveActivity.valueAt(i); final int code = getSystemHashCode(ar); mCache.onIdRemoved(code); } // clear snapshot on cache and delete files for (int i = mPendingDeleteActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingDeleteActivity.valueAt(i); final int code = getSystemHashCode(ar); mCache.onIdRemoved(code); removeIfUserSavedFileExist(code, ar.mUserId); } // load snapshot to cache for (int i = mPendingLoadActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingLoadActivity.valueAt(i); Loading @@ -258,6 +241,8 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider) { @Override void write() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "load_activity_snapshot"); final TaskSnapshot snapshot = mSnapshotLoader.loadTask(code, userId, false /* loadLowResolutionBitmap */); synchronized (mService.getWindowManagerLock()) { Loading @@ -265,16 +250,36 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord mCache.putSnapshot(ar, snapshot); } } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } }); } } } // clear mTmpRemoveActivity from cache for (int i = mPendingRemoveActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingRemoveActivity.valueAt(i); final int code = getSystemHashCode(ar); mCache.onIdRemoved(code); } // clear snapshot on cache and delete files for (int i = mPendingDeleteActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingDeleteActivity.valueAt(i); final int code = getSystemHashCode(ar); mCache.onIdRemoved(code); removeIfUserSavedFileExist(code, ar.mUserId); } // don't keep any reference resetTmpFields(); } private void recordSnapshot(ActivityRecord activity) { void recordSnapshot(ActivityRecord activity) { if (shouldDisableSnapshots()) { return; } if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#recordSnapshot " + activity); } final TaskSnapshot snapshot = recordSnapshotInner(activity, false /* allowSnapshotHome */); if (snapshot != null) { final int code = getSystemHashCode(activity); Loading @@ -285,15 +290,20 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord /** * Called when the visibility of an app changes outside the regular app transition flow. */ void notifyAppVisibilityChanged(ActivityRecord appWindowToken, boolean visible) { void notifyAppVisibilityChanged(ActivityRecord ar, boolean visible) { if (shouldDisableSnapshots()) { return; } final Task task = ar.getTask(); if (task == null) { return; } // Doesn't need to capture activity snapshot when it converts from translucent. if (!visible) { resetTmpFields(); addBelowTopActivityIfExist(appWindowToken.getTask(), mPendingRemoveActivity, addBelowActivityIfExist(ar, mPendingRemoveActivity, false, "remove-snapshot"); onCommitTransition(); postProcess(); } } Loading @@ -301,65 +311,146 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord return System.identityHashCode(activity); } void handleOpenActivityTransition(TransitionState<ActivityRecord> transitionState) { ArraySet<ActivityRecord> participant = transitionState.getParticipant(false /* open */); for (ActivityRecord ar : participant) { mPendingCaptureActivity.add(ar); // remove the snapshot for the one below close final ActivityRecord below = ar.getTask().getActivityBelow(ar); if (below != null) { mPendingRemoveActivity.add(below); @VisibleForTesting void handleTransitionFinish(@NonNull ArrayList<WindowContainer> windows) { mTmpTransitionParticipants.clear(); mTmpTransitionParticipants.addAll(windows); for (int i = mTmpTransitionParticipants.size() - 1; i >= 0; --i) { final WindowContainer next = mTmpTransitionParticipants.get(i); if (next.asTask() != null) { handleTaskTransition(next.asTask()); } else if (next.asTaskFragment() != null) { final TaskFragment tf = next.asTaskFragment(); final ActivityRecord ar = tf.getTopMostActivity(); if (ar != null) { handleActivityTransition(ar); } } else if (next.asActivityRecord() != null) { handleActivityTransition(next.asActivityRecord()); } } } void handleCloseActivityTransition(TransitionState<ActivityRecord> transitionState) { ArraySet<ActivityRecord> participant = transitionState.getParticipant(true /* open */); for (ActivityRecord ar : participant) { private void handleActivityTransition(@NonNull ActivityRecord ar) { if (shouldDisableSnapshots()) { return; } if (ar.isVisibleRequested()) { mPendingDeleteActivity.add(ar); // load next one if exists. final ActivityRecord below = ar.getTask().getActivityBelow(ar); if (below != null) { mPendingLoadActivity.add(below); } addBelowActivityIfExist(ar, mPendingLoadActivity, true, "load-snapshot"); } else { // remove the snapshot for the one below close addBelowActivityIfExist(ar, mPendingRemoveActivity, true, "remove-snapshot"); } } void handleCloseTaskTransition(TransitionState<Task> closeTaskTransitionRecord) { ArraySet<Task> participant = closeTaskTransitionRecord.getParticipant(false /* open */); for (Task close : participant) { // this is close task transition // remove the N - 1 from cache addBelowTopActivityIfExist(close, mPendingRemoveActivity, "remove-snapshot"); private void handleTaskTransition(Task task) { if (shouldDisableSnapshots()) { return; } final ActivityRecord topActivity = task.getTopMostActivity(); if (topActivity == null) { return; } void handleOpenTaskTransition(TransitionState<Task> openTaskTransitionRecord) { ArraySet<Task> participant = openTaskTransitionRecord.getParticipant(true /* open */); for (Task open : participant) { // this is close task transition // remove the N - 1 from cache addBelowTopActivityIfExist(open, mPendingLoadActivity, "load-snapshot"); if (task.isVisibleRequested()) { // this is open task transition // load the N - 1 to cache addBelowActivityIfExist(topActivity, mPendingLoadActivity, true, "load-snapshot"); // Move the activities to top of mSavedFilesInOrder, so when purge happen, there // will trim the persisted files from the most non-accessed. adjustSavedFileOrder(open); adjustSavedFileOrder(task); } else { // this is close task transition // remove the N - 1 from cache addBelowActivityIfExist(topActivity, mPendingRemoveActivity, true, "remove-snapshot"); } } // Add the top -1 activity to a set if it exists. private void addBelowTopActivityIfExist(Task task, ArraySet<ActivityRecord> set, String debugMessage) { final ActivityRecord topActivity = task.getTopMostActivity(); if (topActivity != null) { final ActivityRecord below = task.getActivityBelow(topActivity); if (below != null) { set.add(below); /** * Add the top -1 activity to a set if it exists. * @param inTransition true if the activity must participant in transition. */ private void addBelowActivityIfExist(ActivityRecord currentActivity, ArraySet<ActivityRecord> set, boolean inTransition, String debugMessage) { getActivityBelow(currentActivity, inTransition, mTmpBelowActivities); for (int i = mTmpBelowActivities.size() - 1; i >= 0; --i) { set.add(mTmpBelowActivities.get(i)); if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#addBelowTopActivityIfExist " + below + " from " + debugMessage); + mTmpBelowActivities.get(i) + " from " + debugMessage); } } mTmpBelowActivities.clear(); } private void getActivityBelow(ActivityRecord currentActivity, boolean inTransition, ArrayList<ActivityRecord> result) { final Task currentTask = currentActivity.getTask(); if (currentTask == null) { return; } final ActivityRecord initPrev = currentTask.getActivityBelow(currentActivity); if (initPrev == null) { return; } final TaskFragment currTF = currentActivity.getTaskFragment(); final TaskFragment prevTF = initPrev.getTaskFragment(); final TaskFragment prevAdjacentTF = prevTF != null ? prevTF.getAdjacentTaskFragment() : null; if (currTF == prevTF && currTF != null || prevAdjacentTF == null) { // Current activity and previous one is in the same task fragment, or // previous activity is not in a task fragment, or // previous activity's task fragment doesn't adjacent to any others. if (!inTransition || isInParticipant(initPrev, mTmpTransitionParticipants)) { result.add(initPrev); } return; } if (prevAdjacentTF == currTF) { // previous activity A is adjacent to current activity B. // Try to find anyone below previous activityA, which are C and D if exists. // A | B // C (| D) getActivityBelow(initPrev, inTransition, result); } else { // previous activity C isn't adjacent to current activity A. // A // B | C final Task prevAdjacentTask = prevAdjacentTF.getTask(); if (prevAdjacentTask == currentTask) { final int currentIndex = currTF != null ? currentTask.mChildren.indexOf(currTF) : currentTask.mChildren.indexOf(currentActivity); final int prevAdjacentIndex = prevAdjacentTask.mChildren.indexOf(prevAdjacentTF); // prevAdjacentTF already above currentActivity if (prevAdjacentIndex > currentIndex) { return; } } if (!inTransition || isInParticipant(initPrev, mTmpTransitionParticipants)) { result.add(initPrev); } // prevAdjacentTF is adjacent to another one final ActivityRecord prevAdjacentActivity = prevAdjacentTF.getTopMostActivity(); if (prevAdjacentActivity != null && (!inTransition || isInParticipant(prevAdjacentActivity, mTmpTransitionParticipants))) { result.add(prevAdjacentActivity); } } } static boolean isInParticipant(ActivityRecord ar, ArrayList<WindowContainer> transitionParticipants) { for (int i = transitionParticipants.size() - 1; i >= 0; --i) { final WindowContainer wc = transitionParticipants.get(i); if (ar == wc || ar.isDescendantOf(wc)) { return true; } } return false; } private void adjustSavedFileOrder(Task nextTopTask) { Loading @@ -376,6 +467,9 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord @Override void onAppRemoved(ActivityRecord activity) { if (shouldDisableSnapshots()) { return; } super.onAppRemoved(activity); final int code = getSystemHashCode(activity); removeIfUserSavedFileExist(code, activity.mUserId); Loading @@ -386,6 +480,9 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord @Override void onAppDied(ActivityRecord activity) { if (shouldDisableSnapshots()) { return; } super.onAppDied(activity); final int code = getSystemHashCode(activity); removeIfUserSavedFileExist(code, activity.mUserId); Loading Loading @@ -440,7 +537,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord private void removeIfUserSavedFileExist(int code, int userId) { final UserSavedFile usf = getUserFiles(userId).get(code); if (usf != null) { mUserSavedFiles.remove(code); mUserSavedFiles.get(userId).remove(code); mSavedFilesInOrder.remove(usf); mPersister.removeSnap(code, userId); } Loading Loading @@ -490,11 +587,13 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider) { @Override void write() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activity_remove_files"); for (int i = files.size() - 1; i >= 0; --i) { final UserSavedFile usf = files.get(i); mSnapshotPersistQueue.deleteSnapshot( usf.mFileId, usf.mUserId, mPersistInfoProvider); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } }); } Loading
services/core/java/com/android/server/wm/BackNavigationController.java +7 −0 Original line number Diff line number Diff line Loading @@ -1177,6 +1177,8 @@ class BackNavigationController { if (!composeAnimations(mCloseTarget, mOpenTarget, openActivity)) { return null; } mCloseTarget.mTransitionController.mSnapshotController .mActivitySnapshotController.clearOnBackPressedActivities(); applyPreviewStrategy(mOpenAdaptor, openActivity); final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback(); Loading Loading @@ -1222,6 +1224,8 @@ class BackNavigationController { // Call it again to make sure the activity could be visible while handling the pending // animation. activity.commitVisibility(true, true); activity.mTransitionController.mSnapshotController .mActivitySnapshotController.addOnBackPressedActivity(activity); } activity.mLaunchTaskBehind = true; Loading @@ -1248,6 +1252,9 @@ class BackNavigationController { // Restore the launch-behind state. activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token); activity.mLaunchTaskBehind = false; // Ignore all change activity.mTransitionController.mSnapshotController .mActivitySnapshotController.clearOnBackPressedActivities(); ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Setting Activity.mLauncherTaskBehind to false. Activity=%s", activity); Loading
services/core/java/com/android/server/wm/SnapshotController.java +54 −253 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/core/java/com/android/server/wm/SnapshotPersistQueue.java +6 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.graphics.Bitmap.CompressFormat.JPEG; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; Loading @@ -26,6 +27,7 @@ import android.annotation.TestApi; import android.graphics.Bitmap; import android.os.Process; import android.os.SystemClock; import android.os.Trace; import android.util.AtomicFile; import android.util.Slog; import android.window.TaskSnapshot; Loading Loading @@ -249,6 +251,7 @@ class SnapshotPersistQueue { @Override void write() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "StoreWriteQueueItem"); if (!mPersistInfoProvider.createDirectory(mUserId)) { Slog.e(TAG, "Unable to create snapshot directory for user dir=" + mPersistInfoProvider.getDirectory(mUserId)); Loading @@ -263,6 +266,7 @@ class SnapshotPersistQueue { if (failed) { deleteSnapshot(mId, mUserId, mPersistInfoProvider); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } boolean writeProto() { Loading Loading @@ -373,7 +377,9 @@ class SnapshotPersistQueue { @Override void write() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "DeleteWriteQueueItem"); deleteSnapshot(mId, mUserId, mPersistInfoProvider); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } }
services/core/java/com/android/server/wm/TaskSnapshotController.java +11 −16 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.server.wm; import static com.android.server.wm.SnapshotController.TASK_CLOSE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; Loading Loading @@ -77,13 +76,6 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot setSnapshotEnabled(snapshotEnabled); } void systemReady() { if (!shouldDisableSnapshots()) { mService.mSnapshotController.registerTransitionStateConsumer(TASK_CLOSE, this::handleTaskClose); } } static PersistInfoProvider createPersistInfoProvider(WindowManagerService service, BaseAppSnapshotPersister.DirectoryResolver resolver) { final float highResTaskSnapshotScale = service.mContext.getResources().getFloat( Loading Loading @@ -116,20 +108,23 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot enableLowResSnapshots, lowResScaleFactor, use16BitFormat); } void handleTaskClose(SnapshotController.TransitionState<Task> closeTaskTransitionRecord) { // Still needed for legacy transition.(AppTransitionControllerTest) void handleClosingApps(ArraySet<ActivityRecord> closingApps) { if (shouldDisableSnapshots()) { return; } // We need to take a snapshot of the task if and only if all activities of the task are // either closing or hidden. mTmpTasks.clear(); final ArraySet<Task> tasks = closeTaskTransitionRecord.getParticipant(false /* open */); if (mService.mAtmService.getTransitionController().isShellTransitionsEnabled()) { mTmpTasks.addAll(tasks); } else { for (Task task : tasks) { for (int i = closingApps.size() - 1; i >= 0; i--) { final ActivityRecord activity = closingApps.valueAt(i); final Task task = activity.getTask(); if (task == null) continue; getClosingTasksInner(task, mTmpTasks); } } snapshotTasks(mTmpTasks); mTmpTasks.clear(); mSkipClosingAppSnapshotTasks.clear(); } Loading