本文采用自述的方式带大家认识 ActivityManagerService 是啥,它有哪些功能,它的启动过程,它的模块有哪些以及模块的作用是啥。(文中代码基于Android13) 本文大纲 大家好,我是 ActivityManagerService ,我存在于systemserver进程,大家可以看到我的名字中带有Service这个单词,没错我是一个服务是一个binder服务,在systemserver进程中存在着很多像我一样的binder服务。
既然我是一个服务,那我肯定会提供很多的功能供我的使用方来使用,请大家上眼看下图:(下图只是罗列了一部分功能) 如上图,可以看到我提供的功能的使用方主要是App,它们与我不在同一进程,因此它们想要使用我的功能是需要通过ActivityManager和ActivityTaskManager进行binder调用来使用,这也就是为啥我被称为binder服务,而使用方自然被称为binder client。 从上图还可以看出凡是与Service、ContentProvider、BroadcastReceiver三大组件有关系的事情都归我 ActivityManagerService 负责,而Activity相关的事情都归 ActivityTaskManagerService 负责 (以下简称ATMS),其实在原先的Android版本中,Activity相关的事情是归我 ActivityManagerService 负责的,但是存在一个很大的问题,就是 ActivityManagerService 中的代码量越来越多,进而导致高耦合、难以维护等问题产生,为了解决这些问题故把Activity相关的事情放入了ATMS内。别看ATMS也是一个binder服务,但它还是归我 ActivityManagerService 管理的。 我虽然是一个服务,但是我更愿意称自己为集中处理中心,正如上图四大组件的启动、销毁及生命周期方法的变化这些事情统统都需要经过我进行处理。比如某App要启动一个Activity,那启动该Activity的事件会通知到ATMS,ATMS会进行一些检查,最终“批准”是否能启动该Activity;比如某个Service需要销毁了,那我会把销毁的事件通过binder通信通知相应的App;比如某个BroadcastReceiver需要接收广播了,则我会把广播内容通过binder通信发送给相应App。 你要是以为我的工作只是管理四大组件,那可是就小瞧我了,我可是systemserver进程中最忙碌、包含功能最多的服务,我还负责进程管理、App错误/崩溃管理、性能分析等事情。 为啥进程管理这么重要的事情交给我呢?其主要原因是每个App进程的产生源头都是由于四大组件的启动,也就是说只有启动四大组件才会导致App进程的产生,并且四大组件的生命周期变化都会导致App进程状态发生变化,比如一个App的最后一个Activity由resume状态变为stop状态,那该App就变为了后台进程。由于以上原因,我就把进程管理功能也据为己有了。 进程管理就是管理App进程,比如App死亡了,那进程管理就需要把该App对应的进程信息进行销毁处理;比如App由前台退到后台了,那进程管理就需要把App对应进程的进程状态置为后台状态,并且为进程计算一个oom_score (一个分数值),该分数值和该进程id会交给 lmkd进程 , lmkd进程 会在低内存的时候根据oom_score杀掉对应进程以释放内存。当然进程管理可不止上面这点内容,后面文章会有详细介绍。 App错误/崩溃管理就是在App由于crash/ANR (Application not response)/自杀等原因导致App死亡,该模块会负责处理App死亡的相关事情,比如收集崩溃的堆栈信息,记录App死亡的信息等。性能分析可以帮助罗列出每个App占用的内存大小等这些数据,来帮助进行性能分析。 大家对我拥有的能力有一定了解后,会不会有一种感觉,觉得我的名字 ActivityManagerService 是完全没有把我具有的能力表达出来的,还以为我只与Activity有关系。确实是这样的,我也一直在为这个“不合格的名字”而烦恼。但烦恼有啥用啊,已经是既定事实了,那只能接受了。 以上就是关于我的一个介绍,因为我在整个Android系统中非常的有名气,就像大家对名人/伟人的成长史有非常浓厚的兴趣一样,大家肯定对于我的“成长史”,也就是我的的启动过程也非常的感兴趣,那我就毫不保留的分享给大家。
在介绍我的启动过程之前,我觉得非常有必要给大家简单介绍一个背景知识SystemServer启动(SystemServer是一个类),为啥要介绍SystemServer启动呢?首先因为我的启动过程是SystemServer启动过程中的一部分,我启动成功与否会关系到SystemServer启动成功与否;其次SystemServer启动时会发送各种阶段值,而和我 ActivityManagerService 有关的阶段值就有俩。 2.1 背景知识 systemserver进程被zygote进程fork成功后,SystemServer启动就是重头戏了,而SystemServer的启动过程其实就是各种服务的启动过程,只有SystemServer启动成功后,Android设备才可以被用户使用。下图展示了SystemServer启动过程的主要方法:(下面的方法都属于SystemServer类) 因为systemserver进程包含的服务非常多,那该如何保证这些服务顺利启动呢,SystemServer把所有的服务分类为bootstrap service、core service、other service、apex service这四种类型。先在 startBootstrapServi ces 方法中启动bootstrap类型的服务,其次在 startCoreServices 方法中启动core类型的服务,再次在 startOtherServices 方法中启动other类型的服务,最后在startApexServices启动apex类型的服务。因此SystemServer启动过程就是依照上面的顺序启动各种服务,而我 ActivityManagerService 很荣幸属于bootstrap类型的服务,因此是最早被初始化,为啥是初始化呢,因为 A ctivityManagerService 的真正启动过程还在后面流程中。 2.1.1 阶段值 (phase) 对所有的服务进行分类,只是解决了它们启动先后的问题,而服务与服务之间是存在依赖关系的,比如 InputManagerService 、 WindowManagerService 等是需要知道 ActivityManagerService 是否启动完成了,当得知 ActivityManagerService 启动完成后,才可以使用它提供的功能比如注册广播接收器、发送广播等。而解决这个问题的办法就是发送阶段值 (phase),下图展示了SystemServer启动过程中发送的阶段值: 如上图,在SystemServer的启动过程中会分发不同的阶段值,不同的阶段值所代表的含义各不相同,服务收到这些阶段值就可以知道当前是到了哪个启动阶段了,同时根据自己的需求来做不同的事情。 PHASE_WAIT_FOR_DEFAULT_DISPLAY 代表当前阶段正在等待获取显示屏幕的硬件信息,这时候SystemServer的启动过程就暂时处于暂停状态,若屏幕硬件信息获取失败则停止启动;否则继续启动。 PHASE_ACTIVITY_MANAGER_READY 代表 ActivityManagerService 已经准备好了,其他的服务可以使用 ActivityManagerService 提供的服务了,比如发送广播。 PHASE_BOOT_COMPLETED 代表SystemServer启动完成了,所有的服务都已经准备好“进入工作状态”了,Android设备可以被用户使用了 (当然这只是解释几个常用的阶段值)。 想了解更多SystemServer的内容,可以看 此文章 2.1.2 小结 ActivityManagerService 的启动过程对于SystemServer的启动来说非常重要, ActivityManagerService 在 StartBootstrapServices 方法中被初始化,在 StartOtherServices 方法做收尾工作。 而 PHASE_ACTIVITY_MANAGER_READY 、 PHASE_BOOT_COMPLETED 这两个阶段值是与 ActivityManagerServi ce 有关系的。 PHASE_ACTIVITY_MANAGER_READY 自不用说代表我 ActivityManagerService 已经准备好了。而 PHASE_BOOT_COMPLETED 阶段值是由我发送的,我再重复一遍PHASE_BOOT_COMPLETED这个值可是由我来发送的 。 2.2 启动步骤 好了背景知识介绍完毕后,那来看下我的启动分为哪些步骤,请大家看下图 如上图,我的启动可以分为出生、设置系统进程、准备、等待boot anim完成 这四个步骤,出生这个步骤发生于 startBootstrapServices 方法的最前面,而设置系统进程这个步骤发生于 startBootstrapServices 方法的中间部分,准备这个步骤发生于 startOtherServices 方法的结尾部分,而等待boot anim则是最后一个步骤。可以看到 ActivityManagerService 的启动贯穿了Systemserver启动流程的全过程。那就按这四个步骤来介绍下我的启动吧。 2.3 出生 别看我是一个服务,但我也像其他类一样也是一个类,我的“出生”是指创建一个 ActivityManagerService 实例,而我的“出生地”是在SystemServer类的 startBootstrapServices 的方法中,既然创建 ActivityManagerService 实例,那肯定需要调用它的构造方法,在 ActivityManagerService 的构造方法中对很多的属性做了初始化的操作,以下列出了对主要属性做的一些初始化操作: mProcessList属性 ,它是ProcessList类型,它负责进程管理的工作,会构造该类型的实例,并且调用它的init方法进行初始化。 mAppProfiler属性 ,它是AppProfiler类型,它负责性能分析的工作,会创建该类型的实例。 mOomAdjuster属性 ,它是OomAdjuster类型,它也负责进程管理的工作,同样也会创建该类型的实例。 mFgBroadcastQueue、mBgBroadcastQueue、mBgOffloadBroadcastQueue、mFgOffloadBroadcastQueue 都是BroadcastQueue类型的,它们对BroadcastReceiver进行管理,同样也会创建这些类型的实例。 mServices属性 ,它是ActiveServices类型,它对Service进行管理,同样也会创建该类型的实例。 mCpHelper属性 ,它是ContentProviderHelper类型,它对ContentProvider进行管理,同样也会创建该类型的实例。 mAppErrors属性 ,它是AppErrors类型,它对App的死亡进行管理,同样也会创建该类型的实例。 上面只是列出了主要的属性初始化,在 ActivityManagerService 构造方法中还对其他的属性进行了初始化,自此我 ActivityManagerService 就“出生”了,在内存中占有了一席之地。 2.4 设置系统进程 我虽然“出生”了,但是我所在的systemserver进程很多信息还没有设置,它就犹如一个“黑户”的存在。大家都知道我有一个功能是进程管理,而进程管理有一个规定就是凡是App进程甚至包含systemserver进程在被创建后,都需要使用ProcessRecord对象把进程信息记录下来,这样进程管理才可以更好的对进程进行管理。 并且 lmkd进程 也同样有一个规定,就是需要进程管理把进程的pid、 oom_score 交给它,这样它才可以查杀进程,而这里的进程是所有的App进程和systemserver进程,因此进程管理也需要把systemserver进程的pid和它的 oom_score 传递给lmkd进程。 而上面这些事情就是设置系统进程这一步所要做的,当然还做了别的一些事情。因为我具有进程管理的功能,因此设置系统进程的事情就落在了我的头上。设置系统进程同样也发生于 startBootstrapServices 方法,那该步到底都做了哪些事情呢,那就听我细细道来。 2.4.1 添加到ServiceManager服务 大家都知道我是一个binder服务,并且我是一个具名binder服务,为了让使用方能使用到我提供的这些能力,我需要做的一件事情就是把我自己添加到ServiceManager服务中,ServiceManager服务是位于servicemanager进程的服务,它的作用就是管理所有的具名binder服务。当然除了把我自己添加到ServiceManager服务外,还把其他的binder服务也加到了ServiceManager服务中,请看下面代码: //ActivityManagerService public void setSystemProcess () { 省略代码······ //Context.ACTIVITY_SERVICE的值是activity,下面方法把ActivityManagerService加入到ServiceManager服务中 ServiceManager.addService(Context.ACTIVITY_SERVICE, this , /* allowIsolated= */ true , DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO); //下面代码把其他具名binder服务加入到ServiceManager服务中 ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats); ServiceManager.addService("meminfo" , new MemBinder(this ), /* allowIsolated= */ false , DUMP_FLAG_PRIORITY_HIGH); 省略代码······ }
2.4.2 创建ProcessRecord 创建ProcessRecord对象把systemserver进程信息保存下来。大家都知道每个App进程都有对应的包名,而systemserver进程也不例外,我把它的包名定义为android,下面代码做了以上这些事情: //ActivityManagerService public void setSystemProcess () { 省略代码······ //创建包名为 android 的ApplicationInfo对象 ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( "android" , STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY); mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader()); synchronized (this ) { //创建ProcessRecord对象 ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName, false , 0 , false , 0 , null , new HostingRecord(HostingRecord.HOSTING_TYPE_SYSTEM)); app.setPersistent(true ); //设置为persistent app.setPid(MY_PID); app.mState.setMaxAdj(ProcessList.SYSTEM_ADJ);//设置最大adj值,SYSTEM_ADJ的值为-900 app.makeActive(mSystemThread.getApplicationThread(), mProcessStats); app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_SYSTEM); addPidLocked(app); //把app保存到ProcessLisst对象中 updateLruProcessLocked(app, false , null ); } 省略代码······ }
2.4.3 传递信息给lmkd进程 lmkd进程 规定在查杀进程的时候是按照 oom_score 从高到低进行查杀,也就是 oom_score 越高越先被杀掉。而我所在systemserver进程那可是非常非常重要的进程,肯定是不能随随便便让lmkd杀掉的,因此我把systemserver进程的 oom_score 设置为一个固定的值-900,这样lmkd就不会杀掉它了。如下是相应代码: //ActivityManagerService public void setSystemProcess () { 省略代码······ //下面方法,会更新进程的oom_score及进程状态等信息,并且会把进程的新的oom_score及pid发送给lmkd进程 updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); 省略代码······ }
2.4.4 小结 经过此步骤,我被添加到ServiceManager服务中,这样我的使用方比如各种App就可以使用我的功能了。我所在的systemserver进程被ProcessRecord对象记录下来,并且它不再“无名无姓”了,它的包名就是android。这样进程管理就可以对systemserver进程进行管理了。同时systemserver进程的pid和 oom_score:-900 信息也传递给lmkd进程,便于lmkd更好的查杀进程。 经过此步骤后,SystemServer后面的启动流程中各种服务就可以从进程管理根据包名android拿到systemserver进程对应的ProcessRecord对象,进而做相应的处理了。 2.5 准备 SystemServer的启动流程依然在继续进行,经过 startBootstrapServices 、 startCoreServices 方法后,进入到 startOtherServices 方法的尾声时,这时候SystemServer的启动算是接近了尾声。而SystemServer会调用我 ActivityManagerService 的 systemReady 方法,告知我系统准备好了,但是准备好并不代表Android设备可以被用户使用了,而要达到完全可以工作状态,那剩下的事情还需要我来处理。自此我的启动进入了准备这一步。 而准备这一步又被我划分为准备前、准备好、准备后 这三小步,那就依次来介绍下它们吧。 2.5.1 准备前 在“出生”那一步的时候, ActivityManagerService 实例被创建并且它包含的很多属性也被初始化,比如四大组件的管理类。虽然它们被初始化了,但是系统准备好这个激动人心的消息它们还一无所知,而准备前这一步,我会把系统准备好这个消息通知给它们,当然还做一些别的工作,请看下面代码: //ActivityManagerService public void systemReady (final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) { 省略代码······ synchronized (this ) { 省略代码······ mLocalDeviceIdleController = LocalServices.getService(DeviceIdleInternal.class); //告知相应模块,系统已经准备好了 mActivityTaskManager.onSystemReady(); // Make sure we have the current profile info, since it is needed for security checks. mUserController.onSystemReady(); mAppOpsService.systemReady(); mProcessList.onSystemReady(); mAppRestrictionController.onSystemReady(); mSystemReady = true ; } 省略代码······ retrieveSettings();//检索一些数据从settings了或者其他地方,并且用这些数据来初始化一些属性 省略代码······ }
2.5.2 准备好 准备前的事情做完后,我就进入准备好这一步,因为我及所有的属性都准备好了,可以很好的工作了,因此我会把 PHASE_ACTIVITY_MANAGER_READY 这个阶段值发送出去,告知各种服务,我 ActivityManagerService 已经准备好了啊,你们可以使用我的提供的服务了啊。 private void startOtherServices(@NonNull TimingsTraceAndSlog t) { 省略代码······ mActivityManagerService.systemReady(() -> { 省略代码······ // 发送PHASE_ACTIVITY_MANAGER_READY阶段值 mSystemServiceManager.startBootPhase(t, SystemService.PHASE_ACTIVITY_MANAGER_READY); 省略代码······ }
2.5.3 准备后 我把我准备好的消息告知所有服务后,我还得继续回来把剩余的事情做完,其中最重要的一件事情是启动launcher,只有launcher启动起来后Android设备才可以被用户使用。 //ActivityManagerService public void systemReady (final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) { 省略代码······ mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady" ); //启动launcher 省略代码······ }
2.6 等待boot anim完成 首先我来介绍下boot anim,它是在Android系统启动过程中显示的一个启动动画,这个启动动画消失后才可以代表Android设备完全可以被用户使用了,而该动画消失的一个前提是launcher已经启动完成了。而我在收到launcher启动完成的消息后会发送 PHASE_BOOT_COMPLETED 阶段值,该值一发出去后,就代表Android设备可以被用户使用了,所有的服务都打起精神来进入工作状态了。 ActivityManagerServicefinal void finishBooting () { 省略代码······ // Let system services know. mSystemServiceManager.startBootPhase(t, SystemService.PHASE_BOOT_COMPLETED); 省略代码······ }
2.7 小结 我的启动贯穿了SystemServer启动的整个流程,如下是启动过程所做的事情: 在SystemServer最先启动的时候,会创建 ActivityManagerService 的实例,并且初始化它包含的各种属性 我还承担了设置系统进程的任务,我会创建ProcessRecord对象把systemserver进程信息记录下来,并且为systemserver进程提供android这样的包名,这样systemserver进程就可以被记录并且被进程管理进行管理了,同时我还会把systemserver进程的pid和 oom_score:-900 的信息传递给lmkd进程 在准备阶段我会把 PHASE_ACTIVITY_MANAGER_READY 这个阶段值发送给所有服务,并且还会启动launcher,启动launcher可是一个系统能不能被使用的一个重要环节 当收到launcher启动完成的消息后,boot anim会消失,这时候我会发送 PHASE_BOOT_COMPLETED 阶段值,该值可是代表Android设备可以被用户使用了。 既然Android系统已经启动完成了,systemserver进程中的服务以及其他的各种服务都已经进入“工作状态”了,那接下来我给大家介绍下我的“小伙伴”吧,正是由于它们的帮助才能保证我 ActivityManagerService 的工作能够顺利进行。
大家大可不必把我想象成超人,能胜任这么多复杂的工作,完全是由我和我的“小伙伴”们一起完成的,先来通过下图来认识下我的主要“小伙伴”
如上图,我的主要“小伙伴”有Activity管理模块、Service管理模块、BroadcastReceiver管理模块、ContentProvider管理模块、进程管理模块、App错误管理模块、App性能分析模块 ,当然我还有别的不是很重要的模块没有展示出来,那就依次把我的“小伙伴”介绍给大家吧。 3.1 Activity管理模块 Activity管理模块的主要作用是管理整个Android系统中的所有Activity,比如Activity的启动,Activity的pause,Activity的stop等可都是要经过该模块,而每个被启动的Activity是使用一个ActivityRecord对象保存的,我把该模块所做的事情全权委托给了 ActivityTaskManagerService 类,该类也是一个binder服务。关于该模块就暂时介绍到这,后面文章会详细介绍它。 3.2 Service管理模块 Service管理模块的主要作用是管理所有的Service,Service的启动、销毁等等都是该模块负责,而每个被启动的Service是使用一个ServiceRecord对象保存的,我同样把该模块所做的事情交给了ActiveServices类,该类可不是一个binder服务。 3.3 BroadcastReceiver管理模块 BroadcastReceiver管理模块的主要作用是管理所有的BroadcastReceiver,而每个被启动的BroadcastReceiver是使用一个BroadcastRecord对象保存的,我同样把该模块所做的事情交给了BroadcastQueue,而关于BroadcastQueue的分类可是有好几种分发,会在后面专题中详细介绍。 3.4 ContentProvider管理模块 ContentProvider管理模块的主要作用是管理所有的ContentProvider,而每个被启动的ContentProvider同样使用一个ContentProviderRecord对象保存的,我同样把该模块所做的事情交给了ContentProviderHelper类。同样会在后面有专题详细介绍该模块。 3.5 进程管理模块 上面的四个模块所做的事情是管理四大组件,而我除了管理四大组件外我还有非常重要的一个功能就是进程管理,而进程管理主要是进程管理模块在负责,进程管理模块所做的事情主要由ProcessList和OomAdjuster两个类完成,那就来看下进程管理模块都做了哪些事情吧。 首先在App进程开始孵化(fork)之前,ProcessList会使用ProcessRecord对象来保存App进程,ProcessList把孵化 (fork)App进程的请求发送给zygote进程,zygote进程孵化成功App进程后,ProcessList会收到这个消息,进而把孵化成功的App进程的pid (进程id)等信息保存到ProcessRecord对象中。因此ProcessList中保存了所有的App进程。 进程管理模块所做的事情可不是仅仅把App进程保存起来这么简单,不知道大家是否记得lmkd进程 (不记得可以看 lmkd进程杀手 这篇文章),lmkd进程的主要作用是根据内存的使用情况来杀掉分数最高的进程,而具有运行Java/Kotlin代码的进程的分数是由OomAdjuster来完成的,OomAdjuster会对所有的进程都计算出一个分数 (oom_score),比如当前正在显示的Activity对应的App的分数值是0,并且把分数、进程id、uid这些信息发送给lmkd进程。 OomAdjuster在计算每个进程的分数时,也同时会计算出每个进程对应的进程状态 (procState),比如正在显示的Activity对应的进程状态值是PROCESS_STATE_TOP (它的值是2),和进程分数一样,进程状态值越大越容易被杀掉以及分配的资源越少。 当然除了依靠lmkd进程杀进程外,OomAdjuster也会在合适的时机根据一些条件来把进程状态为 PROCESS_STATE_CACHED_EMPTY 或者 PROCESS_STATE_CACHED_ACTIVITY 或者 PROCESS_STATE_CACHED_ACTIVITY_CLIENT 的进程杀掉,这个杀进程的过程可是不需要lmkd进程参与的。 对于一些处于后台又没有BroadcastReceiver或者Service或者ContentProvider运行的进程,该模块会选择把它冻结或者杀死,负责冻结功能的类是CachedAppOptimizer。 这里只是先简单带大家认识进程管理模块,同样也会在后面专题中着重介绍它。 3.6 App错误管理模块 App进程同生物的生命一样也会存在生、死,当App进程死掉的时候,不管是由于崩溃或者ANR (Application not response)或者自身原因的死掉,都需要App错误管理模块来处理App进程的“后世”,若App死掉该模块会把App进程当时死掉的堆栈状态保存下来,如果是由于ANR导致的死亡,也会把ANR的各种信息保存下来。负责该模块的主要类是AppErrors。 App进程在死掉的时候,也会把App进程死掉的相关重要信息保存在文件中,而做这个工作的类是AppExitInfoTracker,当然除了做这些工作之外,还有其他的工作内容就暂时不细说了。 3.7 App性能分析模块 App性能分析模块的主要作用是可以统计每个App进程所暂用的CPU资源、内存的使用情况等数据,负责该模块的主要类是AppProfiler,关于该模块会在后面专题详细介绍。 3.8 小结 通过上面的介绍大家应该对我 ActivityManagerService 和我的主要模块有了一个清晰的了解,当然对以上模块的介绍只是先简单带大家认识它们,后面会有各自专题详细的介绍它们。
本文带大家认识了 ActivityManagerService ,及它的启动过程以及它的各个模块及模块作用。因为 ActivityManagerService 的功能实在是太多了,一两篇文章是根本不可能把它的“魅力”全部都给展示出来的,因此后面的文章会针对每个模块进行详细的介绍,比如进程管理、Activity管理、OomAdj、Service管理、ANR及ANR分析等内容,欢迎大家关注我。