第七章 ActivityManagerService(AMS):Android系统的“大管家”

说实话,在Android Framework里,AMS是我个人觉得最“有灵魂”的一个服务。它不像Binder那样只是个通信工具,也不像SurfaceFlinger那样只管画图。AMS管的是啥?它管的是你手机上每一个App的“生老病死”——启动、运行、切换、销毁,全在它手里。

我刚开始啃AMS源码的时候,说实话有点懵。代码量太大了,光一个AMS.java就上万行。但后来我找到了一个方法:别把它当代码看,把它当“操作系统”看。AMS本质上就是一个进程和组件的调度中心。今天我们就来拆开它,看看它到底是怎么工作的。

核心要点:AMS是Android系统中管理Activity、Service、BroadcastReceiver、ContentProvider以及进程优先级的核心服务。它运行在SystemServer进程中,是Framework层的“大脑”。

7.1 AMS启动流程:从SystemServer到世界主宰

AMS是怎么启动的?嗯,这得从SystemServer说起。SystemServer是Zygote孵化出的第一个Java进程,它负责启动所有系统服务。

在SystemServer的run()方法里,会调用startBootstrapServices()startCoreServices()startOtherServices()这几个方法。AMS就是在startBootstrapServices()里被创建的。

// 简化后的AMS启动流程
private void startBootstrapServices() {
    // 1. 创建AMS实例
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class);
    
    // 2. 设置系统进程
    mActivityManagerService.setSystemProcess();
    
    // 3. 安装系统Provider
    mActivityManagerService.installSystemProviders();
}

这里有个细节我想提一下。AMS的构造函数里会创建mHandlerThread,也就是AMS自己的消息循环线程。为什么需要这个?因为AMS要处理大量的跨进程调用,如果都在主线程里搞,系统UI就卡死了。我在项目里遇到过一个问题:某个三方App频繁启动Activity,导致AMS的Handler消息队列积压,整个系统都变得迟钝。后来我们加了一个限流策略,才把问题解决。

个人经验:AMS启动后,会调用setSystemProcess()把自己注册到ServiceManager中。这时候其他进程就能通过Binder拿到AMS的代理了。但注意,此时AMS还没完全准备好——它还需要等待systemReady()被调用,才能开始处理App的请求。

7.2 Activity栈管理:TaskRecord与ActivityRecord

Activity栈管理,说白了就是管理“哪个Activity在哪个任务里”。AMS用两个核心数据结构来干这事:ActivityRecordTaskRecord

  • ActivityRecord:代表一个Activity实例。它记录了Activity的状态、Intent、所在进程等信息。
  • TaskRecord:代表一个任务栈。它包含了一组ActivityRecord,这些Activity按启动顺序排列。

你想想看,当你在手机上点开一个App,再点开另一个App,再切回来——这些操作背后,AMS都在维护一个叫mStackSupervisor的对象。它管理着所有的TaskRecord和ActivityRecord。

// Activity栈的核心数据结构(简化)
class ActivityStackSupervisor {
    // 所有任务栈
    ArrayList<TaskRecord> mTaskHistory;
    
    // 当前聚焦的栈
    TaskRecord mFocusedStack;
    
    // 根据Intent查找或创建Task
    TaskRecord findTaskToMoveToFront(TaskRecord task, int flags, 
                                      ActivityRecord source) {
        // 查找逻辑...
    }
}

我记得有一次调试一个“App启动后闪退”的问题,查了半天发现是TaskRecord的mActivities列表里出现了空指针。原因是某个Activity被销毁后,AMS没有及时清理它的ActivityRecord引用。嗯,这种边界情况在源码里其实挺多的。

避坑指南:我曾经在适配Android 10时发现,launchMode="singleTask"的Activity在特定场景下会创建新的Task,而不是复用已有的。原因是AMS在startActivityUnchecked()中判断Task归属时,会检查taskAffinity属性。如果没设置,默认使用包名,这就可能导致“看起来应该复用,实际上新建了”的情况。

7.3 Activity生命周期管理:谁在背后调度?

Activity的onCreate()onResume()onPause()这些方法是谁调用的?很多人以为是App自己,其实不是。这些调用都来自AMS。

AMS通过ApplicationThread这个Binder接口,向App进程发送生命周期变更的请求。App进程收到请求后,再通过ActivityThreadH(Handler)把消息分发到主线程,最终调用Activity对应的方法。

// AMS端:通知App进入Resume状态
void resumeActivity(IBinder token, ...) {
    // 找到对应的ActivityRecord
    ActivityRecord r = ActivityRecord.forToken(token);
    
    // 通过ApplicationThread通知App
    r.app.thread.scheduleResumeActivity(r.appToken, ...);
}

// App端:收到通知后执行
private class H extends Handler {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case RESUME_ACTIVITY:
                // 最终调用Activity.onResume()
                handleResumeActivity(...);
                break;
        }
    }
}

这里有个关键点:AMS和App进程之间的通信是异步的。AMS发送一个schedulePauseActivity()后,不会傻等App处理完。它会继续处理其他请求。那怎么保证生命周期顺序呢?靠的是ActivityRecord里的状态机。

每个ActivityRecord都有一个state字段,取值如INITIALIZINGRESUMEDPAUSEDSTOPPED等。AMS在切换状态前,会检查当前状态是否合法。比如,你不能从一个STOPPED的Activity直接跳到RESUMED——必须先经过STARTED

核心逻辑:Activity的生命周期管理,本质上是AMS和App进程之间通过Binder进行状态同步的过程。AMS维护全局状态,App维护本地状态,两者通过ApplicationThread保持一致性。

7.4 进程优先级与OOM调整:谁该被杀死?

Android系统有个特点:它不会主动杀死进程。当内存不足时,它会根据优先级选择“最不重要”的进程杀掉。这个优先级就是由AMS来维护的。

AMS为每个进程维护一个ProcessRecord,里面有个maxAdj字段,代表进程的OOM调整值。这个值越小,进程越不容易被杀死。

进程类型 adj值 典型场景
系统进程 -1000 SystemServer
前台进程 0 当前正在交互的App
可见进程 100 Activity可见但不在前台
服务进程 200 正在运行Service的App
后台进程 300 Activity已暂停的App
空进程 900 没有任何组件的进程

AMS会在updateOomAdjLocked()方法中,遍历所有进程,重新计算它们的adj值。计算依据是什么?主要是看进程里有哪些组件正在运行。

举个例子:如果一个进程里有一个前台Activity,那它的adj就是0。如果这个Activity被暂停了,但还有一个前台Service在运行,那adj会变成200。如果Service也停了,那就变成300。

我遇到过一个问题:某个App在后台播放音乐,但用户切到其他App后,音乐被卡顿了。查下来发现,AMS把那个进程的adj算成了300(后台进程),结果系统内存紧张时把它杀了。解决方案是让音乐播放使用前台Service,这样adj就变成了200,被杀的概率大大降低。

个人建议:如果你想让自己的App在后台更“抗杀”,可以考虑使用前台Service。但注意,前台Service会显示一个通知,用户是可以关掉的。另外,不要滥用这个机制——我曾经见过一个App,为了保活,开了5个前台Service,结果被用户骂惨了。

7.5 知识体系总览

下面这张图是我自己整理的AMS核心知识结构。你可以把它当作一个“地图”,以后遇到相关问题,先定位到图中的某个节点,再深入细节。

ActivityManagerService 启动流程 Activity栈管理 生命周期管理 进程优先级与OOM SystemServer启动 TaskRecord ActivityRecord ApplicationThread ProcessRecord AMS是Android系统的核心调度器,管理着所有App的启动、运行和销毁

这张图把AMS的核心职责分成了四个部分:启动流程、栈管理、生命周期、进程优先级。每个部分之间都有联系——比如,启动一个Activity会涉及栈管理和生命周期,而进程优先级又会影响Activity能否正常运行。

好了,关于AMS的核心内容就讲到这里。说实话,AMS的代码量很大,但核心逻辑并不复杂。你只要抓住“状态机”和“Binder通信”这两条主线,就能看懂大部分代码。下次遇到App启动慢、闪退、被杀等问题,不妨先从AMS的角度去分析——说不定会有意想不到的收获。

公众号:蓝海资料掘金营,微信deep3321