以Android 8.0版本为基础,以启动运行在新进程的Service为场景,分析启动的流程,了解了Binder和AMS后会好理解些。
客户端进程向AMS发起启动Service请求
在Activity中调用startService()
启动Service,但实际上Activity没有此方法,是其父类ContextWrapper实现的。
ContextWrapper.startService
1 | public ComponentName startService(Intent service) { |
mBase
:ContextImpl;
为什么是ContextImpl?
在AT.performLaunchActivity()
中,把创建好的ContextImpl传到Activity.attach()
中,然后又传到attachBaseContext()
中,最后赋给了ContextWrapper的mBase
变量。
ContextImpl.startService
1 | public ComponentName startService(Intent service) { |
ContextImpl.startServiceCommon
1 | private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) { |
经过Binder驱动,最终AMS.startService()
被调用。
AMS处理Intent信息及一些情况
AMS.startService
1 | public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, |
mServices
:ActiveServices。caller
:客户端进程的IApplicationThread在AMS所在进程的本地代理,可间接调用客户端进程的ApplicationThread。
ActiveServices.startServiceLocked
1 | ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, |
处理Intent信息是否合法;
针对Service前台后台的情况判断是否可以启动;
设置ServiceRecord参数;
处理延迟启动Service。
ActiveServices.startServiceInnerLocked
1 | ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, |
ActiveServices.bringUpServiceLocked
1 | private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, |
如果ServiceRecord已经绑定了ProcessRecord,并且ProcessRecord绑定了客户端进程的IApplicationThread的本地代理,则直接回调Service的onStartCommand方法。
准备启动Service了,这里分为2种情况:
- 首先判断进程如果存在,则直接调用
ActiveServices.realStartServiceLocked()
进行Service真正的启动; - 如果进程不存在,会先调用
AMS.startProcessLocked()
创建进程,然后把待启动的ServiceRecord添加到mPendingServices
中。AMS通知Zygote进程fork出新的子进程,经过一系列的调用后回到AMS.attachApplicationLocked()
方法中,然后调用ActiveServices.attachApplicationLocked()
处理mPendingServices
,判断uid和进程名相同时后调用ActiveServices.realStartServiceLocked()
。后面的流程便和进程存在的情况相一致了。其中从AMS.startProcessLocked()
到AMS.attachApplicationLocked()
和Activity启动流程第3部分是一样的,不再分析
(点击查看)
然后往下看ActiveServices.realStartServiceLocked()
:
ActiveServices.realStartServiceLocked
1 | private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { |
- ServiceRecord和ProcessRecord相互绑定;
- 发送一个
创建Service
超时的ANR消息; - 调用
app.thread.scheduleCreateService()
向客户端发起IPC进行Service的创建; - 调用
sendServiceArgsLocked()
,向客户端发起IPC回调Service的onStartCommand()
方法。
发送Service创建超时的延时消息
调用bumpServiceExecutingLocked()
发送一个延时消息,如果这个消息没有被移除,就会执行Service创建超时的流程,最终弹出ANR对话框;如果在超时之前执行完Service的onCreate()
,便会移除这个延时消息。
ActiveServices.bumpServiceExecutingLocked
1 | private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) { |
ActiveServices.scheduleServiceTimeoutLocked
1 | void scheduleServiceTimeoutLocked(ProcessRecord proc) { |
AMS的MainHandler发送一个延时的Service超时的消息,SERVICE_TIMEOUT
:前台服务超时时间20秒。SERVICE_BACKGROUND_TIMEOUT
:是前台服务的10倍,200秒。
向客户端发起IPC进行Service的创建
app.thread
是Service所在进程的IApplicationThread在AMS的本地代理,经过Binder驱动,回到客户端进程,ApplicationThread.scheduleCreateService()
被调用。
ApplicationThread.scheduleCreateService
1 | public final void scheduleCreateService(IBinder token, ServiceInfo info, CompatibilityInfo compatInfo, int processState) { |
token
:ServiceRecord是Binder类型,token是ServiceRecord在客户端进程的本地代理,用来映射客户端进程的Service和AMS进程的ServiceRecord。
构造CreateServiceData并发送给Hander,最终ActivityThread.handleCreateService()
被调用。
ActivityThread.handleCreateService
1 | private void handleCreateService(CreateServiceData data) { |
LoadedApk使用AppComponentFactory.instantiateService()反射构造Service;
调用Service.attach()保存ActivityThread、ServiceRecord本地代理和AMS本地代理等到Service;
调用Service.onCreate方法,onCreate()只在第一次创建的时候被回调,后面只调用onStartCommand方法;
把ServiceRecord和Service缓存到ActivityThread;
通知AMS调用serviceDoneExecuting()
方法。
AMS.serviceDoneExecuting
1 | public void serviceDoneExecuting(IBinder token, int type, int startId, int res) { |
ActiveServices.serviceDoneExecutingLocked
1 | void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) { |
调用serviceDoneExecutingLocked()
方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) {
r.executeNesting--;
if (r.executeNesting <= 0) {
if (r.app != null) {
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
}
...
}
...
}
}
移除了前面发送的Service创建超时ANR的延时消息。
回调Service的onStartCommand()方法
完成Service的创建之后,开始通知客户端进程回调Service的onStartCommand()方法。
ActiveServices.sendServiceArgsLocked
1 | private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg, |
发送Service启动超时的延时消息。类似流程3,当客户端进程成功回调onStartCommand()
后,会通知AMS调用serviceDoneExecuting()
移除ANS延时消息.
调用sendServiceArgsLocked()
回调Service的onStartCommand()
方法。
客户端进程回调onStartCommand
经过Binder驱动,最终客户端进程的ApplicationThread.scheduleServiceArgs()
被调用
ApplicationThread.scheduleServiceArgs
1 | public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) { |
token
:ServiceRecord。
构造ServiceStartArgs并发送给Hander,最终ActivityThread.handleServiceArgs()
被调用。
ActivityThread.handleServiceArgs
1 | private void handleServiceArgs(ServiceArgsData data) { |
通过token
取出缓存的Service,回调其onStartCommand()
;
跨进程调用AMS.serviceDoneExecuting()
,根据onStartCommand()
返回值处理Service被杀死后重启的逻辑,然后是移除Service启动超时ANR的消息(见4.2-4.4)。
总结
- Service的创建依靠和AMS进程的交互,由AMS控制Service的合法性和权限,然后再通知客户端进程进行创建等操作。
- Service的创建流程:
- 进程A和AMS进程进行IPC,向AMS发送startService();
- AMS进程收到请求后验证Intent信息,然后查询待启动Service所在进程是否启动,如果未启动则先通知Zygote进程创建待启动Service所在的进程B,并把Service添加到待启动Service列表中;
- AMS进程通过Socket向Zygote进程通信,请求创建新进程,Zygote收到请求后fork子进程,当fork成功后子进程的ActivityThread的main方法被调用;
- 回到进程B中,进程B和AMS进程进行IPC,向AMS发送attachApplication();
- 回到AMS进程中,AMS查询待启动Service列表,调用ActiveServices.realStartServiceLocked()准备创建Service,前面如果待启动Service所在进程如果存在,则直接调用此方法;
- AMS进程和进程B进程IPC,向进程B发送创建Service并回调其onCreate()、回调Service.onStartCommand()的命令;
- 进程B接受请求,反射创建Service并回调onCreate()、onStartCommand(),Service创建并启动完成。
- AMS在准备进行IPC调用进程B的onCreate()、onStartCommand()等之前均调用ActiveServices.bumpServiceExecutingLocked()发送一个延时的ANR的消息,当进程B完成onCreate()、onStartCommand()等之后,会再向AMS进程发起IPC调用AMS.serviceDoneExecuting()去移除那个延时的AND消息,如果时间到了进程B还未完成调用则会弹出ANR对话框。不要在onCreate()、onStartCommand()方法中做耗时任务,因为它们都运行在主线程
- ANR超时时常:
SERVICE_TIMEOUT
:前台服务超时时间20秒。SERVICE_BACKGROUND_TIMEOUT
:是前台服务的10倍,200秒。 - 关于AMS为Service创建新进程的形式和创建Activity当流程一致,均是和Zygote进程进行Socket通信,fork出子进程后再回到AMS进程继续Service的创建。