summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Chang <louischang@google.com>2023-04-21 06:31:44 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-04-28 15:54:56 +0000
commitc71edbd8e02a106785efa6a097f3fad000c69c09 (patch)
tree221ebda36c6d9ef6f0968f1235ca58c367548341
parent6cfe32c5840965a948f390e64eb316d7af912449 (diff)
downloadbase-c71edbd8e02a106785efa6a097f3fad000c69c09.tar.gz
Prevents activity being stopped while folding/unfolding device
Display is turning off while swapping the physical display, usually happens while folding/unfolding a foldable device. The display will be turn back on after some time later, but the top activity could be stopped if the display is not turning back on soon enough. Bug: 271098735 Test: tested on Youtube and some other apps (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:fc8087ce7b50877d6a73ba85976212258b87718e) Merged-In: I687f35f4989f9e23276451c9b3a3ce8578e64280 Change-Id: I687f35f4989f9e23276451c9b3a3ce8578e64280
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java4
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java10
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java10
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java17
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java2
9 files changed, 73 insertions, 13 deletions
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 47e880a3fce2..8eed76505847 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -2094,14 +2094,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
&& !mScreenOffBecauseOfProximity) {
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF);
unblockScreenOn();
- mWindowManagerPolicy.screenTurnedOff(mDisplayId);
+ mWindowManagerPolicy.screenTurnedOff(mDisplayId, mIsInTransition);
} else if (!isOff
&& mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_OFF) {
// We told policy already that screen was turning off, but now we changed our minds.
// Complete the full state transition on -> turningOff -> off.
unblockScreenOff();
- mWindowManagerPolicy.screenTurnedOff(mDisplayId);
+ mWindowManagerPolicy.screenTurnedOff(mDisplayId, mIsInTransition);
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF);
}
if (!isOff
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f064f83393c0..74d87cd60b68 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4756,11 +4756,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Called on the DisplayManager's DisplayPowerController thread.
@Override
- public void screenTurnedOff(int displayId) {
+ public void screenTurnedOff(int displayId, boolean isSwappingDisplay) {
if (DEBUG_WAKEUP) Slog.i(TAG, "Display" + displayId + " turned off...");
if (displayId == DEFAULT_DISPLAY) {
- updateScreenOffSleepToken(true);
+ updateScreenOffSleepToken(true, isSwappingDisplay);
mRequestedOrSleepingDefaultDisplay = false;
mDefaultDisplayPolicy.screenTurnedOff();
synchronized (mLock) {
@@ -4811,7 +4811,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (displayId == DEFAULT_DISPLAY) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn",
0 /* cookie */);
- updateScreenOffSleepToken(false);
+ updateScreenOffSleepToken(false /* acquire */, false /* isSwappingDisplay */);
mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
mBootAnimationDismissable = false;
@@ -5330,9 +5330,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
// TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
- private void updateScreenOffSleepToken(boolean acquire) {
+ private void updateScreenOffSleepToken(boolean acquire, boolean isSwappingDisplay) {
if (acquire) {
- mScreenOffSleepTokenAcquirer.acquire(DEFAULT_DISPLAY);
+ mScreenOffSleepTokenAcquirer.acquire(DEFAULT_DISPLAY, isSwappingDisplay);
} else {
mScreenOffSleepTokenAcquirer.release(DEFAULT_DISPLAY);
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 77007fa229a2..cd63caa063f0 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -829,8 +829,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
/**
* Called when the display has turned off.
+ * @param displayId The display to apply to.
+ * @param isSwappingDisplay Whether the display is swapping to another physical display.
*/
- public void screenTurnedOff(int displayId);
+ void screenTurnedOff(int displayId, boolean isSwappingDisplay);
public interface ScreenOnListener {
void onScreenOn();
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d872ada1fd0c..f3d7448f19ab 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -8417,6 +8417,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return inTransitionSelfOrParent();
}
+ boolean isDisplaySleepingAndSwapping() {
+ for (int i = mDisplayContent.mAllSleepTokens.size() - 1; i >= 0; i--) {
+ RootWindowContainer.SleepToken sleepToken = mDisplayContent.mAllSleepTokens.get(i);
+ if (sleepToken.isDisplaySwapping()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
* orientation then aspect ratio restrictions are also already respected.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 2792f4265caa..9123ffa329df 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -141,6 +141,13 @@ public abstract class ActivityTaskManagerInternal {
void acquire(int displayId);
/**
+ * Acquires a sleep token.
+ * @param displayId The display to apply to.
+ * @param isSwappingDisplay Whether the display is swapping to another physical display.
+ */
+ void acquire(int displayId, boolean isSwappingDisplay);
+
+ /**
* Releases the sleep token.
* @param displayId The display to apply to.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f6e92a642900..863bf94b13c1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4747,10 +4747,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void acquire(int displayId) {
+ acquire(displayId, false /* isSwappingDisplay */);
+ }
+
+ @Override
+ public void acquire(int displayId, boolean isSwappingDisplay) {
synchronized (mGlobalLock) {
if (!mSleepTokens.contains(displayId)) {
mSleepTokens.append(displayId,
- mRootWindowContainer.createSleepToken(mTag, displayId));
+ mRootWindowContainer.createSleepToken(mTag, displayId,
+ isSwappingDisplay));
updateSleepIfNeededLocked();
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 9b9337e24f53..371480884391 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -179,6 +179,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// How long we can hold the launch wake lock before giving up.
private static final int LAUNCH_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
+ // How long we delay processing the stopping and finishing activities.
+ private static final int SCHEDULE_FINISHING_STOPPING_ACTIVITY_MS = 200;
+
/** How long we wait until giving up on the activity telling us it released the top state. */
private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT = 500;
@@ -1933,13 +1936,15 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
boolean processPausingActivities, String reason) {
// Stop any activities that are scheduled to do so but have been waiting for the transition
// animation to finish.
+ boolean displaySwapping = false;
ArrayList<ActivityRecord> readyToStopActivities = null;
for (int i = mStoppingActivities.size() - 1; i >= 0; --i) {
final ActivityRecord s = mStoppingActivities.get(i);
final boolean animating = s.isInTransition();
+ displaySwapping |= s.isDisplaySleepingAndSwapping();
ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b "
+ "finishing=%s", s, s.nowVisible, animating, s.finishing);
- if (!animating || mService.mShuttingDown) {
+ if ((!animating && !displaySwapping) || mService.mShuttingDown) {
if (!processPausingActivities && s.isState(PAUSING)) {
// Defer processing pausing activities in this iteration and reschedule
// a delayed idle to reprocess it again
@@ -1958,6 +1963,16 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
}
+ // Stopping activities are deferred processing if the display is swapping. Check again
+ // later to ensure the stopping activities can be stopped after display swapped.
+ if (displaySwapping) {
+ mHandler.postDelayed(() -> {
+ synchronized (mService.mGlobalLock) {
+ scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
+ }
+ }, SCHEDULE_FINISHING_STOPPING_ACTIVITY_MS);
+ }
+
final int numReadyStops = readyToStopActivities == null ? 0 : readyToStopActivities.size();
for (int i = 0; i < numReadyStops; i++) {
final ActivityRecord r = readyToStopActivities.get(i);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index a4e08dfb1e3b..76afdc387dbd 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2569,6 +2569,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
SleepToken createSleepToken(String tag, int displayId) {
+ return createSleepToken(tag, displayId, false /* isSwappingDisplay */);
+ }
+
+ SleepToken createSleepToken(String tag, int displayId, boolean isSwappingDisplay) {
final DisplayContent display = getDisplayContent(displayId);
if (display == null) {
throw new IllegalArgumentException("Invalid display: " + displayId);
@@ -2577,7 +2581,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final int tokenKey = makeSleepTokenKey(tag, displayId);
SleepToken token = mSleepTokens.get(tokenKey);
if (token == null) {
- token = new SleepToken(tag, displayId);
+ token = new SleepToken(tag, displayId, isSwappingDisplay);
mSleepTokens.put(tokenKey, token);
display.mAllSleepTokens.add(token);
ProtoLog.d(WM_DEBUG_STATES, "Create sleep token: tag=%s, displayId=%d", tag, displayId);
@@ -3526,18 +3530,34 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
private final String mTag;
private final long mAcquireTime;
private final int mDisplayId;
+ private final boolean mIsSwappingDisplay;
final int mHashKey;
- SleepToken(String tag, int displayId) {
+ // The display could remain in sleep after the physical display swapped, adding a 1
+ // seconds display swap timeout to prevent activities staying in PAUSED state.
+ // Otherwise, the sleep token should be removed once display turns back on after swapped.
+ private static final long DISPLAY_SWAP_TIMEOUT = 1000;
+
+ SleepToken(String tag, int displayId, boolean isSwappingDisplay) {
mTag = tag;
mDisplayId = displayId;
mAcquireTime = SystemClock.uptimeMillis();
+ mIsSwappingDisplay = isSwappingDisplay;
mHashKey = makeSleepTokenKey(mTag, mDisplayId);
}
+ public boolean isDisplaySwapping() {
+ long now = SystemClock.uptimeMillis();
+ if (now - mAcquireTime > DISPLAY_SWAP_TIMEOUT) {
+ return false;
+ }
+ return mIsSwappingDisplay;
+ }
+
@Override
public String toString() {
return "{\"" + mTag + "\", display " + mDisplayId
+ + (mIsSwappingDisplay ? " is swapping " : "")
+ ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index e2db2e6b19e1..148dd8dfd25a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -147,7 +147,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public void screenTurnedOff(int displayId) {
+ public void screenTurnedOff(int displayId, boolean isSwappingDisplay) {
}
@Override