diff options
| author | 2021-09-08 15:57:39 -0600 | |
|---|---|---|
| committer | 2021-09-08 11:47:36 +0000 | |
| commit | 1d3084bb0e1b84a3e55948759e816d977b19709f (patch) | |
| tree | 433a3f4c2cce9d4cbabaf622412e41dc1634ae3d | |
| parent | 08774f2ffc033d4e8186b5a7914b7e08a1fed84c (diff) | |
Consider process priority of unknown visibility launching app
When launching a show-when-locked activity on keyguard or switch
between show-when-locked activities while keyguard is locked, because
the activity visibility may be unknown before knowing whether it can
show on keyguard, the device may enter sleeping state before the
activity becomes visible. That causes the power mode and top process
state are lost during launching the app and slow down the launch time.
So add a new flag to indicate that if there are still unknown visibility
records, then keep the power mode and top process state. This may
improve 30% launch time for the cases.
Currently it only applies when the caller is no system ui because the
launch time may be affected by counting the time of double resume-stop
lifecycle depends on the timing of keyguard-going-away. And the case
should be addressed once keyguard remote animation is enabled in the
future, that will trigger keyguard-going-away earlier.
Bug: 197963579
Test: atest ActivityTaskManagerServiceTests#testUpdateSleep
Change-Id: If8beb4547be8dad3748474d0813729516f502798
3 files changed, 86 insertions, 16 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 081c618b62aa..0ff43ae6b464 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -653,16 +653,25 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ volatile int mTopProcessState = ActivityManager.PROCESS_STATE_TOP; + /** Whether to keep higher priority to launch app while device is sleeping. */ + private volatile boolean mRetainPowerModeAndTopProcessState; + + /** The timeout to restore power mode if {@link #mRetainPowerModeAndTopProcessState} is set. */ + private static final long POWER_MODE_UNKNOWN_VISIBILITY_TIMEOUT_MS = 1000; + @Retention(RetentionPolicy.SOURCE) @IntDef({ POWER_MODE_REASON_START_ACTIVITY, POWER_MODE_REASON_FREEZE_DISPLAY, + POWER_MODE_REASON_UNKNOWN_VISIBILITY, POWER_MODE_REASON_ALL, }) @interface PowerModeReason {} static final int POWER_MODE_REASON_START_ACTIVITY = 1 << 0; static final int POWER_MODE_REASON_FREEZE_DISPLAY = 1 << 1; + /** @see UnknownAppVisibilityController */ + static final int POWER_MODE_REASON_UNKNOWN_VISIBILITY = 1 << 2; /** This can only be used by {@link #endLaunchPowerMode(int)}.*/ static final int POWER_MODE_REASON_ALL = (1 << 2) - 1; @@ -4245,15 +4254,39 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } void startLaunchPowerMode(@PowerModeReason int reason) { - if (mPowerManagerInternal == null) return; - mPowerManagerInternal.setPowerMode(Mode.LAUNCH, true); + if (mPowerManagerInternal != null) { + mPowerManagerInternal.setPowerMode(Mode.LAUNCH, true); + } mLaunchPowerModeReasons |= reason; + if ((reason & POWER_MODE_REASON_UNKNOWN_VISIBILITY) != 0) { + if (mRetainPowerModeAndTopProcessState) { + mH.removeMessages(H.END_POWER_MODE_UNKNOWN_VISIBILITY_MSG); + } + mRetainPowerModeAndTopProcessState = true; + mH.sendEmptyMessageDelayed(H.END_POWER_MODE_UNKNOWN_VISIBILITY_MSG, + POWER_MODE_UNKNOWN_VISIBILITY_TIMEOUT_MS); + Slog.d(TAG, "Temporarily retain top process state for launching app"); + } } void endLaunchPowerMode(@PowerModeReason int reason) { - if (mPowerManagerInternal == null || mLaunchPowerModeReasons == 0) return; + if (mLaunchPowerModeReasons == 0) return; mLaunchPowerModeReasons &= ~reason; - if (mLaunchPowerModeReasons == 0) { + + if ((mLaunchPowerModeReasons & POWER_MODE_REASON_UNKNOWN_VISIBILITY) != 0) { + boolean allResolved = true; + for (int i = mRootWindowContainer.getChildCount() - 1; i >= 0; i--) { + allResolved &= mRootWindowContainer.getChildAt(i).mUnknownAppVisibilityController + .allResolved(); + } + if (allResolved) { + mLaunchPowerModeReasons &= ~POWER_MODE_REASON_UNKNOWN_VISIBILITY; + mRetainPowerModeAndTopProcessState = false; + mH.removeMessages(H.END_POWER_MODE_UNKNOWN_VISIBILITY_MSG); + } + } + + if (mLaunchPowerModeReasons == 0 && mPowerManagerInternal != null) { mPowerManagerInternal.setPowerMode(Mode.LAUNCH, false); } } @@ -5120,6 +5153,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final class H extends Handler { static final int REPORT_TIME_TRACKER_MSG = 1; static final int UPDATE_PROCESS_ANIMATING_STATE = 2; + static final int END_POWER_MODE_UNKNOWN_VISIBILITY_MSG = 3; static final int FIRST_ACTIVITY_TASK_MSG = 100; static final int FIRST_SUPERVISOR_TASK_MSG = 200; @@ -5143,6 +5177,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } break; + case END_POWER_MODE_UNKNOWN_VISIBILITY_MSG: { + synchronized (mGlobalLock) { + mRetainPowerModeAndTopProcessState = false; + endLaunchPowerMode(POWER_MODE_REASON_UNKNOWN_VISIBILITY); + if (mTopApp != null + && mTopProcessState == ActivityManager.PROCESS_STATE_TOP_SLEEPING) { + // Restore the scheduling group for sleeping. + mTopApp.updateProcessInfo(false /* updateServiceConnection */, + false /* activityChange */, true /* updateOomAdj */, + false /* addPendingTopUid */); + } + } + } + break; } } } @@ -5461,6 +5509,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @HotPath(caller = HotPath.OOM_ADJUSTMENT) @Override public int getTopProcessState() { + if (mRetainPowerModeAndTopProcessState) { + // There is a launching app while device may be sleeping, force the top state so + // the launching process can have top-app scheduling group. + return ActivityManager.PROCESS_STATE_TOP; + } return mTopProcessState; } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 6c2322b6d7e5..c48dba4078c8 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -3545,14 +3545,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } void startPowerModeLaunchIfNeeded(boolean forceSend, ActivityRecord targetActivity) { - final boolean sendPowerModeLaunch; - - if (forceSend) { - sendPowerModeLaunch = true; - } else if (targetActivity == null || targetActivity.app == null) { - // Set power mode if we don't know what we're launching yet. - sendPowerModeLaunch = true; - } else { + if (!forceSend && targetActivity != null && targetActivity.app != null) { // Set power mode when the activity's process is different than the current top resumed // activity on all display areas, or if there are no resumed activities in the system. boolean[] noResumedActivities = {true}; @@ -3568,13 +3561,28 @@ class RootWindowContainer extends WindowContainer<DisplayContent> !resumedActivityProcess.equals(targetActivity.app); } }); - sendPowerModeLaunch = noResumedActivities[0] || allFocusedProcessesDiffer[0]; + if (!noResumedActivities[0] && !allFocusedProcessesDiffer[0]) { + // All focused activities are resumed and the process of the target activity is + // the same as them, e.g. delivering new intent to the current top. + return; + } } - if (sendPowerModeLaunch) { - mService.startLaunchPowerMode( - ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY); + int reason = ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY; + // If the activity is launching while keyguard is locked (including occluded), the activity + // may be visible until its first relayout is done (e.g. apply show-when-lock flag). To + // avoid power mode from being cleared before that, add a special reason to consider whether + // the unknown visibility is resolved. The case from SystemUI is excluded because it should + // rely on keyguard-going-away. + if (mService.mKeyguardController.isKeyguardLocked() && targetActivity != null + && !targetActivity.isLaunchSourceType(ActivityRecord.LAUNCH_SOURCE_TYPE_SYSTEMUI)) { + final ActivityOptions opts = targetActivity.getOptions(); + if (opts == null || opts.getSourceInfo() == null + || opts.getSourceInfo().type != ActivityOptions.SourceInfo.TYPE_LOCKSCREEN) { + reason |= ActivityTaskManagerService.POWER_MODE_REASON_UNKNOWN_VISIBILITY; + } } + mService.startLaunchPowerMode(reason); } // TODO(b/191434136): handle this properly when we add multi-window support on secondary diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index b95d56b58d06..40a5a8159515 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -301,6 +301,15 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { // The top app should not change while sleeping. assertEquals(topActivity.app, mAtm.mInternal.getTopApp()); + mAtm.startLaunchPowerMode(ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY + | ActivityTaskManagerService.POWER_MODE_REASON_UNKNOWN_VISIBILITY); + assertEquals(ActivityManager.PROCESS_STATE_TOP, mAtm.mInternal.getTopProcessState()); + // Because there is no unknown visibility record, the state will be restored if other + // reasons are all done. + mAtm.endLaunchPowerMode(ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY); + assertEquals(ActivityManager.PROCESS_STATE_TOP_SLEEPING, + mAtm.mInternal.getTopProcessState()); + // If all activities are stopped, the sleep wake lock must be released. final Task topRootTask = topActivity.getRootTask(); doReturn(true).when(rootHomeTask).goToSleepIfPossible(anyBoolean()); |