场景一: Activity调用bindService后,不调用unbindService,直接调用finish销毁Activity,看下会对Service有什么影响?
1 ActivityThread#handleDestroyActivity
从ActivityThread#H对DESTROY_ACTIVITY消息处理开始看起。
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case DESTROY_ACTIVITY:
handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0, msg.arg2, false);
break;
...
}
}
}
private void handleDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) {
ActivityClientRecord r = performDestroyActivity(token, finishing,
configChanges, getNonConfigInstance);
if (r != null) {
//处理Window相关
...
// getBaseContext()返回的context在启动Activity中被赋值为ContextImpl的一个实例。
// 具体见Activity#performLaunchActivity
Context c = r.activity.getBaseContext();
if (c instanceof ContextImpl) {
((ContextImpl) c).scheduleFinalCleanup(
r.activity.getClass().getName(), "Activity");
}
}
...
}
ContextImpl#scheduleFinalCleanup
final void scheduleFinalCleanup(String who, String what) {
mMainThread.scheduleContextCleanup(this, who, what);
}
final void scheduleContextCleanup(ContextImpl context, String who,
String what) {
ContextCleanupInfo cci = new ContextCleanupInfo();
cci.context = context;
cci.who = who;
cci.what = what;
sendMessage(H.CLEAN_UP_CONTEXT, cci);
}
case CLEAN_UP_CONTEXT:
ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
cci.context.performFinalCleanup(cci.who, cci.what);
break;
final void performFinalCleanup(String who, String what) {
//Log.i(TAG, "Cleanup up context: " + this);
mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
}
可以看到handleDestroyActivity主要调了ContextImpl#scheduleFinalCleanup,之后在ContextImpl、ActivityThread间相互调用,最后进入LoadedApk
2 LoadedApk#removeContextRegistrations
public void removeContextRegistrations(Context context,
String who, String what) {
final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
synchronized (mReceivers) {
// 注销未及时注销的广播
...
}
//断开已经建立的连接
synchronized (mServices) {
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
mServices.remove(context);
if (smap != null) {
for (int i = 0; i < smap.size(); i++) {
LoadedApk.ServiceDispatcher sd = smap.valueAt(i);
...
try {
ActivityManagerNative.getDefault().unbindService(
sd.getIServiceConnection());
} catch (RemoteException e) {
// system crashed, nothing we can do
}
sd.doForget();
}
}
mUnboundServices.remove(context);
}
}
系统对在当前Activity注册的Broadcast和Service都做相应的处理,这里只看Service的部分。AMN调用AMS,AMS再到ActiveService的unBinderServiceLocked
3 AMS#unbindService
public boolean unbindService(IServiceConnection connection) {
synchronized (this) {
return mServices.unbindServiceLocked(connection);
}
}
4 ActivieServices#unbindServiceLocked
boolean unbindServiceLocked(IServiceConnection connection) {
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {// 没有连接建立
Slog.w(TAG, "Unbind failed: could not find connection for "
+ connection.asBinder());
return false;
}
final long origId = Binder.clearCallingIdentity();
try {
while (clist.size() > 0) {//遍历连接集合
ConnectionRecord r = clist.get(0);
removeConnectionLocked(r, null, null); //依次做连接移除操作
if (clist.size() > 0 && clist.get(0) == r) {
// In case it didn't get removed above, do it now.
Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
clist.remove(0);
}
...
}
} finally {
Binder.restoreCallingIdentity(origId);
}
return true;
}
ActivieServices#removeConnectionLocked
void removeConnectionLocked(
ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding;
ServiceRecord s = b.service;
//------------集合移除连接记录----------
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);
if (c.activity != null && c.activity != skipAct) {
if (c.activity.connections != null) {
c.activity.connections.remove(c);
}
}
if (b.client != skipApp) {
b.client.connections.remove(c);
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
b.client.updateHasAboveClientLocked();
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
}
clist = mServiceConnections.get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
mServiceConnections.remove(binder);
}
}
mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);
if (b.connections.size() == 0) {// 当前APP所在进程已经与Service没有连接
b.intent.apps.remove(b.client);
}
if (!c.serviceDead) {
if (s.app != null && s.app.thread != null // Service正在运行中
&& b.intent.apps.size() == 0 //没有进程与当前Service连接
&& b.intent.hasBound) { //hasBound?
try {
...
b.intent.hasBound = false;
s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
} catch (Exception e) {
Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
serviceProcessGoneLocked(s);
}
}
if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
boolean hasAutoCreate = s.hasAutoCreateConnections();
...
//如果必要,销毁Service
bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
}
}
}
注意下调用scheduleUnbindService的前提条件:
if (s.app != null && s.app.thread != null // Service正在运行中
&& b.intent.apps.size() == 0 //没有进程与当前Service存在绑定关系
&& b.intent.hasBound)
也就是说,如果Activity销毁时,Service还有其他活跃连接,那么不会调用Service的onUnbind、onDestroy回调。
4.1 scheduleUnbindService
public final void scheduleUnbindService(IBinder token, Intent intent) {
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
sendMessage(H.UNBIND_SERVICE, s);
}
private void handleUnbindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
boolean doRebind = s.onUnbind(data.intent);// 调用Service onUnbind方法
try {
if (doRebind) {
ActivityManagerNative.getDefault().unbindFinished(
data.token, data.intent, doRebind);
} else {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
}
} catch (Exception e) {
...
}
}
}
handleUnbindService调用Service onUnbind回调。注意Service#onUnbind方法返回一个boolean结果doRebind,字面意思就知道该变量控制是否重新绑定Service。
4.2 bringDownServiceIfNeededLocked
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
boolean hasConn) {
if (isServiceNeeded(r, knowConn, hasConn)) {
return;
}
// Are we in the process of launching?
if (mPendingServices.contains(r)) {
return;
}
bringDownServiceLocked(r);
}
这里主要看下isServiceNeeded方法,其中ServiceRecord的startRequested字段在启动Service时被赋值为true,此时值为true。而在以下方法中ServiceRecord的startRequested字段会被赋值为false。
killServicesLocked
stopServiceLocked
stopServiceTokenLocked
也就是说当Service不再被需要时,就会执行bringDownServiceLocked的逻辑
private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) {
// Are we still explicitly being asked to run?
if (r.startRequested) { // true
return true;
}
// Is someone still bound to us keepign us running?
if (!knowConn) {
hasConn = r.hasAutoCreateConnections();
}
if (hasConn) {
return true;
}
return false;
}
看下bringDownServiceLocked的逻辑,
private final void bringDownServiceLocked(ServiceRecord r) {
for (int conni=r.connections.size()-1; conni>=0; conni--) { // 遍历与当前Service建立的所有连接
ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
for (int i=0; i<c.size(); i++) {
ConnectionRecord cr = c.get(i);
cr.serviceDead = true; // 标识当前连接的服务已死
try {
cr.conn.connected(r.name, null); // 继续回调IServiceConnection connected
} catch (Exception e) {
...
}
}
}
// Tell the service that it has been unbound.
//note (r.app != null && r.app.thread != null) 这个条件判断表明Service正在正常运行中。相当于Service被动告知要停止运行
if (r.app != null && r.app.thread != null) {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (ibr.hasBound) {//如果hasBound为true就先执行scheduleUnbindService。如果已经执行过scheduleUnbindService,hasBound已被置为false
try {
...
ibr.hasBound = false;
//执行unbind操作
r.app.thread.scheduleUnbindService(r,
ibr.intent.getIntent());
} catch (Exception e) {
...
}
}
}
}
r.destroyTime = SystemClock.uptimeMillis();
final ServiceMap smap = getServiceMap(r.userId);
smap.mServicesByName.remove(r.name);
smap.mServicesByIntent.remove(r.intent);
r.totalRestartCount = 0;
unscheduleServiceRestartLocked(r, 0, true);// 不重新启动Service
// Also make sure it is not on the pending list.
for (int i=mPendingServices.size()-1; i>=0; i--) {// 如果Service已经加入待启动集合,也一并移除
if (mPendingServices.get(i) == r) {
mPendingServices.remove(i);
}
}
//重置ServiceRecord中的一些变量
r.cancelNotification();
r.isForeground = false;
r.foregroundId = 0;
r.foregroundNoti = null;
// Clear start entries.
r.clearDeliveredStartsLocked();
r.pendingStarts.clear();
if (r.app != null) {
synchronized (r.stats.getBatteryStats()) {
r.stats.stopLaunchedLocked();
}
r.app.services.remove(r);
if (r.app.thread != null) {
updateServiceForegroundLocked(r.app, false);
try {
bumpServiceExecutingLocked(r, false, "destroy");
mDestroyingServices.add(r);
r.destroying = true;
mAm.updateOomAdjLocked(r.app);
r.app.thread.scheduleStopService(r);// stop正常运行中的Service
} catch (Exception e) {
Slog.w(TAG, "Exception when destroying service "
+ r.shortName, e);
serviceProcessGoneLocked(r);
}
} else {
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Removed service that has no process: " + r);
}
} else {
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Removed service that is not running: " + r);
}
if (r.bindings.size() > 0) {
r.bindings.clear();
}
//确保当前Service不会在后台启动
smap.ensureNotStartingBackground(r);
}
也就是当Service不再被需要时,则所有的连接需要断开,Service调用onUnbind、onDestroy被销毁。汇总下bringDownServiceLocked的逻辑。
- 首先遍历当前Service已经建立的连接,依次调用IServiceConnection#connected方法,具体逻辑见4.2.1
- 判断当前Service正在正常运行中,(满足intentBindRecord.hasBound == true),调用Service scheduleUnbindService,具体逻辑见4.1
- 处理Service可能存在的重启、待启动后,执行scheduleStopService,具体逻辑见4.2.2
4.2.1
接着看IServiceConnection接口在LoadedApk#ServiceDispatcher相应的实现,
public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service); //注意此时service是null
}
}
最终调用到ServieDispatcher#doConnected,bindService调用链也调到这里,所以这个方法是bind、unbind共用,看下unbind时的逻辑
// 注意,service传入null
public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
...
//bind过程已经加入该集合,所以此时old不为null
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {//service为null, 不会进入if块
return;
}
if (service != null) {//service == null
...
} else {
// The named service is being disconnected... clean up.
mActiveConnections.remove(name); //移除<name, connectionInfo>
}
if (old != null) {// Service已死, 所以Client清除Service死亡通知
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
// If there was an old service, it is not disconnected.
if (old != null) {// 此时old != null
mConnection.onServiceDisconnected(name); //调用ServiceConnection#onServiceDisconnected回调
}
// If there is a new service, it is now connected.
if (service != null) {
...
}
}
4.2.2 scheduleStopService
scheduleStopService发送STOP_SERVICE消息
case STOP_SERVICE:
handleStopService((IBinder)msg.obj);
maybeSnapshot();
break;
private void handleStopService(IBinder token) {
Service s = mServices.remove(token);
if (s != null) {
try {
s.onDestroy(); //调用Service的onDestroy方法
Context context = s.getBaseContext();
if (context instanceof ContextImpl) {// 执行当前Service绑定的其他Service的清理工作
final String who = s.getClassName();
((ContextImpl) context).scheduleFinalCleanup(who, "Service");
}
QueuedWork.waitToFinish();
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
} catch (Exception e) {
...
}
} else {
Slog.i(TAG, "handleStopService: token=" + token + " not found.");
}
//Slog.i(TAG, "Running services: " + mServices);
}
该方法首先执行Service的onDestroy方法。然后继续调用ContextImpl#scheduleFinalCleanup执行当前Service绑定的其他Service的清理工作。这里可能有疑惑,为啥又调一次scheduleFinalCleanup? 文章开头调用是Activity的销毁引发的已绑定Service的清理工作。这里要做一个区分。
场景二、 bindService之后调用unbindService
unbindService的调用链和场景一的大部分场景比较重合,简单列下代码
public void unbindService(ServiceConnection conn) {
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
getOuterContext(), conn);
try {
ActivityManagerNative.getDefault().unbindService(sd);
} catch (RemoteException e) {
}
} else {
throw new RuntimeException("Not supported in system context");
}
}
public boolean unbindService(IServiceConnection connection) {
synchronized (this) {
return mServices.unbindServiceLocked(connection);
}
}
mServices.unbindServiceLocked及往下参照上面第4点即可