3. AMS初始化流程与SystemServer集成:main函数、注册服务、binder线程池
AMS(ActivityManagerService)的初始化是SystemServer启动的核心环节。本章将剖析AMS从main函数入口到SystemServer集成,再到binder线程池建立的全过程。掌握这一流程后,你将能够理解AMS如何作为Android系统“大管家”在开机时完成就绪,并为后续的服务注册、Activity管理打下基础。
3.1 SystemServer.main() —— 启动入口
Zygote进程通过fork创建SystemServer进程后,执行的第一行Java代码是SystemServer.main()。该函数位于frameworks/base/services/java/com/android/server/SystemServer.java。其核心工作流如下表所示:
| 阶段 | 关键操作 | 线程/进程上下文 |
|---|---|---|
| ① 初始化SystemServer | 调用SystemServer()构造,加载本地库android_servers |
主线程 |
| ② 启动ServerThread | 创建ServerThread线程并运行run() |
主线程→子线程 |
| ③ 加载系统服务 | 在ServerThread.run()中按序启动引导服务、核心服务、其他服务 |
ServerThread |
| ④ 注册服务到ServiceManager | 调用ServiceManager.addService("activity", ams) |
ServerThread |
| ⑤ 进入Looper循环 | 主线程(或ServerThread)开始消息循环,等待binder请求 | ServerThread |
关键点:SystemServer进程内部使用ServerThread(实为SystemServiceManager驱动的线程)来串行化服务启动,避免竞态。AMS必须在binder线程池就绪后才能被注册,否则其他进程无法通过binder调用到AMS。
// frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
// … 设置系统属性、加载本地库 …
// 创建消息循环
Looper.prepareMainLooper();
// 初始化系统上下文
createSystemContext();
// 创建SystemServiceManager
mSystemServiceManager = new SystemServiceManager(mSystemContext);
// 启动服务
try {
startBootstrapServices(); // 包含AMS
startCoreServices();
startOtherServices();
} catch (Throwable ex) { … }
// 循环等待
Looper.loop();
}
3.2 AMS的创建与ServiceManager注册
在startBootstrapServices()中,AMS通过mSystemServiceManager.startService(ActivityManagerService.class)被实例化并初始化。初始化完成后,立即向ServiceManager注册,使得其他进程可以通过ServiceManager.getService("activity")获取AMS的binder代理。
// SystemServer.java startBootstrapServices()
private void startBootstrapServices() {
// … 安装Provider …
// 启动AMS
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.class);
// 注册到ServiceManager
ServiceManager.addService(Context.ACTIVITY_SERVICE, mActivityManagerService);
// … 后续服务 …
}
注意:AMS的构造函数会触发大量初始化,包括进程记录、权限控制、内存管理等。如果此处抛出异常,SystemServer会直接崩溃导致设备重启。调试时可在ActivityManagerService.java构造函数中打日志,观察Binder线程池是否已启动。
3.3 Binder线程池初始化
Binder通信依赖线程池来处理跨进程请求。系统服务在加入ServiceManager之前,必须先确保ProcessState已经启动binder线程池。Android系统在Zygote阶段就已经通过ProcessState::self()->startThreadPool()启动了C++层的binder线程池,但Java层的BinderInternal也会在SystemServer中做最终确认。AMS的onStart()方法中调用了BinderInternal.setThreadPolicy(...)以及ProcessState::self()->setThreadPoolMaxThreadCount(...)来调整线程数。关键代码如下:
// ActivityManagerService.java onStart()
@Override
public void onStart() {
// 发布内部服务
publishBinderService(Context.ACTIVITY_SERVICE, this);
// 设置binder线程池最大线程数(通常为4)
Process.setThreadPoolMaxThreadCount(4);
// 启动binder线程池(如果尚未启动)
BinderInternal.setThreadStarvationCheckEnabled(true);
// … 其他初始化 …
}
原理说明:Binder线程池的默认大小为16(framework侧),但AMS服务由于高频调用,通常会通过setThreadPoolMaxThreadCount限制为4~8个线程,避免过多线程导致锁竞争。你可以通过Process.getThreadPoolMaxThreadCount()在运行时查看当前值。
3.4 完整初始化流程图
下图总结了AMS从SystemServer启动到Binder线程池就绪的完整流程:
3.5 关键代码与调试技巧
- 验证AMS是否注册成功:在设备上执行
adb shell service list | grep activity,若能输出类似Found 1 services: activity则表示注册成功。 - binder线程池状态监控:抓取trace时关注
Binder: thread pool相关日志,若出现Binder: thread pool starved说明线程不够用,可增大setThreadPoolMaxThreadCount的值。 - AMS初始化故障定位:如果设备在开机动画后反复重启,可抓取
logcat -b system,搜索ActivityManagerService或SystemServer异常堆栈。
// 查看当前binder线程池信息 (root权限)
adb shell su -c dumpsys activity | grep "binder"
// 通常输出类似:
// Binder: thread pool size: 8, max: 8, starved: 0
性能优化建议:在低内存设备上,可以将AMS的binder线程池上限从8调整为4,减少线程栈占用内存。调整位置:ActivityManagerService.java的onStart()方法中修改Process.setThreadPoolMaxThreadCount(4)。