summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java71
-rw-r--r--services/core/java/com/android/server/wm/Task.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java12
3 files changed, 88 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 422cc696224b..622a80920526 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -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;
@@ -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> {
@@ -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.
*
@@ -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) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9d3ffa95f744..f23a440eb0ed 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -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);
@@ -4878,6 +4880,7 @@ class Task extends TaskFragment {
top.setWindowingMode(WINDOWING_MODE_UNDEFINED);
top.mWaitForEnteringPinnedMode = false;
}
+ return true;
}
void resumeNextFocusAfterReparent() {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index e3f06c27da77..1573d09364ea 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -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;
@@ -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); });
}