Merge "Fix a fun bug with multiple service bindings from an activity." into gingerbread

This commit is contained in:
Dianne Hackborn
2010-08-25 16:31:34 -07:00
committed by Android (Google) Code Review
2 changed files with 198 additions and 143 deletions

View File

@ -609,8 +609,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* All currently bound service connections. Keys are the IBinder of * All currently bound service connections. Keys are the IBinder of
* the client's IServiceConnection. * the client's IServiceConnection.
*/ */
final HashMap<IBinder, ConnectionRecord> mServiceConnections final HashMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections
= new HashMap<IBinder, ConnectionRecord>(); = new HashMap<IBinder, ArrayList<ConnectionRecord>>();
/** /**
* List of services that we have been asked to start, * List of services that we have been asked to start,
@ -7376,12 +7376,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mServiceConnections.size() > 0) { if (mServiceConnections.size() > 0) {
if (needSep) pw.println(" "); if (needSep) pw.println(" ");
pw.println(" Connection bindings to services:"); pw.println(" Connection bindings to services:");
Iterator<ConnectionRecord> it Iterator<ArrayList<ConnectionRecord>> it
= mServiceConnections.values().iterator(); = mServiceConnections.values().iterator();
while (it.hasNext()) { while (it.hasNext()) {
ConnectionRecord r = it.next(); ArrayList<ConnectionRecord> r = it.next();
pw.print(" * "); pw.println(r); for (int i=0; i<r.size(); i++) {
r.dump(pw, " "); pw.print(" * "); pw.println(r.get(i));
r.get(i).dump(pw, " ");
}
} }
needSep = true; needSep = true;
} }
@ -7659,18 +7661,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
while (it.hasNext()) { while (it.hasNext()) {
ServiceRecord r = it.next(); ServiceRecord r = it.next();
if (r.connections.size() > 0) { if (r.connections.size() > 0) {
Iterator<ConnectionRecord> jt Iterator<ArrayList<ConnectionRecord>> jt
= r.connections.values().iterator(); = r.connections.values().iterator();
while (jt.hasNext()) { while (jt.hasNext()) {
ConnectionRecord c = jt.next(); ArrayList<ConnectionRecord> cl = jt.next();
if (c.binding.client != app) { for (int i=0; i<cl.size(); i++) {
try { ConnectionRecord c = cl.get(i);
//c.conn.connected(r.className, null); if (c.binding.client != app) {
} catch (Exception e) { try {
// todo: this should be asynchronous! //c.conn.connected(r.className, null);
Slog.w(TAG, "Exception thrown disconnected servce " } catch (Exception e) {
+ r.shortName // todo: this should be asynchronous!
+ " from app " + app.processName, e); Slog.w(TAG, "Exception thrown disconnected servce "
+ r.shortName
+ " from app " + app.processName, e);
}
} }
} }
} }
@ -7700,7 +7705,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
sr.app = null; sr.app = null;
sr.executeNesting = 0; sr.executeNesting = 0;
mStoppingServices.remove(sr); if (mStoppingServices.remove(sr)) {
if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
}
boolean hasClients = sr.bindings.size() > 0; boolean hasClients = sr.bindings.size() > 0;
if (hasClients) { if (hasClients) {
@ -7753,6 +7760,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ServiceRecord sr = mStoppingServices.get(i); ServiceRecord sr = mStoppingServices.get(i);
if (sr.app == app) { if (sr.app == app) {
mStoppingServices.remove(i); mStoppingServices.remove(i);
if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
} }
} }
@ -8016,11 +8024,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.app != null && r.app.persistent) { if (r.app != null && r.app.persistent) {
info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS; info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
} }
for (ConnectionRecord conn : r.connections.values()) {
if (conn.clientLabel != 0) { for (ArrayList<ConnectionRecord> connl : r.connections.values()) {
info.clientPackage = conn.binding.client.info.packageName; for (int i=0; i<connl.size(); i++) {
info.clientLabel = conn.clientLabel; ConnectionRecord conn = connl.get(i);
break; if (conn.clientLabel != 0) {
info.clientPackage = conn.binding.client.info.packageName;
info.clientLabel = conn.clientLabel;
return info;
}
} }
} }
return info; return info;
@ -8055,9 +8067,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (this) { synchronized (this) {
ServiceRecord r = mServices.get(name); ServiceRecord r = mServices.get(name);
if (r != null) { if (r != null) {
for (ConnectionRecord conn : r.connections.values()) { for (ArrayList<ConnectionRecord> conn : r.connections.values()) {
if (conn.clientIntent != null) { for (int i=0; i<conn.size(); i++) {
return conn.clientIntent; if (conn.get(i).clientIntent != null) {
return conn.get(i).clientIntent;
}
} }
} }
} }
@ -8234,8 +8248,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
while (r.pendingStarts.size() > 0) { while (r.pendingStarts.size() > 0) {
try { try {
ServiceRecord.StartItem si = r.pendingStarts.remove(0); ServiceRecord.StartItem si = r.pendingStarts.remove(0);
if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to service: " if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to: "
+ r.name + " " + r.intent + " args=" + si.intent); + r + " " + r.intent + " args=" + si.intent);
if (si.intent == null) { if (si.intent == null) {
// If somehow we got a dummy start at the front, then // If somehow we got a dummy start at the front, then
// just drop it here. // just drop it here.
@ -8248,6 +8262,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid, grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid,
r.packageName, si.intent, si); r.packageName, si.intent, si);
} }
if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING start of " + r);
bumpServiceExecutingLocked(r); bumpServiceExecutingLocked(r);
if (!oomAdjusted) { if (!oomAdjusted) {
oomAdjusted = true; oomAdjusted = true;
@ -8264,6 +8279,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (RemoteException e) { } catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take // Remote process gone... we'll let the normal cleanup take
// care of this. // care of this.
if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while scheduling start: " + r);
break; break;
} catch (Exception e) { } catch (Exception e) {
Slog.w(TAG, "Unexpected exception", e); Slog.w(TAG, "Unexpected exception", e);
@ -8280,9 +8296,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
if ((!i.requested || rebind) && i.apps.size() > 0) { if ((!i.requested || rebind) && i.apps.size() > 0) {
try { try {
if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bind of " + r
+ " in " + i + ": shouldUnbind=" + i.hasBound);
bumpServiceExecutingLocked(r); bumpServiceExecutingLocked(r);
if (DEBUG_SERVICE) Slog.v(TAG, "Connecting binding " + i
+ ": shouldUnbind=" + i.hasBound);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind); r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
if (!rebind) { if (!rebind) {
i.requested = true; i.requested = true;
@ -8290,6 +8306,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
i.hasBound = true; i.hasBound = true;
i.doRebind = false; i.doRebind = false;
} catch (RemoteException e) { } catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);
return false; return false;
} }
} }
@ -8316,13 +8333,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
app.services.add(r); app.services.add(r);
if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING create of " + r + " " + r.intent);
bumpServiceExecutingLocked(r); bumpServiceExecutingLocked(r);
updateLruProcessLocked(app, true, true); updateLruProcessLocked(app, true, true);
boolean created = false; boolean created = false;
try { try {
if (DEBUG_SERVICE) Slog.v(TAG, "Scheduling start service: "
+ r.name + " " + r.intent);
mStringBuilder.setLength(0); mStringBuilder.setLength(0);
r.intent.getIntent().toShortString(mStringBuilder, false, true); r.intent.getIntent().toShortString(mStringBuilder, false, true);
EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE, EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
@ -8482,8 +8498,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return true; return true;
} }
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up service " + r.name if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
+ " " + r.intent);
// We are now bringing the service up, so no longer in the // We are now bringing the service up, so no longer in the
// restarting state. // restarting state.
@ -8534,27 +8549,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (!force) { if (!force) {
// XXX should probably keep a count of the number of auto-create // XXX should probably keep a count of the number of auto-create
// connections directly in the service. // connections directly in the service.
Iterator<ConnectionRecord> it = r.connections.values().iterator(); Iterator<ArrayList<ConnectionRecord>> it = r.connections.values().iterator();
while (it.hasNext()) { while (it.hasNext()) {
ConnectionRecord cr = it.next(); ArrayList<ConnectionRecord> cr = it.next();
if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) { for (int i=0; i<cr.size(); i++) {
return; if ((cr.get(i).flags&Context.BIND_AUTO_CREATE) != 0) {
return;
}
} }
} }
} }
// Report to all of the connections that the service is no longer // Report to all of the connections that the service is no longer
// available. // available.
Iterator<ConnectionRecord> it = r.connections.values().iterator(); Iterator<ArrayList<ConnectionRecord>> it = r.connections.values().iterator();
while (it.hasNext()) { while (it.hasNext()) {
ConnectionRecord c = it.next(); ArrayList<ConnectionRecord> c = it.next();
try { for (int i=0; i<c.size(); i++) {
// todo: shouldn't be a synchronous call! try {
c.conn.connected(r.name, null); c.get(i).conn.connected(r.name, null);
} catch (Exception e) { } catch (Exception e) {
Slog.w(TAG, "Failure disconnecting service " + r.name + Slog.w(TAG, "Failure disconnecting service " + r.name +
" to connection " + c.conn.asBinder() + " to connection " + c.get(i).conn.asBinder() +
" (in " + c.binding.client.processName + ")", e); " (in " + c.get(i).binding.client.processName + ")", e);
}
} }
} }
} }
@ -8568,6 +8586,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ ": hasBound=" + ibr.hasBound); + ": hasBound=" + ibr.hasBound);
if (r.app != null && r.app.thread != null && ibr.hasBound) { if (r.app != null && r.app.thread != null && ibr.hasBound) {
try { try {
if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bring down unbind of " + r
+ " for " + ibr);
bumpServiceExecutingLocked(r); bumpServiceExecutingLocked(r);
updateOomAdjLocked(r.app); updateOomAdjLocked(r.app);
ibr.hasBound = false; ibr.hasBound = false;
@ -8582,15 +8602,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
} }
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down service " + r.name if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent);
+ " " + r.intent);
EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE, EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
System.identityHashCode(r), r.shortName, System.identityHashCode(r), r.shortName,
(r.app != null) ? r.app.pid : -1); (r.app != null) ? r.app.pid : -1);
mServices.remove(r.name); mServices.remove(r.name);
mServicesByIntent.remove(r.intent); mServicesByIntent.remove(r.intent);
if (localLOGV) Slog.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
r.totalRestartCount = 0; r.totalRestartCount = 0;
unscheduleServiceRestartLocked(r); unscheduleServiceRestartLocked(r);
@ -8599,8 +8617,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {
if (mPendingServices.get(i) == r) { if (mPendingServices.get(i) == r) {
mPendingServices.remove(i); mPendingServices.remove(i);
if (DEBUG_SERVICE) Slog.v( if (DEBUG_SERVICE) Slog.v(TAG, "Removed pending: " + r);
TAG, "Removed pending service: " + r.shortName);
i--; i--;
N--; N--;
} }
@ -8622,8 +8639,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app.services.remove(r); r.app.services.remove(r);
if (r.app.thread != null) { if (r.app.thread != null) {
try { try {
if (DEBUG_SERVICE) Slog.v(TAG, if (DEBUG_SERVICE) {
"Stopping service: " + r.shortName); RuntimeException here = new RuntimeException();
here.fillInStackTrace();
Slog.v(TAG, ">>> EXECUTING stop of " + r, here);
}
bumpServiceExecutingLocked(r); bumpServiceExecutingLocked(r);
mStoppingServices.add(r); mStoppingServices.add(r);
updateOomAdjLocked(r.app); updateOomAdjLocked(r.app);
@ -8636,11 +8656,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
updateServiceForegroundLocked(r.app, false); updateServiceForegroundLocked(r.app, false);
} else { } else {
if (DEBUG_SERVICE) Slog.v( if (DEBUG_SERVICE) Slog.v(
TAG, "Removed service that has no process: " + r.shortName); TAG, "Removed service that has no process: " + r);
} }
} else { } else {
if (DEBUG_SERVICE) Slog.v( if (DEBUG_SERVICE) Slog.v(
TAG, "Removed service that is not running: " + r.shortName); TAG, "Removed service that is not running: " + r);
} }
} }
@ -8675,8 +8695,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int targetPermissionUid = checkGrantUriPermissionFromIntentLocked( int targetPermissionUid = checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service); callingUid, r.packageName, service);
if (unscheduleServiceRestartLocked(r)) { if (unscheduleServiceRestartLocked(r)) {
if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
+ r.shortName);
} }
r.startRequested = true; r.startRequested = true;
r.callStart = false; r.callStart = false;
@ -8970,7 +8989,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (unscheduleServiceRestartLocked(s)) { if (unscheduleServiceRestartLocked(s)) {
if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: " if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+ s.shortName); + s);
} }
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
@ -8978,7 +8997,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
connection, flags, clientLabel, clientIntent); connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder(); IBinder binder = connection.asBinder();
s.connections.put(binder, c); ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c); b.connections.add(c);
if (activity != null) { if (activity != null) {
if (activity.connections == null) { if (activity.connections == null) {
@ -8987,7 +9011,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
activity.connections.add(c); activity.connections.add(c);
} }
b.client.connections.add(c); b.client.connections.add(c);
mServiceConnections.put(binder, c); clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) { if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis(); s.lastActivity = SystemClock.uptimeMillis();
@ -9038,7 +9067,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
IBinder binder = c.conn.asBinder(); IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding; AppBindRecord b = c.binding;
ServiceRecord s = b.service; ServiceRecord s = b.service;
s.connections.remove(binder); ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
s.connections.remove(binder);
}
}
b.connections.remove(c); b.connections.remove(c);
if (c.activity != null && c.activity != skipAct) { if (c.activity != null && c.activity != skipAct) {
if (c.activity.connections != null) { if (c.activity.connections != null) {
@ -9048,7 +9083,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (b.client != skipApp) { if (b.client != skipApp) {
b.client.connections.remove(c); b.client.connections.remove(c);
} }
mServiceConnections.remove(binder); clist = mServiceConnections.get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
mServiceConnections.remove(binder);
}
}
if (b.connections.size() == 0) { if (b.connections.size() == 0) {
b.intent.apps.remove(b.client); b.intent.apps.remove(b.client);
@ -9059,6 +9100,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) { && b.intent.hasBound) {
try { try {
if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING unbind of " + s
+ " from " + b);
bumpServiceExecutingLocked(s); bumpServiceExecutingLocked(s);
updateOomAdjLocked(s.app); updateOomAdjLocked(s.app);
b.intent.hasBound = false; b.intent.hasBound = false;
@ -9081,8 +9124,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (this) { synchronized (this) {
IBinder binder = connection.asBinder(); IBinder binder = connection.asBinder();
if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder); if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder);
ConnectionRecord r = mServiceConnections.get(binder); ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (r == null) { if (clist == null) {
Slog.w(TAG, "Unbind failed: could not find connection for " Slog.w(TAG, "Unbind failed: could not find connection for "
+ connection.asBinder()); + connection.asBinder());
return false; return false;
@ -9090,11 +9133,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final long origId = Binder.clearCallingIdentity(); final long origId = Binder.clearCallingIdentity();
removeConnectionLocked(r, null, null); while (clist.size() > 0) {
ConnectionRecord r = clist.get(0);
removeConnectionLocked(r, null, null);
if (r.binding.service.app != null) { if (r.binding.service.app != null) {
// This could have made the service less important. // This could have made the service less important.
updateOomAdjLocked(r.binding.service.app); updateOomAdjLocked(r.binding.service.app);
}
} }
Binder.restoreCallingIdentity(origId); Binder.restoreCallingIdentity(origId);
@ -9117,7 +9163,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final long origId = Binder.clearCallingIdentity(); final long origId = Binder.clearCallingIdentity();
if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING SERVICE " + r.name if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING " + r
+ " " + intent + ": " + service); + " " + intent + ": " + service);
if (r != null) { if (r != null) {
Intent.FilterComparison filter Intent.FilterComparison filter
@ -9128,26 +9174,29 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
b.requested = true; b.requested = true;
b.received = true; b.received = true;
if (r.connections.size() > 0) { if (r.connections.size() > 0) {
Iterator<ConnectionRecord> it Iterator<ArrayList<ConnectionRecord>> it
= r.connections.values().iterator(); = r.connections.values().iterator();
while (it.hasNext()) { while (it.hasNext()) {
ConnectionRecord c = it.next(); ArrayList<ConnectionRecord> clist = it.next();
if (!filter.equals(c.binding.intent.intent)) { for (int i=0; i<clist.size(); i++) {
if (DEBUG_SERVICE) Slog.v( ConnectionRecord c = clist.get(i);
TAG, "Not publishing to: " + c); if (!filter.equals(c.binding.intent.intent)) {
if (DEBUG_SERVICE) Slog.v( if (DEBUG_SERVICE) Slog.v(
TAG, "Bound intent: " + c.binding.intent.intent); TAG, "Not publishing to: " + c);
if (DEBUG_SERVICE) Slog.v( if (DEBUG_SERVICE) Slog.v(
TAG, "Published intent: " + intent); TAG, "Bound intent: " + c.binding.intent.intent);
continue; if (DEBUG_SERVICE) Slog.v(
} TAG, "Published intent: " + intent);
if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c); continue;
try { }
c.conn.connected(r.name, service); if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
} catch (Exception e) { try {
Slog.w(TAG, "Failure sending service " + r.name + c.conn.connected(r.name, service);
" to connection " + c.conn.asBinder() + } catch (Exception e) {
" (in " + c.binding.client.processName + ")", e); Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e);
}
} }
} }
} }
@ -9208,9 +9257,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ServiceRecord r = (ServiceRecord)token; ServiceRecord r = (ServiceRecord)token;
boolean inStopping = mStoppingServices.contains(token); boolean inStopping = mStoppingServices.contains(token);
if (r != null) { if (r != null) {
if (DEBUG_SERVICE) Slog.v(TAG, "DONE EXECUTING SERVICE " + r.name
+ ": nesting=" + r.executeNesting
+ ", inStopping=" + inStopping);
if (r != token) { if (r != token) {
Slog.w(TAG, "Done executing service " + r.name Slog.w(TAG, "Done executing service " + r.name
+ " with incorrect token: given " + token + " with incorrect token: given " + token
@ -9267,13 +9313,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
serviceDoneExecutingLocked(r, inStopping); serviceDoneExecutingLocked(r, inStopping);
Binder.restoreCallingIdentity(origId); Binder.restoreCallingIdentity(origId);
} else { } else {
Slog.w(TAG, "Done executing unknown service " + r.name Slog.w(TAG, "Done executing unknown service from pid "
+ " with token " + token); + Binder.getCallingPid());
} }
} }
} }
public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) { public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
+ ": nesting=" + r.executeNesting
+ ", inStopping=" + inStopping + ", app=" + r.app);
r.executeNesting--; r.executeNesting--;
if (r.executeNesting <= 0 && r.app != null) { if (r.executeNesting <= 0 && r.app != null) {
r.app.executingServices.remove(r); r.app.executingServices.remove(r);
@ -9281,6 +9330,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app); mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
} }
if (inStopping) { if (inStopping) {
if (DEBUG_SERVICE) Slog.v(TAG, "doneExecuting remove stopping " + r);
mStoppingServices.remove(r); mStoppingServices.remove(r);
} }
updateOomAdjLocked(r.app); updateOomAdjLocked(r.app);
@ -11071,61 +11121,64 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) { || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
Iterator<ConnectionRecord> kt Iterator<ArrayList<ConnectionRecord>> kt
= s.connections.values().iterator(); = s.connections.values().iterator();
while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) { while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
// XXX should compute this based on the max of ArrayList<ConnectionRecord> clist = kt.next();
// all connected clients. for (int i=0; i<clist.size() && adj > FOREGROUND_APP_ADJ; i++) {
ConnectionRecord cr = kt.next(); // XXX should compute this based on the max of
if (cr.binding.client == app) { // all connected clients.
// Binding to ourself is not interesting. ConnectionRecord cr = clist.get(i);
continue; if (cr.binding.client == app) {
} // Binding to ourself is not interesting.
if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) { continue;
ProcessRecord client = cr.binding.client; }
int myHiddenAdj = hiddenAdj; if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
if (myHiddenAdj > client.hiddenAdj) { ProcessRecord client = cr.binding.client;
if (client.hiddenAdj >= VISIBLE_APP_ADJ) { int myHiddenAdj = hiddenAdj;
myHiddenAdj = client.hiddenAdj; if (myHiddenAdj > client.hiddenAdj) {
} else { if (client.hiddenAdj >= VISIBLE_APP_ADJ) {
myHiddenAdj = VISIBLE_APP_ADJ; myHiddenAdj = client.hiddenAdj;
} else {
myHiddenAdj = VISIBLE_APP_ADJ;
}
}
int clientAdj = computeOomAdjLocked(
client, myHiddenAdj, TOP_APP, true);
if (adj > clientAdj) {
adj = clientAdj >= VISIBLE_APP_ADJ
? clientAdj : VISIBLE_APP_ADJ;
if (!client.hidden) {
app.hidden = false;
}
app.adjType = "service";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE;
app.adjSource = cr.binding.client;
app.adjTarget = s.name;
}
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
schedGroup = Process.THREAD_GROUP_DEFAULT;
}
} }
} }
int clientAdj = computeOomAdjLocked( ActivityRecord a = cr.activity;
client, myHiddenAdj, TOP_APP, true); //if (a != null) {
if (adj > clientAdj) { // Slog.i(TAG, "Connection to " + a ": state=" + a.state);
adj = clientAdj >= VISIBLE_APP_ADJ //}
? clientAdj : VISIBLE_APP_ADJ; if (a != null && adj > FOREGROUND_APP_ADJ &&
if (!client.hidden) { (a.state == ActivityState.RESUMED
app.hidden = false; || a.state == ActivityState.PAUSING)) {
} adj = FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.hidden = false;
app.adjType = "service"; app.adjType = "service";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE; .REASON_SERVICE_IN_USE;
app.adjSource = cr.binding.client; app.adjSource = a;
app.adjTarget = s.name; app.adjTarget = s.name;
} }
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
schedGroup = Process.THREAD_GROUP_DEFAULT;
}
}
}
ActivityRecord a = cr.activity;
//if (a != null) {
// Slog.i(TAG, "Connection to " + a ": state=" + a.state);
//}
if (a != null && adj > FOREGROUND_APP_ADJ &&
(a.state == ActivityState.RESUMED
|| a.state == ActivityState.PAUSING)) {
adj = FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.hidden = false;
app.adjType = "service";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE;
app.adjSource = a;
app.adjTarget = s.name;
} }
} }
} }

View File

@ -72,8 +72,8 @@ class ServiceRecord extends Binder {
final HashMap<Intent.FilterComparison, IntentBindRecord> bindings final HashMap<Intent.FilterComparison, IntentBindRecord> bindings
= new HashMap<Intent.FilterComparison, IntentBindRecord>(); = new HashMap<Intent.FilterComparison, IntentBindRecord>();
// All active bindings to the service. // All active bindings to the service.
final HashMap<IBinder, ConnectionRecord> connections final HashMap<IBinder, ArrayList<ConnectionRecord>> connections
= new HashMap<IBinder, ConnectionRecord>(); = new HashMap<IBinder, ArrayList<ConnectionRecord>>();
// IBinder -> ConnectionRecord of all bound clients // IBinder -> ConnectionRecord of all bound clients
ProcessRecord app; // where this service is running or null. ProcessRecord app; // where this service is running or null.
@ -296,10 +296,12 @@ class ServiceRecord extends Binder {
} }
if (connections.size() > 0) { if (connections.size() > 0) {
pw.print(prefix); pw.println("All Connections:"); pw.print(prefix); pw.println("All Connections:");
Iterator<ConnectionRecord> it = connections.values().iterator(); Iterator<ArrayList<ConnectionRecord>> it = connections.values().iterator();
while (it.hasNext()) { while (it.hasNext()) {
ConnectionRecord c = it.next(); ArrayList<ConnectionRecord> c = it.next();
pw.print(prefix); pw.print(" "); pw.println(c); for (int i=0; i<c.size(); i++) {
pw.print(prefix); pw.print(" "); pw.println(c.get(i));
}
} }
} }
} }