深入理解 SurfaceFlinger —— 如何调试 SurfaceFlinger

SurfaceFlinger 系列文章持续更新中(公众号:阿豪讲Framework):

  • 如何调试 SurfaceFlinger
  • SurfaceFlinger 概述
  • 启动过程总览
  • SurfaceFlinger 对象初始化
  • ........

工欲善其事,必先利其器!SurfaceFlinger 常用的调试手段主要有:

  1. 日志调试
  2. 单步调试
  3. Perfetto
  4. 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 就会进入到断点处:

总结

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

参考资料

相关推荐
2501_9160088920 小时前
Web 前端开发常用工具推荐与团队实践分享
android·前端·ios·小程序·uni-app·iphone·webview
我科绝伦(Huanhuan Zhou)21 小时前
MySQL一键升级脚本(5.7-8.0)
android·mysql·adb
怪兽20141 天前
Android View, SurfaceView, GLSurfaceView 的区别
android·面试
龚礼鹏1 天前
android 图像显示框架二——流程分析
android
消失的旧时光-19431 天前
kmp需要技能
android·设计模式·kotlin
帅得不敢出门1 天前
Linux服务器编译android报no space left on device导致失败的定位解决
android·linux·服务器
雨白1 天前
协程间的通信管道 —— Kotlin Channel 详解
android·kotlin
TimeFine1 天前
kotlin协程 容易被忽视的CompletableDeferred
android
czhc11400756631 天前
Linux1023 mysql 修改密码等
android·mysql·adb
GOATLong1 天前
MySQL内置函数
android·数据库·c++·vscode·mysql