前言
绑定过程与启动过程类似,也是分成两个部分:既ContextImpl到AMS调用过程和Service的绑定过程
ContextImpl到AMS调用过程
这个过程如图:
入口是bindService方法,经历ContextWrapper和ContextImpl,最终会执行ContextImpl的bindServiceCommon,代码如下:
private boolean bindServiceCommon(...) {
...
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);//1
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
...
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier()); //2
...
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
代码1将ServiceConnection封装成IServiceConnection对象,这个IServiceConnection实现了Binder机制,这样Service的绑定就可以跨进程。
代码2调用了AMS的bindService方法,这样就进入了AMS进程。
Service绑定过程
AMS的bindService方法会调用ActiveServcie的bindServiceLocked,这块需要重点说一下,代码如下:
int bindServiceLocked(...) throws TransactionTooLargeException {
...
try {
...
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); //1
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent,
callerApp.uid, callerApp.processName, callingPackage);
IBinder binder = connection.asBinder();
...
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
...
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) { //2
return 0;
}
}
...
if (s.app != null && b.intent.received) { //3
try {
c.conn.connected(s.name, b.intent.binder, false); //4
} catch (Exception e) {
...
}
if (b.intent.apps.size() == 1 && b.intent.doRebind) { //5
requestServiceBindingLocked(s, b.intent, callerFg, true); //6
}
} else if (!b.intent.requested) { //7
requestServiceBindingLocked(s, b.intent, callerFg, false); //8
}
}
...
return 1;
}
这里先介绍几个与Service相关的对象类型:
- ServiceRecord:这个很熟悉了,描述一个Service
- IntentBindRecord:用于描述绑定Service的Intent
- AppBindRecord:维护Service与应用程序进程之间的关联,内部记录了绑定Service的Intent和所有绑定通信记录的信息
- ConnectRecord:用于描述应用程序进程和Service建立的一次通信
这么说大家可能还不是很清楚,下面通过它们的关系来更全面了解一下:
- ServiceRecord中有一个IntentBindRecord列表,Service可以通过不同的Intent进行绑,每一种都会有一个IntentBindRecord
- IntentBindRecord维护了一个<ProcessRecord,AppBindRecord>的map,会有不同的应用绑定Servcie,这样每个应用程序进程都会对应一个AppBindRecord
- AppBindRecord中维护了一个ConnectRecord列表,在这个应用程序进程中每次与Service连接都会生成一个记录
通过上面的解释,大家就应该清楚这几个对象的作用了,也解释了一个Service为什么可以被多次绑定。
下面回到bindServiceLocked代码中。代码1通过ServiceRecord的retrieveAppBindingLocked创建IntentBindRecord和AppBindRecord并返回AppBindRecord;代码2出调用了bringUpServiceLocked,这个在上一篇Servcie启动流程详细讲解了,这一步启动了Servcie,这里就不细说了
代码3中s.app != null
表示Service已经启动,而b.intent.received
则表示当前应用程序进程已经绑定Service并返回了Binder,这样我们就可以直接通过Binder来与Servcie通信;所以接下来代码4中调用ServcieDespatcher.InnerConnection的connect方法,在这个方法中会通过Handler向主线程发送消息。
代码5表示当前应用程序进程已经解绑了,则需要执行代码6的requestServiceBindingLocked重新绑定
代码7则是如果未绑定过,则执行代码8调用requestServiceBindingLocked进行绑定。
所以执行绑定的都是requestServiceBindingLocked方法,只不过它的最后一个参数是boolean值,用来表示是否时重新绑定。
在requestServiceBindingLocked中最终会执行IApplicationThread的scheduleBindService方法,这块大家应该非常熟悉了,不论是Activity启动、Servcie启动还是Service绑定都会进入IApplicationThread的对应方法,然后再扔给ActivityThread的对应方法来处理,最终都是通过Handler消息进行分发处理,这样就进入了应用程序进程中了。
在这个流程里,最终是在ActivityThread的handlerBindeServcie方法中来处理的,代码如下:
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token); //1
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) { //2
IBinder binder = s.onBind(data.intent); //3
ActivityManager.getService().publishService(
data.token, data.intent, binder); //4
} else {
s.onRebind(data.intent); //5
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
...
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
...
}
}
}
代码1处获取要绑定的Servcie,在上一篇文章Servcie的启动过程中我们知道在创建Servcie后会将它加入mServices,这一步正是从这里获取的,因为到这一步之前我们分析过,如果Service没启动一定会先启动。
然后代码2判断是否是重新绑定,如果不是则执行代码3调用Servcie的onBind方法绑定,并执行代码4调用AMS的publishService方法;如果是则执行代码5调用Servcie的onRebind。
因为这部分流程比较复杂,所以先来看看前面这部分的大致流程:
继续上面的步骤,在AMS的publishService方法中会调用ActiveServices的publishServcieLocked方法,在这个方法中会执行ServcieDespatcher.InnerConnection的connect方法,是不是很熟悉?
在上面的一开始的bindServiceLocked方法中也有这样一段代码,当时是如果Servcie已经启动并且绑定会进行连接,如果不是则会进入绑定流程。而现在绑定结束了,所以还需要进行一次连接,所以两部分代码目的是一样的。
connect代码非常简单:
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
通过mActivityThread.post在主线程中执行RunConnection,而在RunConnection中最终也是执行doConnected方法,代码如下:
public void doConnected(ComponentName name, IBinder service, boolean dead) {
...
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
if (service != null) {
mConnection.onServiceConnected(name, service); //1
} else
mConnection.onNullBinding(name);
}
}
可以看到执行了ServiceConnection的onServiceConnected方法,这样在客户端实现了ServiceConnection接口的类的onServiceConnected就会被调用。到这整个Service绑定流程才算真正的完成。后面这部分流程如下:
总结
通过两篇文章,我们弄清楚了Servcie的启动流程和绑定流程,可以看到启动流程相对简单一些,但是总体的过程都是差不多的,经过AMS再到应用程序进程中处理。