summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java34
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java19
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();