From 440f88b43a6b88f08e290623f77423a0b35b9c41 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Wed, 6 Nov 2019 22:17:35 +0800 Subject: [PATCH] Add task snapshot for home task The real home activity usually takes longer time than a snapshot to complete drawing. Especially when unlocking to home, the duration becomes more noticeable. This CL enables snapshot of home task when turning screen off. And because the snapshot is only used when entering home from a sleeping state, the snapshot will be removed once it is used. Also provide a method for home activity to remove its snapshot while the content of home activity has significant change after taking the snapshot. Bug: 140811348 Test: 1. Set an unlock method that doesn't need to show lockscreen when unlocking. 2. Turn off screen while home is on top. 3. Unlock device to enter home. 4. Check the duration of trace "screenTurningOn". Change-Id: Ic516cdcfd84ca4a85e19798537f9f5a85077392b --- .../android/app/IActivityTaskManager.aidl | 8 +++ .../shared/system/ActivityManagerWrapper.java | 18 +++++++ .../server/policy/PhoneWindowManager.java | 3 ++ .../com/android/server/wm/ActivityRecord.java | 11 +++++ .../server/wm/ActivityTaskManagerService.java | 11 +++++ .../android/server/wm/TaskSnapshotCache.java | 2 +- .../server/wm/TaskSnapshotController.java | 49 +++++++++++++------ 7 files changed, 85 insertions(+), 17 deletions(-) diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index 37136a110d38a..368a1bc35e71e 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -404,6 +404,14 @@ interface IActivityTaskManager { */ void setDisablePreviewScreenshots(IBinder token, boolean disable); + /** + * It should only be called from home activity to remove its outdated snapshot. The home + * snapshot is used to speed up entering home from screen off. If the content of home activity + * is significantly different from before taking the snapshot, then the home activity can use + * this method to avoid inconsistent transition. + */ + void invalidateHomeTaskSnapshot(IBinder homeToken); + /** * Return the user id of last resumed activity. */ diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index 70f8e15eb83d8..deaafca7a98ce 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -28,6 +28,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.NonNull; +import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RecentTaskInfo; import android.app.ActivityManager.RunningTaskInfo; @@ -160,6 +161,23 @@ public class ActivityManagerWrapper { } } + /** + * Removes the outdated snapshot of home task. + */ + public void invalidateHomeTaskSnapshot(final Activity homeActivity) { + mBackgroundExecutor.submit(new Runnable() { + @Override + public void run() { + try { + ActivityTaskManager.getService().invalidateHomeTaskSnapshot( + homeActivity.getActivityToken()); + } catch (RemoteException e) { + Log.w(TAG, "Failed to invalidate home snapshot", e); + } + } + }); + } + /** * @return the activity label, badging if necessary. */ diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 8435a82027628..c05b70413a401 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -157,6 +157,7 @@ import android.os.ServiceManager; import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.Trace; import android.os.UEventObserver; import android.os.UserHandle; import android.os.VibrationEffect; @@ -4603,6 +4604,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void screenTurningOn(final ScreenOnListener screenOnListener) { if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on..."); + Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */); updateScreenOffSleepToken(false); mDefaultDisplayPolicy.screenTurnedOn(screenOnListener); @@ -4665,6 +4667,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!mDefaultDisplayPolicy.finishScreenTurningOn()) { return; // Spurious or not ready yet. } + Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */); final boolean enableScreen; final boolean awake = mDefaultDisplayPolicy.isAwake(); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index bc2fa4eab2354..59fb3198b8e6b 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1640,6 +1640,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A allowTaskSnapshot, activityCreated, fromRecents, snapshot); if (type == STARTING_WINDOW_TYPE_SNAPSHOT) { + if (isActivityTypeHome()) { + // The snapshot of home is only used once because it won't be updated while screen + // is on (see {@link TaskSnapshotController#screenTurningOff}). + mWmService.mTaskSnapshotController.removeSnapshotCache(task.mTaskId); + // TODO(b/9684093): Use more general condition to specify the case. + if (mDisplayContent.mAppTransition + .getAppTransition() != WindowManager.TRANSIT_KEYGUARD_GOING_AWAY) { + // Only use snapshot of home as starting window when unlocking. + return false; + } + } return createSnapshot(snapshot); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 46c4d874cb533..c405100ea66db 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -4572,6 +4572,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } + @Override + public void invalidateHomeTaskSnapshot(IBinder token) { + synchronized (mGlobalLock) { + final ActivityRecord r = ActivityRecord.isInStackLocked(token); + if (r == null || !r.isActivityTypeHome()) { + return; + } + mWindowManager.mTaskSnapshotController.removeSnapshotCache(r.getTask().mTaskId); + } + } + /** Return the user id of the last resumed activity. */ @Override public @UserIdInt diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java index 5cbab5d1b1f52..7b0d841483bb0 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java @@ -109,7 +109,7 @@ class TaskSnapshotCache { removeRunningEntry(taskId); } - private void removeRunningEntry(int taskId) { + void removeRunningEntry(int taskId) { final CacheEntry entry = mRunningCache.get(taskId); if (entry != null) { mAppTaskMap.remove(entry.topApp); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index c1a36c49fc1a1..12b2845e9d712 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -171,22 +171,30 @@ class TaskSnapshotController { } void snapshotTasks(ArraySet tasks) { + snapshotTasks(mTmpTasks, false /* allowSnapshotHome */); + } + + private void snapshotTasks(ArraySet tasks, boolean allowSnapshotHome) { for (int i = tasks.size() - 1; i >= 0; i--) { final Task task = tasks.valueAt(i); - final int mode = getSnapshotMode(task); final TaskSnapshot snapshot; - switch (mode) { - case SNAPSHOT_MODE_NONE: - continue; - case SNAPSHOT_MODE_APP_THEME: - snapshot = drawAppThemeSnapshot(task); - break; - case SNAPSHOT_MODE_REAL: - snapshot = snapshotTask(task); - break; - default: - snapshot = null; - break; + final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome(); + if (snapshotHome) { + snapshot = snapshotTask(task); + } else { + switch (getSnapshotMode(task)) { + case SNAPSHOT_MODE_NONE: + continue; + case SNAPSHOT_MODE_APP_THEME: + snapshot = drawAppThemeSnapshot(task); + break; + case SNAPSHOT_MODE_REAL: + snapshot = snapshotTask(task); + break; + default: + snapshot = null; + break; + } } if (snapshot != null) { final GraphicBuffer buffer = snapshot.getSnapshot(); @@ -196,8 +204,11 @@ class TaskSnapshotController { + buffer.getHeight()); } else { mCache.putSnapshot(task, snapshot); - mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot); - task.onSnapshotChanged(snapshot); + // Don't persist or notify the change for the temporal snapshot. + if (!snapshotHome) { + mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot); + task.onSnapshotChanged(snapshot); + } } } } @@ -450,6 +461,10 @@ class TaskSnapshotController { mPersister.onTaskRemovedFromRecents(taskId, userId); } + void removeSnapshotCache(int taskId) { + mCache.removeRunningEntry(taskId); + } + /** * See {@link TaskSnapshotPersister#removeObsoleteFiles} */ @@ -485,7 +500,9 @@ class TaskSnapshotController { mTmpTasks.add(task); } }); - snapshotTasks(mTmpTasks); + // Allow taking snapshot of home when turning screen off to reduce the delay of + // unlocking/waking to home. + snapshotTasks(mTmpTasks, true /* allowSnapshotHome */); } } finally { listener.onScreenOff();