欢迎读者阅读我的个人博客点击前往我的个人博客
更精美的UI,拥有更舒适的阅读体验。
本文章个人博客链接Android中Service的启动与绑定过程详解(基于api29)
前言
前面我写到一个文章是关于Activity启动流程的点击链接前往。这一篇的内容是关于Service的启动和绑定的流程详解。Service和Activity一样,都是受AMS和ActivityThread的管理,所以在启动流程上两者有一些相似。不同的是Service有绑定的流程,相对比较复杂一点,结合Service的生命周期来理解,也不是很复杂。
了解启动源码的好处是整个Service对于你来说已经是透明的了,我们所做的每一个操作,心里都很清楚他的背后发生了什么。这是一种自信,也是一种能力,一种区别于入门与高级工程师的能力。
文章涉及到很多的源码,我以“思路先行,代码后讲”的思维来讲解这一过程。先对总体有个感知,再对具体代码进行研究会有更深刻的理解。希望可以认真看完每一处的代码。我更加建议把一边看文章一边自己查看源码,这样可以加深理解。文章涉及到跨进程通信,如果对此还没有学习的话,可能看起来一些步骤比较难以理解,建议先学一下跨进程通信AIDL。
代码中我加了非常多的注释来帮助大家理解每个重点的内容,请一定要看代码内容。代码外的讲解仅仅只是总体流程的概述。
理解源码需要对Service的生命周期有一个完整的认识,可以帮助理解源码中的内容。在下面的解析中我也会穿插生命周期的一些补充,希望可以帮助大家理解。
本文内容大纲:
![av8XNT.png](https://i-blog.csdnimg.cn/blog_migrate/5f60dae586d896054a372d4901c3840a.png)
总体工作流程思路概述
这一部分主要为大家有个整体的流程感知,不会在源码中丢失自己。分为两个部分:启动流程与绑定流程。
直接启动流程概述
概述
直接启动,也就是我们在Activity中调用startService来启动一个Service的方式。
图解
![Service启动整体流程概述.png](https://i-blog.csdnimg.cn/blog_migrate/3b046129552c66dc6170762f35f9ab0b.png)
简析
启动的步骤:
- Activity向AMS,即ActivityManagerService请求启动Service。
- AMS判断Service所在的进程是否已经创建,注意Service和Activity是可以同个进程的。
- 如果还没创建则通过Zygote进程fork一个进程。
- AMS请求Service所在进程的ActivityThread创建Service和启动,并回调Service的onCreate方法。
- Service创建完成之后,AMS再次请求ActivityThread进行相关操作并回调onStartCommand方法。
过程中onCreate和onStartCommand是在两次跨进程通信中完成的,需要注意一下。总共最多涉及到四个进程。
绑定流程概述
概述
绑定服务即我们在Activity中调用bindService来绑定服务。绑定的过程相对直接启动来说比较复杂一点,因为涉及到一些生命周期,需要进行一些条件判断。
图解
图有点复杂,配合下面的解析一起看
![avlXND.png](https://i-blog.csdnimg.cn/blog_migrate/2e987fff35be522a5692db9b73867221.png)
简析
介绍一下步骤:
- Activity请求AMS绑定Service。
- AMS判断Service是否已经启动了。如果还没启动会先去启动Service。
- AMS调用Service的onBind方法获取Service的IBinder对象。
- Service把自己的IBinder对象发布到AMS中保存,这样下次绑定就不需要再调用onBind了。
- 把拿到的IBinder对象返回给Activity。
- Activity可以直接通过这个IBinder对象访问Service。
这里是主体的流程。绑定的过程涉及到很多情况的判断,如:进程是否创建,是否已经绑定过,是否已经调用了onUnBind方法等。后面的源码讲解会讲到。这里我只放整体的流程。
源码讲解
这一部分内容枯燥,但我把源码尽量提取相关的代码,其他的用省略号进行省略,减少无用的代码干扰。源码中的重点我用了很多的注释解析,一定要看注释,是非常重要的一部分。
直接启动流程源码讲解
一、Activity访问AMS的过程
图解
![Service启动流程-1.png](https://i-blog.csdnimg.cn/blog_migrate/9b9da99fe2323df8a6a0296f1db777fc.png)
源码解析
-
我们在Activity中调用startService方法,其实是调用ContentWrapper的startService,因为Activity是继承自ContextWrapper的。startService是Context的抽象方法,ContentWrapper继承自Content,但是他运行了装饰者模式,本身没有真正实现Context,他的内部有一个真正的实例mBase,他是ContextImpl的实例,所以最终的真正实现是在ContextImpl中。
/frameworks/base/core/java/android/content/ContextWrapper.java // 这里的mBase是startService的真正实现。他是从哪里来的?从activit的创建开始看 Context mBase; public ComponentName startService(Intent service) { return mBase.startService(service); }
想要知道什么时候得到Context,要回到ActivityThread创建Activity的时候创建的Context。最终可以看到就是ContextImpl这个类是具体的实现。
/frameworks/base/core/java/android/app/ActivityThread.java private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // 在这里创建了Content,可以看到他的类型是ContentImpl ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; ... // 在这里把appContext给到了activity。说明这个就是Activity里面的Context的具体实现 appContext.setOuterContext(activity); activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback, r.assistToken); ... }
-
ContextImpl的处理逻辑是直接调用AMS在本地的代理对象IActivityManagerService来请求AMS。
/frameworks/base/core/java/android/app/ContextImpl.java; // 直接跳转下个方法 public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, false, mUser); } private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) { // 如果了解过activity启动流程看到这个ActivityManager.getService()应该很熟悉 // 这里直接调用AMS在本地的IBinder接口,进行跨进程通信。不了解的可以去看一下我的 // 关于解析activity启动流程的文章。链接在上头。 ComponentName cn = ActivityManager.getService().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( getContentResolver()), requireForeground, getOpPackageName(), user.getIdentifier()); }
这里再次简单介绍一下这个IActivityManager。这一步是通过AIDL技术进行跨进行通信。拿到AMS的代理对象,把启动任务交给了AMS。
/frameworks/base/core/java/android/app/ActivityManager.java/; //单例类 public static IActivityManager getService() { return IActivityManagerSingleton.get(); } private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() { protected IActivityManager create() { //得到AMS的IBinder接口 final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); //转化成IActivityManager对象。远程服务实现了这个接口,所以可以直接调用这个 //AMS代理对象的接口方法来请求AMS。这里采用的技术是AIDL final IActivityManager am = IActivityManager.Stub.asInterface(b); return am; } };
二、AMS处理服务启动请求的过程
图解
![Service启动流程-2.png](https://i-blog.csdnimg.cn/blog_migrate/311d4cd621d67a6e5327d6ddc8d68d2b.png)
源码解析
-
AMS调用ActivityServices进行处理。有点类似activity启动中的调用ActivityStarter进行启动。把业务分给他的小弟。
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java; public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, boolean requireForeground, String callingPackage, int userId) throws TransactionTooLargeException { final ActiveServices mServices; ... // 这里的mServices是ActivityServices,跳转-> res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, requireForeground, callingPackage, userId); ... }
-
ActivityServices类是整个服务创建过程的主要逻辑类。基本上AMS接收到请求后就把事务直接交给ActivityServices来处理了,所以整个流程都在这里进行。ActivityServices主要是获取Service的信息ServiceRecord,然后判断各种信息如权限,进程是否创建等。然后再创建一个StartItem,这个StartItem是后续执行onStartCommand的事务。这里要注意一下他。
/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java; // 方法中涉及到mAm就是AMS final ActivityManagerService mAm; // 直接跳下个方法 ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId) throws TransactionTooLargeException { // 跳转下个方法 return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired, callingPackage, userId, false); } // 这一步主要是获取ServiceRecord。也就是服务的各种信息,来检查服务的各个资源是否已经完备 // 同时会新建一个StartItem,这个Item是后面负责回调Service的onStartCommand事务 ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId, boolean allowBackgroundActivityStarts) throws TransactionTooLargeException { ... // 这里会去查找ServiceRecord,和ActivityRecord差不多,描述Service的信息。 // 如果没有找到则会调用PackageManagerService去获取service信息 // 并封装到ServiceLookResult中返回 ServiceLookupResult res = retrieveServiceLocked(service, null, resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg, false, false); if (res == null) { return null; } if (res.record == null) { return new ComponentName("!", res.permission != null ? res.permission : "private to package"); } // 这里从ServiceLookResult中得到Record信息 ServiceRecord r = res.record; // 这里新建一个StartItem,注意他的第二个参数是false,这个参数名是taskRemove r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), service, neededGrants, callingUid)); ... // 继续跳转 ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); }
-
这一步主要是检查Service所在进程是否已经启动。如果没有则先启动进程。
/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java; ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) throws TransactionTooLargeException { ... // 继续跳转 String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false); if (error != null) { return new ComponentName("!!", error); } ... } // 此方法主要判断服务所在的进程是否已经启动,如果还没启动那么就去创建进程再启动服务; // 第一次绑定或者直接启动都会调用此方法 // 进程启动完了就调用realStartServiceLocked下一步 private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired) throws TransactionTooLargeException { ... // 这里获取进程名字。在启动的时候可以指定进程,默认是当前进程 final String procName = r.processName; HostingRecord hostingRecord = new HostingRecord("service", r.instanceName); ProcessRecord app; if (!isolated) { // 根据进程名字获取ProcessRecord app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); ... // 这里判断进程是否为空。如果进程已经启动那就直接转注释1;否则转注释2 // 创建进程的流程这里不讲,所以后面的逻辑直接进入启动service if (app != null && app.thread != null) { ... // 1 // 启动服务 realStartServiceLocked(r, app, execInFg); return null; } ... } // 如果进程为空,那么执行注释2进行创建进程,再去启动服务 if (app == null && !permissionsReviewRequired) { // 2 if ((app=mAm.startProcessLocked(procName, r.appInfo, true<