Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c17418e0 authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

Clean-up ActivityRecord reparenting/adding to Task (57/n)

- Updated Configuration#onParentChanged to take params newParent and
oldParent to make logic of reparenting less complex to deal with in
classes that extend.
- Introduced WindowContainer#reparent to consolidate reparenting logic
and also allow us to only set onParentChanged once for the operation.
- Simplfied logic flow around adding/remove/reparenting activity to
task by using methods like addChild(), onChildAdded(), and such.
- Removed Task.mDeferRemoval which no longer makes sense and was leading
to task and stack leaks.

Bug: 80414790
Test: Existing tests pass
Change-Id: I4ffa79a1c731dc137213bdd3d7f04b8f013decc4
parent 5acd00da
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -216,7 +216,8 @@ message TaskProto {
    optional bool fills_parent = 4;
    optional .android.graphics.RectProto bounds = 5;
    optional .android.graphics.RectProto displayed_bounds = 6;
    optional bool defer_removal = 7;
    // Will be removed soon.
    optional bool defer_removal = 7 [deprecated=true];
    optional int32 surface_width = 8;
    optional int32 surface_height = 9;
}
+12 −18
Original line number Diff line number Diff line
@@ -817,12 +817,6 @@
      "group": "WM_DEBUG_ORIENTATION",
      "at": "com\/android\/server\/wm\/DisplayRotation.java"
    },
    "-415912575": {
      "message": "setTask: %s at top.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_ADD_REMOVE",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-415865166": {
      "message": "findFocusedWindow: Found new focus @ %s",
      "level": "VERBOSE",
@@ -883,6 +877,12 @@
      "group": "WM_DEBUG_ADD_REMOVE",
      "at": "com\/android\/server\/wm\/WindowState.java"
    },
    "-303497363": {
      "message": "reparent: moving activity=%s to task=%d at %d",
      "level": "INFO",
      "group": "WM_DEBUG_ADD_REMOVE",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-253016819": {
      "message": "applyAnimation: transition animation is disabled or skipped. atoken=%s",
      "level": "VERBOSE",
@@ -1237,12 +1237,6 @@
      "group": "WM_DEBUG_FOCUS_LIGHT",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "393054329": {
      "message": "reParentWindowToken: removing window token=%s from task=%s",
      "level": "INFO",
      "group": "WM_DEBUG_ADD_REMOVE",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "399841913": {
      "message": "SURFACE RECOVER DESTROY: %s",
      "level": "INFO",
@@ -1351,6 +1345,12 @@
      "group": "WM_SHOW_TRANSACTIONS",
      "at": "com\/android\/server\/wm\/Session.java"
    },
    "609651209": {
      "message": "addChild: %s at top.",
      "level": "VERBOSE",
      "group": "WM_DEBUG_ADD_REMOVE",
      "at": "com\/android\/server\/wm\/TaskRecord.java"
    },
    "620368427": {
      "message": "******* TELLING SURFACE FLINGER WE ARE BOOTED!",
      "level": "INFO",
@@ -1999,12 +1999,6 @@
      "group": "WM_SHOW_TRANSACTIONS",
      "at": "com\/android\/server\/wm\/WindowAnimator.java"
    },
    "1995048598": {
      "message": "reparent: moving app token=%s to task=%d at %d",
      "level": "INFO",
      "group": "WM_DEBUG_ADD_REMOVE",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "2016061474": {
      "message": "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d Callers=%s",
      "level": "VERBOSE",
+75 −154
Original line number Diff line number Diff line
@@ -137,10 +137,8 @@ import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
@@ -299,10 +297,10 @@ import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.animation.Animation;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.ReferrerIntent;
import com.android.internal.R;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.XmlUtils;
import com.android.server.AttributeCache;
@@ -426,8 +424,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    // Last configuration reported to the activity in the client process.
    private MergedConfiguration mLastReportedConfiguration;
    private int mLastReportedDisplayId;
    private boolean mLastReportedMultiWindowMode;
    private boolean mLastReportedPictureInPictureMode;
    boolean mLastReportedMultiWindowMode;
    boolean mLastReportedPictureInPictureMode;
    CompatibilityInfo compat;// last used compatibility mode
    ActivityRecord resultTo; // who started this entry, so will get our reply
    final String resultWho; // additional identifier for use by resultTo.
@@ -490,7 +488,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    long lastLaunchTime;    // time of last launch of this activity
    ComponentName requestedVrComponent; // the requested component for handling VR mode.

    private boolean inHistory;  // are we in the history stack?
    boolean inHistory;  // are we in the history stack?
    final ActivityStackSupervisor mStackSupervisor;
    final RootActivityContainer mRootActivityContainer;

@@ -530,10 +528,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    // True if we are current in the process of removing this app token from the display
    private boolean mRemovingFromDisplay = false;

    // Flag set while reparenting to prevent actions normally triggered by an individual parent
    // change.
    private boolean mReparenting;

    private RemoteAnimationDefinition mRemoteAnimationDefinition;

    private AnimatingActivityRegistry mAnimatingActivityRegistry;
@@ -1189,7 +1183,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        }
    }

    // TODO: Remove once TaskRecord and Task are unified.
    // TODO(task-unify): Remove once TaskRecord and Task are unified.
    TaskRecord getTaskRecord() {
        return task;
    }
@@ -1201,16 +1195,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
     * {@link ActivityStack}.
     * @param task The new parent {@link TaskRecord}.
     */
    // TODO(task-unify): Can be remove after task level unification. Callers can just use addChild
    void setTask(TaskRecord task) {
        setTask(task /* task */, false /* reparenting */);
    }

    /**
     * This method should only be called by {@link TaskRecord#removeActivity(ActivityRecord)}.
     * @param task          The new parent task.
     * @param reparenting   Whether we're in the middle of reparenting.
     */
    void setTask(TaskRecord task, boolean reparenting) {
        // Do nothing if the {@link TaskRecord} is the same as the current {@link getTaskRecord}.
        if (task != null && task == getTaskRecord()) {
            return;
@@ -1222,7 +1208,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // Inform old stack (if present) of activity removal and new stack (if set) of activity
        // addition.
        if (oldStack != newStack) {
            if (!reparenting && oldStack != null) {
            if (oldStack != null) {
                oldStack.onActivityRemovedFromStack(this);
            }

@@ -1231,38 +1217,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            }
        }

        final TaskRecord oldTask = this.task;
        this.task = task;

        // This is attaching the activity to the task which we only want to do once.
        // TODO: Need to re-work after unifying the task level since it will already have a parent
        // then. Just need to restructure the re-parent case not to do this. NOTE that the
        // reparenting flag passed in can't be used directly for this as it isn't set in
        // TODO(task-unify): Need to re-work after unifying the task level since it will already
        // have a parent then. Just need to restructure the re-parent case not to do this. NOTE that
        // the reparenting flag passed in can't be used directly for this as it isn't set in
        // ActivityRecord#reparent() case that ends up calling this method.
        if (task != null && getParent() == null) {
            inHistory = true;
            final Task container = task.getTask();
            if (container != null) {
                onAttachToTask(task.voiceSession != null, container.getDisplayContent(),
                        getInputDispatchingTimeoutLocked(this) * 1000000L);
                ProtoLog.v(WM_DEBUG_ADD_REMOVE, "setTask: %s at top.", this);
                container.addChild(this, Integer.MAX_VALUE /* add on top */);
            }

            // TODO(b/36505427): Maybe this call should be moved inside
            // updateOverrideConfiguration()
            task.updateOverrideConfigurationFromLaunchBounds();
            // Make sure size-compat is up-to-date before using to create window controller.
            updateSizeCompatMode();

            task.addActivityToTop(this);

            // When an activity is started directly into a split-screen fullscreen stack, we need to
            // update the initial multi-window modes so that the callbacks are scheduled correctly
            // when the user leaves that mode.
            mLastReportedMultiWindowMode = inMultiWindowMode();
            mLastReportedPictureInPictureMode = inPinnedWindowingMode();
        } else if (!reparenting) {
            onParentChanged();
            task.addChild(this);
        } else {
            onParentChanged(task, oldTask);
        }
    }

@@ -1288,15 +1254,38 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    }

    @Override
    void onParentChanged() {
        super.onParentChanged();
    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
        final TaskRecord oldTask = (oldParent != null) ? ((Task) oldParent).mTaskRecord : null;
        final TaskRecord newTask = (newParent != null) ? ((Task) newParent).mTaskRecord : null;
        this.task = newTask;

        super.onParentChanged(newParent, oldParent);

        final Task task = getTask();

        if (oldParent == null && newParent != null) {
            // First time we are adding the activity to the system.
            // TODO(task-unify): See if mVoiceInteraction variable is really needed after task level
            // unification.
            mVoiceInteraction = task.mTaskRecord != null && task.mTaskRecord.voiceSession != null;
            mInputDispatchingTimeoutNanos = getInputDispatchingTimeoutLocked(this) * 1000000L;
            onDisplayChanged(task.getDisplayContent());
            if (task.mTaskRecord != null) {
                task.mTaskRecord.updateOverrideConfigurationFromLaunchBounds();
            }
            // Make sure override configuration is up-to-date before using to create window
            // controller.
            updateSizeCompatMode();
            // When an activity is started directly into a split-screen fullscreen stack, we need to
            // update the initial multi-window modes so that the callbacks are scheduled correctly
            // when the user leaves that mode.
            mLastReportedMultiWindowMode = inMultiWindowMode();
            mLastReportedPictureInPictureMode = inPinnedWindowingMode();
        }

        // When the associated task is {@code null}, the {@link ActivityRecord} can no longer
        // access visual elements like the {@link DisplayContent}. We must remove any associations
        // such as animations.
        if (!mReparenting) {
        if (task == null) {
            // It is possible we have been marked as a closing app earlier. We must remove ourselves
            // from this list so we do not participate in any future animations.
@@ -1306,7 +1295,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        } else if (mLastParent != null && mLastParent.mStack != null) {
            task.mStack.mExitingActivities.remove(this);
        }
        }
        final TaskStack stack = getStack();

        // If we reparent, make sure to remove ourselves from the old animation registry.
@@ -1320,6 +1308,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        mLastParent = task;

        updateColorTransform();

        final ActivityStack oldStack = (oldTask != null) ? oldTask.getStack() : null;
        final ActivityStack newStack = (newTask != null) ? newTask.getStack() : null;
        // Inform old stack (if present) of activity removal and new stack (if set) of activity
        // addition.
        if (oldStack != newStack) {
            // TODO(task-unify): Might be better to use onChildAdded and onChildRemoved signal for
            // this once task level is unified.
            if (oldStack !=  null) {
                oldStack.onActivityRemovedFromStack(this);
            }
            if (newStack !=  null) {
                newStack.onActivityAddedToStack(this);
            }
        }
    }

    private void updateColorTransform() {
@@ -1697,17 +1700,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        return hasProcess() && app.hasThread();
    }

    void onAttachToTask(boolean voiceInteraction, DisplayContent dc,
            long inputDispatchingTimeoutNanos) {
        mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
        mVoiceInteraction = voiceInteraction;
        onDisplayChanged(dc);

        // Application tokens start out hidden.
        setHidden(true);
        hiddenRequested = true;
    }

    boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
            IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
@@ -1967,12 +1959,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        });
    }

    void removeWindowContainer() {
    private void removeAppTokenFromDisplay() {
        if (mWmService.mRoot == null) return;

        final DisplayContent dc = mWmService.mRoot.getDisplayContent(getDisplayId());
        if (dc == null) {
            Slog.w(TAG, "removeWindowContainer: Attempted to remove token: "
            Slog.w(TAG, "removeAppTokenFromDisplay: Attempted to remove token: "
                    + appToken + " from non-existing displayId=" + getDisplayId());
            return;
        }
@@ -2005,56 +1997,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                    + " r=" + this + " (" + prevTask.getStackId() + ")");
        }

        final Task task = newTask.getTask();
        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving app token=%s"
        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving activity=%s"
                + " to task=%d at %d", this, task.mTaskId, position);

        if (task == null) {
            throw new IllegalArgumentException("reparent: could not find task");
        }
        final Task currentTask = getTask();
        if (task == currentTask) {
            throw new IllegalArgumentException(
                    "window token=" + this + " already child of task=" + currentTask);
        reparent(newTask.getTask(), position);
    }

        if (currentTask.mStack != task.mStack) {
            throw new IllegalArgumentException(
                    "window token=" + this + " current task=" + currentTask
                            + " belongs to a different stack than " + task);
        }

        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reParentWindowToken: removing window token=%s"
                + " from task=%s"  , this, currentTask);
        final DisplayContent prevDisplayContent = getDisplayContent();

        mReparenting = true;

        getParent().removeChild(this);
        task.addChild(this, position);

        mReparenting = false;

        // Relayout display(s).
        final DisplayContent displayContent = task.getDisplayContent();
        displayContent.setLayoutNeeded();
        if (prevDisplayContent != displayContent) {
            onDisplayChanged(displayContent);
            prevDisplayContent.setLayoutNeeded();
        }
        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();

        // Reparenting prevents informing the parent stack of activity removal in the case that
        // the new stack has the same parent. we must manually signal here if this is not the case.
        final ActivityStack prevStack = prevTask.getStack();

        if (prevStack != newTask.getStack()) {
            prevStack.onActivityRemovedFromStack(this);
        }
        // Remove the activity from the old task and add it to the new task.
        prevTask.removeActivity(this, true /* reparenting */);

        newTask.addActivityAtIndex(position, this);
    // TODO(task-unify): Remove once Task level is unified.
    void onParentChanged(TaskRecord newParent, TaskRecord oldParent) {
        onParentChanged(
                newParent != null ? newParent.mTask : null,
                oldParent != null ? oldParent.mTask : null);
    }

    private boolean isHomeIntent(Intent intent) {
@@ -2895,6 +2848,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    }

    /** Note: call {@link #cleanUp(boolean, boolean)} before this method. */
    // TODO(task-unify): Look into consolidating this with TaskRecord.removeChild once we unify
    // task level.
    void removeFromHistory(String reason) {
        finishActivityResults(Activity.RESULT_CANCELED, null /* resultData */);
        makeFinishingLocked();
@@ -2912,41 +2867,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        setState(DESTROYED, "removeFromHistory");
        if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
        app = null;
        removeWindowContainer();
        final TaskRecord task = getTaskRecord();
        final boolean lastActivity = task.removeActivity(this);
        // If we are removing the last activity in the task, not including task overlay activities,
        // then fall through into the block below to remove the entire task itself
        final boolean onlyHasTaskOverlays =
                task.onlyHasTaskOverlayActivities(false /* excludingFinishing */);

        if (lastActivity || onlyHasTaskOverlays) {
            if (DEBUG_STATES) {
                Slog.i(TAG, "removeFromHistory: last activity removed from " + this
                        + " onlyHasTaskOverlays=" + onlyHasTaskOverlays);
            }

            // The following block can be executed multiple times if there is more than one overlay.
            // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
            // of the task by id and exiting early if not found.
            if (onlyHasTaskOverlays) {
                // When destroying a task, tell the supervisor to remove it so that any activity it
                // has can be cleaned up correctly. This is currently the only place where we remove
                // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
                // state into removeTask(), we just clear the task here before the other residual
                // work.
                // TODO: If the callers to removeTask() changes such that we have multiple places
                //       where we are destroying the task, move this back into removeTask()
                mStackSupervisor.removeTaskByIdLocked(task.mTaskId, false /* killProcess */,
                        !REMOVE_FROM_RECENTS, reason);
            }

            // We must keep the task around until all activities are destroyed. The following
            // statement will only execute once since overlays are also considered activities.
            if (lastActivity) {
                stack.removeTask(task, reason, REMOVE_TASK_MODE_DESTROYING);
            }
        }
        removeAppTokenFromDisplay();

        cleanUpActivityServices();
        removeUriPermissionsLocked();
+12 −9
Original line number Diff line number Diff line
@@ -246,12 +246,13 @@ class ActivityStack extends ConfigurationContainer {
        ActivityDisplay current = getParent();
        if (current != parent) {
            mDisplayId = parent.mDisplayId;
            onParentChanged();
            onParentChanged(parent, current);
        }
    }

    @Override
    protected void onParentChanged() {
    protected void onParentChanged(
            ConfigurationContainer newParent, ConfigurationContainer oldParent) {
        ActivityDisplay display = getParent();
        if (display != null) {
            // Rotations are relative to the display. This means if there are 2 displays rotated
@@ -264,7 +265,7 @@ class ActivityStack extends ConfigurationContainer {
            getConfiguration().windowConfiguration.setRotation(
                    display.getWindowConfiguration().getRotation());
        }
        super.onParentChanged();
        super.onParentChanged(newParent, oldParent);
        if (display != null && inSplitScreenPrimaryWindowingMode()) {
            // If we created a docked stack we want to resize it so it resizes all other stacks
            // in the system.
@@ -915,12 +916,13 @@ class ActivityStack extends ConfigurationContainer {

    /** Removes the stack completely. Also calls WindowManager to do the same on its side. */
    void remove() {
        final ActivityDisplay oldDisplay = getDisplay();
        removeFromDisplay();
        if (mTaskStack != null) {
            mTaskStack.removeIfPossible();
            mTaskStack = null;
        }
        onParentChanged();
        onParentChanged(null, oldDisplay);
    }

    ActivityDisplay getDisplay() {
@@ -4719,11 +4721,12 @@ class ActivityStack extends ConfigurationContainer {
     *             {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}.
     */
    void removeTask(TaskRecord task, String reason, int mode) {
        final boolean removed = mTaskHistory.remove(task);
        if (!mTaskHistory.remove(task)) {
            // Not really in this stack anymore...
            return;
        }

        if (removed) {
        EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, task.mTaskId, getStackId());
        }

        removeActivitiesFromLRUList(task);
        updateTaskMovement(task, true);
@@ -4758,7 +4761,7 @@ class ActivityStack extends ConfigurationContainer {
        if (inPinnedWindowingMode()) {
            mService.getTaskChangeNotificationController().notifyActivityUnpinned();
        }
        if (display.isSingleTaskInstance()) {
        if (display != null && display.isSingleTaskInstance()) {
            mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
        }
    }
+3 −4
Original line number Diff line number Diff line
@@ -1864,9 +1864,8 @@ class ActivityStarter {
                    mLaunchFlags);

            // The above code can remove {@code reusedActivity} from the task, leading to the
            // the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
            // task reference is needed in the call below to
            // {@link setTargetStackAndMoveToFrontIfNeeded}.
            // {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The task
            // reference is needed in the call below to {@link setTargetStackAndMoveToFrontIfNeeded}
            if (targetTaskTop.getTaskRecord() == null) {
                targetTaskTop.setTask(targetTask);
            }
@@ -2450,7 +2449,7 @@ class ActivityStarter {

    private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
        if (mStartActivity.getTaskRecord() == null || mStartActivity.getTaskRecord() == parent) {
            parent.addActivityToTop(mStartActivity);
            parent.addChild(mStartActivity);
        } else {
            mStartActivity.reparent(parent, parent.getChildCount() /* top */, reason);
        }
Loading