summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Bryce Lee <brycelee@google.com> 2018-02-23 18:38:37 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-02-23 18:38:37 +0000
commite4c5e3b55259b0787ac2eec2fc95e6bca9c64bb2 (patch)
treed2294900f8c409fed9a19a572a79848527830c50
parenta8e26b2e16f1bf800072194055ade22e1f1df4be (diff)
parent7ace395d65edb4764fc537ac1c9ed3c07bc72c33 (diff)
Merge "Always finish activity when moving to a destroyed state."
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java12
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java112
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java122
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java22
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java4
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java30
7 files changed, 195 insertions, 109 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index efe51723612e..6fcdc3ee0d42 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5689,8 +5689,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final long origId = Binder.clearCallingIdentity();
- if (self.state == ActivityState.RESUMED
- || self.state == ActivityState.PAUSING) {
+ if (self.isState(ActivityState.RESUMED, ActivityState.PAUSING)) {
mWindowManager.overridePendingAppTransition(packageName,
enterAnim, exitAnim, null);
}
@@ -22774,7 +22773,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
break;
- } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
+ } else if (r.isState(ActivityState.PAUSING, ActivityState.PAUSED)) {
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "pause-activity";
@@ -22789,7 +22788,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.cached = false;
app.empty = false;
foregroundActivities = true;
- } else if (r.state == ActivityState.STOPPING) {
+ } else if (r.isState(ActivityState.STOPPING)) {
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "stop-activity";
@@ -23183,9 +23182,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final ActivityRecord a = cr.activity;
if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
- if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
- (a.visible || a.state == ActivityState.RESUMED ||
- a.state == ActivityState.PAUSING)) {
+ if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ && (a.visible
+ || a.isState(ActivityState.RESUMED, ActivityState.PAUSING))) {
adj = ProcessList.FOREGROUND_APP_ADJ;
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index e6c1cd5ccfc0..06faeb9398b3 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -288,7 +288,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
UriPermissionOwner uriPermissions; // current special URI access perms.
ProcessRecord app; // if non-null, hosting application
- ActivityState state; // current state we are in
+ private ActivityState mState; // current state we are in
Bundle icicle; // last saved activity state
PersistableBundle persistentState; // last persistently saved activity state
// TODO: See if this is still needed.
@@ -381,8 +381,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
String getLifecycleDescription(String reason) {
return "name= " + this + ", component=" + intent.getComponent().flattenToShortString()
- + ", package=" + packageName + ", state=" + state + ", reason=" + reason + ", time="
- + System.currentTimeMillis();
+ + ", package=" + packageName + ", state=" + mState + ", reason=" + reason
+ + ", time=" + System.currentTimeMillis();
}
void dump(PrintWriter pw, String prefix) {
@@ -503,7 +503,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
pw.println();
pw.print(prefix); pw.print("haveState="); pw.print(haveState);
pw.print(" icicle="); pw.println(icicle);
- pw.print(prefix); pw.print("state="); pw.print(state);
+ pw.print(prefix); pw.print("state="); pw.print(mState);
pw.print(" stopped="); pw.print(stopped);
pw.print(" delayedResume="); pw.print(delayedResume);
pw.print(" finishing="); pw.println(finishing);
@@ -841,7 +841,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
resultTo = _resultTo;
resultWho = _resultWho;
requestCode = _reqCode;
- state = INITIALIZING;
+ setState(INITIALIZING, "ActivityRecord ctor");
frontOfTask = false;
launchFailed = false;
stopped = false;
@@ -1000,6 +1000,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
void removeWindowContainer() {
+ // Do not try to remove a window container if we have already removed it.
+ if (mWindowContainerController == null) {
+ return;
+ }
+
// Resume key dispatching if it is currently paused before we remove the container.
resumeKeyDispatchingLocked();
@@ -1259,7 +1264,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
return false;
}
- switch (state) {
+ switch (mState) {
case RESUMED:
// When visible, allow entering PiP if the app is not locked. If it is over the
// keyguard, then we will prompt to unlock in the caller before entering PiP.
@@ -1385,13 +1390,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
// - It is currently resumed or paused. i.e. it is currently visible to the user and we want
// the user to see the visual effects caused by the intent delivery now.
// - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
- if ((state == RESUMED || state == PAUSED
+ if ((mState == RESUMED || mState == PAUSED
|| isTopActivityWhileSleeping) && app != null && app.thread != null) {
try {
ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
ar.add(rintent);
service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
- NewIntentItem.obtain(ar, state == PAUSED));
+ NewIntentItem.obtain(ar, mState == PAUSED));
unsent = false;
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -1573,6 +1578,63 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
}
+ void setState(ActivityState state, String reason) {
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState()
+ + " to:" + state + " reason:" + reason);
+ final boolean stateChanged = mState != state;
+ mState = state;
+
+ if (stateChanged && isState(DESTROYING, DESTROYED)) {
+ makeFinishingLocked();
+
+ // When moving to the destroyed state, immediately destroy the activity in the
+ // associated stack. Most paths for finishing an activity will handle an activity's path
+ // to destroy through mechanisms such as ActivityStackSupervisor#mFinishingActivities.
+ // However, moving to the destroyed state directly (as in the case of an app dying) and
+ // marking it as finished will lead to cleanup steps that will prevent later handling
+ // from happening.
+ if (isState(DESTROYED)) {
+ final ActivityStack stack = getStack();
+ if (stack != null) {
+ stack.activityDestroyedLocked(this, reason);
+ }
+ }
+ }
+ }
+
+ ActivityState getState() {
+ return mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in the specified state.
+ */
+ boolean isState(ActivityState state) {
+ return state == mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in one of the specified states.
+ */
+ boolean isState(ActivityState state1, ActivityState state2) {
+ return state1 == mState || state2 == mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in one of the specified states.
+ */
+ boolean isState(ActivityState state1, ActivityState state2, ActivityState state3) {
+ return state1 == mState || state2 == mState || state3 == mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in one of the specified states.
+ */
+ boolean isState(ActivityState state1, ActivityState state2, ActivityState state3,
+ ActivityState state4) {
+ return state1 == mState || state2 == mState || state3 == mState || state4 == mState;
+ }
+
void notifyAppResumed(boolean wasStopped) {
mWindowContainerController.notifyAppResumed(wasStopped);
}
@@ -1602,9 +1664,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
void makeVisibleIfNeeded(ActivityRecord starting) {
// This activity is not currently visible, but is running. Tell it to become visible.
- if (state == RESUMED || this == starting) {
+ if (mState == RESUMED || this == starting) {
if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
- "Not making visible, r=" + this + " state=" + state + " starting=" + starting);
+ "Not making visible, r=" + this + " state=" + mState + " starting=" + starting);
return;
}
@@ -1627,13 +1689,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
mStackSupervisor.mGoingToSleepActivities.remove(this);
// If the activity is stopped or stopping, cycle to the paused state.
- if (state == STOPPED || state == STOPPING) {
+ if (isState(STOPPED, STOPPING)) {
// Capture reason before state change
final String reason = getLifecycleDescription("makeVisibleIfNeeded");
// An activity must be in the {@link PAUSING} state for the system to validate
// the move to {@link PAUSED}.
- state = PAUSING;
+ setState(PAUSING, "makeVisibleIfNeeded");
service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
PauseActivityItem.obtain(finishing, false /* userLeaving */,
configChangeFlags, false /* dontReport */)
@@ -1654,7 +1716,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
} catch(RemoteException e) {
}
- return state == RESUMED;
+ return mState == RESUMED;
}
static void activityResumedLocked(IBinder token) {
@@ -1728,7 +1790,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState,
CharSequence description) {
final ActivityStack stack = getStack();
- if (state != STOPPING) {
+ if (mState != STOPPING) {
Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this);
stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this);
return;
@@ -1751,7 +1813,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this);
stopped = true;
- state = STOPPED;
+ setState(STOPPED, "activityStoppedLocked");
mWindowContainerController.notifyAppStopped();
@@ -2021,8 +2083,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
* currently pausing, or is resumed.
*/
public boolean isInterestingToUserLocked() {
- return visible || nowVisible || state == PAUSING ||
- state == RESUMED;
+ return visible || nowVisible || mState == PAUSING || mState == RESUMED;
}
void setSleeping(boolean _sleeping) {
@@ -2084,8 +2145,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
final boolean isDestroyable() {
- if (finishing || app == null || state == DESTROYING
- || state == DESTROYED) {
+ if (finishing || app == null) {
// This would be redundant.
return false;
}
@@ -2151,7 +2211,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
- state.ordinal() >= RESUMED.ordinal() && state.ordinal() <= STOPPED.ordinal(),
+ mState.ordinal() >= RESUMED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
fromRecents);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
@@ -2328,7 +2388,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
// Skip updating configuration for activity that are stopping or stopped.
- if (state == STOPPING || state == STOPPED) {
+ if (mState == STOPPING || mState == STOPPED) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Skipping config check stopped or stopping: " + this);
return true;
@@ -2378,7 +2438,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
setLastReportedConfiguration(service.getGlobalConfiguration(), newMergedOverrideConfig);
- if (state == INITIALIZING) {
+ if (mState == INITIALIZING) {
// No need to relaunch or schedule new config for activity that hasn't been launched
// yet. We do, however, return after applying the config to activity record, so that
// it will use it for launch transaction.
@@ -2431,7 +2491,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is destroying non-running " + this);
stack.destroyActivityLocked(this, true, "config");
- } else if (state == PAUSING) {
+ } else if (mState == PAUSING) {
// A little annoying: we are waiting for this activity to finish pausing. Let's not
// do anything now, but just flag that it needs to be restarted when done pausing.
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -2439,7 +2499,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
deferRelaunchUntilPaused = true;
preserveWindowOnDeferredRelaunch = preserveWindow;
return true;
- } else if (state == RESUMED) {
+ } else if (mState == RESUMED) {
// Try to optimize this case: the configuration is changing and we need to restart
// the top, resumed activity. Instead of doing the normal handshaking, just say
// "restart!".
@@ -2609,7 +2669,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
service.showAskCompatModeDialogLocked(this);
} else {
service.mHandler.removeMessages(PAUSE_TIMEOUT_MSG, this);
- state = PAUSED;
+ setState(PAUSED, "relaunchActivityLocked");
// if the app is relaunched when it's stopped, and we're not resuming,
// put it back into stopped state.
if (stopped) {
@@ -2853,7 +2913,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
final long token = proto.start(fieldId);
super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
writeIdentifierToProto(proto, IDENTIFIER);
- proto.write(STATE, state.toString());
+ proto.write(STATE, mState.toString());
proto.write(VISIBLE, visible);
proto.write(FRONT_OF_TASK, frontOfTask);
if (app != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index fe1067096609..817b69964f24 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -70,7 +70,12 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_USER_LEAV
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
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.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.am.ActivityStack.ActivityState.FINISHING;
import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
+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;
@@ -1353,8 +1358,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
- if (r.state == STOPPING || r.state == STOPPED
- || r.state == ActivityState.PAUSED || r.state == ActivityState.PAUSING) {
+ if (r.isState(STOPPING, STOPPED, PAUSED, PAUSING)) {
r.setSleeping(true);
}
}
@@ -1401,7 +1405,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
ActivityRecord resuming, boolean pauseImmediately) {
if (mPausingActivity != null) {
Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
- + " state=" + mPausingActivity.state);
+ + " state=" + mPausingActivity.getState());
if (!shouldSleepActivities()) {
// Avoid recursion among check for sleep and complete pause during sleeping.
// Because activity will be paused immediately after resume, just let pause
@@ -1431,7 +1435,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
mLastPausedActivity = prev;
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
- prev.state = ActivityState.PAUSING;
+ prev.setState(PAUSING, "startPausingLocked");
prev.getTask().touchActiveTime();
clearLaunchTime(prev);
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
@@ -1525,8 +1529,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
r.userId, System.identityHashCode(r), r.shortComponentName,
mPausingActivity != null
? mPausingActivity.shortComponentName : "(none)");
- if (r.state == ActivityState.PAUSING) {
- r.state = ActivityState.PAUSED;
+ if (r.isState(PAUSING)) {
+ r.setState(PAUSED, "activityPausedLocked");
if (r.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG,
"Executing finish of failed to pause activity: " + r);
@@ -1544,8 +1548,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
if (prev != null) {
- final boolean wasStopping = prev.state == STOPPING;
- prev.state = ActivityState.PAUSED;
+ final boolean wasStopping = prev.isState(STOPPING);
+ prev.setState(PAUSED, "completePausedLocked");
if (prev.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
@@ -1566,7 +1570,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// We are also stopping, the stop request must have gone soon after the pause.
// We can't clobber it, because the stop confirmation will not be handled.
// We don't need to schedule another stop, we only need to let it happen.
- prev.state = STOPPING;
+ prev.setState(STOPPING, "completePausedLocked");
} else if (!prev.visible || shouldSleepOrShutDownActivities()) {
// Clear out any deferred client hide we might currently have.
prev.setDeferHidingClient(false);
@@ -1843,7 +1847,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
if (reallyVisible) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
- + " finishing=" + r.finishing + " state=" + r.state);
+ + " finishing=" + r.finishing + " state=" + r.getState());
// First: if this is not the current activity being started, make
// sure it matches the current configuration.
if (r != starting) {
@@ -1875,7 +1879,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
configChanges |= r.configChangeFlags;
} else {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r
- + " finishing=" + r.finishing + " state=" + r.state
+ + " finishing=" + r.finishing + " state=" + r.getState()
+ " stackShouldBeVisible=" + stackShouldBeVisible
+ " behindFullscreenActivity=" + behindFullscreenActivity
+ " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
@@ -2059,7 +2063,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
// Now for any activities that aren't visible to the user, make sure they no longer are
// keeping the screen frozen.
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.getState());
try {
final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
"makeInvisible", true /* beforeStopping */);
@@ -2071,11 +2075,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// the current contract for "auto-Pip" is that the app should enter it before onPause
// returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
- && r.state != STOPPING && r.state != STOPPED && r.state != PAUSED;
+ && !r.isState(STOPPING, STOPPED, PAUSED);
r.setDeferHidingClient(deferHidingClient);
r.setVisible(false);
- switch (r.state) {
+ switch (r.getState()) {
case STOPPING:
case STOPPED:
if (r.app != null && r.app.thread != null) {
@@ -2255,7 +2259,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// TODO: move mResumedActivity to stack supervisor,
// there should only be 1 global copy of resumed activity.
mResumedActivity = r;
- r.state = ActivityState.RESUMED;
+ r.setState(RESUMED, "setResumedActivityLocked");
mService.setResumedActivityUncheckLocked(r, reason);
mStackSupervisor.mRecentTasks.add(r.getTask());
}
@@ -2294,8 +2298,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
next.delayedResume = false;
// If the top activity is the resumed one, nothing to do.
- if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
- mStackSupervisor.allResumedActivitiesComplete()) {
+ if (mResumedActivity == next && next.isState(RESUMED)
+ && mStackSupervisor.allResumedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
@@ -2389,8 +2393,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
- } else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
- mStackSupervisor.allResumedActivitiesComplete()) {
+ } else if (mResumedActivity == next && next.isState(RESUMED)
+ && mStackSupervisor.allResumedActivitiesComplete()) {
// It is possible for the activity to be resumed when we paused back stacks above if the
// next activity doesn't have to wait for pause to complete.
// So, nothing else to-do except:
@@ -2539,7 +2543,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
ActivityRecord lastResumedActivity =
lastStack == null ? null :lastStack.mResumedActivity;
- ActivityState lastState = next.state;
+ final ActivityState lastState = next.getState();
mService.updateCpuStats();
@@ -2645,7 +2649,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// Whoops, need to restart this activity!
if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
+ lastState + ": " + next);
- next.state = lastState;
+ next.setState(lastState, "resumeTopActivityInnerLocked");
if (lastStack != null) {
lastStack.mResumedActivity = lastResumedActivity;
}
@@ -3408,7 +3412,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
r.stopped = false;
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to STOPPING: " + r + " (stop requested)");
- r.state = STOPPING;
+ r.setState(STOPPING, "stopActivityLocked");
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Stopping visible=" + r.visible + " for " + r);
if (!r.visible) {
@@ -3432,7 +3436,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// Just in case, assume it to be stopped.
r.stopped = true;
if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + r);
- r.state = STOPPED;
+ r.setState(STOPPED, "stopActivityLocked");
if (r.deferRelaunchUntilPaused) {
destroyActivityLocked(r, true, "stop-except");
}
@@ -3505,9 +3509,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
if (activityNdx >= 0) {
r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);
- if (r.state == ActivityState.RESUMED
- || r.state == ActivityState.PAUSING
- || r.state == ActivityState.PAUSED) {
+ if (r.isState(RESUMED, PAUSING, PAUSED)) {
if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
@@ -3671,7 +3673,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (endTask) {
mService.mLockTaskController.clearLockedTask(task);
}
- } else if (r.state != ActivityState.PAUSING) {
+ } else if (!r.isState(PAUSING)) {
// If the activity is PAUSING, we will complete the finish once
// it is done pausing; else we can just directly finish it here.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
@@ -3738,7 +3740,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to STOPPING: "+ r + " (finish requested)");
- r.state = STOPPING;
+ r.setState(STOPPING, "finishCurrentActivityLocked");
if (oomAdj) {
mService.updateOomAdjLocked();
}
@@ -3752,15 +3754,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (mResumedActivity == r) {
mResumedActivity = null;
}
- final ActivityState prevState = r.state;
+ final ActivityState prevState = r.getState();
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
- r.state = ActivityState.FINISHING;
+ r.setState(FINISHING, "finishCurrentActivityLocked");
final boolean finishingActivityInNonFocusedStack
= r.getStack() != mStackSupervisor.getFocusedStack()
- && prevState == ActivityState.PAUSED && mode == FINISH_AFTER_VISIBLE;
+ && prevState == PAUSED && mode == FINISH_AFTER_VISIBLE;
if (mode == FINISH_IMMEDIATELY
- || (prevState == ActivityState.PAUSED
+ || (prevState == PAUSED
&& (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode()))
|| finishingActivityInNonFocusedStack
|| prevState == STOPPING
@@ -3981,7 +3983,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (setState) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + r + " (cleaning up)");
- r.state = ActivityState.DESTROYED;
+ r.setState(DESTROYED, "cleanupActivityLocked");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during cleanUp for activity " + r);
r.app = null;
}
@@ -4030,7 +4032,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
removeTimeoutsForActivityLocked(r);
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to DESTROYED: " + r + " (removed from history)");
- r.state = ActivityState.DESTROYED;
+ r.setState(DESTROYED, "removeActivityFromHistoryLocked");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r);
r.app = null;
r.removeWindowContainer();
@@ -4114,7 +4116,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
continue;
}
if (r.isDestroyable()) {
- if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.state
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r
+ + " in state " + r.getState()
+ " resumed=" + mResumedActivity
+ " pausing=" + mPausingActivity + " for reason " + reason);
if (destroyActivityLocked(r, true, reason)) {
@@ -4131,7 +4134,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final boolean safelyDestroyActivityLocked(ActivityRecord r, String reason) {
if (r.isDestroyable()) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
- "Destroying " + r + " in state " + r.state + " resumed=" + mResumedActivity
+ "Destroying " + r + " in state " + r.getState() + " resumed=" + mResumedActivity
+ " pausing=" + mPausingActivity + " for reason " + reason);
return destroyActivityLocked(r, true, reason);
}
@@ -4159,7 +4162,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final ActivityRecord activity = activities.get(actNdx);
if (activity.app == app && activity.isDestroyable()) {
if (DEBUG_RELEASE) Slog.v(TAG_RELEASE, "Destroying " + activity
- + " in state " + activity.state + " resumed=" + mResumedActivity
+ + " in state " + activity.getState() + " resumed=" + mResumedActivity
+ " pausing=" + mPausingActivity + " for reason " + reason);
destroyActivityLocked(activity, true, reason);
if (activities.get(actNdx) != activity) {
@@ -4253,13 +4256,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (r.finishing && !skipDestroy) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYING: " + r
+ " (destroy requested)");
- r.state = ActivityState.DESTROYING;
+ r.setState(DESTROYING,
+ "destroyActivityLocked. finishing and not skipping destroy");
Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG, r);
mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
} else {
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to DESTROYED: " + r + " (destroy skipped)");
- r.state = ActivityState.DESTROYED;
+ r.setState(DESTROYED,
+ "destroyActivityLocked. not finishing or skipping destroy");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + r);
r.app = null;
}
@@ -4270,7 +4275,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
removedFromHistory = true;
} else {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + r + " (no app)");
- r.state = ActivityState.DESTROYED;
+ r.setState(DESTROYED, "destroyActivityLocked. not finishing and had no app");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + r);
r.app = null;
}
@@ -4288,24 +4293,29 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final void activityDestroyedLocked(IBinder token, String reason) {
final long origId = Binder.clearCallingIdentity();
try {
- ActivityRecord r = ActivityRecord.forTokenLocked(token);
- if (r != null) {
- mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
- }
- if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + r);
-
- if (isInStackLocked(r) != null) {
- if (r.state == ActivityState.DESTROYING) {
- cleanUpActivityLocked(r, true, false);
- removeActivityFromHistoryLocked(r, reason);
- }
- }
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ activityDestroyedLocked(ActivityRecord.forTokenLocked(token), reason);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
+ final void activityDestroyedLocked(ActivityRecord record, String reason) {
+ if (record != null) {
+ mHandler.removeMessages(DESTROY_TIMEOUT_MSG, record);
+ }
+
+ if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + record);
+
+ if (isInStackLocked(record) != null) {
+ if (record.isState(DESTROYING, DESTROYED)) {
+ cleanUpActivityLocked(record, true, false);
+ removeActivityFromHistoryLocked(record, reason);
+ }
+ }
+
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ }
+
private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
ProcessRecord app, String listName) {
int i = list.size();
@@ -4374,14 +4384,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
+ ": haveState=" + r.haveState
+ " stateNotNeeded=" + r.stateNotNeeded
+ " finishing=" + r.finishing
- + " state=" + r.state + " callers=" + Debug.getCallers(5));
+ + " state=" + r.getState() + " callers=" + Debug.getCallers(5));
if (!r.finishing) {
Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
r.userId, System.identityHashCode(r),
r.getTask().taskId, r.shortComponentName,
"proc died without state saved");
- if (r.state == ActivityState.RESUMED) {
+ if (r.getState() == RESUMED) {
mService.updateUsageStats(r, false);
}
}
@@ -4417,7 +4427,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
private void updateTransitLocked(int transit, ActivityOptions options) {
if (options != null) {
ActivityRecord r = topRunningActivityLocked();
- if (r != null && r.state != ActivityState.RESUMED) {
+ if (r != null && !r.isState(RESUMED)) {
r.updateOptionsLocked(options);
} else {
ActivityOptions.abort(options);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 9a3b10299155..55771867302c 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1005,7 +1005,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final ActivityStack stack = display.getChildAt(stackNdx);
if (isFocusedStack(stack)) {
final ActivityRecord r = stack.mResumedActivity;
- if (r != null && r.state != RESUMED) {
+ if (r != null && !r.isState(RESUMED)) {
return false;
}
}
@@ -1069,10 +1069,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
final ActivityRecord r = stack.mPausingActivity;
- if (r != null && r.state != PAUSED && r.state != STOPPED && r.state != STOPPING) {
+ if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) {
if (DEBUG_STATES) {
Slog.d(TAG_STATES,
- "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
+ "allPausedActivitiesComplete: r=" + r + " state=" + r.getState());
pausing = false;
} else {
return false;
@@ -1522,7 +1522,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// current icicle and other state.
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to PAUSED: " + r + " (starting in paused state)");
- r.state = PAUSED;
+ r.setState(PAUSED, "realStartActivityLocked");
}
// Launch the new version setup screen if needed. We do this -after-
@@ -2099,9 +2099,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
- if (r == null || r.state != RESUMED) {
+ if (r == null || !r.isState(RESUMED)) {
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
- } else if (r.state == RESUMED) {
+ } else if (r.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
@@ -3540,14 +3540,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// First, if we find an activity that is in the process of being destroyed,
// then we just aren't going to do anything for now; we want things to settle
// down before we try to prune more activities.
- if (r.finishing || r.state == DESTROYING || r.state == DESTROYED) {
+ if (r.finishing || r.isState(DESTROYING, DESTROYED)) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Abort release; already destroying: " + r);
return;
}
// Don't consider any activies that are currently not in a state where they
// can be destroyed.
- if (r.visible || !r.stopped || !r.haveState || r.state == RESUMED || r.state == PAUSING
- || r.state == PAUSED || r.state == STOPPING) {
+ if (r.visible || !r.stopped || !r.haveState
+ || r.isState(RESUMED, PAUSING, PAUSED, STOPPING)) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
continue;
}
@@ -3683,7 +3683,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
? stack.shouldSleepOrShutDownActivities()
: mService.isSleepingOrShuttingDownLocked();
if (!waitingVisible || shouldSleepOrShutDown) {
- if (!processPausingActivities && s.state == PAUSING) {
+ if (!processPausingActivities && s.isState(PAUSING)) {
// Defer processing pausing activities in this iteration and reschedule
// a delayed idle to reprocess it again
removeTimeoutsForActivityLocked(idleActivity);
@@ -3710,7 +3710,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
final ActivityRecord r = stack.topRunningActivityLocked();
- final ActivityState state = r == null ? DESTROYED : r.state;
+ final ActivityState state = r == null ? DESTROYED : r.getState();
if (isFocusedStack(stack)) {
if (r == null) Slog.e(TAG,
"validateTop...: null top activity, stack=" + stack);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 8205265ba047..fcdf3d2918ed 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1107,7 +1107,7 @@ class ActivityStarter {
case START_TASK_TO_FRONT: {
// ActivityRecord may represent a different activity, but it should not be
// in the resumed state.
- if (r.nowVisible && r.state == RESUMED) {
+ if (r.nowVisible && r.isState(RESUMED)) {
outResult.timeout = false;
outResult.who = r.realActivity;
outResult.totalTime = 0;
@@ -1516,7 +1516,7 @@ class ActivityStarter {
final TaskRecord task = mSupervisor.anyTaskForIdLocked(
mOptions.getLaunchTaskId());
final ActivityRecord top = task != null ? task.getTopActivity() : null;
- if (top != null && top.state != RESUMED) {
+ if (top != null && !top.isState(RESUMED)) {
// The caller specifies that we'd like to be avoided to be moved to the
// front, so be it!
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index d679439d3b7d..a07afde44db2 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1103,7 +1103,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
// Increment the total number of non-finishing activities
reportOut.numActivities++;
- if (reportOut.top == null || (reportOut.top.state == ActivityState.INITIALIZING)) {
+ if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
reportOut.top = r;
// Reset the number of running activities until we hit the first non-initializing
// activity
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index d3df9241283a..5161114baf0f 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -22,6 +22,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
@@ -119,20 +121,20 @@ public class ActivityRecordTests extends ActivityTestsBase {
}
return null;
}).when(mActivity.app.thread).scheduleTransaction(any());
- mActivity.state = STOPPED;
+ mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
mActivity.makeVisibleIfNeeded(null /* starting */);
- assertEquals(mActivity.state, PAUSING);
+ assertTrue(mActivity.isState(PAUSING));
assertTrue(pauseFound.value);
// Make sure that the state does not change for current non-stopping states.
- mActivity.state = INITIALIZING;
+ mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
mActivity.makeVisibleIfNeeded(null /* starting */);
- assertEquals(mActivity.state, INITIALIZING);
+ assertTrue(mActivity.isState(INITIALIZING));
}
@Test
@@ -197,7 +199,23 @@ public class ActivityRecordTests extends ActivityTestsBase {
record.canBeLaunchedOnDisplay(DEFAULT_DISPLAY);
- verify(mService.mStackSupervisor, times(1)).canPlaceEntityOnDisplay(anyInt(), eq(expected), anyInt(), anyInt(),
- eq(record.info));
+ verify(mService.mStackSupervisor, times(1)).canPlaceEntityOnDisplay(anyInt(), eq(expected),
+ anyInt(), anyInt(), eq(record.info));
+ }
+
+ @Test
+ public void testFinishingAfterDestroying() throws Exception {
+ assertFalse(mActivity.finishing);
+ mActivity.setState(DESTROYING, "testFinishingAfterDestroying");
+ assertTrue(mActivity.isState(DESTROYING));
+ assertTrue(mActivity.finishing);
+ }
+
+ @Test
+ public void testFinishingAfterDestroyed() throws Exception {
+ assertFalse(mActivity.finishing);
+ mActivity.setState(DESTROYED, "testFinishingAfterDestroyed");
+ assertTrue(mActivity.isState(DESTROYED));
+ assertTrue(mActivity.finishing);
}
}