概述

基于Android 10.0源码(AOSP-10.0.0-r1)分析startService流程,剖析相关流程的关键点和framework核心机制。

过程

service的启动过程主要分为三大部分,包括发出startService调用的机制、system_server中对service的处理、应用进程中对service的创建流程和生命周期回调。

Context.startService

  1. Context是Abstract类,它是由ContextImpl实现的,并通常以装饰器模式被ContextWrapper包装。App中Context.startService()调用实质上是由ContextWrapper.mBaseContextImpl.startService()实现的。
  2. ContextImpl.startService()首先会调用 warnIfCallingFromSystemProcess()来检查调用者是否为系统进程。日志中的警告信息就是这里打印店额。
  3. ContextImpl.startService()关键实现是ContextImpl.startServiceCommon,它在完成对Intent的检查后(高版本SDK检查Intent是否是不被允许的隐式intent),调用 ActivityManager.getService().startService()通过Binder向AMS申请启动服务,并对该调用的结果做检查,其中startService相关的permission异常就是在这里抛出。
  4. ActivityManager.getService()获取了IActivityManager.Stub的Binder Proxy实例,它的Server端实现就是ActivityManagerService
  5. 通过Binder调用的startService()方法中有几个关键参数。IApplicationThread是一个Binder,服务端为ActivityThread,Proxy通过startService()传递到system_server,方便AMS处理完成后通过该Binder回调到应用进程。另外两个重要参数是启动服务的Intent和确定是否为前台服务的requireForeground

SystemServer

ActivityManagerService.startService

  1. AMS.startService()
    1. 经过Binder调用,startService会处理App的请求。该方法的第一步就是检查用户有没有启动服务的权限(检查调用者是否是isolated uid,不是常规的Android Manifest内的权限)
    2. 调用mServices.startServiceLocked(),其中mServicesActiveServices。启动服务的所有逻辑都是在这个方法实现的。

ActiveServices

  1. ActiveServices.startServiceLocked()

    1. 首先通过retrieveServiceLocked()检索服务信息(ServiceLookupResult)。ServiceLookupResultActiveiServices的内部类,它仅包含ServiceRecord和表示权限的String两个成员。
    2. retrieveServiceLocked的作用是返回service对应的ServiceRecord。会从ServiceMap中查找是否已有该ServiceRecord(service已经启动的情况),否则就通过PackageManagermAm.getPackageManagerInternalLocked().resolveService)查找已安装的应用是否有匹配该service intent的服务(ServiceInfo)。如果ServiceMapPackageManager都不能提供对应的ServiceRecrodServiceInfo,那么就是Service not found的情况,无法启动服务。
    3. ServiceMap不包含该ServiceRecord时,ActiveServices会从PackageManager获取已安装应用中解析出来的ServiceInfo,并根据此来生成返回给调用者的ComponentName这里可以看出,ServiceMap是一个运行时缓冲状态表,维护一个已有的Record,减少访问PMS。但是实际上从PMS解析出来的ServiceInfo对应的ServiceRecord不一定会加入到这个Map中,对应的package必须相互允许集成对方包的情况下才会加入(mAm.validateAssociationAllowedLocked())
    4. validateAssociationAllowedLocked()返回true时,在BIND_EXTERNAL_SERVICE的情况下,ActiveServices不仅会将创建的ComponentName(这个对象返回给AMS时,AMS用这个来启动service,返回给App时,App根据返回值直到自己的启动情况和结果)修改为自身的包名(即bind的external service的包名改为发起startService的包名,还会将内部使用的ServiceInfo和方法外部入参Intent都做对应的修改。
    5. 最后,从PMS成功解析后,创建ServiceRecord并放入ServiceMap。到这里找到了目标service,创建了ServiceRecord,实际上retrieveServiceLocked()的关键流程就已经完成了,但是还有一些额外的功能在最后可能影响服务的启动。
    6. 在最后时刻,ActiveServices会最后确定解析的ServiceLookupResult是否真的应该返回。最后有三道检测关卡,包括IntentFirewallPermission机制和AppOps机制。其中通过mAm.mIntentFirewall.checkService()调用IntentFirewall来检查是否应该"blocked by firewall"IntentFirewall的机制是,它读取/data/system/ifw内的xml配置文件创建Firewall rules,当Intent被rules匹配时阻止Intent启动四大组件。另外两个PermissionAppOps是Android常规的权限机制。
    7. 最后,retrieveServiceLocked()检查一下权限后返回包装了ServiceRecordServiceLookupResultActiveServices.startServiceLocked()
  2. fgRequired

    1. 返回的ServiceLookupResult内的ServiceRecord有效时,当调用的是startForegroundService时,会通过AppOps机制检查是否允许启动前台service,否则会退出,并从Binder返回foreground not allowed
    2. 接下来处理一下延时启动相关的东西(后台进程申请启动的后台服务可能会被延迟启动)
  3. startServiceInnerLocked

    1. 将上面的ServiceMapIntentServiceRecord等作为参数调用startServiceInnerLocked()。它首先将ServiceRecord.ServiceState标记为STARTED、启动StatsLog统计使用信息。
    2. 然后调用bringUpServiceLocked()方法启动服务。该方法开头检查ServiceRecordProcessRecordIApplicationThread是否存在,如果存在则表明该Service在之前就已经启动了(被其他startService调用创建过,onCreate()流程已经调用过了)。这种情况下不需要再次创建服务,只需要回调服务的onStartCommand()即可——调用sendServiceArgsLocked()并提前return。它通过IApplicationThread这个Binder回调到应用进程,调用对应service的onStartCommand()。具体流程是,该方法内部调用了r.app.thread.scheduleServiceArgs(),这个方法定义于IApplicationThread.aidl,system_server的AMS调用这个Binder的Proxy,对应server即App内的scheduleServiceArgs()方法。与启动Activity一样,这个方法向ActivityThread的Handler发送了一个Message,Handler内回调onServiceArgs(),最终调用了service的onStartCommand()
    3. bringUpServiceLocked()在service没有创建的情况下往下运行。有一个细节,首先它通过AppGlobals.getPackageManager().setPackageStoppedState()的调用,短暂地阻止ServiceRecord对应的package不能被stop,然后再执行启动service的流程。
    4. 在启动service之前,需要先确保service对应的进程已经存在。否则需要进行创建。而创建service的时候又要分两种情况:service运行于调用者同一个进程、运行于另一个进程。
  4. startServiceInnerLocked创建进程

    1. 接下来区分service是否为独立的进程(isolated)来进行启动。当service运行于同一个进程时,通过mAm.getProcessRecordLocked()获取ProcessRecord,调用realStartServiceLocked()启动服务。否则先启动对应的进程。
    2. 如果目标进程还没有启动,则启动进程。调用AMS.startProcessLocked()来启动目标进程。该方法可以接收一个HostingRecord可以携带Service的ComponentName,AMS在启动进程时会启动该服务,再次回到本方法的已创建进程的流程里面来启动服务。
  5. realStartServiceLocked

    1. realStartServiceLocked()做了一些准备工作。其中通过bumpServiceExecutingLocked()调用scheduleServiceTimeoutLocke()向AMS发送一个Message,该Message的目的是,监控service的启动耗时。service启动完成后会清除该Message,而超时没有清除时,就会触发该Message,会让AMS认为该服务启动异常,做出响应。(ActivityThread.handleServiceCreate()完成后,通过Binder调用AMS,AMS再调用ActiveServices移除掉该Message)
    2. 调用ProcessRecord.IApplicationThread.scheduleCreateService()回调到应用进程。在ActivityThread中发送Message到Handler,回调handleCreateService()方法。这个方法内部加载目标service,并回调onCreate()。并调用AMSserviceDoneExecuting()移除ActiveServices发出的服务启动超时信息。
    3. scheduleCreateService()调用完成后,紧接着会调用ServiceRecord.postNotification()在标题栏展示前台服务必备的Notification。直到这一步,通知栏的通知就可见了。
    4. 下一步就是触发App进程的Service的onStartCommand()了。接着调用sendServiceArgsLocked()通过IApplicationThread发送Message到ActivityThread.H,在对应的ActivityThread.handleServiceArgs()调用service的onStartCommand()
    5. 到这里,整个Service的启动流程已经完成了。最后一步会通过检查ServiceRecord.delayedStop标志,如果它为true则表示服务启动过程中收到了停止该服务的请求。该flag表示该服务已经被请求关闭,只是它已经处于delayed队列了,需要等当前动作完成后再处理stop请求。因此再start流程的最后一步发现这个关闭请求则会响应这个stop,将服务关闭。

ActivityThread

ActivityThread主要是作为客户端使用ActivityManagerProxy与AMS通信,主要是发出startService()的API调用。ActivityThread提供IApplicationThread到AMS,用以接收四大组件的生命周期的回调。回调的处理函数全部都是向Handler发送Message,各个Message的处理函数创建对应的四大组件、调用四大组件的生命周期回调。

TODO: ActivityThread创建service的流程。

总结

AMS通过ActiveServices以及ServiceMapServiceRecord来管理service,并基于它们来执行权限检查,通过IApplicationThread回调到应用进程,并通过H这个Handler来在主线程完成对Service的创建和关键生命周期方法的回调。

参考

  1. ContextImpl.startServiceCommon
  2. ActiveServices
  3. IntentFirewall
  4. IntentFirewall
  5. NBSEIntentFirewall