Android稳定性-02-Android 系统架构:从 App 到 Kernel 的调用链
做 Android 系统稳定性测试时,最容易犯的错误,是把问题只看成一个表层现象。
比如:
- 应用闪退了,就只看应用日志
- 页面卡住了,就只怀疑 UI 自动化脚本不稳定
- 设备黑屏了,就只截图留证
- 系统重启了,就只说“机器不稳定”
- Monkey 跑出了 ANR,就只把 ANR traces 发给开发
这些动作不是没用,但如果测试同学对 Android 系统架构没有基本认知,很容易只停在“发现问题”和“转交日志”这一步。真正难的是继续往下判断:
- 这是 App 自己的问题,还是 Framework 服务异常
- 是主线程卡住,还是 Binder 调用链路卡住
- 是 Window、Input、Display、SurfaceFlinger 这一层的问题,还是底层驱动问题
- 是 Native Service 崩了,还是 HAL 返回异常
- 是 system_server 卡死,还是 Kernel 触发了 panic
所以 Android 稳定性测试不能只会跑 Monkey、抓 logcat、导 bugreport。至少要先把一条基本链路讲清楚:
一个 App 发起动作后,系统从 App 到 Framework、System Server、Native Service、HAL、Kernel、驱动大致是怎么协作的。
这篇文章就从稳定性测试视角,把这条调用链拆开。
一、先建立一张简化架构图
Android 系统可以先粗略拆成下面几层:
1 | App 层 |
这张图很简化,但对测试定位已经够用了。
因为大多数稳定性问题,最后都能放回这几层里判断:
- App 层:业务代码、三方 SDK、主线程、资源使用、生命周期
- Framework 层:Android 对外暴露的系统能力和 Java API
- System Server:Activity、Window、Package、Power、Input、Display 等核心系统服务
- Native Service:SurfaceFlinger、AudioFlinger、media、netd、vold、servicemanager 等 Native 组件
- HAL 层:相机、音频、传感器、蓝牙、定位、显示等硬件抽象接口
- Kernel / Driver 层:进程调度、内存、文件系统、网络、Binder 驱动、设备驱动
稳定性测试看这张图,不是为了背架构,而是为了形成一个判断习惯:
看到现象后,先判断它最可能发生在哪一层,再决定优先看什么日志。
二、App 层:稳定性问题最容易被看到的地方
App 层是测试最容易接触的一层。
比如:
- 点击某个页面后闪退
- 某个按钮无响应
- 页面加载很慢
- 切后台再回来白屏
- Monkey 随机点出 Crash
- 长时间运行后内存持续上涨
这些现象都发生在 App 表面,但根因不一定都在 App。
App 层最常见的问题包括:
- Java Crash
- Native Crash
- ANR
- 主线程阻塞
- 内存泄漏
- 线程泄漏
- 文件描述符泄漏
- 生命周期处理错误
- 权限或系统能力调用异常
- 三方 SDK 异常
如果只是普通 App 测试,看到 App 崩溃,通常先看 logcat 里的 FATAL EXCEPTION。但系统稳定性测试要多问一步:
这个 App 异常有没有触发系统服务异常,或者是不是由系统服务异常导致的?
比如相机应用打开失败,可能是 App 自己逻辑错,也可能是:
- CameraService 异常
- camera provider 异常
- camera HAL 异常
- 驱动返回错误
- 权限状态异常
- 设备资源被占用
所以 App 层日志是入口,但不能天然等于根因。
常用观察命令:
1 | adb shell ps -A |
测试判断重点:
- 目标进程是否还在
- 是否出现
FATAL EXCEPTION - 是否出现
ANR in <package> - 主线程是否阻塞在 Binder、锁、I/O、网络或渲染
- 异常前后是否有系统服务报错
- 是否只有单个 App 异常,还是多个 App 同时异常
如果多个 App 同时出现卡顿、无响应或启动失败,通常就不应该只盯着某一个 App。
三、Framework 层:App 调系统能力的入口
App 不会直接操作大多数硬件和系统资源。
比如 App 想要:
- 启动 Activity
- 申请权限
- 打开相机
- 播放音频
- 获取定位
- 操作蓝牙
- 访问剪贴板
- 获取窗口焦点
- 注册广播
- 使用传感器
它通常会先调用 Android Framework 提供的 API。
Framework 层可以理解成 App 和系统服务之间的一层 Java 世界。它把底层复杂能力包装成开发者能调用的接口,同时也负责参数检查、权限校验、生命周期管理和跨进程通信封装。
以启动页面为例,简化链路大致是:
1 | App |
从稳定性测试角度看,Framework 层的价值在于:
- 它是很多系统能力的统一入口
- 它会留下大量可分析日志
- 它和 system_server 里的系统服务高度相关
- 它能帮助判断问题是 App 调用错误,还是系统服务处理异常
比如 App 报权限异常,可能要看:
- App 是否真的声明了权限
- 运行时权限是否授权
- PackageManager 状态是否正常
- AppOps 是否拦截
- 设备策略或系统配置是否限制
常用观察命令:
1 | adb shell dumpsys package <package> |
测试判断重点:
- App 调用的系统能力是哪一类
- Framework 是否有明确异常日志
- 权限、状态、生命周期是否符合预期
- 是否涉及跨进程 Binder 调用
- 是否进一步进入 system_server 的系统服务
很多 Android 问题表面看是“某个功能打不开”,实际上是 Framework 调系统服务时失败了。
四、System Server:系统稳定性的核心现场
system_server 是 Android 稳定性测试里必须重点关注的进程。
它里面运行着大量核心系统服务,例如:
- ActivityManagerService
- ActivityTaskManagerService
- WindowManagerService
- PackageManagerService
- PowerManagerService
- InputManagerService
- DisplayManagerService
- AlarmManagerService
- BatteryService
- ConnectivityService
这些服务直接影响应用启动、窗口显示、输入事件、电源状态、包管理、网络状态、后台调度等关键能力。
所以很多严重稳定性问题,最后都会和 system_server 有关系。
比如:
- App 启动很慢
- 页面切换卡住
- 输入无响应
- 锁屏解锁异常
- 黑屏
- 系统弹窗不出现
- 全局卡死
- Watchdog 重启
这些问题都可能需要看 system_server。
一条典型调用链可能是:
1 | App 调用 Framework API |
这里最关键的是 Binder。
App 和系统服务通常不在同一个进程里,跨进程通信主要依赖 Binder。如果 Binder 调用长时间不返回,App 主线程可能会卡住;如果 system_server 某个关键线程被锁住,可能影响一大片系统功能。
稳定性测试里看到 ANR 时,不能只看 App 主线程最后停在哪一行,还要判断它是不是在等系统服务。
例如 traces 里如果看到类似方向:
1 | main thread |
就要继续追:
- 它在等哪个系统服务
- system_server 对应线程在做什么
- 是否有锁等待
- 是否有 CPU 饥饿
- 是否有 I/O 阻塞
- 是否出现 Watchdog 相关日志
常用观察命令:
1 | adb shell ps -A | grep system_server |
测试判断重点:
system_server是否发生 crash- 是否出现 Watchdog
- 是否有大量 Binder 阻塞
- Window、Input、Power、Display 状态是否异常
- 问题是否影响多个 App 或整个系统
- 是否伴随系统重启或卡死
如果一个问题影响范围从单 App 扩大到系统级能力,system_server 通常是必须排查的一站。
五、Native Service:很多系统能力真正干活的地方
Android 不是只有 Java Framework 和 system_server。
很多核心能力实际由 Native Service 承担,例如:
surfaceflinger:合成和显示相关audioserver/AudioFlinger:音频相关cameraserver:相机相关mediaextractor、mediacodec、mediaserver:媒体相关netd:网络管理相关vold:存储卷管理相关servicemanager:Binder 服务管理hwservicemanager:HAL 服务管理
这些 Native 组件一旦异常,表现可能非常“上层”:
- 相机打不开
- 视频播放黑屏
- 音频无声
- 系统界面卡顿
- 屏幕不刷新
- 网络状态异常
- 外部存储不可用
但根因并不一定在 App,也不一定在 Java Framework。
以显示链路为例,简化后大致是:
1 | App 绘制界面 |
如果用户看到黑屏或画面不刷新,可能要看:
- App 是否还在绘制
- Window 是否可见
- Surface 是否创建成功
- SurfaceFlinger 是否正常合成
- Display 状态是否正常
- 底层显示驱动是否异常
常用观察命令:
1 | adb shell ps -A | grep -E "surfaceflinger|audioserver|cameraserver|media|netd|vold" |
测试判断重点:
- Native Service 是否 crash 或频繁重启
- 是否出现 tombstone
- 是否出现 service died、binder died、transaction failed
- 是否只有某个硬件相关功能异常
- 是否需要继续追到 HAL 或 Kernel
Native Service 是系统稳定性测试里很容易被忽略的一层。很多黑屏、音视频、相机、网络、存储问题,如果只看 App 日志,会完全看不到关键现场。
六、HAL 层:系统和硬件之间的抽象边界
HAL 是 Hardware Abstraction Layer,也就是硬件抽象层。
它的价值是让 Android Framework 和系统服务不需要直接理解每一种硬件驱动细节,而是通过统一接口访问硬件能力。
常见 HAL 包括:
- Camera HAL
- Audio HAL
- Sensors HAL
- Bluetooth HAL
- GPS / GNSS HAL
- Wi-Fi 相关 HAL
- Graphics / Composer HAL
- Power HAL
从稳定性测试角度看,HAL 层问题通常有几个特点:
- 现象很像 App 或 Framework 问题
- 复现往往和具体硬件、版本、场景有关
- 日志可能分散在 logcat、kernel log、vendor log 中
- 测试同学通常不能直接修改,但要能判断方向
比如相机黑屏,可能链路是:
1 | Camera App |
如果 CameraService 日志显示调用 HAL 超时,或者 provider 进程异常退出,就不能简单归因给 App。
同理,音频、蓝牙、定位、传感器这类问题也经常需要判断是否进入 HAL 层。
常用观察方向:
1 | adb shell lshal |
测试判断重点:
- 是否只有特定硬件能力异常
- 是否涉及 vendor 进程或 HAL service
- 是否有调用超时、返回错误码、服务死亡
- 是否和特定设备、硬件批次、系统版本相关
- 是否需要提供更完整的 bugreport、tombstone、kernel log 给底层开发
测试不一定要能深入 HAL 源码,但至少要能识别:
这个问题已经不是普通 App 层问题,需要拉系统或驱动侧一起看。
七、Kernel / Driver 层:系统卡死、重启和资源问题的底座
Kernel / Driver 层是 Android 系统运行的底座。
它负责:
- 进程和线程调度
- 内存管理
- 文件系统
- 网络协议栈
- Binder 驱动
- 电源管理
- 设备驱动
- 安全机制
很多严重稳定性问题,最后都要看这一层。
典型现象包括:
- Kernel Panic
- 随机重启
- 设备完全无响应
- 系统级卡死
- I/O 长时间阻塞
- 内存耗尽导致 LMK / OOM
- 驱动异常导致某个硬件不可用
- 温升降频导致整体响应变慢
比如设备突然重启,不能只看重启后的 logcat。因为重启后,很多现场已经丢了。需要优先确认:
- reboot reason 是什么
- pstore / console-ramoops 是否存在
- last_kmsg 是否保留
- 是否有 kernel panic
- 是否 Watchdog 触发
- 是否电源、温度或硬件异常
常用观察命令:
1 | adb shell cat /proc/meminfo |
不同设备权限不一样,有些命令在 user 版本上可能无法直接执行,这时就更依赖 bugreport、厂商日志工具或测试版本权限。
测试判断重点:
- 是否发生重启、panic、Watchdog 或低内存杀进程
- 是否有 pstore / last_kmsg 证据
- 是否有明显驱动报错
- 是否和高负载、温升、I/O、弱网、频繁插拔相关
- 是否只有特定硬件版本或批次复现
Kernel 层问题通常不是测试同学独立闭环,但测试需要把证据收集完整。否则底层开发拿不到现场,只能要求复现。
八、用一个“打开相机黑屏”的例子串起来
为了让这条链路更具体,可以用“打开相机黑屏”做例子。
用户现象:
- 点击相机图标后进入相机页面
- 页面黑屏
- 没有预览画面
- 返回桌面后再打开偶现恢复
如果只从 App 层看,可能会记录为:
1 | 相机 App 打开后黑屏 |
但从系统链路看,至少要拆成几层:
1. App 层
先确认:
- 相机 App 是否 crash
- 页面 Activity 是否正常启动
- 是否有权限异常
- 是否有预览初始化失败日志
- App 是否阻塞在主线程
常看:
1 | adb logcat -b all -v threadtime |
2. Framework / System Server 层
继续确认:
- Activity 是否处于 resumed
- Window 是否可见
- 屏幕是否处于 on 状态
- 是否有系统权限或 AppOps 拦截
- 是否存在系统服务超时
常看:
1 | adb shell dumpsys activity |
3. Native Service 层
再确认:
- CameraService 是否正常
- SurfaceFlinger 是否有对应 layer
- 是否有 native crash 或 tombstone
- 是否出现 service died
常看:
1 | adb shell dumpsys media.camera |
4. HAL / Driver 层
最后确认:
- Camera HAL 是否返回错误
- provider 是否异常
- kernel log 是否有 camera driver 报错
- 是否只在某一批设备上复现
常看:
1 | adb shell lshal |
这样分析后,提单就不只是“相机黑屏”,而可以变成:
1 | 现象:相机应用打开后黑屏,Activity 已 resumed,Window 可见,App 无 Java Crash。 |
这种描述对研发的价值,明显高于一句“相机黑屏,请分析”。
九、稳定性测试里更实用的分层判断法
实际排障时,不需要每次都从 App 一层层查到 Kernel。更实用的方法是根据现象先判断影响范围。
1. 只影响单个 App
优先看:
- App log
- Java Crash
- Native Crash
- ANR traces
- App 权限
- App 资源使用
但要留意系统服务是否有伴随异常。
2. 影响多个 App
优先看:
- system_server
- Activity / Window / Input / Power 状态
- Binder 阻塞
- CPU / 内存 / I/O 压力
- bugreport
多个 App 同时异常,通常不适合只从单个 App 归因。
3. 影响某一类硬件能力
比如只有相机、音频、蓝牙、定位、传感器异常。
优先看:
- 对应系统服务
- 对应 Native Service
- HAL service
- vendor log
- kernel log
这类问题经常需要系统侧或驱动侧介入。
4. 整机卡死、黑屏、重启
优先看:
- bugreport
- pstore / last_kmsg
- Watchdog
- Kernel Panic
- Power / Display / SurfaceFlinger
- 温度、电量、重启原因
这类问题要优先保现场,不要只重启设备继续跑。
十、不同层常见日志和命令入口
可以先记一张简表。
| 层级 | 常见对象 | 常用证据 |
|---|---|---|
| App | 业务进程、主线程、三方 SDK | logcat、ANR traces、meminfo、截图录屏 |
| Framework | Android API、权限、生命周期 | dumpsys package、activity、appops、permission |
| System Server | AMS、WMS、PMS、Power、Input、Display | bugreport、dumpsys activity/window/power/input/display |
| Native Service | SurfaceFlinger、CameraService、AudioFlinger、netd、vold | logcat、tombstone、dumpsys SurfaceFlinger/media.camera/audio |
| HAL | camera、audio、sensors、bluetooth、gnss、composer | lshal、vendor log、service log、bugreport |
| Kernel / Driver | 调度、内存、文件系统、Binder、设备驱动 | dmesg、pstore、last_kmsg、vmcore、reboot reason |
这张表不是为了替代分析,而是帮助测试在第一时间知道:
我现在应该先抓哪些证据。
十一、常见误判
理解 Android 分层时,最常见的误判有四类。
第一,把问题出现的位置当成根因位置。比如黑屏出现在相机 App 页面,不代表根因一定在相机 App;也可能是 CameraService、Camera HAL、SurfaceFlinger 或显示驱动异常。
第二,把 App Crash 和系统稳定性完全切开。单个 App Crash 看起来是应用问题,但如果多个 App 都在同一时间出现 Binder timeout、资源申请失败或系统服务异常,就要继续看 system_server 和底层资源状态。
第三,只看 Java 世界,忽略 Native Service 和 HAL。音频、相机、显示、媒体、蓝牙、定位这类问题,经常需要把 logcat、tombstone、dumpsys、vendor log、kernel log 放在一起看。
第四,重启后继续跑测试但不保现场。重启、卡死、Watchdog、Kernel Panic 这类问题的关键证据可能在 pstore、last_kmsg、dropbox 或 bugreport 里,错过第一次现场,后面即使复现路径相同,也不一定还能拿到同样的证据。
所以分层不是为了把问题复杂化,而是为了减少错误归因。
十二、这篇文章真正要建立的能力
Android 系统架构很复杂,但测试开发不需要一开始就把每个模块源码都读完。对稳定性测试来说,更重要的是先建立三种能力。
1. 能把现象放回系统层级里
看到 Crash、ANR、黑屏、卡死、重启时,不只说现象,而是先判断:
- 单 App 问题
- Framework / system_server 问题
- Native Service 问题
- HAL / Driver 问题
- Kernel 层问题
判断不一定一次准确,但要有方向。
2. 能按层收集证据
不同层的问题需要不同证据。
只给一个截图,无法分析系统服务异常。只给一段 App log,也无法分析 kernel panic。测试要能根据问题类型补齐:
- logcat
- bugreport
- dumpsys
- tombstone
- traces
- pstore
- Perfetto / systrace
- 复现视频
3. 能输出初步归因,而不是只转发日志
好的稳定性问题单不一定要求测试直接给最终根因,但至少要能说明:
- 影响范围
- 发生时间
- 复现路径
- 关键证据
- 初步怀疑层级
- 建议责任方向
- 还缺哪些日志
这就是系统稳定性测试和普通功能测试最大的区别之一。
十三、小结
Android 从 App 到 Kernel 的调用链,可以先按六层理解:
- App 层负责业务逻辑和用户交互。
- Framework 层提供系统 API 和调用封装。
- System Server 承载大量核心系统服务,是系统稳定性的关键现场。
- Native Service 承担显示、音频、相机、媒体、网络、存储等底层系统能力。
- HAL 层连接系统服务和硬件能力。
- Kernel / Driver 层负责调度、内存、I/O、网络、电源、驱动和硬件交互。
做稳定性测试时,不能只看问题发生在哪个界面,而要继续追问:
这个现象背后的调用链走到了哪一层,哪一层最可能先出问题,哪一层还缺证据。
只要这个意识建立起来,后面再学 logcat、bugreport、tombstone、ANR traces、dumpsys、pstore、Perfetto,就不会变成零散命令,而会变成一套有方向的问题定位方法。