Skip to content

Commit b61a026

Browse files
author
Dianne Hackborn
committed
Fix issue #6020164: Settings crashed on orientation change...
...while listening to TTS example This was a nice one. What was happening is that immediately upon being created, the activity was starting another activity in a different process. The second activity would never show, just immediately exit. However the original activity had time to pause and get into stopping itself before the second activity had come back to the activity manager to say it was going away, resulting in the activity manager asking the original activity to resume. At this point the activity manager's state is that the second activity is finishing and gone, and the original activity is resumed. However in the app process the original activity is still working on stopping itself, and it eventually completes this and tells the activity manager. The activity manager now changes its state to STOPPED, even though it is actually resumed and that is the last thing it told it to be, and it is now proceeding to set itself in that state. This would result later in the activity manager sending an unnecessary state change to the application. In the case of the screen here, we next do a rotation change, the activity manager thinks the current state is STOPPED not RESUMED, so it tells the application to relaunch the activity in a new config but not in the resumed state. Now it does the whole "start a new temporary activity" thing again, at which point it tries to pause the original activity again, and we have an unbalanced onPause() call to the app and it falls over. Change-Id: I38b680746f4c61ae30e7ce831e1de187adf60902
1 parent 04d3521 commit b61a026

File tree

2 files changed

+18
-7
lines changed

2 files changed

+18
-7
lines changed

core/java/android/app/ActivityThread.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ public boolean isPreHoneycomb() {
275275
}
276276

277277
public String toString() {
278-
ComponentName componentName = intent.getComponent();
278+
ComponentName componentName = intent != null ? intent.getComponent() : null;
279279
return "ActivityRecord{"
280280
+ Integer.toHexString(System.identityHashCode(this))
281281
+ " token=" + token + " " + (componentName == null

services/java/com/android/server/am/ActivityStack.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,11 @@ final void activityPaused(IBinder token, boolean timeout) {
10361036

10371037
final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
10381038
CharSequence description) {
1039+
if (r.state != ActivityState.STOPPING) {
1040+
Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);
1041+
mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
1042+
return;
1043+
}
10391044
if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
10401045
if (icicle != null) {
10411046
// If icicle is null, this is happening due to a timeout, so we
@@ -4394,14 +4399,14 @@ final boolean ensureActivityConfigurationLocked(ActivityRecord r,
43944399
r.forceNewConfig = false;
43954400
if (r.app == null || r.app.thread == null) {
43964401
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4397-
"Switch is destroying non-running " + r);
4402+
"Config is destroying non-running " + r);
43984403
destroyActivityLocked(r, true, false, "config");
43994404
} else if (r.state == ActivityState.PAUSING) {
44004405
// A little annoying: we are waiting for this activity to
44014406
// finish pausing. Let's not do anything now, but just
44024407
// flag that it needs to be restarted when done pausing.
44034408
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4404-
"Switch is skipping already pausing " + r);
4409+
"Config is skipping already pausing " + r);
44054410
r.configDestroy = true;
44064411
return true;
44074412
} else if (r.state == ActivityState.RESUMED) {
@@ -4410,12 +4415,12 @@ final boolean ensureActivityConfigurationLocked(ActivityRecord r,
44104415
// Instead of doing the normal handshaking, just say
44114416
// "restart!".
44124417
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4413-
"Switch is restarting resumed " + r);
4418+
"Config is relaunching resumed " + r);
44144419
relaunchActivityLocked(r, r.configChangeFlags, true);
44154420
r.configChangeFlags = 0;
44164421
} else {
44174422
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
4418-
"Switch is restarting non-resumed " + r);
4423+
"Config is relaunching non-resumed " + r);
44194424
relaunchActivityLocked(r, r.configChangeFlags, false);
44204425
r.configChangeFlags = 0;
44214426
}
@@ -4461,15 +4466,17 @@ private final boolean relaunchActivityLocked(ActivityRecord r,
44614466
r.startFreezingScreenLocked(r.app, 0);
44624467

44634468
try {
4464-
if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
4469+
if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG,
4470+
(andResume ? "Relaunching to RESUMED " : "Relaunching to PAUSED ")
4471+
+ r);
44654472
r.forceNewConfig = false;
44664473
r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents,
44674474
changes, !andResume, new Configuration(mService.mConfiguration));
44684475
// Note: don't need to call pauseIfSleepingLocked() here, because
44694476
// the caller will only pass in 'andResume' if this activity is
44704477
// currently resumed, which implies we aren't sleeping.
44714478
} catch (RemoteException e) {
4472-
return false;
4479+
if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Relaunch failed", e);
44734480
}
44744481

44754482
if (andResume) {
@@ -4478,6 +4485,10 @@ private final boolean relaunchActivityLocked(ActivityRecord r,
44784485
if (mMainStack) {
44794486
mService.reportResumedActivityLocked(r);
44804487
}
4488+
r.state = ActivityState.RESUMED;
4489+
} else {
4490+
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4491+
r.state = ActivityState.PAUSED;
44814492
}
44824493

44834494
return true;

0 commit comments

Comments
 (0)