diff options
5 files changed, 87 insertions, 25 deletions
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index f4a4af2775b7..666f3a254175 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -347,6 +347,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai private final Rect mTmpRect2 = new Rect(); private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic(); + /** List for processing through a set of activities */ + private final ArrayList<ActivityRecord> mTmpActivities = new ArrayList<>(); + /** Run all ActivityStacks through this */ protected final ActivityStackSupervisor mStackSupervisor; @@ -4405,11 +4408,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai "Removing app " + app + " from history with " + i + " entries"); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; - for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { - final ActivityRecord r = activities.get(activityNdx); - --i; + mTmpActivities.clear(); + mTmpActivities.addAll(activities); + + while (!mTmpActivities.isEmpty()) { + final int targetIndex = mTmpActivities.size() - 1; + final ActivityRecord r = mTmpActivities.remove(targetIndex); if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, - "Record #" + i + " " + r + ": app=" + r.app); + "Record #" + targetIndex + " " + r + ": app=" + r.app); + if (r.app == app) { if (r.visible) { hasVisibleActivities = true; @@ -4827,9 +4834,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai ComponentName homeActivity = null; for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; - int numActivities = activities.size(); - for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { - ActivityRecord r = activities.get(activityNdx); + mTmpActivities.clear(); + mTmpActivities.addAll(activities); + + while (!mTmpActivities.isEmpty()) { + ActivityRecord r = mTmpActivities.remove(0); final boolean sameComponent = (r.packageName.equals(packageName) && (filterByClasses == null || filterByClasses.contains(r.realActivity.getClassName()))) @@ -4862,12 +4871,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai r.app = null; } lastTask = r.getTask(); - if (finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop", - true)) { - // r has been deleted from mActivities, accommodate. - --numActivities; - --activityNdx; - } + finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop", + true); } } } diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 6f6e0d989f13..8174f405684a 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -2002,7 +2002,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } else if (intent != null) { sb.append(" I="); sb.append(intent.getComponent().flattenToShortString()); - } else if (affinityIntent != null) { + } else if (affinityIntent != null && affinityIntent.getComponent() != null) { sb.append(" aI="); sb.append(affinityIntent.getComponent().flattenToShortString()); } else { diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index 32a29a21cdbb..d60623d2e095 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -486,4 +486,45 @@ public class ActivityStackTests extends ActivityTestsBase { verify(lifecycleManager, times(1)).scheduleTransaction(eq(app.thread), eq(r.appToken), any(DestroyActivityItem.class)); } + + @Test + public void testFinishDisabledPackageActivities() throws Exception { + final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build(); + + // Making the second activity a task overlay without an app means it will be removed from + // the task's activities as well once first activity is removed. + secondActivity.mTaskOverlay = true; + secondActivity.app = null; + + assertEquals(mTask.mActivities.size(), 2); + + mStack.finishDisabledPackageActivitiesLocked(firstActivity.packageName, null, + true /* doit */, true /* evenPersistent */, UserHandle.USER_ALL); + + assertTrue(mTask.mActivities.isEmpty()); + assertTrue(mStack.getAllTasks().isEmpty()); + } + + @Test + public void testHandleAppDied() throws Exception { + final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build(); + + // Making the first activity a task overlay means it will be removed from the task's + // activities as well once second activity is removed as handleAppDied processes the + // activity list in reverse. + firstActivity.mTaskOverlay = true; + firstActivity.app = null; + + // second activity will be immediately removed as it has no state. + secondActivity.haveState = false; + + assertEquals(mTask.mActivities.size(), 2); + + mStack.handleAppDiedLocked(secondActivity.app); + + assertTrue(mTask.mActivities.isEmpty()); + assertTrue(mStack.getAllTasks().isEmpty()); + } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java index b58c7003f39e..fdabfb4360f9 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java @@ -197,11 +197,6 @@ public class ActivityStarterTests extends ActivityTestsBase { final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO) ? null : new ActivityInfo(); - if (aInfo != null) { - aInfo.applicationInfo = new ApplicationInfo(); - aInfo.applicationInfo.packageName = ActivityBuilder.DEFAULT_PACKAGE; - } - IVoiceInteractionSession voiceSession = containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION) ? mock(IVoiceInteractionSession.class) : null; @@ -210,6 +205,11 @@ public class ActivityStarterTests extends ActivityTestsBase { final ActivityBuilder builder = new ActivityBuilder(service).setTask( new TaskBuilder(service.mStackSupervisor).setVoiceSession(voiceSession).build()); + if (aInfo != null) { + aInfo.applicationInfo = new ApplicationInfo(); + aInfo.applicationInfo.packageName = builder.getDefaultComponentPackageName(); + } + // Offset uid by one from {@link ActivityInfo} to simulate different uids. if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) { builder.setUid(aInfo.applicationInfo.uid + 1); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index ff7b1d0644ba..1195188157c4 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -67,6 +67,12 @@ public class ActivityTestsBase { private final Context mContext = InstrumentationRegistry.getContext(); private HandlerThread mHandlerThread; + // Default package name + static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo"; + + // Default base activity name + private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity"; + @Before public void setUp() throws Exception { if (!sOneTimeSetupDone) { @@ -106,11 +112,7 @@ public class ActivityTestsBase { // An id appended to the end of the component name to make it unique private static int sCurrentActivityId = 0; - // Default package name - static final String DEFAULT_PACKAGE = "com.foo"; - // Default base activity name - private static final String DEFAULT_BASE_ACTIVITY_NAME = ".BarActivity"; private final ActivityManagerService mService; @@ -149,11 +151,15 @@ public class ActivityTestsBase { return this; } + String getDefaultComponentPackageName() { + return DEFAULT_COMPONENT_PACKAGE_NAME; + } + ActivityRecord build() { if (mComponent == null) { final int id = sCurrentActivityId++; - mComponent = ComponentName.createRelative(DEFAULT_PACKAGE, - DEFAULT_BASE_ACTIVITY_NAME + id); + mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, + DEFAULT_COMPONENT_CLASS_NAME + id); } if (mCreateTask) { @@ -191,6 +197,9 @@ public class ActivityTestsBase { * Builder for creating new tasks. */ protected static class TaskBuilder { + // Default package name + static final String DEFAULT_PACKAGE = "com.bar"; + private final ActivityStackSupervisor mSupervisor; private ComponentName mComponent; @@ -252,6 +261,11 @@ public class ActivityTestsBase { aInfo.applicationInfo.packageName = mPackage; Intent intent = new Intent(); + if (mComponent == null) { + mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, + DEFAULT_COMPONENT_CLASS_NAME); + } + intent.setComponent(mComponent); intent.setFlags(mFlags); @@ -312,6 +326,8 @@ public class ActivityTestsBase { doNothing().when(supervisor).ensureActivitiesVisibleLocked(any(), anyInt(), anyBoolean()); // Do not schedule idle timeouts doNothing().when(supervisor).scheduleIdleTimeoutLocked(any()); + // unit test version does not handle launch wake lock + doNothing().when(supervisor).acquireLaunchWakelock(); supervisor.initialize(); |