上一篇我们讲了Context和Activity的相关知识,
Android 插件化开发——基础底层知识(Context家族史,Activity启动流程)
本篇我们讲述Service的工作流程
关于Service的创建启动流程,其实和Activity的创建启动流程是相似的。都是和AMS交互,通信介质是:Binder
关于Service的启动方式,我们分为两种:startService和bindService, 关于这两个启动方式的区别以及使用方法,在此不再赘述。
启动创建Service,我们分为两种:同一进程,不同进程。
新进程启动Service
假设要在新进程启动一个Service,可分为5个阶段:
1: APP给AMS发送消息,附带Manifest定义的相关信息。
以startService为例,该方法最终调用的是ContextWrapper中的startService方法。
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
我们知道mBase实际上就是ContextImp, 进入ContextImp,最终调用的是:startServiceCommon方法,可以看到这么一句话:
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
发送消息给AMS。
2.AMS检查新的进程是否存在,如果不存在,就创建一个新的进程,并且把Service信息保存起来。
AMS会首先检查Manifest中是否生命了Service,如果没有直接报错。有的话,就创建进程,并且把Service的相关信息封装成ServiceRecord对象保存。
3.启动新进程,然后通知AMS,:新的进程已经存在
Service在启动的新进程的过程中和上一篇博客讲的APP的启动流程相似。
此时会创建一个ActivityThread。然后ActivityThread会告诉AMS:新进程启动成功。
4.此时AMS发送刚才存储的Service信息给新进程
AMS收到消息时候,会把之前存储的ServiceRecord通过ApplicationThread发送给新进程。这个ServiceRecord就是将要启动的Service的相关信息。
5:新进程启动Service
还是以startService为例,AMS发送消息给APT(ApplicationThread),执行:scheduleCreateService, 再给H 执行handleCreateService方法,其中可以看到这个代码块:
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
可以看出通过classloader反射出(新建)了一个新的Service,这里用的是反射。
注意:实际上可以回顾一下,创建Activity的时候,用到的也是反射,可以在Instrumentation中看到,在此不赘述。
至此,新进程的Service就创建启动完成了。
同一进程绑定Service
在同一进程绑定Service,大致分为五个步骤:
最后两把绕了一圈 Binder又给了APP,考虑的因素可能是:不在同一个进程。所以这样代码公用。
调用bindService还是走的ContextWrapper,
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
接着走了ContextImp的bindServiceCommon方法
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
.....
ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
}
最终传递给AMS。
AMS收到信息之后,检查Manifest,并且会查看新的进程是否存在。
最终发送消息给APP(假设同一进程),然后回调给APP的APT的scheduleCreateService方法, 在传递给H,
private void handleCreateService(CreateServiceData data) {
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
创建完了Service, 最后调用了serviceDoneExecuting方法,是告诉AMS:我创建完毕了,是否有下一步操作。
然后AMS收到消息之后,最终间接会调用APP的handleBindService方法,这是开始了绑定操作。
private void handleBindService(BindServiceData data) {
....
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);
}
......
}
执行了Service的onBind方法,并且告诉调用AMS的publishService方法告诉它:绑定完毕。
其中传递了Binder对象,这个Binder对象是ServiceDispatcher内部类的InnerConnection。 InnerConnection实现了IServiceConnection.Stub。
重新回到ContextImp:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
.....
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
......
}
进入到LoadedApk.java中可自行查看ServiceDispatcher类, 把Binder包装成了ServiceDispatcher对象发送给了AMS。最终调用:connected方法 --> doConnected方法:
// If there is a new viable service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);
} else {
// The binding machinery worked, but the remote returned null from onBind().
mConnection.onNullBinding(name);
}
看到了熟悉的onServiceConnected回调。 如果不在同一个进程,Service 通信的流程是:Service -->AMS -->Activity, 中间是Binder驱动。
附上网上的一张流程图,个人觉得bindService流程跟这幅图完全比配:
至此绑定流程讲述完了。整体的流程和Activity的启动流程是相似的。