diff options
5 files changed, 98 insertions, 31 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 6ae8887a7912..c7e1b8bbf020 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -402,12 +402,25 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** The time at which the previous process was last visible. */ private long mPreviousProcessVisibleTime; + /** It is set from keyguard-going-away to set-keyguard-shown. */ + static final int DEMOTE_TOP_REASON_DURING_UNLOCKING = 1; + /** It is set if legacy recents animation is running. */ + static final int DEMOTE_TOP_REASON_ANIMATING_RECENTS = 1 << 1; + + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + DEMOTE_TOP_REASON_DURING_UNLOCKING, + DEMOTE_TOP_REASON_ANIMATING_RECENTS, + }) + @interface DemoteTopReason {} + /** - * It can be true from keyguard-going-away to set-keyguard-shown. And getTopProcessState() will + * If non-zero, getTopProcessState() will * return {@link ActivityManager#PROCESS_STATE_IMPORTANT_FOREGROUND} to avoid top app from - * preempting CPU while keyguard is animating. + * preempting CPU while another process is running an important animation. */ - private volatile boolean mDemoteTopAppDuringUnlocking; + @DemoteTopReason + volatile int mDemoteTopAppReasons; /** List of intents that were used to start the most recent tasks. */ private RecentTasks mRecentTasks; @@ -2841,8 +2854,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } // Always reset the state regardless of keyguard-showing change, because that means the // unlock is either completed or canceled. - if (mDemoteTopAppDuringUnlocking) { - mDemoteTopAppDuringUnlocking = false; + if ((mDemoteTopAppReasons & DEMOTE_TOP_REASON_DURING_UNLOCKING) != 0) { + mDemoteTopAppReasons &= ~DEMOTE_TOP_REASON_DURING_UNLOCKING; // The scheduling group of top process was demoted by unlocking, so recompute // to restore its real top priority if possible. if (mTopApp != null) { @@ -2883,7 +2896,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; + mDemoteTopAppReasons &= ~DEMOTE_TOP_REASON_DURING_UNLOCKING; final WindowState notificationShade = mRootWindowContainer.getDefaultDisplay() .getDisplayPolicy().getNotificationShade(); proc = notificationShade != null @@ -3425,7 +3438,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mActivityClientController.invalidateHomeTaskSnapshot(null /* token */); } else if (mKeyguardShown) { // Only set if it is not unlocking to launcher which may also animate. - mDemoteTopAppDuringUnlocking = true; + mDemoteTopAppReasons |= DEMOTE_TOP_REASON_DURING_UNLOCKING; } mRootWindowContainer.forAllDisplays(displayContent -> { @@ -4035,6 +4048,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mTaskOrganizerController.dump(pw, " "); mVisibleActivityProcessTracker.dump(pw, " "); mActiveUids.dump(pw, " "); + if (mDemoteTopAppReasons != 0) { + pw.println(" mDemoteTopAppReasons=" + mDemoteTopAppReasons); + } } if (!printedAnything) { @@ -5663,8 +5679,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @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. + if (mDemoteTopAppReasons != 0 && topState == ActivityManager.PROCESS_STATE_TOP) { + // There may be a more important UI/animation than the top app. return ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; } if (mRetainPowerModeAndTopProcessState) { diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index eca201dc2bda..f840171b29b0 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -203,9 +203,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, OnRootTaskOrderChan final LaunchingState launchingState = mTaskSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent); - if (mCaller != null) { - mCaller.setRunningRecentsAnimation(true); - } + setProcessAnimating(true); mService.deferWindowLayout(); try { @@ -409,15 +407,33 @@ class RecentsAnimation implements RecentsAnimationCallbacks, OnRootTaskOrderChan if (mWindowManager.mRoot.isLayoutNeeded()) { mWindowManager.mRoot.performSurfacePlacement(); } - if (mCaller != null) { - mCaller.setRunningRecentsAnimation(false); - } + setProcessAnimating(false); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } }); } } + /** Gives the owner of recents animation higher priority. */ + private void setProcessAnimating(boolean animating) { + if (mCaller == null) return; + // Apply the top-app scheduling group to who runs the animation. + mCaller.setRunningRecentsAnimation(animating); + int demoteReasons = mService.mDemoteTopAppReasons; + if (animating) { + demoteReasons |= ActivityTaskManagerService.DEMOTE_TOP_REASON_ANIMATING_RECENTS; + } else { + demoteReasons &= ~ActivityTaskManagerService.DEMOTE_TOP_REASON_ANIMATING_RECENTS; + } + mService.mDemoteTopAppReasons = demoteReasons; + // Make the demotion of the real top app take effect. No need to restore top app state for + // finishing recents because addToStopping -> scheduleIdle -> activityIdleInternal -> + // trimApplications will have a full update. + if (animating && mService.mTopApp != null) { + mService.mTopApp.scheduleUpdateOomAdj(); + } + } + @Override public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode, boolean sendUserLeaveHint) { diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index 1b19a28a9790..a1d6a5006fef 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -37,13 +37,13 @@ import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; -import android.app.IApplicationThread; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -91,9 +91,15 @@ public class RecentsAnimationTest extends WindowTestsBase { TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); Task recentsStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); + final WindowProcessController wpc = mSystemServicesTestRule.addProcess( + mRecentsComponent.getPackageName(), mRecentsComponent.getPackageName(), + // Use real pid/uid of the test so the corresponding process can be mapped by + // Binder.getCallingPid/Uid. + WindowManagerService.MY_PID, WindowManagerService.MY_UID); ActivityRecord recentActivity = new ActivityBuilder(mAtm) .setComponent(mRecentsComponent) .setTask(recentsStack) + .setUseProcess(wpc) .build(); ActivityRecord topActivity = new ActivityBuilder(mAtm).setCreateTask(true).build(); topActivity.getRootTask().moveToFront("testRecentsActivityVisiblility"); @@ -106,11 +112,14 @@ public class RecentsAnimationTest extends WindowTestsBase { mRecentsComponent, true /* getRecentsAnimation */); // The launch-behind state should make the recents activity visible. assertTrue(recentActivity.mVisibleRequested); + assertEquals(ActivityTaskManagerService.DEMOTE_TOP_REASON_ANIMATING_RECENTS, + mAtm.mDemoteTopAppReasons); // Simulate the animation is cancelled without changing the stack order. recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, false /* sendUserLeaveHint */); // The non-top recents activity should be invisible by the restored launch-behind state. assertFalse(recentActivity.mVisibleRequested); + assertEquals(0, mAtm.mDemoteTopAppReasons); } @Test @@ -138,11 +147,8 @@ public class RecentsAnimationTest extends WindowTestsBase { anyInt() /* startFlags */, any() /* profilerInfo */); // Assume its process is alive because the caller should be the recents service. - WindowProcessController wpc = new WindowProcessController(mAtm, aInfo.applicationInfo, - aInfo.processName, aInfo.applicationInfo.uid, 0 /* userId */, - mock(Object.class) /* owner */, mock(WindowProcessListener.class)); - wpc.setThread(mock(IApplicationThread.class)); - doReturn(wpc).when(mAtm).getProcessController(eq(wpc.mName), eq(wpc.mUid)); + mSystemServicesTestRule.addProcess(aInfo.packageName, aInfo.processName, 12345 /* pid */, + aInfo.applicationInfo.uid); Intent recentsIntent = new Intent().setComponent(mRecentsComponent); // Null animation indicates to preload. diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index 18c4eb964a3a..6c100d76f5fb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -43,12 +43,14 @@ import static org.mockito.Mockito.withSettings; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; +import android.app.IApplicationThread; import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManagerInternal; import android.database.ContentObserver; @@ -430,6 +432,34 @@ public class SystemServicesTestRule implements TestRule { .spiedInstance(sWakeLock).stubOnly()); } + WindowProcessController addProcess(String pkgName, String procName, int pid, int uid) { + return addProcess(mAtmService, pkgName, procName, pid, uid); + } + + static WindowProcessController addProcess(ActivityTaskManagerService atmService, String pkgName, + String procName, int pid, int uid) { + final ApplicationInfo info = new ApplicationInfo(); + info.uid = uid; + info.packageName = pkgName; + return addProcess(atmService, info, procName, pid); + } + + static WindowProcessController addProcess(ActivityTaskManagerService atmService, + ApplicationInfo info, String procName, int pid) { + final WindowProcessListener mockListener = mock(WindowProcessListener.class, + withSettings().stubOnly()); + final int uid = info.uid; + final WindowProcessController proc = new WindowProcessController(atmService, + info, procName, uid, UserHandle.getUserId(uid), mockListener, mockListener); + proc.setThread(mock(IApplicationThread.class, withSettings().stubOnly())); + atmService.mProcessNames.put(procName, uid, proc); + if (pid > 0) { + proc.setPid(pid); + atmService.mProcessMap.put(pid, proc); + } + return proc; + } + void cleanupWindowManagerHandlers() { final WindowManagerService wm = getWindowManagerService(); if (wm == null) { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 50fa4cc9eb7c..8a539cd3ddff 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -64,7 +64,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityOptions; -import android.app.IApplicationThread; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -933,13 +932,15 @@ class WindowTestsBase extends SystemServiceTestsBase { */ protected static class ActivityBuilder { static final int DEFAULT_FAKE_UID = 12345; + static final String DEFAULT_PROCESS_NAME = "procName"; + static int sProcNameSeq; private final ActivityTaskManagerService mService; private ComponentName mComponent; private String mTargetActivity; private Task mTask; - private String mProcessName = "name"; + private String mProcessName = DEFAULT_PROCESS_NAME; private String mAffinity; private int mUid = DEFAULT_FAKE_UID; private boolean mCreateTask = false; @@ -1127,6 +1128,9 @@ class WindowTestsBase extends SystemServiceTestsBase { aInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; aInfo.applicationInfo.packageName = mComponent.getPackageName(); aInfo.applicationInfo.uid = mUid; + if (DEFAULT_PROCESS_NAME.equals(mProcessName)) { + mProcessName += ++sProcNameSeq; + } aInfo.processName = mProcessName; aInfo.packageName = mComponent.getPackageName(); aInfo.name = mComponent.getClassName(); @@ -1191,16 +1195,11 @@ class WindowTestsBase extends SystemServiceTestsBase { if (mWpc != null) { wpc = mWpc; } else { - wpc = new WindowProcessController(mService, - aInfo.applicationInfo, mProcessName, mUid, - UserHandle.getUserId(mUid), mock(Object.class), - mock(WindowProcessListener.class)); - wpc.setThread(mock(IApplicationThread.class)); + final WindowProcessController p = mService.getProcessController(mProcessName, mUid); + wpc = p != null ? p : SystemServicesTestRule.addProcess( + mService, aInfo.applicationInfo, mProcessName, 0 /* pid */); } - wpc.setThread(mock(IApplicationThread.class)); activity.setProcess(wpc); - doReturn(wpc).when(mService).getProcessController( - activity.processName, activity.info.applicationInfo.uid); // Resume top activities to make sure all other signals in the system are connected. mService.mRootWindowContainer.resumeFocusedTasksTopActivities(); |