summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2012-05-14 17:19:18 -0700
committerDianne Hackborn <hackbod@google.com>2012-05-14 17:19:18 -0700
commitb61a02657b9e577179c934bbb5e199ce919c4642 (patch)
tree4da2799e5a097baeda037e7c525334867888132f
parent04d3521839c90d1cccf3ee428963a0aef0088ef9 (diff)
downloadframeworks_base-b61a02657b9e577179c934bbb5e199ce919c4642.zip
frameworks_base-b61a02657b9e577179c934bbb5e199ce919c4642.tar.gz
frameworks_base-b61a02657b9e577179c934bbb5e199ce919c4642.tar.bz2
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
-rw-r--r--core/java/android/app/ActivityThread.java2
-rwxr-xr-xservices/java/com/android/server/am/ActivityStack.java23
2 files changed, 18 insertions, 7 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e2ebeba..5085b1e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -275,7 +275,7 @@ public final class ActivityThread {
}
public String toString() {
- ComponentName componentName = intent.getComponent();
+ ComponentName componentName = intent != null ? intent.getComponent() : null;
return "ActivityRecord{"
+ Integer.toHexString(System.identityHashCode(this))
+ " token=" + token + " " + (componentName == null
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index c300411..b9f63cf 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1036,6 +1036,11 @@ final class ActivityStack {
final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
CharSequence description) {
+ if (r.state != ActivityState.STOPPING) {
+ Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);
+ mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
+ return;
+ }
if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
if (icicle != null) {
// If icicle is null, this is happening due to a timeout, so we
@@ -4394,14 +4399,14 @@ final class ActivityStack {
r.forceNewConfig = false;
if (r.app == null || r.app.thread == null) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is destroying non-running " + r);
+ "Config is destroying non-running " + r);
destroyActivityLocked(r, true, false, "config");
} else if (r.state == ActivityState.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,
- "Switch is skipping already pausing " + r);
+ "Config is skipping already pausing " + r);
r.configDestroy = true;
return true;
} else if (r.state == ActivityState.RESUMED) {
@@ -4410,12 +4415,12 @@ final class ActivityStack {
// Instead of doing the normal handshaking, just say
// "restart!".
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is restarting resumed " + r);
+ "Config is relaunching resumed " + r);
relaunchActivityLocked(r, r.configChangeFlags, true);
r.configChangeFlags = 0;
} else {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is restarting non-resumed " + r);
+ "Config is relaunching non-resumed " + r);
relaunchActivityLocked(r, r.configChangeFlags, false);
r.configChangeFlags = 0;
}
@@ -4461,7 +4466,9 @@ final class ActivityStack {
r.startFreezingScreenLocked(r.app, 0);
try {
- if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG,
+ (andResume ? "Relaunching to RESUMED " : "Relaunching to PAUSED ")
+ + r);
r.forceNewConfig = false;
r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents,
changes, !andResume, new Configuration(mService.mConfiguration));
@@ -4469,7 +4476,7 @@ final class ActivityStack {
// the caller will only pass in 'andResume' if this activity is
// currently resumed, which implies we aren't sleeping.
} catch (RemoteException e) {
- return false;
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Relaunch failed", e);
}
if (andResume) {
@@ -4478,6 +4485,10 @@ final class ActivityStack {
if (mMainStack) {
mService.reportResumedActivityLocked(r);
}
+ r.state = ActivityState.RESUMED;
+ } else {
+ mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+ r.state = ActivityState.PAUSED;
}
return true;