一,写在前面
为了更好的理解Service的绑定流程,建议先了解Activity和Service的启动流程,本篇文章将不再对一些重复的细节进行阐述。建议阅读前,可以参考如下两篇文章:
二,绑定服务的开始
在Activity中调用bindService(intent,ServiceConnection)绑定服务,其实是调用父类ContextWrapper的bindService方法。
ContextWrapper$bindService方法源码如下:
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
mBase是一个Context类型的对象,mBase的值是一个ContextImpl对象。ContextImpl的实例化是在启动Activity时完成的,并作为参数传入Activity$attach方法,具体细节就点到这里吧,详情可参考
Android Activity的启动流程源码解析(8.0)。也就是说,绑定服务接着交给ContextImpl来处理。
ContextImpl$bindService方法源码如下:
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
//继续查看...
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
//...code
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
//...code
}
第5行,调用ContextImpl$bindServiceCommon方法;
第14行,做一个ServiceConnection接口引用的判空检查;
第17行,变量mPackageInfo是一个LoadedApk对象,在启动Activity的流程中也会用到这个类,这里做了判空检查;
第18行,对conn也就是ServiceConnection接口进行封装,借助于一个Binder使ServiceConnection可以在进程间传递,下面会详细分析;
第25行,ActivityManager.getService()是IActivityManager的代理对象,调用代理对象的bindService方法,会向系统服务ActivityManagerService发起请求,基于Binder机制,调用ActivityManagerService$bindService方法。至于为啥将绑定服务的操作交给AMS,可以参考文章
Android Activity的启动流程源码解析(8.0) ,这里不再重复阐述。
分析:
第18行,调用了LoadedApk$getServiceDispatcher方法。
查看LoadedApk源码如下:
public final class LoadedApk {
//...code
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<>();
//...code
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
sd = map.get(c);
}
if (sd == nu