diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index 73ffd5cc4ff40..3568a473b2ecd 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -31,6 +31,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_PRIVATE; import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT; + import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER; import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID; import static com.android.server.am.ActivityDisplayProto.ID; @@ -43,7 +44,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityStackSupervisor.TAG_STATES; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.WindowConfiguration; @@ -103,6 +103,12 @@ class ActivityDisplay extends ConfigurationContainer private boolean mSleeping; + /** + * The display is removed from the system and we are just waiting for all activities on it to be + * finished before removing this object. + */ + private boolean mRemoved; + // Cached reference to some special stacks we tend to get a lot so we don't need to loop // through the list to find them. private ActivityStack mHomeStack = null; @@ -155,6 +161,7 @@ class ActivityDisplay extends ConfigurationContainer + " from displayId=" + mDisplayId); mStacks.remove(stack); removeStackReferenceIfNeeded(stack); + releaseSelfIfNeeded(); mSupervisor.mService.updateSleepIfNeededLocked(); onStackOrderChanged(); } @@ -484,16 +491,11 @@ class ActivityDisplay extends ConfigurationContainer final int windowingMode = stack.getWindowingMode(); if (activityType == ACTIVITY_TYPE_HOME) { - // TODO(b/111363427) Rollback to throws exceptions once we figure out how to properly - // deal with home type stack when external display removed if (mHomeStack != null && mHomeStack != stack) { - // throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack=" - // + mHomeStack + " already exist on display=" + this + " stack=" + stack); - Slog.e(TAG, "addStackReferenceIfNeeded: home stack=" + throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack=" + mHomeStack + " already exist on display=" + this + " stack=" + stack); - } else { - mHomeStack = stack; } + mHomeStack = stack; } else if (activityType == ACTIVITY_TYPE_RECENTS) { if (mRecentsStack != null && mRecentsStack != stack) { throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack=" @@ -796,28 +798,47 @@ class ActivityDisplay extends ConfigurationContainer return false; } + /** + * @see #mRemoved + */ + boolean isRemoved() { + return mRemoved; + } + void remove() { final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove(); - while (getChildCount() > 0) { - final ActivityStack stack = getChildAt(0); - if (destroyContentOnRemoval) { - // Override the stack configuration to make it equal to the current applied one, so - // that we don't accidentally report configuration change to activities that are - // going to be finished. - stack.onOverrideConfigurationChanged(stack.getConfiguration()); - mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, - false /* onTop */); + + // Stacks could be reparented from the removed display to other display. While + // reparenting the last stack of the removed display, the remove display is ready to be + // released (no more ActivityStack). But, we cannot release it at that moment or the + // related WindowContainer and WindowContainerController will also be removed. So, we + // set display as removed after reparenting stack finished. + for (int i = mStacks.size() - 1; i >= 0; --i) { + final ActivityStack stack = mStacks.get(i); + // Always finish non-standard type stacks. + if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) { stack.finishAllActivitiesLocked(true /* immediately */); } else { - // Moving all tasks to fullscreen stack, because it's guaranteed to be - // a valid launch stack for all activities. This way the task history from - // external display will be preserved on primary after move. - mSupervisor.moveTasksToFullscreenStackLocked(stack, true /* onTop */); + // If default display is in split-window mode, set windowing mode of the stack to + // split-screen secondary. Otherwise, set the windowing mode to undefined by + // default to let stack inherited the windowing mode from the new display. + int windowingMode = mSupervisor.getDefaultDisplay().hasSplitScreenPrimaryStack() + ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY : WINDOWING_MODE_UNDEFINED; + mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, true); + stack.setWindowingMode(windowingMode); } } + mRemoved = true; - mWindowContainerController.removeContainer(); - mWindowContainerController = null; + releaseSelfIfNeeded(); + } + + private void releaseSelfIfNeeded() { + if (mStacks.isEmpty() && mRemoved) { + mWindowContainerController.removeContainer(); + mWindowContainerController = null; + mSupervisor.releaseActivityDisplayLocked(mDisplayId); + } } /** Update and get all UIDs that are present on the display and have access to it. */ diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index fbf285596ed9e..78fef65687fdf 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -36,6 +36,15 @@ import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; import static android.view.Display.INVALID_DISPLAY; +import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; +import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN; +import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; +import static android.view.WindowManager.TRANSIT_NONE; +import static android.view.WindowManager.TRANSIT_TASK_CLOSE; +import static android.view.WindowManager.TRANSIT_TASK_OPEN; +import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; +import static android.view.WindowManager.TRANSIT_TASK_TO_BACK; +import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM; import static com.android.server.am.ActivityDisplay.POSITION_TOP; @@ -82,10 +91,6 @@ import static com.android.server.am.ActivityStack.ActivityState.PAUSING; import static com.android.server.am.ActivityStack.ActivityState.RESUMED; import static com.android.server.am.ActivityStack.ActivityState.STOPPED; import static com.android.server.am.ActivityStack.ActivityState.STOPPING; -import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; -import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; -import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; import static com.android.server.am.ActivityStackProto.BOUNDS; import static com.android.server.am.ActivityStackProto.CONFIGURATION_CONTAINER; import static com.android.server.am.ActivityStackProto.DISPLAY_ID; @@ -93,15 +98,10 @@ import static com.android.server.am.ActivityStackProto.FULLSCREEN; import static com.android.server.am.ActivityStackProto.ID; import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY; import static com.android.server.am.ActivityStackProto.TASKS; -import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN; -import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_NONE; -import static android.view.WindowManager.TRANSIT_TASK_CLOSE; -import static android.view.WindowManager.TRANSIT_TASK_OPEN; -import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; -import static android.view.WindowManager.TRANSIT_TASK_TO_BACK; -import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; +import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; +import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; +import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; import static java.lang.Integer.MAX_VALUE; @@ -115,12 +115,12 @@ import android.app.WindowConfiguration.ActivityType; import android.app.WindowConfiguration.WindowingMode; import android.app.servertransaction.ActivityResultItem; import android.app.servertransaction.ClientTransaction; -import android.app.servertransaction.NewIntentItem; -import android.app.servertransaction.WindowVisibilityItem; import android.app.servertransaction.DestroyActivityItem; +import android.app.servertransaction.NewIntentItem; import android.app.servertransaction.PauseActivityItem; import android.app.servertransaction.ResumeActivityItem; import android.app.servertransaction.StopActivityItem; +import android.app.servertransaction.WindowVisibilityItem; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -5191,7 +5191,7 @@ class ActivityStack extends ConfigurationContai if (isAttached()) { getDisplay().positionChildAtBottom(this); } - if (!isActivityTypeHome()) { + if (!isActivityTypeHome() || getDisplay().isRemoved()) { remove(); } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 9809bfa38252a..4cfcbee08a57b 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -48,6 +48,7 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.TYPE_VIRTUAL; +import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS; @@ -81,13 +82,6 @@ import static com.android.server.am.ActivityStack.ActivityState.RESUMED; import static com.android.server.am.ActivityStack.ActivityState.STOPPED; import static com.android.server.am.ActivityStack.ActivityState.STOPPING; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING; -import static com.android.server.am.TaskRecord.INVALID_TASK_ID; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; -import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; -import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; -import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS; import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID; @@ -95,7 +89,13 @@ import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER; import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES; import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY; -import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; +import static com.android.server.am.TaskRecord.INVALID_TASK_ID; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; +import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; +import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; +import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; import static java.lang.Integer.MAX_VALUE; @@ -109,8 +109,6 @@ import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackInfo; import android.app.ActivityManagerInternal; -import com.android.internal.util.function.pooled.PooledLambda; -import com.android.server.wm.ActivityTaskManagerInternal.SleepToken; import android.app.ActivityOptions; import android.app.AppOpsManager; import android.app.ProfilerInfo; @@ -170,11 +168,13 @@ import android.view.Display; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.ReferrerIntent; -import com.android.internal.os.logging.MetricsLoggerWrapper; import com.android.internal.os.TransferPipe; +import com.android.internal.os.logging.MetricsLoggerWrapper; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.wm.ActivityTaskManagerInternal.SleepToken; import com.android.server.wm.ConfigurationContainer; import com.android.server.wm.PinnedStackWindowController; import com.android.server.wm.WindowManagerService; @@ -1862,7 +1862,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(launchDisplayId); - if (activityDisplay == null) { + if (activityDisplay == null || activityDisplay.isRemoved()) { Slog.w(TAG, "Launch on display check: display not found"); return false; } @@ -4359,11 +4359,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D activityDisplay.remove(); releaseSleepTokens(activityDisplay); - - mActivityDisplays.remove(displayId); } } + void releaseActivityDisplayLocked(int displayId) { + mActivityDisplays.remove(displayId); + } + + private void handleDisplayChanged(int displayId) { synchronized (mService.mGlobalLock) { ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 65ee18a56094b..ab38f650bc882 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -20,7 +20,6 @@ import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LE import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; @@ -59,12 +58,25 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; + import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates; -import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; +import static com.android.server.wm.DisplayContentProto.ABOVE_APP_WINDOWS; +import static com.android.server.wm.DisplayContentProto.BELOW_APP_WINDOWS; +import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES; +import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO; +import static com.android.server.wm.DisplayContentProto.DOCKED_STACK_DIVIDER_CONTROLLER; +import static com.android.server.wm.DisplayContentProto.DPI; +import static com.android.server.wm.DisplayContentProto.ID; +import static com.android.server.wm.DisplayContentProto.IME_WINDOWS; +import static com.android.server.wm.DisplayContentProto.PINNED_STACK_CONTROLLER; +import static com.android.server.wm.DisplayContentProto.ROTATION; +import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION; +import static com.android.server.wm.DisplayContentProto.STACKS; +import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; @@ -101,19 +113,7 @@ import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP; import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING; import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW; import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE; -import static com.android.server.wm.DisplayContentProto.ABOVE_APP_WINDOWS; -import static com.android.server.wm.DisplayContentProto.BELOW_APP_WINDOWS; -import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES; -import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO; -import static com.android.server.wm.DisplayContentProto.DOCKED_STACK_DIVIDER_CONTROLLER; -import static com.android.server.wm.DisplayContentProto.DPI; -import static com.android.server.wm.DisplayContentProto.ID; -import static com.android.server.wm.DisplayContentProto.IME_WINDOWS; -import static com.android.server.wm.DisplayContentProto.PINNED_STACK_CONTROLLER; -import static com.android.server.wm.DisplayContentProto.ROTATION; -import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION; -import static com.android.server.wm.DisplayContentProto.STACKS; -import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER; +import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates; import android.annotation.CallSuper; import android.annotation.NonNull; @@ -3469,16 +3469,12 @@ class DisplayContent extends WindowContainer