Fix issue #5461497: Landed on Welcome screen after a tap on 'Next' in Screen 500
The basic problem was that at some points during setup wizard, this would
happen:
1. The app's process is killed.
2. The app's process is restarted, but not to actually resume the
setup wizard activity, just to put it in the stopped state.
When doing this, the saved state is cleared but the app will
never provide a new one.
3. The app's process is killed again. At this point, because the
saved state is cleared, the activity is completely removed.
4. Eventually the entire activity stack becomes empty, and a new
setup wizard activity needs to be created as the home app.
There is a combination of bad stuff going on here.
First, why is the process being killed? At this point the setup
wizard is the home app, so it shouldn't be killed. There were two
reasons why this was happening:
- CryptKeeper still was not completely cleanly going away. To fix
this, I removed the check in the activity manager to not allow
an activity to finish if it is the only activity on the stack and
maybe-kindof looks like the home app. This really wasn't necessary
(we always take care of starting a new home activity if we find the
stack is empty), and outright dangerous with all of these things
purporting to be home but not.
- There was an issue in computing the oom_adj where the home app
would not be marked as "not hidden", and if we had to re-compute
its oom adj in the current sequence would then give it an
adjustment as a background process... and with all the processes
we spin through during boot, it quickly got down to background
#16 and killed.
Second, what is going on with the state? This is easier, the code
in the activity manager to create a new activity but put it in the
stopped state was still clearing the saved state. The saved state
should only be cleared when going in to the resumed state. When
going in to the stopped state, we can just keep holding the same
saved state.
Change-Id: I7d21cdcfa082d98ca70c79d9923e29605ee4353e
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 55fb371..0d6f405 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -165,7 +165,7 @@
static final boolean DEBUG_URI_PERMISSION = localLOGV || false;
static final boolean DEBUG_USER_LEAVING = localLOGV || false;
static final boolean DEBUG_RESULTS = localLOGV || false;
- static final boolean DEBUG_BACKUP = localLOGV || true;
+ static final boolean DEBUG_BACKUP = localLOGV || false;
static final boolean DEBUG_CONFIGURATION = localLOGV || false;
static final boolean DEBUG_POWER = localLOGV || false;
static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
@@ -2607,9 +2607,18 @@
TAG, "Record #" + i + " " + r + ": app=" + r.app);
if (r.app == app) {
if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
- if (localLOGV) Slog.v(
- TAG, "Removing this entry! frozen=" + r.haveState
- + " finishing=" + r.finishing);
+ if (ActivityStack.DEBUG_ADD_REMOVE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.i(TAG, "Removing activity " + r + " from stack at " + i
+ + ": haveState=" + r.haveState
+ + " stateNotNeeded=" + r.stateNotNeeded
+ + " finishing=" + r.finishing
+ + " state=" + r.state, here);
+ }
+ if (!r.finishing) {
+ Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
+ }
r.makeFinishing();
mMainStack.mHistory.remove(i);
r.takeFromHistory();
@@ -2630,6 +2639,8 @@
r.app = null;
r.nowVisible = false;
if (!r.haveState) {
+ if (ActivityStack.DEBUG_SAVED_STATE) Slog.i(TAG,
+ "App died, clearing saved state of " + r);
r.icicle = null;
}
}
@@ -4479,7 +4490,7 @@
}
}
if (pi == null) {
- Slog.w(TAG, "No content provider found for: " + name);
+ Slog.w(TAG, "No content provider found for permission check: " + uri.toSafeString());
return -1;
}
@@ -4735,7 +4746,7 @@
}
}
if (pi == null) {
- Slog.w(TAG, "No content provider found for: " + authority);
+ Slog.w(TAG, "No content provider found for permission revoke: " + uri.toSafeString());
return;
}
@@ -4829,7 +4840,8 @@
}
}
if (pi == null) {
- Slog.w(TAG, "No content provider found for: " + authority);
+ Slog.w(TAG, "No content provider found for permission revoke: "
+ + uri.toSafeString());
return;
}
@@ -13054,11 +13066,13 @@
if (app.foregroundServices) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ app.hidden = false;
app.adjType = "foreground-service";
schedGroup = Process.THREAD_GROUP_DEFAULT;
} else if (app.forcingToForeground != null) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ app.hidden = false;
app.adjType = "force-foreground";
app.adjSource = app.forcingToForeground;
schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -13069,6 +13083,7 @@
// We don't want to kill the current heavy-weight process.
adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ app.hidden = false;
app.adjType = "heavy";
}
@@ -13077,11 +13092,13 @@
// home app, so we don't want to let it go into the background.
adj = ProcessList.HOME_APP_ADJ;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ app.hidden = false;
app.adjType = "home";
}
-
- //Slog.i(TAG, "OOM " + app + ": initial adj=" + adj);
-
+
+ if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
+ + " reason=" + app.adjType);
+
// By default, we use the computed adjustment. It may be changed if
// there are applications dependent on our services or providers, but
// this gives us a baseline and makes sure we don't get into an
@@ -13108,7 +13125,7 @@
while (jt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
ServiceRecord s = jt.next();
if (s.startRequested) {
- if (app.hasShownUi) {
+ if (app.hasShownUi && app != mHomeProcess) {
// If this process has shown some UI, let it immediately
// go to the LRU list because it may be pretty heavy with
// UI stuff. We'll tag it with a label just to help
@@ -13169,7 +13186,7 @@
if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
// Not doing bind OOM management, so treat
// this guy more like a started service.
- if (app.hasShownUi) {
+ if (app.hasShownUi && app != mHomeProcess) {
// If this process has shown some UI, let it immediately
// go to the LRU list because it may be pretty heavy with
// UI stuff. We'll tag it with a label just to help
@@ -13177,6 +13194,7 @@
if (adj > clientAdj) {
adjType = "bound-bg-ui-services";
}
+ app.hidden = false;
clientAdj = adj;
} else {
if (now >= (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
@@ -13200,7 +13218,8 @@
// about letting this process get into the LRU
// list to be killed and restarted if needed for
// memory.
- if (app.hasShownUi && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ if (app.hasShownUi && app != mHomeProcess
+ && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adjType = "bound-bg-ui-services";
} else {
if ((cr.flags&(Context.BIND_ABOVE_CLIENT
@@ -13294,7 +13313,8 @@
int clientAdj = computeOomAdjLocked(
client, myHiddenAdj, TOP_APP, true);
if (adj > clientAdj) {
- if (app.hasShownUi && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ if (app.hasShownUi && app != mHomeProcess
+ && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
app.adjType = "bg-ui-provider";
} else {
adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 1aed7fe0..28c3bae 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -87,6 +87,8 @@
static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
static final boolean DEBUG_STATES = false;
+ static final boolean DEBUG_ADD_REMOVE = false;
+ static final boolean DEBUG_SAVED_STATE = false;
static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
@@ -653,6 +655,9 @@
}
completeResumeLocked(r);
checkReadyForSleepLocked();
+ if (DEBUG_SAVED_STATE) Slog.i(TAG, "Launch completed; removing icicle of " + r.icicle);
+ r.icicle = null;
+ r.haveState = false;
} else {
// This activity is not starting in the resumed state... which
// should look like we asked it to pause+stop (but remain visible),
@@ -664,9 +669,6 @@
r.stopped = true;
}
- r.icicle = null;
- r.haveState = false;
-
// Launch the new version setup screen if needed. We do this -after-
// launching the initial activity (that is, home), so that it can have
// a chance to initialize itself while in the background, making the
@@ -936,6 +938,7 @@
final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
CharSequence description) {
+ if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
r.icicle = icicle;
r.haveState = true;
r.updateThumbnail(thumbnail, description);
@@ -1544,6 +1547,7 @@
}
// Didn't need to use the icicle, and it is now out of date.
+ if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; didn't need icicle of: " + next);
next.icicle = null;
next.haveState = false;
next.stopped = false;
@@ -1590,6 +1594,12 @@
// get started when the user navigates back to it.
addPos = i+1;
if (!startIt) {
+ if (DEBUG_ADD_REMOVE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
+ here);
+ }
mHistory.add(addPos, r);
r.putInHistory();
mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
@@ -1622,6 +1632,11 @@
}
// Slot the activity into the history stack and proceed
+ if (DEBUG_ADD_REMOVE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
+ }
mHistory.add(addPos, r);
r.putInHistory();
r.frontOfTask = newTask;
@@ -1818,6 +1833,12 @@
+ " out to target's task " + target.task);
p.setTask(target.task, curThumbHolder, false);
curThumbHolder = p.thumbHolder;
+ if (DEBUG_ADD_REMOVE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
+ + dstPos, here);
+ }
mHistory.remove(srcPos);
mHistory.add(dstPos, p);
mService.mWindowManager.moveAppToken(dstPos, p);
@@ -1945,6 +1966,12 @@
} else {
lastReparentPos--;
}
+ if (DEBUG_ADD_REMOVE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
+ + lastReparentPos, here);
+ }
mHistory.remove(srcPos);
p.setTask(task, null, false);
mHistory.add(lastReparentPos, p);
@@ -2143,6 +2170,12 @@
ActivityRecord newTop = mHistory.remove(where);
int top = mHistory.size();
ActivityRecord oldTop = mHistory.get(top-1);
+ if (DEBUG_ADD_REMOVE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.i(TAG, "Removing and adding activity " + newTop + " to stack at "
+ + top, here);
+ }
mHistory.add(top, newTop);
oldTop.frontOfTask = false;
newTop.frontOfTask = true;
@@ -2183,7 +2216,7 @@
if (resultTo != null) {
int index = indexOfTokenLocked(resultTo);
if (DEBUG_RESULTS) Slog.v(
- TAG, "Sending result to " + resultTo + " (index " + index + ")");
+ TAG, "Will send result to " + resultTo + " (index " + index + ")");
if (index >= 0) {
sourceRecord = mHistory.get(index);
if (requestCode >= 0 && !sourceRecord.finishing) {
@@ -3279,34 +3312,15 @@
*/
final boolean requestFinishActivityLocked(IBinder token, int resultCode,
Intent resultData, String reason) {
- if (DEBUG_RESULTS) Slog.v(
- TAG, "Finishing activity: token=" + token
- + ", result=" + resultCode + ", data=" + resultData);
-
int index = indexOfTokenLocked(token);
+ if (DEBUG_RESULTS) Slog.v(
+ TAG, "Finishing activity @" + index + ": token=" + token
+ + ", result=" + resultCode + ", data=" + resultData);
if (index < 0) {
return false;
}
ActivityRecord r = mHistory.get(index);
- // Is this the last activity left?
- boolean lastActivity = true;
- for (int i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord p = mHistory.get(i);
- if (!p.finishing && p != r) {
- lastActivity = false;
- break;
- }
- }
-
- // If this is the last activity, but it is the home activity, then
- // just don't finish it.
- if (lastActivity) {
- if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
- return false;
- }
- }
-
finishActivityLocked(r, index, resultCode, resultData, reason);
return true;
}
@@ -3538,6 +3552,11 @@
private final void removeActivityFromHistoryLocked(ActivityRecord r) {
if (r.state != ActivityState.DESTROYED) {
r.makeFinishing();
+ if (DEBUG_ADD_REMOVE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.i(TAG, "Removing activity " + r + " from stack");
+ }
mHistory.remove(r);
r.takeFromHistory();
if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
@@ -3769,6 +3788,11 @@
TAG, "At " + pos + " ckp " + r.task + ": " + r);
if (r.task.taskId == task) {
if (localLOGV) Slog.v(TAG, "Removing and adding at " + top);
+ if (DEBUG_ADD_REMOVE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.i(TAG, "Removing and adding activity " + r + " to stack at " + top, here);
+ }
mHistory.remove(pos);
mHistory.add(top, r);
moved.add(0, r);
@@ -3858,6 +3882,12 @@
TAG, "At " + pos + " ckp " + r.task + ": " + r);
if (r.task.taskId == task) {
if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
+ if (DEBUG_ADD_REMOVE) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.i(TAG, "Removing and adding activity " + r + " to stack at "
+ + bottom, here);
+ }
mHistory.remove(pos);
mHistory.add(bottom, r);
moved.add(r);