一 概述
bindService 和 startService 过程差不多,差别主要是在创建 Service 实例后一个是执行 bind 操作,一个是执行 start 操作。
本篇文章将从进程的角度出发来分析 bindService 流程,在 bindService 的流程中将要涉及到三个主要的进程,分别是 bindService 发起端进程,system_server 进程和目的端 Service 进程,我们将会以这三个进程角度出来阐述 bindService 是怎么在这三个进程之间辗转腾挪达到远程绑定服务或者说是 Binder 传递功能的。
分析的系统源码为 android 12 。
涉及代码如下:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
frameworks/base/core/java/android/app/LoadedApk.java
frameworks/base/core/java/android/app/ContextImpl.java
frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/core/java/android/app/Service.java
二 发起端进程发送 bindService 请求
2.1 ContextImpl.bindService
frameworks/base/core/java/android/app/ContextImpl.java
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
// 和 startService 流程一样,检查是否是系统应用调用的,打印 log
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, null,
mMainThread.getHandler(), null, getUser());
}
注意第5个参数,传入了主线程的 handler,对应着 client 端的主线程 handler,后面会用到它。
2.2 ContextImpl.bindServiceCommon
private boolean bindServiceCommon(Intent service, ServiceConnection conn,
......) {
// 获取 ServiceDispatcher 对象,用来实现进程间通信的核心
// 本质上是一个 ServiceDispatcher.InnerConnection 对象,这个类是
// 实现了 IServiceConnection 接口的 Binder 实体,是服务端
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (handler != null && executor != null) {
throw new IllegalArgumentException("Handler and Executor both supplied");
}
if (mPackageInfo != null) {
if (executor != null) {
sd = mPackageInfo.getServiceDispatcher(conn,
getOuterContext(), executor, flags);
} else {
// conn 封装到了 ServiceDispatcher 中
sd = mPackageInfo.getServiceDispatcher(conn,
getOuterContext(), handler, flags);
}
}
// 获取 Activity token
IBinder token = getActivityToken();
......
// 绑定 isolated 服务.
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
}
将这个方法分为两部分来看,一部分是创建 sd 对象,第二部是调用 AMS 的 bindIsolatedService() 方法与系统进程交互。
先来看 sd 是如何被赋值的。这里 mPackageInfo 不为 null,并且 executor 传入的为 null,所以执行 else 分支调用 mPackageInfo 的 getServiceDispatcher() 方法得到一个 sd 对象,其中第一个参数 conn 为我们在客户端创建的 ServiceConnection,第三个参数 handler 为前文提到的客户端 app 主线程的 handler。mPackageInfo 是 LoadedApk 类型对象。
2.2.1 LoadedApk.getServiceDispatcher
LoadedApk.java
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
return getServiceDispatcherCommon(c, context, handler, null, flags);
}
继续调用 getServiceDispatcherCommon
LoadedApk.java
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>
mServices = new ArrayMap<>();
// 一个 ServiceConnection 对应一个 ServiceDispatcher,一一对应关系
// 以 Context 为键值,存储在 ArrayMap 形式的 mServices 中
private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
Context context, Handler handler, Executor executor, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
// 一个 ServiceConnection 对应一个 ServiceDispatcher,一一对应关系
// 以 Context 为键值,存储在 ArrayMap 形式的 mServices 中
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 == null) {
if (executor != null) {
sd = new ServiceDispatcher(c, context, executor, flags);
} else {
// 创建一个 ServiceDispatcher 实例,封装 context, connection 等
sd = new ServiceDispatcher(c, context, handler, flags);
}
......
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
// 把 connection 和封装这个 connection 的 sd,放入 map 中
map.put(c, sd);
} else {
sd.validate(context, handler, executor);
}
// 返回 sd 的内部类 ServiceDispatcher.InnerConnection 对象
// mIServiceConnection
return sd.getIServiceConnection();
}
}
executor 为空,执行注释2所在的 else 分支,创建一个 ServiceDispatcher 实例。
2.2.2 ServiceDispatcher
LoadedApk.java
static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
// 一个 Binder 实体,是 binder 通信的核心
@UnsupportedAppUsage
private final ServiceConnection mConnection; // 一个连接被封装到此
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P,
trackingBug = 115609023)
private final Context mContext;
private final Handler mActivityThread;
private final Executor mActivityExecutor;
private final ServiceConnectionLeaked mLocation;
private final int mFlags;
......
// 关键内部类 InnerConnection 实现了 IServiceConnection.Stub 接口
// 是为 Binder 服务端
private static class InnerConnection extends IServiceConnection.Stub {
@UnsupportedAppUsage
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
// 构造方法中,包含了 ServiceDispatcher
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
// 跨进程调用的 connected 方法,这里的 service 即为从远程服务端所在进程传递过来的
// Binder 对象,接下来我们重点关注这个对象是怎么传递过来的
public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
// 进而调用 ServiceDispatcher 的 connected 方法
// 进而最终调用到 ServiceDispatcher 中的 ServiceConnection 的
// onServiceConnected 方法
sd.connected(name, service, dead);
}
}
}
......
// ServiceDispatcher 构造方法
@UnsupportedAppUsage
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int fl