From f3139a9e51333b926f5f81a76faf4ccde5afac53 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 17 May 2022 16:24:19 -0600 Subject: [PATCH] Demote top app scheduling group when unlocking SystemUI may be running the unlock animation. If both SystemUI and the resuming top app have top-app scheduling group, there may be CPU contention which causes animation jank. An exceptional case is unlocking to home which may also animate, then keep original behavior: both system ui and home will have top-app scheduling group. Bug: 226367352 Test: Launch calculator. Keep executing command "adb shell dumpsys activity o | grep calc" Lock and unlock device. The dump will have the changes: b/A/TPSL ---- t: 0 20687:calc/u0a158 (top-sleeping) F/A/TOP LCMN t: 0 20687:calc/u0a158 (intermediate-top-activity) T/A/TOP LCMN t: 0 20687:calc/u0a158 (top-activity) (b=BG, F=FG, T=TOP) Change-Id: Id0fd2491a11bac7b81bc654e646b3d01643ca8b4 --- .../com/android/server/am/OomAdjuster.java | 16 ++++++--- .../server/wm/ActivityTaskManagerService.java | 34 +++++++++++++++++-- .../server/wm/WindowProcessController.java | 7 ++++ 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index e7fcc59894672..a61cbbfbfc912 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1554,14 +1554,22 @@ public class OomAdjuster { boolean foregroundActivities = false; boolean hasVisibleActivities = false; - if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) { + if (app == topApp && (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP + || PROCESS_STATE_CUR_TOP == PROCESS_STATE_IMPORTANT_FOREGROUND)) { // The last app on the list is the foreground app. adj = ProcessList.FOREGROUND_APP_ADJ; - schedGroup = ProcessList.SCHED_GROUP_TOP_APP; - state.setAdjType("top-activity"); + if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP) { + schedGroup = ProcessList.SCHED_GROUP_TOP_APP; + state.setAdjType("top-activity"); + } else { + // Demote the scheduling group to avoid CPU contention if there is another more + // important process which also uses top-app, such as if SystemUI is animating. + schedGroup = ProcessList.SCHED_GROUP_DEFAULT; + state.setAdjType("intermediate-top-activity"); + } foregroundActivities = true; hasVisibleActivities = true; - procState = PROCESS_STATE_CUR_TOP; + procState = PROCESS_STATE_TOP; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 06242b391d4bc..546f44359e01e 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -64,8 +64,8 @@ import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS; import static android.provider.Settings.System.FONT_SCALE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT; import static android.view.WindowManager.TRANSIT_PIP; +import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; @@ -402,6 +402,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** The time at which the previous process was last visible. */ private long mPreviousProcessVisibleTime; + /** + * It can be true from keyguard-going-away to set-keyguard-shown. And getTopProcessState() will + * return {@link ActivityManager#PROCESS_STATE_IMPORTANT_FOREGROUND} to avoid top app from + * preempting CPU while keyguard is animating. + */ + private volatile boolean mDemoteTopAppDuringUnlocking; + /** List of intents that were used to start the most recent tasks. */ private RecentTasks mRecentTasks; /** State of external calls telling us if the device is awake or asleep. */ @@ -2832,12 +2839,24 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { keyguardShowing); mH.sendMessage(msg); } + // Always reset the state regardless of keyguard-showing change, because that means the + // unlock is either completed or canceled. + if (mDemoteTopAppDuringUnlocking) { + mDemoteTopAppDuringUnlocking = false; + // The scheduling group of top process was demoted by unlocking, so recompute + // to restore its real top priority if possible. + if (mTopApp != null) { + mTopApp.scheduleUpdateOomAdj(); + } + } try { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "setLockScreenShown"); mRootWindowContainer.forAllDisplays(displayContent -> { mKeyguardController.setKeyguardShown(displayContent.getDisplayId(), keyguardShowing, aodShowing); }); } finally { + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Binder.restoreCallingIdentity(ident); } } @@ -2864,6 +2883,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // animation of system UI. Even if AOD is not enabled, it should be no harm. final WindowProcessController proc; synchronized (mGlobalLockWithoutBoost) { + mDemoteTopAppDuringUnlocking = false; final WindowState notificationShade = mRootWindowContainer.getDefaultDisplay() .getDisplayPolicy().getNotificationShade(); proc = notificationShade != null @@ -3401,8 +3421,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { synchronized (mGlobalLock) { // Keyguard asked us to clear the home task snapshot before going away, so do that. - if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT) != 0) { + if ((flags & KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT) != 0) { mActivityClientController.invalidateHomeTaskSnapshot(null /* token */); + } else if (mKeyguardShown) { + // Only set if it is not unlocking to launcher which may also animate. + mDemoteTopAppDuringUnlocking = true; } mRootWindowContainer.forAllDisplays(displayContent -> { @@ -5639,12 +5662,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @HotPath(caller = HotPath.OOM_ADJUSTMENT) @Override public int getTopProcessState() { + final int topState = mTopProcessState; + if (mDemoteTopAppDuringUnlocking && topState == ActivityManager.PROCESS_STATE_TOP) { + // The unlocking UI is more important, so defer the top state of app. + return ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; + } 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; + return topState; } @HotPath(caller = HotPath.PROCESS_CHANGE) diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 1c64a06036f0b..8fed270c6a1c5 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -1151,6 +1151,13 @@ public class WindowProcessController extends ConfigurationContainer