Fix issue #12031685: Sticky Service Breakage in Android 4.4.1

Got a little too aggressive about cleaning up service state; need to
avoid removing services from an app until we are in the second loop
doing the final cleanup, otherwise we can leave services around with
restarting their process.

Also fix crash:

W/BinderNative(  667): Uncaught exception from death notification
W/BinderNative(  667): java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
W/BinderNative(  667): 	at android.util.ArraySet.valueAt(ArraySet.java:301)
W/BinderNative(  667): 	at com.android.server.am.ActiveServices.killServicesLocked(ActiveServices.java:2069)
W/BinderNative(  667): 	at com.android.server.am.ActivityManagerService.cleanUpApplicationRecordLocked(ActivityManagerService.java:12412)
W/BinderNative(  667): 	at com.android.server.am.ActivityManagerService.handleAppDiedLocked(ActivityManagerService.java:3596)
W/BinderNative(  667): 	at com.android.server.am.ActivityManagerService.appDiedLocked(ActivityManagerService.java:3744)
W/BinderNative(  667): 	at com.android.server.am.ActivityManagerService$AppDeathRecipient.binderDied(ActivityManagerService.java:1024)
W/BinderNative(  667): 	at android.os.BinderProxy.sendDeathNotice(Binder.java:493)
W/BinderNative(  667): 	at dalvik.system.NativeStart.run(Native Method)
This commit is contained in:
Dianne Hackborn
2013-12-09 11:26:11 -08:00
parent 301b1facb2
commit c174288d34

View File

@ -64,7 +64,7 @@ public final class ActiveServices {
static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE; static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE;
static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING; static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING;
static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE; static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE;
static final boolean DEBUG_DELAYED_STATS = DEBUG_DELAYED_SERVICE; static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU; static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
static final String TAG = ActivityManagerService.TAG; static final String TAG = ActivityManagerService.TAG;
static final String TAG_MU = ActivityManagerService.TAG_MU; static final String TAG_MU = ActivityManagerService.TAG_MU;
@ -186,11 +186,11 @@ public final class ActiveServices {
void ensureNotStartingBackground(ServiceRecord r) { void ensureNotStartingBackground(ServiceRecord r) {
if (mStartingBackground.remove(r)) { if (mStartingBackground.remove(r)) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "No longer background starting: " + r); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer background starting: " + r);
rescheduleDelayedStarts(); rescheduleDelayedStarts();
} }
if (mDelayedStartList.remove(r)) { if (mDelayedStartList.remove(r)) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "No longer delaying start: " + r); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer delaying start: " + r);
} }
} }
@ -208,7 +208,7 @@ public final class ActiveServices {
while (mDelayedStartList.size() > 0 while (mDelayedStartList.size() > 0
&& mStartingBackground.size() < mMaxStartingBackground) { && mStartingBackground.size() < mMaxStartingBackground) {
ServiceRecord r = mDelayedStartList.remove(0); ServiceRecord r = mDelayedStartList.remove(0);
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r);
if (r.pendingStarts.size() <= 0) { if (r.pendingStarts.size() <= 0) {
Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested
+ " delayedStop=" + r.delayedStop); + " delayedStop=" + r.delayedStop);
@ -276,7 +276,7 @@ public final class ActiveServices {
ComponentName startServiceLocked(IApplicationThread caller, ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType, Intent service, String resolvedType,
int callingPid, int callingUid, int userId) { int callingPid, int callingUid, int userId) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "startService: " + service if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras()); + " type=" + resolvedType + " args=" + service.getExtras());
final boolean callerFg; final boolean callerFg;
@ -336,7 +336,7 @@ public final class ActiveServices {
if (r.delayed) { if (r.delayed) {
// This service is already scheduled for a delayed start; just leave // This service is already scheduled for a delayed start; just leave
// it still waiting. // it still waiting.
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Continuing to delay: " + r); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Continuing to delay: " + r);
return r.name; return r.name;
} }
if (smap.mStartingBackground.size() >= mMaxStartingBackground) { if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
@ -346,15 +346,15 @@ public final class ActiveServices {
r.delayed = true; r.delayed = true;
return r.name; return r.name;
} }
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying: " + r); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying: " + r);
addToStarting = true; addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) { } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
// We slightly loosen when we will enqueue this new service as a background // We slightly loosen when we will enqueue this new service as a background
// starting service we are waiting for, to also include processes that are // starting service we are waiting for, to also include processes that are
// currently running other services or receivers. // currently running other services or receivers.
addToStarting = true; addToStarting = true;
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying, but counting as bg: " + r); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
} else if (DEBUG_DELAYED_STATS) { } else if (DEBUG_DELAYED_STARTS) {
StringBuilder sb = new StringBuilder(128); StringBuilder sb = new StringBuilder(128);
sb.append("Not potential delay (state=").append(proc.curProcState) sb.append("Not potential delay (state=").append(proc.curProcState)
.append(' ').append(proc.adjType); .append(' ').append(proc.adjType);
@ -367,7 +367,7 @@ public final class ActiveServices {
sb.append(r.toString()); sb.append(r.toString());
Slog.v(TAG, sb.toString()); Slog.v(TAG, sb.toString());
} }
} else if (DEBUG_DELAYED_STATS) { } else if (DEBUG_DELAYED_STARTS) {
if (callerFg) { if (callerFg) {
Slog.v(TAG, "Not potential delay (callerFg=" + callerFg + " uid=" Slog.v(TAG, "Not potential delay (callerFg=" + callerFg + " uid="
+ callingUid + " pid=" + callingPid + "): " + r); + callingUid + " pid=" + callingPid + "): " + r);
@ -404,7 +404,7 @@ public final class ActiveServices {
RuntimeException here = new RuntimeException("here"); RuntimeException here = new RuntimeException("here");
here.fillInStackTrace(); here.fillInStackTrace();
Slog.v(TAG, "Starting background (first=" + first + "): " + r, here); Slog.v(TAG, "Starting background (first=" + first + "): " + r, here);
} else if (DEBUG_DELAYED_STATS) { } else if (DEBUG_DELAYED_STARTS) {
Slog.v(TAG, "Starting background (first=" + first + "): " + r); Slog.v(TAG, "Starting background (first=" + first + "): " + r);
} }
if (first) { if (first) {
@ -422,7 +422,7 @@ public final class ActiveServices {
// If service isn't actually running, but is is being held in the // If service isn't actually running, but is is being held in the
// delayed list, then we need to keep it started but note that it // delayed list, then we need to keep it started but note that it
// should be stopped once no longer delayed. // should be stopped once no longer delayed.
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Delaying stop of pending: " + service); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Delaying stop of pending: " + service);
service.delayedStop = true; service.delayedStop = true;
return; return;
} }
@ -1278,7 +1278,7 @@ public final class ActiveServices {
// Make sure this service is no longer considered delayed, we are starting it now. // Make sure this service is no longer considered delayed, we are starting it now.
if (r.delayed) { if (r.delayed) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r); getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false; r.delayed = false;
} }
@ -1361,7 +1361,7 @@ public final class ActiveServices {
// Oh and hey we've already been asked to stop! // Oh and hey we've already been asked to stop!
r.delayedStop = false; r.delayedStop = false;
if (r.startRequested) { if (r.startRequested) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
stopServiceLocked(r); stopServiceLocked(r);
} }
} }
@ -1432,7 +1432,7 @@ public final class ActiveServices {
sendServiceArgsLocked(r, execInFg, true); sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) { if (r.delayed) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r); getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false; r.delayed = false;
} }
@ -1441,7 +1441,7 @@ public final class ActiveServices {
// Oh and hey we've already been asked to stop! // Oh and hey we've already been asked to stop!
r.delayedStop = false; r.delayedStop = false;
if (r.startRequested) { if (r.startRequested) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (from start): " + r); if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
stopServiceLocked(r); stopServiceLocked(r);
} }
} }
@ -2034,7 +2034,7 @@ public final class ActiveServices {
synchronized (sr.stats.getBatteryStats()) { synchronized (sr.stats.getBatteryStats()) {
sr.stats.stopLaunchedLocked(); sr.stats.stopLaunchedLocked();
} }
if (sr.app != null && !sr.app.persistent) { if (sr.app != app && sr.app != null && !sr.app.persistent) {
sr.app.services.remove(sr); sr.app.services.remove(sr);
} }
sr.app = null; sr.app = null;
@ -2067,13 +2067,19 @@ public final class ActiveServices {
// Now do remaining service cleanup. // Now do remaining service cleanup.
for (int i=app.services.size()-1; i>=0; i--) { for (int i=app.services.size()-1; i>=0; i--) {
ServiceRecord sr = app.services.valueAt(i); ServiceRecord sr = app.services.valueAt(i);
// Unless the process is persistent, this process record is going away,
// so make sure the service is cleaned out of it.
if (!app.persistent) {
app.services.removeAt(i);
}
// Sanity check: if the service listed for the app is not one // Sanity check: if the service listed for the app is not one
// we actually are maintaining, drop it. // we actually are maintaining, just let it drop.
if (smap.mServicesByName.get(sr.name) != sr) { if (smap.mServicesByName.get(sr.name) != sr) {
ServiceRecord cur = smap.mServicesByName.get(sr.name); ServiceRecord cur = smap.mServicesByName.get(sr.name);
Slog.wtf(TAG, "Service " + sr + " in process " + app Slog.wtf(TAG, "Service " + sr + " in process " + app
+ " not same as in map: " + cur); + " not same as in map: " + cur);
app.services.removeAt(i);
continue; continue;
} }