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

总结

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

参考资料

相关推荐
embrace9921 小时前
【C语言学习】结构体详解
android·c语言·开发语言·数据结构·学习·算法·青少年编程
用户693717500138421 小时前
11.Kotlin 类:继承控制的关键 ——final 与 open 修饰符
android·后端·kotlin
用户02738518402621 小时前
【Android】LiveData的使用以及源码浅析
android·程序员
用户693717500138421 小时前
10.Kotlin 类:延迟初始化:lateinit 与 by lazy 的对决
android·后端·kotlin
正经教主1 天前
【Git】Git06:Git 管理 Android 项目教程(含GitHub)
android·git
安卓理事人1 天前
安卓多种通知ui更新的方式(livedata,rxjava,eventbus等)
android·ui·echarts
BS_Li1 天前
【Linux系统编程】Ext系列文件系统
android·linux·ext系列文件系统
zhangphil1 天前
Android宽高不均等Bitmap缩放为指定宽高FitCenter到正方形Bitmap,Kotlin
android·kotlin
别或许1 天前
13.用户管理
android
q***96581 天前
springboot3整合knife4j详细版,包会!(不带swagger2玩)
android·前端·后端