Merge "Ignore activity lifecycle requests without matching client records." into pi-dev
am: 790c5d04c8
Change-Id: I8c8b8799073bc92f0464fa79491db16cc10057ae
This commit is contained in:
@@ -147,7 +147,10 @@ public class TransactionExecutor {
|
||||
pw.println("Executor:");
|
||||
dump(pw, prefix);
|
||||
|
||||
Slog.wtf(TAG, stringWriter.toString());
|
||||
Slog.w(TAG, stringWriter.toString());
|
||||
|
||||
// Ignore requests for non-existent client records for now.
|
||||
return;
|
||||
}
|
||||
|
||||
// Cycle to the state right before the final requested state.
|
||||
|
||||
@@ -1621,12 +1621,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
||||
return;
|
||||
}
|
||||
|
||||
if (isState(DESTROYED) || (state != DESTROYED && isState(DESTROYING))) {
|
||||
// We cannot move backwards from destroyed and destroying states.
|
||||
throw new IllegalArgumentException("cannot move back states once destroying"
|
||||
+ "current:" + mState + " requested:" + state);
|
||||
}
|
||||
|
||||
final ActivityState prev = mState;
|
||||
mState = state;
|
||||
|
||||
@@ -1641,23 +1635,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
||||
if (parent != null) {
|
||||
parent.onActivityStateChanged(this, state, reason);
|
||||
}
|
||||
|
||||
if (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() {
|
||||
|
||||
@@ -3811,14 +3811,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
final ActivityState prevState = r.getState();
|
||||
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
|
||||
|
||||
// We are already destroying / have already destroyed the activity. Do not continue to
|
||||
// modify it. Note that we do not use ActivityRecord#finishing here as finishing is not
|
||||
// indicative of destruction (though destruction is indicative of finishing) as finishing
|
||||
// can be delayed below.
|
||||
if (r.isState(DESTROYING, DESTROYED)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
r.setState(FINISHING, "finishCurrentActivityLocked");
|
||||
final boolean finishingActivityInNonFocusedStack
|
||||
= r.getStack() != mStackSupervisor.getFocusedStack()
|
||||
@@ -4037,26 +4029,16 @@ 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 destroy,
|
||||
boolean clearProcess) {
|
||||
private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) {
|
||||
onActivityRemovedFromStack(r);
|
||||
|
||||
r.deferRelaunchUntilPaused = false;
|
||||
r.frozenBeforeDestroy = false;
|
||||
|
||||
if (destroy) {
|
||||
if (setState) {
|
||||
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;
|
||||
}
|
||||
@@ -4271,7 +4253,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
+ ", app=" + (r.app != null ? r.app.processName : "(null)"));
|
||||
|
||||
if (r.isState(DESTROYING, DESTROYED)) {
|
||||
if (DEBUG_STATES) Slog.v(TAG_STATES, "activity " + r + " already finishing."
|
||||
if (DEBUG_STATES) Slog.v(TAG_STATES, "activity " + r + " already destroying."
|
||||
+ "skipping request with reason:" + reason);
|
||||
return false;
|
||||
}
|
||||
@@ -4282,8 +4264,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
|
||||
boolean removedFromHistory = false;
|
||||
|
||||
cleanUpActivityLocked(r, false /* cleanServices */, false /* destroy */,
|
||||
false /*clearProcess*/);
|
||||
cleanUpActivityLocked(r, false, false);
|
||||
|
||||
final boolean hadApp = r.app != null;
|
||||
|
||||
@@ -4380,6 +4361,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is to only be called from the client via binder when the activity is destroyed
|
||||
* AND finished.
|
||||
*/
|
||||
final void activityDestroyedLocked(ActivityRecord record, String reason) {
|
||||
if (record != null) {
|
||||
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, record);
|
||||
@@ -4389,8 +4374,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
|
||||
if (isInStackLocked(record) != null) {
|
||||
if (record.isState(DESTROYING, DESTROYED)) {
|
||||
cleanUpActivityLocked(record, true /* cleanServices */, false /* destroy */,
|
||||
false /*clearProcess*/);
|
||||
cleanUpActivityLocked(record, true, false);
|
||||
removeActivityFromHistoryLocked(record, reason);
|
||||
}
|
||||
}
|
||||
@@ -4499,8 +4483,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
r.icicle = null;
|
||||
}
|
||||
}
|
||||
cleanUpActivityLocked(r, true /* cleanServices */, remove /* destroy */,
|
||||
true /*clearProcess*/);
|
||||
cleanUpActivityLocked(r, true, true);
|
||||
if (remove) {
|
||||
removeActivityFromHistoryLocked(r, "appDied");
|
||||
}
|
||||
|
||||
@@ -222,35 +222,4 @@ 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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetInvalidState() throws Exception {
|
||||
mActivity.setState(DESTROYED, "testInvalidState");
|
||||
|
||||
boolean exceptionEncountered = false;
|
||||
|
||||
try {
|
||||
mActivity.setState(FINISHING, "testInvalidState");
|
||||
} catch (IllegalArgumentException e) {
|
||||
exceptionEncountered = true;
|
||||
}
|
||||
|
||||
assertTrue(exceptionEncountered);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,28 +478,6 @@ public class ActivityStackTests extends ActivityTestsBase {
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuppressMultipleDestroy() throws Exception {
|
||||
final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
|
||||
final ClientLifecycleManager lifecycleManager = mock(ClientLifecycleManager.class);
|
||||
final ProcessRecord app = r.app;
|
||||
|
||||
// The mocked lifecycle manager must be set on the ActivityStackSupervisor's reference to
|
||||
// the service rather than mService as mService is a spy and setting the value will not
|
||||
// propagate as ActivityManagerService hands its own reference to the
|
||||
// ActivityStackSupervisor during construction.
|
||||
((TestActivityManagerService) mSupervisor.mService).setLifecycleManager(lifecycleManager);
|
||||
|
||||
mStack.destroyActivityLocked(r, true, "first invocation");
|
||||
verify(lifecycleManager, times(1)).scheduleTransaction(eq(app.thread),
|
||||
eq(r.appToken), any(DestroyActivityItem.class));
|
||||
assertTrue(r.isState(DESTROYED, DESTROYING));
|
||||
|
||||
mStack.destroyActivityLocked(r, true, "second invocation");
|
||||
verify(lifecycleManager, times(1)).scheduleTransaction(eq(app.thread),
|
||||
eq(r.appToken), any(DestroyActivityItem.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinishDisabledPackageActivities() throws Exception {
|
||||
final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
|
||||
|
||||
Reference in New Issue
Block a user