深入理解 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 就会进入到断点处:

总结

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

参考资料

相关推荐
千里马学框架5 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台5 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone5 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc5 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo5 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077005 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼5 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone6 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen6 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone6 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui