Rework activity lifecycle so onSaveInstanceState() is after onPause().
The goal is to fix a bunch of fragment-related bugs caused by various
things trying to do fragment transactions after onPause()... which
currently throws an exception, since this is after the activity's state
has been saved so the new fragment state can be lost.
The basic change is relatively simple -- we now consider processes
hosting paused or stopping activities to be unkillable, and the client
code now does the onSaveInstanceState() as part of stopping the
activity.
For compatibility, if an app's targetSdkVersion is < HONEYCOMB, the
client side will still call onSaveInstanceState() prior to onPause()
and just hold on to that state until it needs to report it in once
being stopped.
Also included here is a change to generate thumbnails by taking
screenshots. The code for generating thumbnails by re-rendering
the view hierarchy is thus removed.
Change-Id: Iac1191646bd3cadbfe65779297795f22edf7e74a
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 1a10cff..1bfdcae 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3780,22 +3780,22 @@
}
}
- public final void activityPaused(IBinder token, Bundle icicle) {
+ public final void activityPaused(IBinder token) {
+ final long origId = Binder.clearCallingIdentity();
+ mMainStack.activityPaused(token, false);
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ public final void activityStopped(IBinder token, Bundle icicle, Bitmap thumbnail,
+ CharSequence description) {
+ if (localLOGV) Slog.v(
+ TAG, "Activity stopped: token=" + token);
+
// Refuse possible leaked file descriptors
if (icicle != null && icicle.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
}
- final long origId = Binder.clearCallingIdentity();
- mMainStack.activityPaused(token, icicle, false);
- Binder.restoreCallingIdentity(origId);
- }
-
- public final void activityStopped(IBinder token, Bitmap thumbnail,
- CharSequence description) {
- if (localLOGV) Slog.v(
- TAG, "Activity stopped: token=" + token);
-
ActivityRecord r = null;
final long origId = Binder.clearCallingIdentity();
@@ -3804,7 +3804,11 @@
int index = mMainStack.indexOfTokenLocked(token);
if (index >= 0) {
r = (ActivityRecord)mMainStack.mHistory.get(index);
- r.thumbnail = thumbnail;
+ r.icicle = icicle;
+ r.haveState = true;
+ if (thumbnail != null) {
+ r.thumbnail = thumbnail;
+ }
r.description = description;
r.stopped = true;
r.state = ActivityState.STOPPED;
@@ -4822,6 +4826,10 @@
throw new SecurityException(msg);
}
+ final boolean canReadFb = checkCallingPermission(
+ android.Manifest.permission.READ_FRAME_BUFFER)
+ == PackageManager.PERMISSION_GRANTED;
+
int pos = mMainStack.mHistory.size()-1;
ActivityRecord next =
pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
@@ -4866,7 +4874,13 @@
ci.id = curTask.taskId;
ci.baseActivity = r.intent.getComponent();
ci.topActivity = top.intent.getComponent();
- ci.thumbnail = top.thumbnail;
+ if (canReadFb) {
+ if (top.thumbnail != null) {
+ ci.thumbnail = top.thumbnail;
+ } else if (top.state == ActivityState.RESUMED) {
+ ci.thumbnail = top.stack.screenshotActivities();
+ }
+ }
ci.description = topDescription;
ci.numActivities = numActivities;
ci.numRunning = numRunning;
@@ -11806,7 +11820,7 @@
} else if (app == mHeavyWeightProcess) {
// We don't want to kill the current heavy-weight process.
adj = HEAVY_WEIGHT_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.adjType = "heavy";
} else if (app == mHomeProcess) {
// This process is hosting what we currently consider to be the
@@ -11822,13 +11836,19 @@
app.adjType = "bg-activities";
N = app.activities.size();
for (int j=0; j<N; j++) {
- if (app.activities.get(j).visible) {
+ ActivityRecord r = app.activities.get(j);
+ if (r.visible) {
// This app has a visible activity!
app.hidden = false;
adj = VISIBLE_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "visible";
break;
+ } else if (r.state == ActivityState.PAUSING
+ || r.state == ActivityState.PAUSED
+ || r.state == ActivityState.STOPPING) {
+ adj = PERCEPTIBLE_APP_ADJ;
+ app.adjType = "stopping";
}
}
} else {