“没人调用的代码”是怎么跑起来的?——彻底搞懂系统组件的启动与调用链
发布日期:2025年12月28日
核心标签:AOSP架构、系统服务启动、Binder调用链、Framework API、HAL交互、客制化实战
引言:你是不是也这样困惑过?
你在 AOSP 源码里翻来覆去地看:
“这个
WindowManagerService.java里全是方法,比如openWindow()、addWindow()……
可我搜遍整个项目,都找不到谁在调用它!
难道这些代码是‘死代码’?那 Android 的窗口是怎么弹出来的?”
别急——不是没人调用,而是调用者藏得太深。
就像你家的电灯开关,你按一下就亮,但你不知道背后是电网、变压器、继电器、电线在协同工作。
AOSP 也一样:表面是“函数定义”,背后是一整套“操作系统级调度机制”。
今天,我们就用“拆解一台智能冰箱”的方式,把 AOSP 的系统组件、中间件、调用链,从上到下、从里到外讲得明明白白。
第一章:AOSP 不是 App,它是“操作系统工厂”
🏭 比喻:AOSP 是一座四层自动化工厂
| 楼层 | 名称 | 谁在这里工作? | 产出什么? |
|---|---|---|---|
| 4楼 | 应用层(App) | 用户、第三方开发者 | 微信、抖音、你的 Launcher |
| 3楼 | 框架层(Framework) | 系统工程师 | ActivityManager,LocationManager(给 App 用的接口) |
| 2楼 | 系统服务层(SystemService) | 核心守护者 | ActivityManagerService,WindowManagerService(真正干活的) |
| 1楼 | 硬件抽象层(HAL + Kernel) | 厂商驱动工程师 | 控制摄像头、LED、电池的底层代码 |
✅ 关键理解:
- App 在 4 楼按按钮(调用 API);
- 3 楼的“前台接待”(Framework API)接单;
- 单子通过“内部对讲机”(Binder)传到 2 楼;
- 2 楼的“老师傅”(SystemService)干活;
- 如果需要硬件,就打电话给 1 楼(HAL/Kernel)。
所以,你看到的WindowManagerService.addWindow(),就是 2 楼老师傅的“手艺”,不是没人用,而是用它的人在 4 楼,通过 3 楼转达!
第二章:三大“神秘组件”揭秘——它们到底怎么被调用的?
🔍 组件类型 1:系统服务(SystemService)
代表:ActivityManagerService,PackageManagerService,BatteryService
❓ 问题:谁在 new 它?谁在调用它的方法?
✅ 答案:SystemServer 是“总调度员”
- 启动时刻:手机开机后,
init进程拉起zygote,zygote拉起system_server; - 关键代码(
SystemServer.java):// frameworks/base/services/java/com/android/server/SystemServer.java private void startBootstrapServices() { mActivityManagerService = new ActivityManagerService(...); ServiceManager.addService("activity", mActivityManagerService); // 注册! } - 注册后,这个服务就进入了“全局电话簿”(
ServiceManager),任何人都能查到。
📞 调用过程(以 startActivity 为例):
[微信 App] └─ 调用 startActivity() ↓ [Framework 层:Activity.java] └─ 转发给 IActivityManager.Stub.Proxy ↓ (通过 Binder 驱动跨进程) [SystemServer 进程] └─ IActivityManager.Stub.onTransact() ↓ ActivityManagerService.startActivity() ← 真正执行!💡 所以你在
ActivityManagerService里看不到“谁调用了我”——
因为任何 App 都可以通过字符串 "activity" 找到你!这是动态查找,不是硬编码调用。
🔍 组件类型 2:Framework API(给 App 用的接口)
代表:Context.getSystemService(),SensorManager,CameraManager
❓ 问题:LocationManager.getLastKnownLocation()是怎么连到后台服务的?
✅ 答案:AIDL 自动生成“代理对讲机”
你写 AIDL:
// ILocationManager.aidl interface ILocationManager { Location getLastKnownLocation(); }编译时,AOSP 自动生成两个类:
ILocationManager.Stub→ 服务端存根(在 SystemServer 中)ILocationManager.Stub.Proxy→ 客户端代理(在 App 中)
App 调用时:
LocationManager lm = (LocationManager) context.getSystemService(LOCATION_SERVICE); lm.getLastKnownLocation(); // 实际调用 Proxy→ Proxy 把参数打包,通过 Binder 发给 Stub → Stub 调用
LocationManagerService。
🌟这就是“中间件”:AIDL 自动生成的 Stub/Proxy,是连接 App 和 SystemService 的“翻译官+对讲机”。
🔍 组件类型 3:HAL / Native / Kernel(硬件控制层)
代表:hardware/interfaces/light/,libcamera,/sys/class/backlight/
❓ 问题:Java 代码怎么控制 LED 灯?
✅ 答案:JNI + HAL + sysfs 三级跳
假设你想加一个“健康指示灯”:
[HealthService.java] (Java) ↓ [health_jni.cpp] (JNI 层,C++) ↓ dlopen("libhealth_vendor.so") → 调用 vendor 提供的 HAL 函数 ↓ HAL 写入 /sys/class/leds/health/brightness = "255" ↓ Linux Kernel 驱动点亮 LED💡 关键点:
- Framework不直接操作硬件;
- 通过HAL 接口(由芯片厂商实现)间接控制;
- Google 用 HAL 实现“软硬解耦”——你换高通 or 联发科,Framework 代码不用改!
第三章:为什么你看不到“调用代码”?——因为 AOSP 用的是“注册制”,不是“点名制”
🧩 传统编程 vs AOSP 编程
| 方式 | 传统 App | AOSP 系统 |
|---|---|---|
| 调用方式 | myService.doSomething()(硬编码) | ServiceManager.getService("myservice")(动态查找) |
| 启动方式 | main() 函数入口 | init.rc → zygote → SystemServer(逐层孵化) |
| 通信方式 | 直接函数调用 | Binder 跨进程 + AIDL 代理 |
✅ 所以你在源码里搜
addWindow(,可能只找到定义,找不到调用——
因为调用是通过Binder 字符串名 + 反射 + 动态代理完成的!
第四章:客制化实战——你应该改哪里?
场景:我想让 App 能查询“设备是否过热”
步骤 1:定义服务接口(AIDL)
// frameworks/base/core/java/android/os/IThermalService.aidl interface IThermalService { boolean isDeviceOverheated(); }步骤 2:实现服务(SystemService)
// frameworks/base/services/core/java/com/android/server/ThermalService.java public class ThermalService extends IThermalService.Stub { @Override public boolean isDeviceOverheated() { // 读取 /sys/class/thermal/thermal_zone0/temp return readTemp() > 60000; // 单位:毫摄氏度 } }步骤 3:在 SystemServer 中注册
// SystemServer.java ThermalService thermal = new ThermalService(context); ServiceManager.addService("thermal", thermal);步骤 4:给 App 提供 API(Framework 层)
// ContextImpl.java registerService(THERMAL_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService("thermal"); return IThermalService.Stub.asInterface(b); } });步骤 5:App 就可以这样用
ITherermalService ts = IThermalService.Stub.asInterface( ServiceManager.getService("thermal") ); if (ts.isDeviceOverheated()) { ... }✅ 全流程打通!而你不需要改任何“调用者”代码——因为所有调用都是动态的。
第五章:调试技巧——如何追踪“看不见的调用”?
1. 加日志,看执行路径
Slog.i("ThermalService", "isDeviceOverheated() called by " + mContext.getPackageManager().getNameForUid(Binder.getCallingUid()));2. 用adb shell dumpsys
adb shell dumpsys activity # 查看 AMS 状态 adb shell dumpsys window # 查看 WMS 窗口列表3. 搜索“注册点”
grep -r "addService.*thermal" frameworks/ # 找到谁注册了 thermal 服务4. 画调用链图(强烈推荐!)
用纸笔或工具画出:
App → Context.getSystemService("thermal") → ServiceManager.getService("thermal") → Binder IPC → ThermalService.isDeviceOverheated() → read /sys/...总结:一张图看懂 AOSP 调用全景
[App] │ ├── 调用 getSystemService("xxx") 或直接 ServiceManager.getService("xxx") │ ▼ [Framework API] ← 自动生成的 AIDL Proxy(客户端代理) │ ▼ (Binder IPC) [SystemServer 进程] │ ├── ServiceManager:根据字符串名找到对应服务 │ ▼ [SystemService] ← AIDL Stub(服务端存根)→ 真正业务逻辑 │ ▼ (JNI / HAL) [Native / HAL / Kernel] ← 控制硬件终极心法:如何高效学习 AOSP?
不要从头读代码,从“入口”切入
- 想看服务?从
SystemServer.java开始; - 想看 API?从
ContextImpl.java开始。
- 想看服务?从
理解“注册-查找-调用”模型
- AOSP 90% 的组件都是靠
ServiceManager.addService()+getService()驱动的。
- AOSP 90% 的组件都是靠
善用“动态视角”
- 代码不是静态的,它在系统启动时被“激活”,在运行时被“查找”。
客制化 = 插件化思维
- 你不是重写系统,而是把自己的模块,正确注册进系统插槽。
结语:
AOSP 的美,在于它的架构设计——
表面是“一堆函数定义”,
背后是“一套精密的操作系统引擎”。当你不再问“谁在调用它”,
而是说“我要把它注册到哪里”,
你就真正入门了 AOSP 客制化。下一篇,我们将动手从零定制一个 HAL 模块,让 App 控制一块 RGB LED 灯——
从 Java 到 Kernel,打通全链路!
下一篇预告:《AOSP 客制化内功心法(四):从 App 到 LED——HAL 层深度定制实战》