bindService 调用流程
API 28
一、bindService() 调用流程时序图
二、bindService() 调用流程文字描述
多次编写,欢迎交流,如有错误,感谢指正
ContextImpl#bindService(Intent service, ServiceConnection conn, int flags) ->
ContextImpl#bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) ->
// mPackageInfo 类型为 LoadedApk
// getServiceDispatcher() 方法调用了 LoadedApk#ServiceDispatcher#getServiceDispatcher(),最终返回 LoadedApk#ServiceDispatcher#InnerConnection
// sd:LoadedApk#ServiceDispatcher#InnerConnection,InnerConnection 是 ServiceDispatcher.Stub 的子类(Binder 类型对象),因此 sd 对象可以跨进程传递
// InnerConnection extends IServiceConnection.Stub
IServiceConnection sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
// ########################### 从客户端进程转到 AMS 所在进程 ###########################
// 需要注意的是,当前在客户端进程,sd(ServiceDispatcher.Stub 的子类)这个 Binder 对象跨进程传递到 AMS 所在进程后,AMS 收到的是 BinderProxy 对象
ActivityManager.getService().bindService(..., sd, flags, ...) ->
// 参数 connection 就是上面的 sd
// sd:LoadedApk#ServiceDispatcher#InnerConnection,InnerConnection 是 ServiceDispatcher.Stub 的子类(Binder 类型对象)
ActiveServices#bindServiceLocked(..., final IServiceConnection connection, int flags, ...) ->
ServiceLookupResult res = retrieveServiceLocked(...) ->
// 有个 ServiceMap 内部类,用于绑定用户和其对应的 Service
ServiceMap smap = getServiceMapLocked(userId);
// comp 默认不为空
final ComponentName comp = service.getComponent();
从 smap 中获取 ServiceRecord 对象:
a 若存在,则取出
b 若不存在,则创建 ServiceRecord 对象
作为参数构造 ServiceLookupResult 对象实例后返回
ServiceRecord s = res.record;
// 往 ServiceRecord#bindings 添加键值对(ServiceRecord#bindings 默认为空,具体添加的什么不用关心,重要的是下面 requestServiceBindingsLocked() 方法中会用到)
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
// 当前在 AMS 所在进程
// 把 connection 赋给 ConnectionRecord#conn(下面 publishServiceLocked() 方法中会用到)
// connection 是 LoadedApk#ServiceDispatcher#InnerConnection
// InnerConnection 是 ServiceDispatcher.Stub 的子类(Binder 类型对象)
ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
// 给 ServiceRecord#connections 添加键值对(具体添加的什么不用关心,重要的是下面 publishServiceLocked() 方法中会用到)
// s 类型为 ServiceRecord
s.connections.put(binder, clist);
}
// 如果 ContextImpl#bindService() 第三个参数 flags 带有 BIND_AUTO_CREATE,则调用 bringUpServiceLocked()
bringUpServiceLocked() ->
// 如果没有调用 realStartServiceLocked(),则跳过当前 if
// r.app:默认为 null,在下面 realStartServiceLocked() 方法中被赋值
// 如果调用了 realStartServiceLocked()
// Service 所在进程启动完成,且应用进程也向 AMS 报告过了(AMS 持有 IApplicationThread 应用端 Binder 句柄)
if (r.app != null && r.app.thread != null) {
// bindService() 不用关注这个方法,该方法内部是 startService() 相关的逻辑(内部调用 Service#onStartCommand() 方法)
sendServiceArgsLocked(r, execInFg, false);
return null;
}
// 如果 Service 所在进程不存在,则跳过当前 if
// 如果 Service 所在进程存在
// Service 所在进程启动完成,且应用进程也向 AMS 报告过了(AMS 持有 IApplicationThread 应用端 Binder 句柄),接下来反射创建 Service
if (app != null && app.thread != null) {
realStartServiceLocked() ->
ActivityThread#ApplicationThread#scheduleCreateService()
// 从 AMS 所在进程转到客户端进程
ActivityThread#handleCreateService() ->
// 获取 LoadedApk 实例
LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
// instantiateService() 方法反射创建 Service 实例
service = packageInfo.getAppFactory().instantiateService(cl, data.info.name, data.intent); // 创建 Service
// 创建 ContextImpl 实例
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
// 将创建的 Service 设置为 ContextImpl 的 mOuterContext
context.setOuterContext(service);
// 创建 Application(有就不创建,没有就创建)
packageInfo.makeApplication(false, mInstrumentation);
// 给 Service 设置上下文
service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService());
// 调用 Service#onCreate()
service.onCreate();
// 当前在 AMS 所在进程
// 内部 for 循环遍历 ServiceRecord#bindings,调用 requestServiceBindingLocked()
requestServiceBindingsLocked() ->
requestServiceBindingLocked() ->
// 准备发布 Service
// ########################### 从 AMS 所在进程转到客户端进程 ###########################
ActivityThread#ApplicationThread#scheduleBindService()
ActivityThread#handleBindService()
// 调用 Service#onBind(),一般返回的是 AIDL 的 Stub 的实现类
IBinder binder = s.onBind(data.intent);
// ########################### 从客户端进程转到 AMS 所在进程 ###########################
// 客户端调用 AMS#publishService() 方法发布服务(这是一个跨进程调用)
// 应用端发布的服务是 AIDL 的 Stub 的实现类,类型为 Binder
// AMS 端收到的是服务对应的 BinderProxy 对象
// 同时会传递 binder(类型为 BinderProxy)作为最终 onServiceConnected(name, service) 方法的第二个参数
ActivityManager.getService().publishService(..., binder)
ActivityManagerService#publishService(IBinder token, Intent intent, IBinder service)
ActiveServices#publishServiceLocked(ServiceRecord r, Intent intent, IBinder service)
IntentBindRecord b = r.bindings.get(filter);
b.binder = service;
b.requested = true;
b.received = true;
// for 循环遍历 r.connections(ServiceRecord#connections)
// ########################### 从 AMS 所在进程转到客户端进程 ###########################
// conn:ConnectionRecord 类的成员变量 IServiceConnection(conn 对应上面 new ConnectionRecord() 时传入的第三个参数)
// 一直往上找,该参数是在一开始的 ContextImpl#bindServiceCommon() 中被赋值为 sd,实际类型为 LoadedApk#ServiceDispatcher#InnerConnection,InnerConnection 是 ServiceDispatcher.Stub 的子类(Binder 类型对象)
// 需要注意的是,当前是 AMS 所在进程,AMS 持有的是 sd(ServiceDispatcher.Stub 的子类)对应的 BinderProxy 对象
// 所以 AMS 调用 conn.connected(),实际上跨进程调用的是客户端进程 sd(ServiceDispatcher.Stub 的子类)的 connected() 方法,即 LoadedApk#ServiceDispatcher#InnerConnection#connected()
c.conn.connected(r.name, service, false);
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
sd.connected(name, service, dead);
// mActivityThread 是在 ContextImpl#bindService() 中被赋值,类型为 Handler,不为空
if (mActivityThread != null) {
// 当前在客户端进程
// 通过 Handler 把线程从 Binder 线程池切换到应用主进程
// RunConnection implements Runnable,查看其 run() 方法
mActivityThread.post(new RunConnection(name, service, 0, dead));
RunConnection#run():
doConnected(mName, mService, mDead);
// 这里的 service 是从 ActivityThread#handleBindService() 方法中传下来的
// IBinder binder = s.onBind(data.intent);
// ActivityManager.getService().publishService(data.token, data.intent, binder);
// publishService() 方法的第三个参数 binder 是 onServiceConnected() 方法的第二个参数 service
// 而 binder 是 Service#onBind() 的返回值,这也是我们平时在写 Service#onBind() 方法时,方法要返回一个远程 Binder 接口的实现类
// 且 mConnection 是我们在代码中创建的 ServiceConnection 实例,通过 ContextImpl#bindService() 传下来
// 因此这也是在 Connection#onServiceConnected() 方法中就能获取到远程 Binder 本地代理的原因
mConnection.onServiceConnected(name, service);
} else {
doConnected(name, service, dead);
}
// bindService() 不用关注这个方法,该方法内部是 startService() 相关的逻辑(内部调用 Service#onStartCommand() 方法)
sendServiceArgsLocked(r, execInFg, true);
return null;
}
// Service 所在进程不存在(略),走这里
// 启动 Service 所在进程
// 反射创建 Service,调用 Service#onCreate()(不涉及 bindService() 逻辑)
return 0;
// 不带 BIND_AUTO_CREATE
// 应用进程启动了(s.app:Service 对应的 ProcessRecord 不为空),且 Service 的 Binder 对象已经发布给 AMS 了(是否发布,就看 received 是否为 true)
// b.intent.received:当前为默认 false,在上面调用 publishService() 方法时 IntentBindRecord#received 被置为 true
// b:AppBindRecord
// b.intent:IntentBindRecord
if (s.app != null && b.intent.received)
// 当前在 AMS 所在进程
// Service 已经启动,现在开始连接
// b.intent.binder:在上面调用 publishService() 方法时 IntentBindRecord#binder 赋值为 Service#onBind() 这个服务对应的 BinderProxy 对象
// b:AppBindRecord
// b.intent:IntentBindRecord
c.conn.connected(s.name, b.intent.binder, false);
// 不带 BIND_AUTO_CREATE
// Service 的 Binder 对象当然还未发布给 AMS(是否发布,就看 received 是否为 true)
// 情况一:应用进程没启动,requestServiceBindingLocked() 直接返回,bindService() 流程结束(也就是说,在要绑定的 Service 所在的进程不存在情况下调用 bindService(),且 bindService() 第三个参数不带 BIND_AUTO_CREATE,那么 bindService() 不会帮忙创建要绑定的 Service 所在的进程)
// 调用 bindService() 方法时,会在 bringUpServiceLocked() 方法中创建要绑定的 Service 所在的进程
// 情况二:应用进程启动了
// b.intent.requested:当前为默认 false,在 bindService 过程中调用 publishService() 时被置为 true
else if (!b.intent.requested)
requestServiceBindingLocked()
三、onServiceConnected() 第二个参数类型是 BinderProxy?
代码中 onBind() 的返回值是 Stub,为什么 onServiceConnected() 第二个参数接收到的类型是 BinderProxy
// publishService() 方法的第三个参数 binder 是 onServiceConnected() 方法的第二个参数 service,参数类型为 BinderProxy
mConnection.onServiceConnected(name, service);
Java 层:Parcel#readStrongBinder() 方法返回的是 BinderProxy
AMS 通过 publishService() 方法通知客户端 Service 已创建完毕(这是一个跨进程调用,应用端 ActivityManagerService 向 ServiceManager 注册服务,应用端 ActivityManagerService 收到的 binder 返回值,类型为 BinderProxy)
代码实测:bindService() 第二个参数 ServiceConnection 的 onServiceConnected 回调的第二个参数 service 实际类型是 BinderProxy