android 13 systrace/perfetto視角分析SurfaceFlinger中截圖源碼分析
背景:
截圖是一種開發(fā)過程中經(jīng)常遇到的功能,但是這個功能底層是怎么實現(xiàn)的?今天就來給大家分享一下的,截圖的的實現(xiàn)原理。 截圖場景: 一般截圖都有以下幾個方式:
1、音量下鍵+power
2、systemui中下拉狀態(tài)欄,或者關(guān)機選著界面
3、adb shell命令行方式screencap命令方式
主要就是以上幾個,雖然場景不一樣,但是他們最后調(diào)用的截圖接口其實都是同一個,都是最后會調(diào)用到surfaceflinger中的截圖方法,下面就以adb shell命令行方式screencap案例分析,因為他的接口調(diào)用最為簡單,這次分析方式主要是使用perfetto的trace分析方式
screencap命令相關(guān)源碼及抓取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 這個就是調(diào)用截圖相關(guān)的接口,該接口實現(xiàn)如下:
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();
}
其實本質(zhì)是個跨進程調(diào)用,最后會調(diào)用到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());
}
結(jié)合trace分析
具體上面的流程進行systrace、perfetto展示如下:

這里顯示發(fā)起了一個跨進程調(diào)用,目標段是surfaceflinger進程

trace的總結(jié)圖如下:

surfaceflinger還有一個額外的回調(diào)客戶端操作:

1、準備好buffer來繪制截圖
2、主導surfaceflinger需要相關(guān)的layer預處理
3、使用SkiaGl引擎進行進行相關(guān)的Layer繪制到新buffer
4、通知客戶端,回調(diào)listener
更多干貨內(nèi)容請關(guān)注,及私聊千里馬本人