Stop or destroy activities when all resumed activities are shown

So the stopping activities won't be delayed too long if the resumed
activity doesn't report idle.

Bug: 130340090
Test: atest ActivityVisibilityTests# \
            testActivityStoppedWhileNextActivityNotIdle
            testNoHistoryActivityFinishedResumedActivityNotIdle

Change-Id: Ia161456b6d3e5eb68184c429df3b6bed24d0683e
This commit is contained in:
Riddle Hsu
2020-01-01 00:43:53 +08:00
parent d10dc73df9
commit 01a62ffac9
3 changed files with 31 additions and 33 deletions

View File

@@ -4862,8 +4862,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
void stopIfPossible() {
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + this);
final ActivityStack stack = getActivityStack();
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (isNoHistory()) {
if (!finishing) {
if (!stack.shouldSleepActivities()) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + this);
@@ -6095,20 +6094,26 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token);
scheduleAnimation();
if (mAtmService.mRootWindowContainer.allResumedActivitiesIdle()
|| mAtmService.mStackSupervisor.isStoppingNoHistoryActivity()) {
// If all activities are already idle or there is an activity that must be
// stopped immediately after visible, then we now need to make sure we perform
// the full stop of this activity. This is because we won't do that while they are still
// waiting for the animation to finish.
if (mAtmService.mStackSupervisor.mStoppingActivities.contains(this)) {
if (!mStackSupervisor.mStoppingActivities.isEmpty()
|| !mStackSupervisor.mFinishingActivities.isEmpty()) {
if (mRootWindowContainer.allResumedActivitiesIdle()) {
// If all activities are already idle then we now need to make sure we perform
// the full stop of this activity. This is because we won't do that while they
// are still waiting for the animation to finish.
mStackSupervisor.scheduleIdle();
} else if (mRootWindowContainer.allResumedActivitiesVisible()) {
// If all resumed activities are already visible (and should be drawn, see
// updateReportedVisibility ~ nowVisible) but not idle, we still schedule to
// process the stopping and finishing activities because the transition is done.
// This also avoids if the next activity never reports idle (e.g. animating view),
// the previous will need to wait until idle timeout to be stopped or destroyed.
mStackSupervisor.scheduleProcessStoppingAndFinishingActivities();
} else {
// Instead of doing the full stop routine here, let's just hide any activities
// we now can, and let them stop when the normal idle happens.
mStackSupervisor.processStoppingActivities(null /* launchedActivity */,
true /* onlyUpdateVisibility */, true /* unused */, null /* unused */);
}
} else {
// Instead of doing the full stop routine here, let's just hide any activities
// we now can, and let them stop when the normal idle happens.
mStackSupervisor.processStoppingActivities(null /* launchedActivity */,
true /* onlyUpdateVisibility */, true /* unused */, null /* unused */);
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}

View File

@@ -1414,8 +1414,7 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn
else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev);
mPausingActivity = prev;
mLastPausedActivity = prev;
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
mLastNoHistoryActivity = prev.isNoHistory() ? prev : null;
prev.setState(PAUSING, "startPausingLocked");
prev.getTask().touchActiveTime();
clearLaunchTime(prev);

View File

@@ -183,6 +183,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
private static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2;
private static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3;
private static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4;
private static final int PROCESS_STOPPING_AND_FINISHING_MSG = FIRST_SUPERVISOR_STACK_MSG + 5;
private static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 12;
private static final int RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 13;
private static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 14;
@@ -2067,23 +2068,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
return mService.mAmInternal.isCurrentProfile(userId);
}
/**
* Returns whether a stopping activity is present that should be stopped after visible, rather
* than idle.
* @return {@code true} if such activity is present. {@code false} otherwise.
*/
boolean isStoppingNoHistoryActivity() {
// Activities that are marked as nohistory should be stopped immediately after the resumed
// activity has become visible.
for (ActivityRecord record : mStoppingActivities) {
if (record.isNoHistory()) {
return true;
}
}
return false;
}
/**
* Processes the activities to be stopped or destroyed. This should be called when the resumed
* activities are idle or drawn.
@@ -2403,6 +2387,12 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
}
void scheduleProcessStoppingAndFinishingActivities() {
if (!mHandler.hasMessages(PROCESS_STOPPING_AND_FINISHING_MSG)) {
mHandler.sendEmptyMessage(PROCESS_STOPPING_AND_FINISHING_MSG);
}
}
void removeSleepTimeouts() {
mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
}
@@ -2701,6 +2691,10 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
mLaunchingActivityWakeLock.release();
}
} break;
case PROCESS_STOPPING_AND_FINISHING_MSG: {
processStoppingAndFinishingActivities(null /* launchedActivity */,
false /* processPausingActivities */, "transit");
} break;
case LAUNCH_TASK_BEHIND_COMPLETE: {
final ActivityRecord r = ActivityRecord.forTokenLocked((IBinder) msg.obj);
if (r != null) {