summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java22
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java16
3 files changed, 55 insertions, 6 deletions
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index ae98ca02eba7..519024a0ab94 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1614,16 +1614,36 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
void setState(ActivityState state, String reason) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState()
+ " to:" + state + " reason:" + reason);
+
final ActivityState prev = mState;
+ final boolean stateChanged = prev != state;
+
mState = state;
- if (mState != prev) {
+ if (stateChanged) {
if (mRecentTransitions.size() == MAX_STORED_STATE_TRANSITIONS) {
mRecentTransitions.remove(0);
}
mRecentTransitions.add(new StateTransition(prev, state, reason));
}
+
+ 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() {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a3044f889953..9276abe68663 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4000,16 +4000,26 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
* state to destroy so only the cleanup here is needed.
*
* Note: Call before #removeActivityFromHistoryLocked.
+ *
+ * @param r The {@link ActivityRecord} to cleanup.
+ * @param cleanServices Whether services bound to the {@link ActivityRecord} should also be
+ * cleaned up.
+ * @param destroy Whether the {@link ActivityRecord} should be destroyed.
+ * @param clearProcess Whether the client process should be cleared.
*/
- private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) {
+ private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean destroy,
+ boolean clearProcess) {
onActivityRemovedFromStack(r);
r.deferRelaunchUntilPaused = false;
r.frozenBeforeDestroy = false;
- if (setState) {
+ if (destroy) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + r + " (cleaning up)");
r.setState(DESTROYED, "cleanupActivityLocked");
+ }
+
+ if (clearProcess) {
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during cleanUp for activity " + r);
r.app = null;
}
@@ -4228,7 +4238,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
boolean removedFromHistory = false;
- cleanUpActivityLocked(r, false, false);
+ cleanUpActivityLocked(r, false /* cleanServices */, false /* destroy */,
+ false /*clearProcess*/);
final boolean hadApp = r.app != null;
@@ -4334,7 +4345,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (isInStackLocked(record) != null) {
if (record.isState(DESTROYING, DESTROYED)) {
- cleanUpActivityLocked(record, true, false);
+ cleanUpActivityLocked(record, true /* cleanServices */, false /* destroy */,
+ false /*clearProcess*/);
removeActivityFromHistoryLocked(record, reason);
}
}
@@ -4439,7 +4451,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
r.icicle = null;
}
}
- cleanUpActivityLocked(r, true, true);
+ cleanUpActivityLocked(r, true /* cleanServices */, remove /* destroy */,
+ true /*clearProcess*/);
if (remove) {
removeActivityFromHistoryLocked(r, "appDied");
}
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 a527e17b393b..f2f1b10b5368 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -202,4 +202,20 @@ public class ActivityRecordTests extends ActivityTestsBase {
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);
+ }
}