Addition separation of adding vs. reparenting activity
- Removed method ActivityRecord.setTask which did only half of what
is needed when adding a task and also only did half of what is needed
for reparenting. Previous callers now need to call either
ActivityRecord.reparent() to reparent and activity or
TaskRecord.addActivityAtIndex() to add an activity to a task.
- Fixed some NPE that resulted from the above change.
Test: adb shell am instrument -w -e class
com.google.android.setupwizard.tests.activity.SetupWizardExitActivityTest
com.google.android.setupwizard.tests.activity
Bug: 34179495
Change-Id: Ic69487f51d1bd139825e6a8054a49ce143065a57
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 962056f..3573b8b 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -37,6 +37,8 @@
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
@@ -773,7 +775,10 @@
// Remove the activity from the old task and add it to the new task
prevTask.removeActivity(this);
- setTask(newTask, null);
+ // TODO(b/34179495): This should really be set to null in removeActivity() call above,
+ // but really bad things that I can't track down right now happen when I do that.
+ // So, setting it here now and will change later when there is time for investigation.
+ task = null;
newTask.addActivityAtIndex(position, this);
}
@@ -821,19 +826,8 @@
}
}
- void setTask(TaskRecord newTask, TaskRecord taskToAffiliateWith) {
- if (task != null && task.removeActivity(this) && task != newTask
- && task.getStack() != null) {
- task.getStack().removeTask(task, "setTask");
- }
- task = newTask;
- setTaskToAffiliateWith(taskToAffiliateWith);
- }
-
void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
- if (taskToAffiliateWith != null &&
- launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE &&
- launchMode != ActivityInfo.LAUNCH_SINGLE_TASK) {
+ if (launchMode != LAUNCH_SINGLE_INSTANCE && launchMode != LAUNCH_SINGLE_TASK) {
task.setTaskToAffiliateWith(taskToAffiliateWith);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 54082ea..10d108b 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2775,7 +2775,12 @@
// Slot the activity into the history stack and proceed
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
new RuntimeException("here").fillInStackTrace());
- r.createWindowContainer();
+ // TODO: Need to investigate if it is okay for the controller to already be created by the
+ // time we get to this point. I think it is, but need to double check.
+ // Use test in b/34179495 to trace the call path.
+ if (r.getWindowContainerController() == null) {
+ r.createWindowContainer();
+ }
task.setFrontOfTask();
if (!isHomeOrRecentsStack() || numActivities() > 0) {
@@ -2952,8 +2957,7 @@
+ targetTask + " Callers=" + Debug.getCallers(4));
if (DEBUG_TASKS) Slog.v(TAG_TASKS,
"Pushing next activity " + p + " out to target's task " + target.task);
- p.setTask(targetTask, null);
- targetTask.addActivityAtBottom(p);
+ p.reparent(targetTask, 0 /* position - bottom */, "resetTargetTaskIfNeeded");
}
mWindowContainerController.positionChildAtBottom(
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 73ef88b..c2fc9dc 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1615,7 +1615,7 @@
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity.mActivityType);
- mStartActivity.setTask(task, taskToAffiliate);
+ addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
if (mLaunchBounds != null) {
final int stackId = mTargetStack.mStackId;
if (StackId.resizeStackWithLaunchBounds(stackId)) {
@@ -1625,11 +1625,14 @@
mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
}
}
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Starting new activity " +
- mStartActivity + " in new task " + mStartActivity.task);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ + " in new task " + mStartActivity.task);
} else {
- mStartActivity.setTask(mReuseTask, taskToAffiliate);
+ addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask");
+ }
+
+ if (taskToAffiliate != null) {
+ mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
}
if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
@@ -1719,7 +1722,7 @@
// An existing activity is starting this new activity, so we want to keep the new one in
// the same task as the one that is starting it.
- mStartActivity.setTask(sourceTask, null);
+ addOrReparentStartingActivity(sourceTask, "setTaskFromSourceRecord");
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
return START_SUCCESS;
@@ -1752,7 +1755,8 @@
// Check whether we should actually launch the new activity in to the task,
// or just reuse the current activity on top.
ActivityRecord top = mInTask.getTopActivity();
- if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) {
+ if (top != null && top.realActivity.equals(mStartActivity.realActivity)
+ && top.userId == mStartActivity.userId) {
if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| mLaunchSingleTop || mLaunchSingleTask) {
ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
@@ -1761,7 +1765,8 @@
// anything if that is the case, so this is it!
return START_RETURN_INTENT_TO_CALLER;
}
- top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
+ mStartActivity.launchedFromPackage);
return START_DELIVERED_TO_TOP;
}
}
@@ -1773,9 +1778,9 @@
return START_TASK_TO_FRONT;
}
- mStartActivity.setTask(mInTask, null);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Starting new activity " + mStartActivity + " in explicit task " + mStartActivity.task);
+ addOrReparentStartingActivity(mInTask, "setTaskFromInTask");
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ + " in explicit task " + mStartActivity.task);
return START_SUCCESS;
}
@@ -1790,10 +1795,18 @@
final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
mIntent, null, null, true, mStartActivity.mActivityType);
- mStartActivity.setTask(task, null);
- mStartActivity.task.getStack().positionChildWindowContainerAtTop(mStartActivity.task);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
+ addOrReparentStartingActivity(task, "setTaskToCurrentTopOrCreateNewTask");
+ mTargetStack.positionChildWindowContainerAtTop(task);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ + " in new guessed " + mStartActivity.task);
+ }
+
+ private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
+ if (mStartActivity.task == null) {
+ parent.addActivityToTop(mStartActivity);
+ } else {
+ mStartActivity.reparent(parent, parent.mActivities.size() /* top */, reason);
+ }
}
private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index fef4073..9e09cbb 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -51,6 +51,7 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.util.XmlUtils;
+import com.android.server.wm.AppWindowContainerController;
import com.android.server.wm.TaskWindowContainerController;
import com.android.server.wm.TaskWindowContainerListener;
@@ -1033,6 +1034,12 @@
* be in the current task or unparented to any task.
*/
void addActivityAtIndex(int index, ActivityRecord r) {
+ if (r.task != null && r.task != this) {
+ throw new IllegalArgumentException("Can not add r=" + " to task=" + this
+ + " current parent=" + r.task);
+ }
+ r.task = this;
+
// Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
if (!mActivities.remove(r) && r.fullscreen) {
// Was not previously in list.
@@ -1063,6 +1070,7 @@
}
}
+ index = Math.min(size, index);
mActivities.add(index, r);
updateEffectiveIntent();
if (r.isPersistable()) {
@@ -1071,7 +1079,12 @@
// Sync. with window manager
updateOverrideConfigurationFromLaunchBounds();
- mWindowContainerController.positionChildAt(r.getWindowContainerController(), index);
+ final AppWindowContainerController appController = r.getWindowContainerController();
+ if (appController != null) {
+ // Only attempt to move in WM if the child has a controller. It is possible we haven't
+ // created controller for the activity we are starting yet.
+ mWindowContainerController.positionChildAt(appController, index);
+ }
r.onOverrideConfigurationSent();
}