SurfaceFlinger 系列文章持续更新中(公众号:阿豪讲Framework):
- 如何调试 SurfaceFlinger
- SurfaceFlinger 概述
- 启动过程总览
- SurfaceFlinger 对象初始化
- ........
工欲善其事,必先利其器!SurfaceFlinger 常用的调试手段主要有:
- 日志调试
- 单步调试
- Perfetto
- dumpsys SurfaceFlinger
本文主要讲解前两点,第三点在源码分析过程中穿插讲解,第四点在完成 SurfaceFlinger 核心流程与功能后讲解。
1. 准备工作
首先我们需要一份源码并编译出一个 eng 版本,这里我使用的是 aosp android-15.0.0_r20 源码,硬件上使用 pixel6 手机,其它 pixel 手机或者模拟器都类似。
bash
source build/envsetup.sh
# pixel6
lunch aosp_oriole-bp1a-eng
# pixel8 pro
# lunch aosp_husky-bp1a-eng
m
接着把镜像刷入手机:
bash
adb reboot bootloader
fastboot flashall -w
接着我们需要再 VSCode 中安装好 CodeLLDB 插件

2. 日志调试
这里我们修改 SurfaceFlinger 的主函数 main_surfaceflinger.cpp 来演示打印 Log 和打印调用堆栈:
cpp
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
// 添加头文件和宏
#include "log/log.h"
//直接 define LOG_TAG 会报已定义错误,因为 SurFaceFlinger 模块的 Android.bp 已经定义了 LOG_Tag
//下面这样定义就不会出错了
#ifdef LOG_TAG
#undef LOG_TAG
#define LOG_TAG "ahao-sf"
#endif
//打印堆栈的头文件
#include <utils/CallStack.h>
bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId,
const scheduler::FrameTargets& frameTargets) {
const scheduler::FrameTarget& pacesetterFrameTarget = *frameTargets.get(pacesetterId)->get();
// 添加日志
ALOGD("SurfaceFlinger::commit");
// 打印调用栈
android::CallStack callStack(LOG_TAG, 1);
const VsyncId vsyncId = pacesetterFrameTarget.vsyncId();
// ......
}
主要三个部分的修改:
- 添加头文件和宏
- 添加日志
- 添加调用栈
修改 /frameworks/native/services/surfaceflinger/Android.bp
,添加 CallStack 的库依赖:
接着单编 SurfaceFlinger:
bash
# 源码目录下
source build/envsetup.sh
lunch aosp_oriole-bp1a-eng
make surfaceflinger
接着 push 到手机上:
bash
adb push out/target/product/oriole/system/bin/surfaceflinger /system/bin
adb reboot
最后验证查看日志:
bash
adb logcat | grep "ahao-sf"
07-02 19:41:32.375 556 556 D ahao-sf : SurfaceFlinger::commit
07-02 19:41:32.385 556 556 D ahao-sf : #00 pc 00000000002771a0 /system/bin/surfaceflinger (android::SurfaceFlinger::commit(android::PhysicalDisplayId, android::ftl::SmallMap<android::PhysicalDisplayId, android::scheduler::FrameTarget const*, 3ul, std::__1::equal_to<android::PhysicalDisplayId>> const&)+176) (BuildId: 5e135e484b98796bac0be1710386a2f2)
07-02 19:41:32.385 556 556 D ahao-sf : #01 pc 000000000024dc10 /system/bin/surfaceflinger (android::scheduler::Scheduler::onFrameSignal(android::ICompositor&, android::VsyncId, android::TimePoint)+544) (BuildId: 5e135e484b98796bac0be1710386a2f2)
07-02 19:41:32.385 556 556 D ahao-sf : #02 pc 0000000000011b50 /system/lib64/libutils.so (android::Looper::pollInner(int)+368) (BuildId: 100fa690ab318d6e1873d66d1c3f4c8e)
07-02 19:41:32.385 556 556 D ahao-sf : #03 pc 000000000001197c /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+124) (BuildId: 100fa690ab318d6e1873d66d1c3f4c8e)
07-02 19:41:32.385 556 556 D ahao-sf : #04 pc 000000000023a854 /system/bin/surfaceflinger (android::impl::MessageQueue::waitMessage()+84) (BuildId: 5e135e484b98796bac0be1710386a2f2)
07-02 19:41:32.385 556 556 D ahao-sf : #05 pc 000000000024d9dc /system/bin/surfaceflinger (android::scheduler::Scheduler::run()+28) (BuildId: 5e135e484b98796bac0be1710386a2f2)
07-02 19:41:32.385 556 556 D ahao-sf : #06 pc 00000000002c6688 /system/bin/surfaceflinger (main+1272) (BuildId: 5e135e484b98796bac0be1710386a2f2)
07-02 19:41:32.385 556 556 D ahao-sf : #07 pc 0000000000057854 /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+116) (BuildId: f0cc3fe16b52af6fc8d4e5b18105de09)
3. VSCode 图形化调试
新开一个终端进入系统源码根目录,执行下面的命令:
bash
source build/envsetup.sh
lunch aosp_oriole-bp1a-eng
手机打开 USB 调试并通过 USB 与手机相连,接着找到要调试的进程(surfaceflinger)对应的 pid
bash
adb shell ps -elf | grep surfaceflinger
system 14330 1 0 20:20:06 ? 00:04:27 surfaceflinger
可以看出,surfaceflinger 进程的 pid 为 14330.
接着开启 lldb 服务端
bash
lldbclient.py -p 14330 --setup-forwarding vscode-lldb
该命令会打印一段 json,记录下来(你的可能和我不一样):
json
{
"name": "(lldbclient.py) Attach surfaceflinger (port: 5039)",
"type": "lldb",
"request": "custom",
"relativePathBase": "/home/zzh0838/Project/aosp/android-15.0.0_r20",
"sourceMap": {
"/b/f/w": "/home/zzh0838/Project/aosp/android-15.0.0_r20",
"": "/home/zzh0838/Project/aosp/android-15.0.0_r20",
".": "/home/zzh0838/Project/aosp/android-15.0.0_r20"
},
"initCommands": [
"settings append target.exec-search-paths /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/ /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/hw /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/ssl/engines /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/drm /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/egl /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/soundfx /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/vendor/lib64/ /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/vendor/lib64/hw /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/vendor/lib64/egl /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/apex/com.android.runtime/bin"
],
"targetCreateCommands": [
"target create /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/bin/surfaceflinger",
"target modules search-paths add / /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/"
],
"processCreateCommands": [
"gdb-remote 5039"
]
}
接下来使用 VSCode 打开 Android 源码的根目录。
接着点击菜单栏的 run -> Add Configuration:

选择 LLDB:

接着就会在根目录下生成一个 .vscode 文件夹,其中有一个 launch.json 文件。

接着把 .vscode/launch.json
文件中 configurations 节点的内容都删掉,换成上面记录的 json:
json
{
{
"configurations": [
{
"name": "(lldbclient.py) Attach surfaceflinger (port: 5039)",
"type": "lldb",
"request": "custom",
"relativePathBase": "/home/zzh0838/Project/aosp/android-15.0.0_r20",
"sourceMap": {
"/b/f/w": "/home/zzh0838/Project/aosp/android-15.0.0_r20",
"": "/home/zzh0838/Project/aosp/android-15.0.0_r20",
".": "/home/zzh0838/Project/aosp/android-15.0.0_r20"
},
"initCommands": [
"settings append target.exec-search-paths /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/ /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/hw /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/ssl/engines /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/drm /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/egl /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/lib64/soundfx /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/vendor/lib64/ /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/vendor/lib64/hw /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/vendor/lib64/egl /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/apex/com.android.runtime/bin"
],
"targetCreateCommands": [
"target create /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/system/bin/surfaceflinger",
"target modules search-paths add / /home/zzh0838/Project/aosp/android-15.0.0_r20/out/target/product/oriole/symbols/"
],
"processCreateCommands": [
"gdb-remote 5039"
]
}
]
}
接着在 frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
文件中打好断点:

然后点击菜单栏 run -> Start Debugging 开始调试:

此时,进入到调试模式。
接着操作手机,点击一个 App 图标,VSCode 就会进入到断点处:

总结
写码十分钟,调试一整天!