Loading services/core/java/com/android/server/wm/RootWindowContainer.java +71 −0 Original line number Diff line number Diff line Loading @@ -174,6 +174,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1; private static final int SET_USER_ACTIVITY_TIMEOUT = 2; private static final int MSG_SEND_SLEEP_TRANSITION = 3; private static final int PINNED_TASK_ABORT_TIMEOUT = 1000; static final String TAG_TASKS = TAG + POSTFIX_TASKS; static final String TAG_STATES = TAG + POSTFIX_STATES; Loading Loading @@ -295,6 +296,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> }; // TODO: b/335866033 Remove the abort PiP on timeout once PiP2 flag is on. @Nullable private Runnable mMaybeAbortPipEnterRunnable = null; private final FindTaskResult mTmpFindTaskResult = new FindTaskResult(); static class FindTaskResult implements Predicate<Task> { Loading Loading @@ -2272,8 +2276,67 @@ class RootWindowContainer extends WindowContainer<DisplayContent> resumeFocusedTasksTopActivities(); notifyActivityPipModeChanged(r.getTask(), r); if (!isPip2ExperimentEnabled()) { // TODO: b/335866033 Remove the abort PiP on timeout once PiP2 flag is on. // Set up a timeout callback to potentially abort PiP enter if in an inconsistent state. scheduleTimeoutAbortPipEnter(rootTask); } } private void scheduleTimeoutAbortPipEnter(Task rootTask) { if (mMaybeAbortPipEnterRunnable != null) { // If there is an abort enter PiP check pending already remove it and abort // immediately since we are trying to enter PiP in an inconsistent state mHandler.removeCallbacks(mMaybeAbortPipEnterRunnable); mMaybeAbortPipEnterRunnable.run(); } // Snapshot a throwable early on to display the callstack upon abort later on timeout. final Throwable enterPipThrowable = new Throwable(); // Set up a timeout to potentially roll back the task change to PINNED mode // by aborting PiP. mMaybeAbortPipEnterRunnable = new Runnable() { @Override public void run() { synchronized (mService.mGlobalLock) { if (mTransitionController.inTransition()) { // If this task is a part an active transition aborting PiP might break // it; so run the timeout callback directly once idle. final Runnable expectedMaybeAbortAtTimeout = mMaybeAbortPipEnterRunnable; mTransitionController.mStateValidators.add(() -> { // If a second PiP transition comes in, it runs the abort runnable for // the first transition pre-emptively, so we need to avoid calling // the same runnable twice when validating states. if (expectedMaybeAbortAtTimeout != mMaybeAbortPipEnterRunnable) return; mMaybeAbortPipEnterRunnable = null; run(); }); return; } else { mMaybeAbortPipEnterRunnable = null; } mService.deferWindowLayout(); final ActivityRecord top = rootTask.getTopMostActivity(); final ActivityManager.RunningTaskInfo beforeTaskInfo = rootTask.getTaskInfo(); if (top != null && !top.inPinnedWindowingMode() && rootTask.abortPipEnter(top)) { Slog.wtf(TAG, "Enter PiP was aborted via a scheduled timeout" + "task_state_before=" + beforeTaskInfo + "task_state_after=" + rootTask.getTaskInfo(), enterPipThrowable); } mService.continueWindowLayout(); } } }; mHandler.postDelayed(mMaybeAbortPipEnterRunnable, PINNED_TASK_ABORT_TIMEOUT); Slog.d(TAG, "a delayed check for potentially aborting PiP if " + "in a wrong state is scheduled."); } /** * Notifies when an activity enters or leaves PIP mode. * Loading Loading @@ -2892,6 +2955,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mService.mH.post(mDestroyAllActivitiesRunnable); } void removeAllMaybeAbortPipEnterRunnable() { if (mMaybeAbortPipEnterRunnable == null) { return; } mHandler.removeCallbacks(mMaybeAbortPipEnterRunnable); mMaybeAbortPipEnterRunnable = null; } // Tries to put all activity tasks to sleep. Returns true if all tasks were // successfully put to sleep. boolean putTasksToSleep(boolean allowDelay, boolean shuttingDown) { Loading services/core/java/com/android/server/wm/Task.java +5 −2 Original line number Diff line number Diff line Loading @@ -4852,11 +4852,13 @@ class Task extends TaskFragment { /** * Abort an incomplete pip-entry. If left in this state, it will cover everything but remain * paused. If this is needed, there is a bug -- this should only be used for recovery. * * @return true if there is an inconsistency in the task and activity state. */ void abortPipEnter(ActivityRecord top) { boolean abortPipEnter(ActivityRecord top) { // an incomplete state has the task PINNED but the activity not. if (!inPinnedWindowingMode() || top.inPinnedWindowingMode() || !canMoveTaskToBack(this)) { return; return false; } final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */, mTransitionController, mWmService.mSyncEngine); Loading @@ -4878,6 +4880,7 @@ class Task extends TaskFragment { top.setWindowingMode(WINDOWING_MODE_UNDEFINED); top.mWaitForEnteringPinnedMode = false; } return true; } void resumeNextFocusAfterReparent() { Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +12 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.isStartResultSuccessful; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS; Loading Loading @@ -857,6 +858,17 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } final int childWindowingMode = c.getActivityWindowingMode(); if (!ActivityTaskManagerService.isPip2ExperimentEnabled() && tr.getWindowingMode() == WINDOWING_MODE_PINNED && (childWindowingMode == WINDOWING_MODE_PINNED || childWindowingMode == WINDOWING_MODE_UNDEFINED)) { // If setActivityWindowingMode requested to match its pinned task's windowing mode, // remove any inconsistency checking timeout callbacks for PiP. Slog.d(TAG, "Task and activity windowing modes match, so remove any timeout " + "abort PiP callbacks scheduled if needed; task_win_mode=" + tr.getWindowingMode() + ", activity_win_mode=" + childWindowingMode); mService.mRootWindowContainer.removeAllMaybeAbortPipEnterRunnable(); } if (childWindowingMode > -1) { tr.forAllActivities(a -> { a.setWindowingMode(childWindowingMode); }); } Loading Loading
services/core/java/com/android/server/wm/RootWindowContainer.java +71 −0 Original line number Diff line number Diff line Loading @@ -174,6 +174,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1; private static final int SET_USER_ACTIVITY_TIMEOUT = 2; private static final int MSG_SEND_SLEEP_TRANSITION = 3; private static final int PINNED_TASK_ABORT_TIMEOUT = 1000; static final String TAG_TASKS = TAG + POSTFIX_TASKS; static final String TAG_STATES = TAG + POSTFIX_STATES; Loading Loading @@ -295,6 +296,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> }; // TODO: b/335866033 Remove the abort PiP on timeout once PiP2 flag is on. @Nullable private Runnable mMaybeAbortPipEnterRunnable = null; private final FindTaskResult mTmpFindTaskResult = new FindTaskResult(); static class FindTaskResult implements Predicate<Task> { Loading Loading @@ -2272,8 +2276,67 @@ class RootWindowContainer extends WindowContainer<DisplayContent> resumeFocusedTasksTopActivities(); notifyActivityPipModeChanged(r.getTask(), r); if (!isPip2ExperimentEnabled()) { // TODO: b/335866033 Remove the abort PiP on timeout once PiP2 flag is on. // Set up a timeout callback to potentially abort PiP enter if in an inconsistent state. scheduleTimeoutAbortPipEnter(rootTask); } } private void scheduleTimeoutAbortPipEnter(Task rootTask) { if (mMaybeAbortPipEnterRunnable != null) { // If there is an abort enter PiP check pending already remove it and abort // immediately since we are trying to enter PiP in an inconsistent state mHandler.removeCallbacks(mMaybeAbortPipEnterRunnable); mMaybeAbortPipEnterRunnable.run(); } // Snapshot a throwable early on to display the callstack upon abort later on timeout. final Throwable enterPipThrowable = new Throwable(); // Set up a timeout to potentially roll back the task change to PINNED mode // by aborting PiP. mMaybeAbortPipEnterRunnable = new Runnable() { @Override public void run() { synchronized (mService.mGlobalLock) { if (mTransitionController.inTransition()) { // If this task is a part an active transition aborting PiP might break // it; so run the timeout callback directly once idle. final Runnable expectedMaybeAbortAtTimeout = mMaybeAbortPipEnterRunnable; mTransitionController.mStateValidators.add(() -> { // If a second PiP transition comes in, it runs the abort runnable for // the first transition pre-emptively, so we need to avoid calling // the same runnable twice when validating states. if (expectedMaybeAbortAtTimeout != mMaybeAbortPipEnterRunnable) return; mMaybeAbortPipEnterRunnable = null; run(); }); return; } else { mMaybeAbortPipEnterRunnable = null; } mService.deferWindowLayout(); final ActivityRecord top = rootTask.getTopMostActivity(); final ActivityManager.RunningTaskInfo beforeTaskInfo = rootTask.getTaskInfo(); if (top != null && !top.inPinnedWindowingMode() && rootTask.abortPipEnter(top)) { Slog.wtf(TAG, "Enter PiP was aborted via a scheduled timeout" + "task_state_before=" + beforeTaskInfo + "task_state_after=" + rootTask.getTaskInfo(), enterPipThrowable); } mService.continueWindowLayout(); } } }; mHandler.postDelayed(mMaybeAbortPipEnterRunnable, PINNED_TASK_ABORT_TIMEOUT); Slog.d(TAG, "a delayed check for potentially aborting PiP if " + "in a wrong state is scheduled."); } /** * Notifies when an activity enters or leaves PIP mode. * Loading Loading @@ -2892,6 +2955,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mService.mH.post(mDestroyAllActivitiesRunnable); } void removeAllMaybeAbortPipEnterRunnable() { if (mMaybeAbortPipEnterRunnable == null) { return; } mHandler.removeCallbacks(mMaybeAbortPipEnterRunnable); mMaybeAbortPipEnterRunnable = null; } // Tries to put all activity tasks to sleep. Returns true if all tasks were // successfully put to sleep. boolean putTasksToSleep(boolean allowDelay, boolean shuttingDown) { Loading
services/core/java/com/android/server/wm/Task.java +5 −2 Original line number Diff line number Diff line Loading @@ -4852,11 +4852,13 @@ class Task extends TaskFragment { /** * Abort an incomplete pip-entry. If left in this state, it will cover everything but remain * paused. If this is needed, there is a bug -- this should only be used for recovery. * * @return true if there is an inconsistency in the task and activity state. */ void abortPipEnter(ActivityRecord top) { boolean abortPipEnter(ActivityRecord top) { // an incomplete state has the task PINNED but the activity not. if (!inPinnedWindowingMode() || top.inPinnedWindowingMode() || !canMoveTaskToBack(this)) { return; return false; } final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */, mTransitionController, mWmService.mSyncEngine); Loading @@ -4878,6 +4880,7 @@ class Task extends TaskFragment { top.setWindowingMode(WINDOWING_MODE_UNDEFINED); top.mWaitForEnteringPinnedMode = false; } return true; } void resumeNextFocusAfterReparent() { Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +12 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.isStartResultSuccessful; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS; Loading Loading @@ -857,6 +858,17 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } final int childWindowingMode = c.getActivityWindowingMode(); if (!ActivityTaskManagerService.isPip2ExperimentEnabled() && tr.getWindowingMode() == WINDOWING_MODE_PINNED && (childWindowingMode == WINDOWING_MODE_PINNED || childWindowingMode == WINDOWING_MODE_UNDEFINED)) { // If setActivityWindowingMode requested to match its pinned task's windowing mode, // remove any inconsistency checking timeout callbacks for PiP. Slog.d(TAG, "Task and activity windowing modes match, so remove any timeout " + "abort PiP callbacks scheduled if needed; task_win_mode=" + tr.getWindowingMode() + ", activity_win_mode=" + childWindowingMode); mService.mRootWindowContainer.removeAllMaybeAbortPipEnterRunnable(); } if (childWindowingMode > -1) { tr.forAllActivities(a -> { a.setWindowingMode(childWindowingMode); }); } Loading