1. 程式人生 > >從surfaceflinger歷史變更談截屏

從surfaceflinger歷史變更談截屏

tran cer mage 了解 ext client 每一個 有一個 .cn

眾所周知,有一個程序screencap可以截屏,這個程序十分簡單,只是使用了surfaceflinger服務的截屏功能。

所以要了解截屏,看surfaceflinger服務的代碼是不二首選。但是surfaceflinger也隨android系統顯示子系統的變更而變更,網上最容易搜到的android資料都在11-14年的文章,都是4.x時代甚至2.x時代的技術,而android代代變化,有不少文章已經不再適用。

2.3.6之前,surfaceflinger放於base目錄。這時候的surfaceflinger使用FramebufferNativeWindow。

技術分享

4.0.x開始,suffaceflinger放於native目錄。但仍舊使用FramebufferNativeWindow。

技術分享

技術分享

4.2 開始,DisplayHardware類廢除(註意DisplayHardware目錄或者說組件沒有廢除,因為顯示系統變更了,不再只有一個Display,取而代之的是DisplayDevice類,這個類不在與DisplayHardware目錄同級。換句話說,以前surfaceflinger擁有一個DisplayHardware,現在開始就擁有一組DisplayDevice,這些DisplayDevice只代表某一GL上下文,並且不直接訪問Hardware層的fbDev,fbDev由HWComposer管理,DisplayDevice只能通過FramebufferSurface去訪問Hardware層),不再使用FramebufferNativeWindow,替而引入了FramebufferSurface。

技術分享

4.3 開始,DisplaySurface,VirutalDisplaySurface。並且廢除了libgui中的SurfaceTextureClient。

技術分享

在4.1.x之前,我稱為FramebufferNativeWindow時代,surface是直接從FramebufferNativeWindow創建的。

技術分享

技術分享

技術分享

技術分享

可以看到這是很常規的egl初始化。

在4.2 開始 FramebufferNativeWindow不再使用,因為在以前單一Display的時代,直接將fbDev和ANativeWindow偶合在一起。現在ANativeWindow和fbDev分離開。SurfaceTextureClient替代了FramebufferNativeWindow,並且不與fbDev偶合(,fbDev由HWComposer接管)。這裏必須區分好,android顯示系統有一個Surface,而egl也有一個EGLSurface,它們的連結點就是ANavtiveWindow,其定義路徑在/system/core/include/system/window.h 。

SurfaceTexture之前是直接繼承於BnSurfaceTexture,4.2 開始它與BnSurfaceTexture解偶,轉而繼承ComsumerBase。ComsumerBase擁有的BufferQueue才是繼承於BnSurfaceTexture(,定義在/frameworks/native/include/gui/ISurfaceTexture.h)。SurfaceTexture 與 BnSurfaceTexture生產消費者模式,並只作為消費者。

與此同時,在SurfaceTexture.h同一目錄添加了Surface(,定義在/frameworks/native/include/gui ,也就是 libgui.so), 相應地在surfaceflinger目錄有另一個對應的FramebufferSurface,是surfaceflinger服務私有的類,它是面向DisplayDevice的,是SurfaceTextureClient與HWComposer的結合點(Framebuffer就是指HWComposer,Surface則是SurfaceTextureClient一側,以及用於它的ConsumerBase)。這裏要註意,Surface繼承於(,isa)ANativeWindow,而FramebufferSurface卻繼承於(,isa)ConsumerBase。SurfaceTextureClient 作為ANativeWindow 依賴 ISurfaceTexture 服務器,去實現 ANativeWindow的hook接口queueBuffer以及dequeueBuffer。

下面是surfaceflinger初始化DisplayDevice數組:

技術分享

以及DisplayDevice初始化:

技術分享

技術分享

每個DisplayDevice使用SurfaceTextureClient這個ANativeWIndow去創建EGLSurface,而且這裏的SurfaceTextureClient使用的是FramebufferSurface的BufferQueue。

在 FramebufferNativeWindow時代,截屏直接使用FBO(,Frame Buffer Object)。

技術分享

然後每一個layer都繪制一次到framebuffer:

技術分享

最後GL讀出像素:

技術分享

在4.2開始,發生這些變化,首先實現的函數參數變化了

技術分享

技術分享

可以看到display不再以整型來作為標識,而是通過binder來標識。回看上面surfaceflinger在初始化DisplayDevice過程,只是簡單地 new BBinder() 來作為一個新的DisplayDevice的token,這個token只在binder驅動設備上建立了一個唯一的路徑,作用就是用來系統範圍內唯一標識。

所以在4.1.x及以前,screencap的代碼是:

技術分享

從4.2開始,screencap的代碼是:

技術分享

雖然上面說了一大堆的4.2變化,但是在截屏實現沒有變化,然而接下來的4.3就完全變化了。

4.2,Surface繼承於SurfaceTextureClient,但是4.3後,Surface脫離SurfaceTextureClient繼承樹,實現成另一個ANativeWindow,依賴 producer。記得上面嗎,4.2時,SurfaceTextureClient是一個依賴 FramebufferSurface這個consumer的ANativeWinodw。

下面是surfaceflinger對DisplayDevice的初始化:

技術分享

跟著是DisplayDevice的初始化:

技術分享

技術分享

我們來回顧一下,4.1.x以前使用FramebufferNativeWindow來創建EGLSurface,4.2時候使用SurfaceTextureClient(它使用FramebufferSurface),4.3開始,使用Surface。FramebufferNativeWindow, SurfaceTextureClient, Surface都是ANativeWindow。

4.3開始Surface也另外繼承DisplaySurface。(...有時間再補充寫)。

最重要是captureScreen接口改了

技術分享

實現上也就使用了BufferQueue,而不是IMemory來接收數據。

最最重要是沒有放出screencap的最新代碼,只停留在4.2時候的版本,也就是你不可能通過參照screencap.cpp去使用這個功能 。

技術分享

可參考Transaction_test.cpp

技術分享

從surfaceflinger歷史變更談截屏