diff options
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()); |