news 2026/4/3 6:08:57

AOSP 客制化内功心法(三):

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AOSP 客制化内功心法(三):

“没人调用的代码”是怎么跑起来的?——彻底搞懂系统组件的启动与调用链

发布日期: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进程拉起zygotezygote拉起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 自动生成“代理对讲机”
  1. 你写 AIDL:

    // ILocationManager.aidl interface ILocationManager { Location getLastKnownLocation(); }
  2. 编译时,AOSP 自动生成两个类:

    • ILocationManager.Stub→ 服务端存根(在 SystemServer 中)
    • ILocationManager.Stub.Proxy→ 客户端代理(在 App 中)
  3. 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 编程

方式传统 AppAOSP 系统
调用方式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?

  1. 不要从头读代码,从“入口”切入

    • 想看服务?从SystemServer.java开始;
    • 想看 API?从ContextImpl.java开始。
  2. 理解“注册-查找-调用”模型

    • AOSP 90% 的组件都是靠ServiceManager.addService()+getService()驱动的。
  3. 善用“动态视角”

    • 代码不是静态的,它在系统启动时被“激活”,在运行时被“查找”。
  4. 客制化 = 插件化思维

    • 你不是重写系统,而是把自己的模块,正确注册进系统插槽

结语
AOSP 的美,在于它的架构设计——
表面是“一堆函数定义”,
背后是“一套精密的操作系统引擎”。

当你不再问“谁在调用它”,
而是说“我要把它注册到哪里”,
你就真正入门了 AOSP 客制化。

下一篇,我们将动手从零定制一个 HAL 模块,让 App 控制一块 RGB LED 灯——
从 Java 到 Kernel,打通全链路!


下一篇预告:《AOSP 客制化内功心法(四):从 App 到 LED——HAL 层深度定制实战》

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/27 8:55:08

PMP项目管理证书难不难考?

PMP项目管理证书的考试难度因人而异,但整体而言,通过系统备考和合理规划,通过考试并非难事,具体分析如下: 一、考试内容与结构 知识体系广泛:PMP考试基于《PMBOK指南》,涵盖项目管理五大过程组&…

作者头像 李华
网站建设 2026/3/27 4:34:32

安装包依赖树查看:Miniconda-Python3.10使用pipdeptree分析

Miniconda-Python3.10 使用 pipdeptree 分析安装包依赖树 在人工智能与数据科学项目中,一个看似简单的“导入错误”可能耗费数小时排查——原因往往不是代码本身的问题,而是隐藏在层层依赖背后的版本冲突。你是否曾遇到过这样的场景:本地运行…

作者头像 李华
网站建设 2026/3/28 17:27:51

Linux auditd审计日志:Miniconda-Python3.10监控关键操作行为

Linux auditd审计日志:Miniconda-Python3.10监控关键操作行为 在科研计算、AI开发和企业级数据平台日益复杂的今天,一个看似简单的命令——比如 pip install 或 jupyter-notebook 启动——背后可能隐藏着环境污染、权限滥用甚至安全入侵的风险。尤其是在…

作者头像 李华
网站建设 2026/4/1 22:17:04

无代码还是Vibe Coding? 场景(一)

场景特征: 与编程的接近程度:低问题的复杂性:低工作的紧迫性:低构建的质量:低 延申阅读:Vibe Coding vs. 低代码/无代码平台:为每种构建场景选择合适的工具(序言)​​​…

作者头像 李华
网站建设 2026/3/24 9:54:22

当两个单词可能是同一个:聊聊《最短单词距离 III》背后的“算法洁癖”

当两个单词可能是同一个:聊聊《最短单词距离 III》背后的“算法洁癖” 大家好,我是 Echo_Wish。 今天咱们聊一道看起来简单、实则很容易被低估的题目——最短单词距离 III(Shortest Word Distance III)。 如果你刷过 I、II 版本,第一次看到 III,大概率会嘀咕一句: “不…

作者头像 李华
网站建设 2026/4/3 5:00:09

Conda info查看环境信息:Miniconda-Python3.10诊断配置问题

使用 conda info 诊断 Miniconda-Python3.10 环境配置问题 在人工智能与数据科学项目中,环境配置的稳定性往往决定了开发效率的高低。一个看似简单的“包无法导入”或“命令未找到”问题,背后可能是 Python 版本错乱、Conda 环境未激活,或是路…

作者头像 李华