写在最前面
上一篇中,我们分析了从 Launcher 启动一个 App 整体的流程。本篇我们就仿照上篇一篇的分析方法来分析 Service 绑定是怎样的一个过程。本篇采用的源码版本是 API 27。

向 ActivityManagerService 发出请求
我们直接在 Activity 中调用 bindService 方法。由于 Activity 继承于 ContextImpl,因此直接调用了 ContextImpl.bindServiceCommon 方法:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) {
IServiceConnection sd;
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
...
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
...
}
将 ServiceConnection 转换成 IServiceConnection, 并直接跨进程传递给了 ActivityManagerService.bindService 来进行绑定操做。
ActivityManagerService 创建进程
ActivityManagerService 中经过调用转到 ActiveServices.bindServiceLocked 方法:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId){
...
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
...
requestServiceBindingLocked(s, b.intent, callerFg, false);
...
}
当我们传入的 flag 包含 BIND_AUTO_CREATE,则会先判断此 Service 是否已经创建成功。
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired){
...
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
...
realStartServiceLocked(r, app, execInFg);
return null;
}
...
if (app == null && !permissionsReviewRequired) {
mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false);
...
}
}
这里会判断是否存在所需的进程,如果存在直接 realStartServiceLocked 调用会调用 app.thread.scheduleCreateService 方法,类似上一篇的 app.thread.scheduleCreateActivity 就是直接创建了 Service,如果进程不存在,则要先通过调用 startProcessLocked 创建新的进程。就跟上一篇的思路一样的。我们这里还以第二种情况为例,假如没有目标进程,则会先创建进程,创建新的 ActivityThread,将 ApplicationThread 和 AMS 向绑定:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
ProcessRecord app;
...
app.makeActive(thread, mProcessStats);
...
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
...
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
...
// Find any services that should be running in this process...
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
badApp = true;
}
}
}
AMS.attachApplicationLocked 这个方法,我们上篇已经分析过了,这次创建新的进程又一次调用到了这个方法。这次没有 Activity 需要添加,只有一个 Service 需要操作,便调用了 ActiveServices.attachApplicationLocked 方法,将 Services 和 Application 向关联。
boolean attachApplicationLocked(ProcessRecord proc, String processName){
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
...
realStartServiceLocked(sr, proc, sr.createdFromFg);
...
}
}
}
这样调用,便像 bringUpServiceLocked 方法一样调用了 realStartServiceLocked 方法来启动 Service。
ApplicationThread 创建服务
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg){
...
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
...
requestServiceBindingsLocked(r, execInFg);
}
这样便将创建 Service 的任务发送给了 ApplicationThread 发送了过去。最后都是 ApplicationThread 通知 ActivityThread 来做事情
private void handleCreateService(CreateServiceData data) {
...
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
...
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
mServices.put(data.token, service);
ActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
代码很清晰了,创建 Service 和 Context 绑定,同时也说明运行的线程就是主线程,将 Service 保存到 HashMap 中,最后通知 AMS 完成了创建。由于跨进程是同步进行的,当 ActivityThread 创建完成了 Service 之后,realStartServiceLocked 方法中的 requestServiceBindingsLocked 才会被调用到。那这里我们再看看绑定这里是怎么做的。
ApplicationThread 绑定服务
ActivitServices 中直接调用 ServiceRecord 进程所在的 Applications 的 scheduleBindService方法:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean execInFg, boolean rebind){
...
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.repProcState);
...
}
当然最后还是再 ActivityThread 中进行绑定:
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
...
if (s != null) {
...
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
...
}
}
这样就把 Service 和调用者的 Intent 绑定了起来。最后还将 onBind 返回的 IBinder 返回给了 AMS,进而调用了 ActivitServices.publishServiceLocked 。最后我们看下 ActivitServices 是怎么处理这个的:
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
...
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
...
try {
c.conn.connected(r.name, service, false);
} catch (Exception e) {
...
}
}
}
...
}
最后其实调用的是:ConnectionRecord.IServiceConnection.connected 方法,而 IServiceConnection 又是 ServiceConnection 转换来的,所以是 ServiceConnection 与 IBinder 建立了联系,至此跨进程绑定一个 Service 就此结束了。
小结
整体来说,会了上一篇的分析再看绑定 Service 的操作,感觉会清晰不少,毕竟也是由于不需要操作 Activity 整体来说代码思路会更加清晰一些。本篇的内容到此结束,下篇再见。