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.csdn.net/learnframework/article/details/132739059
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/learnframework/article/details/133565273