Android screencap的处理流程
以下分析基于Android Q的代码
先大体整理screencap的处理流程
1.获取DisplayID
std::optional<PhysicalDisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
2. 调用ScreenshotClient::capture截取屏幕图像,数据保存在一个GraphicBuffer中
ui::Dataspace outDataspace;
sp<GraphicBuffer> outBuffer;
status_t result = ScreenshotClient::capture(*displayId, &outDataspace, &outBuffer);
3. BInder IPC 呼叫到 SurfaceFlinger::captureScreen
根据DisplayId获取到DisplayDevice信息,width/height/orientation/renderArea
4. 继续呼叫 SurfaceFlinger::captureScreenCommon
createGraphicBuffer
5. 继续调用 SurfaceFlinger::captureScreenImplLocked
找到belongsToDisplay 并判断(layer->isVisible() && layer->isSecure()的情况
6. 继续走到 SurfaceFlinger::renderScreenImplLocked
遍历belongsToDisplay的所有layer ==>layer->prepareClientLayer
7. 使用getRenderEngine().drawLayers 绘制合成到一个GraphicBuffer中
GLESRenderEngine::drawLayers中使用GLES完成图像绘制
大体如上过程screencap中就得到了最后保存屏幕截图的GraphicBuffer,然后利用Skia中的方法经encode保存在PNG图片
Android原生recent app机制的重点就是去获取screenshots of each task,具体是去调用 :
WindowManagerService::getTaskSnapshot
TaskSnapshot实际是在TaskSnapshotController中获取的
frameworks/base/services/core/java/com/android/server/wm/TaskSnapshotController.java
大体如下流程:
1. TaskSnapshotController::createTaskSnapshot
2. SurfaceControl::captureLayers
经JNI
3. ScreenshotClient::captureChildLayers
经binder
4. SurfaceFlinger::captureLayers
5. SurfaceFlinger::captureScreenCommon
6. SurfaceFlinger::captureScreenImplLocked
7. SurfaceFlinger::renderScreenImplLocked
8. GLESRenderEngine::drawLayers
处理过程和screencap截取屏幕是类似的,区别在于
screencap:呼叫ScreenshotClient::capture,传递displayId给SurfaceFlinger,会把和这个display相关的layer合成绘制到一张图片
TaskSnapshot: 呼叫ScreenshotClient::captureChildLayers,传递和task相关的layerHandle给SurfaceFlinger,会把和这个layerHandle相关的layers / child layers合成绘制到一张图片
差不多简单理解:
screencap:截取屏幕显示的内容
TaskSnapshot:截取一个apk界面显示的内容
但从SurfaceFlinger处理来说基本一致,最终都是通过GPU合成 画到一张图片,数据存到GraphicBuffer中返回给caller。