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

总结

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

参考资料

相关推荐
CANI_PLUS4 小时前
ESP32将DHT11温湿度传感器采集的数据上传到XAMPP的MySQL数据库
android·数据库·mysql
来来走走5 小时前
Flutter SharedPreferences存储数据基本使用
android·flutter
安卓开发者6 小时前
Android模块化架构深度解析:从设计到实践
android·架构
雨白6 小时前
HTTP协议详解(二):深入理解Header与Body
android·http
阿豪元代码7 小时前
深入理解 SurfaceFlinger —— 概述
android
CV资深专家8 小时前
Launcher3启动
android
stevenzqzq9 小时前
glide缓存策略和缓存命中
android·缓存·glide
雅雅姐9 小时前
Android 16 的用户和用户组定义
android
没有了遇见9 小时前
Android ConstraintLayout 之ConstraintSet
android