Loading services/core/java/com/android/server/wm/ActivityStarter.java +15 −0 Original line number Diff line number Diff line Loading @@ -2285,6 +2285,15 @@ class ActivityStarter { mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; } if (r.info.requiredDisplayCategory != null && mSourceRecord != null && !r.info.requiredDisplayCategory.equals( mSourceRecord.info.requiredDisplayCategory)) { // Adding NEW_TASK flag for activity with display category attribute if the display // category of the source record is different, so that the activity won't be launched // in source record's task. mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; } sendNewTaskResultRequestIfNeeded(); if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) { Loading Loading @@ -2372,6 +2381,12 @@ class ActivityStarter { Slog.w(TAG, "Starting activity in task not in recents: " + inTask); mInTask = null; } // Prevent to start activity in Task with different display category if (mInTask != null && !mInTask.isSameRequiredDisplayCategory(r.info)) { Slog.w(TAG, "Starting activity in task with different display category: " + mInTask); mInTask = null; } mInTaskFragment = inTaskFragment; mStartFlags = startFlags; Loading services/core/java/com/android/server/wm/RootWindowContainer.java +2 −1 Original line number Diff line number Diff line Loading @@ -418,7 +418,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } else if (!isDocument && !taskIsDocument && mIdealRecord == null && mCandidateRecord == null && task.rootAffinity != null) { if (task.rootAffinity.equals(mTaskAffinity)) { if (task.rootAffinity.equals(mTaskAffinity) && task.isSameRequiredDisplayCategory(mInfo)) { ProtoLog.d(WM_DEBUG_TASKS, "Found matching affinity candidate!"); // It is possible for multiple tasks to have the same root affinity especially // if they are in separate root tasks. We save off this candidate, but keep Loading services/core/java/com/android/server/wm/Task.java +13 −0 Original line number Diff line number Diff line Loading @@ -491,6 +491,9 @@ class Task extends TaskFragment { private int mForceHiddenFlags = 0; private boolean mForceTranslucent = false; // The display category name for this task. String mRequiredDisplayCategory; // TODO(b/160201781): Revisit double invocation issue in Task#removeChild. /** * Skip {@link ActivityTaskSupervisor#removeTask(Task, boolean, boolean, String)} execution if Loading Loading @@ -1011,6 +1014,7 @@ class Task extends TaskFragment { // affinity -- we don't want it changing after initially set, but the initially // set value may be null. rootAffinity = affinity; mRequiredDisplayCategory = info.requiredDisplayCategory; } effectiveUid = info.applicationInfo.uid; mIsEffectivelySystemApp = info.applicationInfo.isSystemApp(); Loading Loading @@ -6078,6 +6082,15 @@ class Task extends TaskFragment { } } /** * Return true if the activityInfo has the same requiredDisplayCategory as this task. */ boolean isSameRequiredDisplayCategory(@NonNull ActivityInfo info) { return mRequiredDisplayCategory != null && mRequiredDisplayCategory.equals( info.requiredDisplayCategory) || (mRequiredDisplayCategory == null && info.requiredDisplayCategory == null); } @Override public void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { Loading services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +115 −0 Original line number Diff line number Diff line Loading @@ -62,11 +62,13 @@ import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowTestsBase.ActivityBuilder.DEFAULT_FAKE_UID; 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.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; Loading Loading @@ -1617,6 +1619,119 @@ public class ActivityStarterTests extends WindowTestsBase { assertNull(starter2.mMovedToTopActivity); } /** * Tests a task with specific display category exist in system and then launching another * activity with the same affinity but without define the display category. Make sure the * lunching activity is placed on the different task. */ @Test public void testLaunchActivityWithoutDisplayCategory() { final ActivityInfo info = new ActivityInfo(); info.applicationInfo = new ApplicationInfo(); info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID, 0 /* launchMode */); info.requiredDisplayCategory = "automotive"; final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info) .build(); final ActivityRecord target = new ActivityBuilder(mAtm).setAffinity(info.taskAffinity) .build(); final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK, false); startActivityInner(starter, target, null /* source */, null /* options */, null /* inTask */, null /* inTaskFragment */); assertNotEquals(task, target.getTask()); } /** * Tests a task with a specific display category exist in the system and then launches another * activity with the different display category. Make sure the launching activity is not placed * on the sourceRecord's task. */ @Test public void testLaunchActivityWithDifferentDisplayCategory() { final ActivityInfo info = new ActivityInfo(); info.applicationInfo = new ApplicationInfo(); info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID, 0 /* launchMode */); info.requiredDisplayCategory = "automotive"; final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info) .build(); final ActivityRecord target = new ActivityBuilder(mAtm).setRequiredDisplayCategory("auto") .setAffinity(info.taskAffinity).build(); final ActivityStarter starter = prepareStarter(0, false); startActivityInner(starter, target, task.getBottomMostActivity(), null /* options */, null /* inTask */, null /* inTaskFragment */); assertNotEquals(task, target.getTask()); } /** * Tests a task with specific display category exist in system and then launching another * activity with the same display category. Make sure the launching activity is placed on the * same task. */ @Test public void testLaunchActivityWithSameDisplayCategory() { final ActivityInfo info = new ActivityInfo(); info.applicationInfo = new ApplicationInfo(); info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID, 0 /* launchMode */); info.requiredDisplayCategory = "automotive"; final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info) .build(); final ActivityRecord target = new ActivityBuilder(mAtm) .setRequiredDisplayCategory(info.requiredDisplayCategory) .setAffinity(info.taskAffinity).build(); final ActivityStarter starter = prepareStarter(0, false); startActivityInner(starter, target, task.getBottomMostActivity(), null /* options */, null /* inTask */, null /* inTaskFragment */); assertEquals(task, target.getTask()); } /** * Tests a task with specific display category exist in system and launching activity into the * specific task within inTask attribute. Make sure the activity is not placed on the task since * the display category is different. */ @Test public void testLaunchActivityInTaskWithDisplayCategory() { final ActivityInfo info = new ActivityInfo(); info.applicationInfo = new ApplicationInfo(); info.requiredDisplayCategory = "automotive"; final Task inTask = new TaskBuilder(mSupervisor).setActivityInfo(info).build(); inTask.inRecents = true; final ActivityStarter starter = prepareStarter(0, false); final ActivityRecord target = new ActivityBuilder(mAtm).build(); startActivityInner(starter, target, null /* source */, null /* options */, inTask, null /* inTaskFragment */); assertNotEquals(inTask, target.getTask()); } /** * Tests a task without a specific display category exist in the system and launches activity * with display category into the task within the inTask attribute. Make sure the activity is * not placed on the task since the display category is different. */ @Test public void testLaunchDisplayCategoryActivityInTask() { final Task inTask = new TaskBuilder(mSupervisor).build(); inTask.inRecents = true; final ActivityStarter starter = prepareStarter(0, false); final ActivityRecord target = new ActivityBuilder(mAtm).setRequiredDisplayCategory("auto") .build(); startActivityInner(starter, target, null /* source */, null /* options */, inTask, null /* inTaskFragment */); assertNotEquals(inTask, target.getTask()); } private static void startActivityInner(ActivityStarter starter, ActivityRecord target, ActivityRecord source, ActivityOptions options, Task inTask, TaskFragment inTaskFragment) { Loading services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +9 −0 Original line number Diff line number Diff line Loading @@ -1017,6 +1017,7 @@ class WindowTestsBase extends SystemServiceTestsBase { private ActivityInfo.WindowLayout mWindowLayout; private boolean mVisible = true; private ActivityOptions mLaunchIntoPipOpts; private String mRequiredDisplayCategory; ActivityBuilder(ActivityTaskManagerService service) { mService = service; Loading Loading @@ -1157,6 +1158,11 @@ class WindowTestsBase extends SystemServiceTestsBase { return this; } ActivityBuilder setRequiredDisplayCategory(String requiredDisplayCategory) { mRequiredDisplayCategory = requiredDisplayCategory; return this; } ActivityRecord build() { SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock); try { Loading Loading @@ -1201,6 +1207,9 @@ class WindowTestsBase extends SystemServiceTestsBase { aInfo.configChanges |= mConfigChanges; aInfo.taskAffinity = mAffinity; aInfo.windowLayout = mWindowLayout; if (mRequiredDisplayCategory != null) { aInfo.requiredDisplayCategory = mRequiredDisplayCategory; } if (mCreateTask) { mTask = new TaskBuilder(mService.mTaskSupervisor) Loading Loading
services/core/java/com/android/server/wm/ActivityStarter.java +15 −0 Original line number Diff line number Diff line Loading @@ -2285,6 +2285,15 @@ class ActivityStarter { mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; } if (r.info.requiredDisplayCategory != null && mSourceRecord != null && !r.info.requiredDisplayCategory.equals( mSourceRecord.info.requiredDisplayCategory)) { // Adding NEW_TASK flag for activity with display category attribute if the display // category of the source record is different, so that the activity won't be launched // in source record's task. mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; } sendNewTaskResultRequestIfNeeded(); if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) { Loading Loading @@ -2372,6 +2381,12 @@ class ActivityStarter { Slog.w(TAG, "Starting activity in task not in recents: " + inTask); mInTask = null; } // Prevent to start activity in Task with different display category if (mInTask != null && !mInTask.isSameRequiredDisplayCategory(r.info)) { Slog.w(TAG, "Starting activity in task with different display category: " + mInTask); mInTask = null; } mInTaskFragment = inTaskFragment; mStartFlags = startFlags; Loading
services/core/java/com/android/server/wm/RootWindowContainer.java +2 −1 Original line number Diff line number Diff line Loading @@ -418,7 +418,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } else if (!isDocument && !taskIsDocument && mIdealRecord == null && mCandidateRecord == null && task.rootAffinity != null) { if (task.rootAffinity.equals(mTaskAffinity)) { if (task.rootAffinity.equals(mTaskAffinity) && task.isSameRequiredDisplayCategory(mInfo)) { ProtoLog.d(WM_DEBUG_TASKS, "Found matching affinity candidate!"); // It is possible for multiple tasks to have the same root affinity especially // if they are in separate root tasks. We save off this candidate, but keep Loading
services/core/java/com/android/server/wm/Task.java +13 −0 Original line number Diff line number Diff line Loading @@ -491,6 +491,9 @@ class Task extends TaskFragment { private int mForceHiddenFlags = 0; private boolean mForceTranslucent = false; // The display category name for this task. String mRequiredDisplayCategory; // TODO(b/160201781): Revisit double invocation issue in Task#removeChild. /** * Skip {@link ActivityTaskSupervisor#removeTask(Task, boolean, boolean, String)} execution if Loading Loading @@ -1011,6 +1014,7 @@ class Task extends TaskFragment { // affinity -- we don't want it changing after initially set, but the initially // set value may be null. rootAffinity = affinity; mRequiredDisplayCategory = info.requiredDisplayCategory; } effectiveUid = info.applicationInfo.uid; mIsEffectivelySystemApp = info.applicationInfo.isSystemApp(); Loading Loading @@ -6078,6 +6082,15 @@ class Task extends TaskFragment { } } /** * Return true if the activityInfo has the same requiredDisplayCategory as this task. */ boolean isSameRequiredDisplayCategory(@NonNull ActivityInfo info) { return mRequiredDisplayCategory != null && mRequiredDisplayCategory.equals( info.requiredDisplayCategory) || (mRequiredDisplayCategory == null && info.requiredDisplayCategory == null); } @Override public void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { Loading
services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +115 −0 Original line number Diff line number Diff line Loading @@ -62,11 +62,13 @@ import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowTestsBase.ActivityBuilder.DEFAULT_FAKE_UID; 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.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; Loading Loading @@ -1617,6 +1619,119 @@ public class ActivityStarterTests extends WindowTestsBase { assertNull(starter2.mMovedToTopActivity); } /** * Tests a task with specific display category exist in system and then launching another * activity with the same affinity but without define the display category. Make sure the * lunching activity is placed on the different task. */ @Test public void testLaunchActivityWithoutDisplayCategory() { final ActivityInfo info = new ActivityInfo(); info.applicationInfo = new ApplicationInfo(); info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID, 0 /* launchMode */); info.requiredDisplayCategory = "automotive"; final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info) .build(); final ActivityRecord target = new ActivityBuilder(mAtm).setAffinity(info.taskAffinity) .build(); final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK, false); startActivityInner(starter, target, null /* source */, null /* options */, null /* inTask */, null /* inTaskFragment */); assertNotEquals(task, target.getTask()); } /** * Tests a task with a specific display category exist in the system and then launches another * activity with the different display category. Make sure the launching activity is not placed * on the sourceRecord's task. */ @Test public void testLaunchActivityWithDifferentDisplayCategory() { final ActivityInfo info = new ActivityInfo(); info.applicationInfo = new ApplicationInfo(); info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID, 0 /* launchMode */); info.requiredDisplayCategory = "automotive"; final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info) .build(); final ActivityRecord target = new ActivityBuilder(mAtm).setRequiredDisplayCategory("auto") .setAffinity(info.taskAffinity).build(); final ActivityStarter starter = prepareStarter(0, false); startActivityInner(starter, target, task.getBottomMostActivity(), null /* options */, null /* inTask */, null /* inTaskFragment */); assertNotEquals(task, target.getTask()); } /** * Tests a task with specific display category exist in system and then launching another * activity with the same display category. Make sure the launching activity is placed on the * same task. */ @Test public void testLaunchActivityWithSameDisplayCategory() { final ActivityInfo info = new ActivityInfo(); info.applicationInfo = new ApplicationInfo(); info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID, 0 /* launchMode */); info.requiredDisplayCategory = "automotive"; final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info) .build(); final ActivityRecord target = new ActivityBuilder(mAtm) .setRequiredDisplayCategory(info.requiredDisplayCategory) .setAffinity(info.taskAffinity).build(); final ActivityStarter starter = prepareStarter(0, false); startActivityInner(starter, target, task.getBottomMostActivity(), null /* options */, null /* inTask */, null /* inTaskFragment */); assertEquals(task, target.getTask()); } /** * Tests a task with specific display category exist in system and launching activity into the * specific task within inTask attribute. Make sure the activity is not placed on the task since * the display category is different. */ @Test public void testLaunchActivityInTaskWithDisplayCategory() { final ActivityInfo info = new ActivityInfo(); info.applicationInfo = new ApplicationInfo(); info.requiredDisplayCategory = "automotive"; final Task inTask = new TaskBuilder(mSupervisor).setActivityInfo(info).build(); inTask.inRecents = true; final ActivityStarter starter = prepareStarter(0, false); final ActivityRecord target = new ActivityBuilder(mAtm).build(); startActivityInner(starter, target, null /* source */, null /* options */, inTask, null /* inTaskFragment */); assertNotEquals(inTask, target.getTask()); } /** * Tests a task without a specific display category exist in the system and launches activity * with display category into the task within the inTask attribute. Make sure the activity is * not placed on the task since the display category is different. */ @Test public void testLaunchDisplayCategoryActivityInTask() { final Task inTask = new TaskBuilder(mSupervisor).build(); inTask.inRecents = true; final ActivityStarter starter = prepareStarter(0, false); final ActivityRecord target = new ActivityBuilder(mAtm).setRequiredDisplayCategory("auto") .build(); startActivityInner(starter, target, null /* source */, null /* options */, inTask, null /* inTaskFragment */); assertNotEquals(inTask, target.getTask()); } private static void startActivityInner(ActivityStarter starter, ActivityRecord target, ActivityRecord source, ActivityOptions options, Task inTask, TaskFragment inTaskFragment) { Loading
services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +9 −0 Original line number Diff line number Diff line Loading @@ -1017,6 +1017,7 @@ class WindowTestsBase extends SystemServiceTestsBase { private ActivityInfo.WindowLayout mWindowLayout; private boolean mVisible = true; private ActivityOptions mLaunchIntoPipOpts; private String mRequiredDisplayCategory; ActivityBuilder(ActivityTaskManagerService service) { mService = service; Loading Loading @@ -1157,6 +1158,11 @@ class WindowTestsBase extends SystemServiceTestsBase { return this; } ActivityBuilder setRequiredDisplayCategory(String requiredDisplayCategory) { mRequiredDisplayCategory = requiredDisplayCategory; return this; } ActivityRecord build() { SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock); try { Loading Loading @@ -1201,6 +1207,9 @@ class WindowTestsBase extends SystemServiceTestsBase { aInfo.configChanges |= mConfigChanges; aInfo.taskAffinity = mAffinity; aInfo.windowLayout = mWindowLayout; if (mRequiredDisplayCategory != null) { aInfo.requiredDisplayCategory = mRequiredDisplayCategory; } if (mCreateTask) { mTask = new TaskBuilder(mService.mTaskSupervisor) Loading