android 13 systrace/perfetto视角分析SurfaceFlinger中截图源码分析

背景:

截图是一种开发过程中经常遇到的功能,但是这个功能底层是怎么实现的?今天就来给大家分享一下的,截图的的实现原理。
截图场景:
一般截图都有以下几个方式:
1、音量下键+power
2、systemui中下拉状态栏,或者关机选着界面
3、adb shell命令行方式screencap命令方式

主要就是以上几个,虽然场景不一样,但是他们最后调用的截图接口其实都是同一个,都是最后会调用到surfaceflinger中的截图方法,下面就以adb shell命令行方式screencap案例分析,因为他的接口调用最为简单,这次分析方式主要是使用perfetto的trace分析方式

screencap命令相关源码及抓取perfetto操作

抓取perfetto方式:

1、输入如下命令进行perfetto抓取

test@test:~$ aosp/external/perfetto/tools/record_android_trace -o $(date +%Y%m%d_%H%M%S)_trace_file.perfetto-trace -t 5s -b 32mb sched freq idle am wm gfx view binder_driver hal dalvik camera input res memory gfx view wm am ss video camera hal res sync idle binder_driver binder_lock ss

2、另一个终端输入如下命令进行截图:

screencap -p /sdcard/1.png

代码位置:

frameworks/base/cmds/screencap/screencap.cpp

int main(int argc, char** argv)
{
    std::optional<DisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
   //省略部分
    ProcessState::self()->setThreadPoolMaxThreadCount(0);
    ProcessState::self()->startThreadPool();

    sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
    //最为核心的方法ScreenshotClient::captureDisplay
    status_t result = ScreenshotClient::captureDisplay(*displayId, captureListener);
    if (result != NO_ERROR) {
        close(fd);
        return 1;
    }

    ScreenCaptureResults captureResults = captureListener->waitForResults();
    if (captureResults.result != NO_ERROR) {
        close(fd);
        return 1;
    }
    ui::Dataspace dataspace = captureResults.capturedDataspace;
    sp<GraphicBuffer> buffer = captureResults.buffer;

    result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);


    if (png) {
        AndroidBitmapInfo info;
        info.format = flinger2bitmapFormat(buffer->getPixelFormat());
        info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
        info.width = buffer->getWidth();
        info.height = buffer->getHeight();
        info.stride = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());

        int result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base,
                                            ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100, &fd,
                                            [](void* fdPtr, const void* data, size_t size) -> bool {
                                                int bytesWritten = write(*static_cast<int*>(fdPtr),
                                                                         data, size);
                                                return bytesWritten == size;
                                            });
    
   //省略部分

        if (fn != NULL) {
            notifyMediaScanner(fn);
        }
    }
     
   //省略部分
    return 0;
}

其实整个screencap最为核心代码就是只有一句:
ScreenshotClient::captureDisplay
这个就是调用截图相关的接口,该接口实现如下:

status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
                                          const sp<IScreenCaptureListener>& captureListener) {
    sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService());
    if (s == nullptr) return NO_INIT;

    binder::Status status = s->captureDisplay(captureArgs, captureListener);
    return status.transactionError();
}

其实本质是个跨进程调用,最后会调用到surfaceflinger的captureDisplay方法:

status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
                                        const sp<IScreenCaptureListener>& captureListener) {
    ui::LayerStack layerStack;
    wp<const DisplayDevice> displayWeak;
    ui::Size size;
    ui::Dataspace dataspace;
    {
        Mutex::Autolock lock(mStateLock);

        const auto display = getDisplayDeviceLocked(displayId);
        if (!display) {
            return NAME_NOT_FOUND;
        }

        displayWeak = display;
        layerStack = display->getLayerStack();
        size = display->getLayerStackSpaceRect().getSize();

        dataspace =
                pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode);
    }

    RenderAreaFuture renderAreaFuture = ftl::defer([=] {
        return DisplayRenderArea::create(displayWeak, Rect(), size, dataspace,
                                         false /* useIdentityTransform */,
                                         false /* captureSecureLayers */);
    });

    auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) {
        traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor);
    };


    auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
                                      ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale,
                                      captureListener);
    return fenceStatus(future.get());
}
结合trace分析

具体上面的流程进行systrace、perfetto展示如下:
在这里插入图片描述
这里显示发起了一个跨进程调用,目标段是surfaceflinger进程
在这里插入图片描述trace的总结图如下:

在这里插入图片描述surfaceflinger还有一个额外的回调客户端操作:
在这里插入图片描述

1、准备好buffer来绘制截图
2、主导surfaceflinger需要相关的layer预处理
3、使用SkiaGl引擎进行进行相关的Layer绘制到新buffer
4、通知客户端,回调listener

更多干货手把手教学framework视频内容可以关注公众号或者b站up主(千里马学框架)
https://blog.youkuaiyun.com/learnframework/article/details/132739059
在这里插入图片描述

<think>好的,用户现在问的是关于systrace分析方法。之前他们询问过Android Camera Trace,我介绍了整体架构、工具和常见问题定位,其中提到过Systrace/Perfetto的使用。现在他们可能想更深入了解如何具体使用systrace分析性能问题,尤其是在Android开发或调试中。 首先,我需要确定用户的背景。他们可能是Android开发者,或者测试人员,遇到了性能问题,比如应用卡顿、启动慢等,想用systrace来定位问题。也可能是刚接触Android性能优化,想学习工具的使用方法。 用户之前的问题涉及Camera Trace,可能他们现在的问题依然在摄像头相关的问题上,比如预览卡顿,或者想更广泛地了解systrace的应用。不管怎样,我需要详细解释systrace的使用步骤、分析方法以及常见场景。 我需要确保回答结构清晰,步骤明确,符合用户要求的逐步解决问题的方式。同时,要记住系统级指令,比如行内数学表达式用$...$,但这里可能用不上。需要检查LaTeX语法是否正确,不过systrace相关内容可能更多是代码块和命令行示例,需要注意格式。 另外,用户可能需要知道如何安装、捕获trace文件,以及如何解读结果。还要提到Perfetto,因为它是systrace的升级版,Android官方现在推荐使用。需要比较两者的区别,但可能用户更关注systrace的具体方法。 还要考虑常见错误或用户可能遇到的难点,比如权限问题,如何正确配置trace类别,如何过滤关键信息。同时,举一些例子,比如分析UI卡顿、Binder调用延迟等,让用户更容易理解。 需要注意不要遗漏关键点,比如工具的准备步骤,命令行参数,以及如何利用工具中的不同视图(比如线程、CPU频率)来分析性能。还要提醒用户注意时间段的选取,复现问题时的操作同步标记,比如使用按键或添加自定义事件。 最后,检查是否所有信息准确,比如命令的正确性,参数是否适用最新Android版本,是否需要root权限等。如果有不确定的地方,可能需要提到参考官方文档或厂商特定信息,但尽量保证回答的可靠性。</think>以下是 Systrace分析方法及步骤详解,帮助开发者定位 Android 系统或应用性能问题: --- ### 一、Systrace 基础概念 1. **作用**:捕获系统关键组件(如 CPU、SurfaceFlinger、Binder、App 主线程)的实时行为,生成时间轴可视化图表。 2. **底层原理**:基于 Linux 内核的 `ftrace` 机制,记录线程调度、锁竞争、IO 操作等事件。 3. **替代工具**:Android 10+ 推荐使用 **Perfetto**(功能更强大,操作类似)。 --- ### 二、抓取 Trace 文件 #### 步骤 1:安装 Python 环境 - 需安装 Python 2.7(Systrace 依赖)或使用 Android Studio 内置工具(推荐)。 #### 步骤 2:命令行抓取 Trace ```bash # 进入 Android SDK 的 platform-tools/systrace 目录 cd ~/Library/Android/sdk/platform-tools/systrace # 执行抓取命令(示例:抓取 10 秒,包含 app、sched、gfx 类别) python systrace.py -t 10 -o output.html sched gfx input view webview wm am app ``` - **常用参数**: - `-t N`:抓取时长(秒)。 - `-o file`:输出文件路径。 - `-a <包名>`:仅追踪特定应用。 - 类别列表:`gfx`(图形)、`input`(触控)、`sched`(CPU 调度)、`binder_driver`(Binder 调用)等。 #### 步骤 3(可选):通过代码插入标记 在应用中添加自定义事件(需 API 18+): ```java Trace.beginSection("MyCustomEvent"); // 你的代码 Trace.endSection(); ``` --- ### 三、分析 Trace 文件 #### 1. **整体观察 - **时间轴**:横向为时间,纵向为不同线程/进程。 - **关键区域**: - **Alerts**(红色警告):直接指出性能问题(如 UI 帧超过 16.6ms)。 - **CPU 频率**:检查 CPU 是否降频或满。 - **主线程状态**:重点关注 `RUNNABLE`(执行中)、`SLEEPING`(休眠)、`Uninterruptible Sleep`(阻塞)。 #### 2. **UI 卡顿分析 1. **定位掉帧**: - 查看 `SurfaceFlinger` 的 `vsync` 信号间隔(正常 16.6ms/帧)。 - 检查 `Choreographer#doFrame` 的耗时(应用绘制时间)。 - **示例**:某帧耗时 30ms → 超出 16.6ms,触发掉帧。 2. **阻塞原因**: - **主线程阻塞**:查找主线程长时间处于 `RUNNABLE` 或 `Uninterruptible Sleep`。 - **锁竞争**:观察 `Monitor` 锁的等待时间(红色高亮)。 - **Binder 调用**:检查跨进程调用(如 `Binder.transact`)是否耗时过长。 #### 3. **CPU 调度分析 - **CPU 闲置**:检查是否有线程因等待 CPU 资源而长时间处于 `runnable` 状态。 - **核心负不均**:观察任务是否集中在某几个 CPU 核心。 #### 4. **I/O 或网络延迟 - 查找 `binder`、`disk I/O` 或 `network` 相关线程的阻塞事件。 --- ### 四、快捷键与操作技巧 1. **导航**: - `WASD`:缩放/平移时间轴。 - `M`:标记选中区域的时间跨度。 2. **搜索**: - `Ctrl + F`:搜索关键词(如线程名、方法名)。 3. **查看详情**: - 点击事件查看参数(如锁名称、Binder 事务 ID)。 --- ### 五、典型案例分析 #### 案例 1:应用启动慢 1. 抓取应用启动期间的 Trace。 2. 分析主线程: - 检查 `ActivityThread` 的 `bindApplication` 和 `activityStart` 耗时。 - 定位 `ClassLoader` 或 `inflate` 布局的瓶颈。 #### 案例 2:列表滑动卡顿 1. 滑动列表时抓取 Trace。 2. 查找 `RecyclerView` 的 `onBindViewHolder` 或 `onDraw` 耗时。 3. 检查是否有主线程的磁盘读写(如 `SQLite` 操作)。 --- ### 六、注意事项 1. **抓取时间**:不宜过长(通常 5~20 秒),避免文件过大。 2. **复现问题**:抓取期间需手动复现问题(如卡顿场景)。 3. **结合其他工具**: - 使用 `dumpsys gfxinfo` 获取更详细的帧数据。 - 配合 `CPU Profiler` 或 `Perfetto` 进行深度分析。 通过 Systrace 的时间轴和事件详情,开发者可快速定位性能瓶颈,优化代码或系统配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值