溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android中的SurfaceFlinger工作原理是什么

發(fā)布時間:2021-12-20 09:02:23 來源:億速云 閱讀:915 作者:柒染 欄目:開發(fā)技術(shù)

這篇文章將為大家詳細講解有關(guān)Android中的SurfaceFlinger工作原理是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

概念

SurfaceFlinger是一個系統(tǒng)服務,如:audioflinger,audiopolicyservice等等,系統(tǒng)的主要服務通過這個文章進行了解,Android的系統(tǒng)服務一覽。這個系統(tǒng)服務主要實現(xiàn)了Surface的建立、控制、管理等功能。換種說法就是,在Android 的實現(xiàn)中它是一個service,提供系統(tǒng)范圍內(nèi)的surface composer功能,它能夠?qū)⒏鞣N應用程序的2D、3D surface進行組合。

原理分析

讓我們首先看一下下面的屏幕簡略圖:

Android中的SurfaceFlinger工作原理是什么

每個應用程序可能對應著一個或者多個圖形界面,而每個界面我們就稱之為一個surface ,或者說是window ,在上面的圖中我們能看到4 個surface,一個是home 界面,還有就是紅、綠、藍分別代表的3 個surface ,而兩個button 實際是home surface 里面的內(nèi)容。在這里我們能看到我們進行圖形顯示所需要解決的問題:

  • a、首先每個surface 在屏幕上有它的位置,以及大小,然后每個surface 里面還有要顯示的內(nèi)容,內(nèi)容,大小,位置 這些元素 在我們改變應用程序的時候都可能會改變,改變時應該如何處理 ?

  • b、然后就各個surface 之間可能有重疊,比如說在上面的簡略圖中,綠色覆蓋了藍色,而紅色又覆蓋了綠色和藍色以及下面的home ,而且還具有一定透明度。這種層之間的關(guān)系應該如何描述?      

我們首先來看第二個問題,我們可以想象在屏幕平面的垂直方向還有一個Z 軸,所有的surface 根據(jù)在Z 軸上的坐標來確定前后,這樣就可以描述各個surface 之間的上下覆蓋關(guān)系了,而這個在Z 軸上的順序,圖形上有個專業(yè)術(shù)語叫Z-order 。  

對于第一個問題,我們需要一個結(jié)構(gòu)來記錄應用程序界面的位置,大小,以及一個buffer 來記錄需要顯示的內(nèi)容,所以這就是我們surface 的概念,surface 實際我們可以把它理解成一個容器,這個容器記錄著應用程序界面的控制信息,比如說大小啊,位置啊,而它還有buffer 來專門存儲需要顯示的內(nèi)容。

在這里還存在一個問題,那就是當存在圖形重合的時候應該如何處理呢,而且可能有些surface 還帶有透明信息,這里就是我們SurfaceFlinger 需要解決問題,它要把各個surface 組合(compose/merge) 成一個main Surface ,最后將Main Surface 的內(nèi)容發(fā)送給FB/V4l2 Output ,這樣屏幕上就能看到我們想要的效果。  在實際中對這些Surface 進行merge 可以采用兩種方式,一種就是采用軟件的形式來merge ,還一種就是采用硬件的方式,軟件的方式就是我們的SurfaceFlinger ,而硬件的方式就是Overlay 。

OverLay

因為硬件merge 內(nèi)容相對簡單,我們首先來看overlay 。 Overlay 實現(xiàn)的方式有很多,但都需要硬件的支持。以IMX51 為例子,當IPU 向內(nèi)核申請FB的時候它會申請3 個FB ,一個是主屏的,還一個是副屏的,還一個就是Overlay 的。 簡單地來說,Overlay就是我們將硬件所能接受的格式數(shù)據(jù) 和控制信息送到這個Overlay FrameBuffer,由硬件驅(qū)動來負責merge Overlay buffer和主屏buffer中的內(nèi)容。

一般來說現(xiàn)在的硬件都只支持一個Overlay,主要用在視頻播放以及camera preview上,因為視頻內(nèi)容的不斷變化用硬件Merge比用軟件Merge要有效率得多,下面就是使用Overlay和不使用Overlay的過程:

Android中的SurfaceFlinger工作原理是什么

SurfaceFlinger中加入了Overlay hal,只要實現(xiàn)這個Overlay hal可以使用overlay的功能,這個頭文件在:

/hardware/libhardware/include/harware/Overlay.h

可以使用FB或者V4L2 output來實現(xiàn),這個可能是我們將來工作的內(nèi)容。實現(xiàn)Overlay hal以后,使用Overlay接口的sequence就在 :

 /frameworks/base/libs/surfaceflinger/tests/overlays/Overlays.cpp,

這個sequnce是很重要的,后面我們會講到。

不過在實際中我們不一定需要實現(xiàn)Overlay hal,如果了解硬件的話,可以在驅(qū)動中直接把這些信息送到Overlay Buffer,而不需要走上層的Android。Fsl現(xiàn)在的Camera preview就是采用的這種方式,而且我粗略看了r3補丁的內(nèi)容,應該在opencore的視頻播放這塊也實現(xiàn)了Overlay。

SurfaceFlinger

現(xiàn) 在就來看看最復雜的SurfaceFlinger,首先要明確的是SurfaceFlinger只是負責merge Surface的控制,比如說計算出兩個Surface重疊的區(qū)域,至于Surface需要顯示的內(nèi)容,則通過skia,opengl和 pixflinger來計算。 所以我們在介紹SurfaceFlinger 之前先忽略里面存儲的內(nèi)容究竟是什么,先弄清楚它對merge 的一系列控制的過程,然后再結(jié)合2D ,3D 引擎來看它的處理過程。

3.1 、Surface 的創(chuàng)建過程

前面提到了每個應用程序可能有一個或者多個Surface , 我們需要一些數(shù)據(jù)結(jié)構(gòu)來存儲我們的窗口信息,我們還需要buffer 來存儲我們的窗口內(nèi)容, 而且最主要的是我們應該確定一個方案來和SurfaceFlinger 來交互這些信息,讓我們首先看看下面的Surface 創(chuàng)建過程的類圖 :

Android中的SurfaceFlinger工作原理是什么

在IBinder 左邊的就是客戶端部分,也就是需要窗口顯示的應用程序,而右邊就是我們的Surface Flinger service 。 創(chuàng)建一個surface 分為兩個過程,一個是在SurfaceFlinger 這邊為每個應用程序(Client) 創(chuàng)建一個管理 結(jié)構(gòu),另一個就是創(chuàng)建存儲內(nèi)容的buffer ,以及在這個buffer 上的一系列畫圖之類的操作。

因為SurfaceFlinger 要管理多個應用程序的多個窗口界面,為了進行管理它提供了一個Client 類,每個來請求服務的應用程序就對應了一個Client 。因為surface 是在SurfaceFlinger 創(chuàng)建的,必須返回一個結(jié)構(gòu)讓應用程序知道自己申請的surface 信息,因此SurfaceFlinger 將Client 創(chuàng)建的控制結(jié)構(gòu)per_client_cblk_t 經(jīng)過BClient 的封裝以后返回SurfaceComposerClient ,并向應用程序提供了一組創(chuàng)建和銷毀surface 的操作:

Android中的SurfaceFlinger工作原理是什么

為應用程序創(chuàng)建一個 Client 以后,下面需要做的就是為這個 Client 分配 Surface , Flinger 為每個 Client 提供了 8M的空間,包括控制信息和存儲內(nèi)容的 buffer 。在說創(chuàng)建 surface 之前首先要理解 layer 這個概念,回到我們前面看的屏幕簡略圖,實際上每個窗口就是 z 軸上的一個 layer , layer 提供了對窗口控制信息的操作,以及內(nèi)容的處理 ( 調(diào)用 opengl 或者 skia) ,也就是說 SurfaceFlinger 只是控制什么時候應該進行這些信息的處理以及處理的過程,所有實際的處理都是在 layer 中進行的,可以理解為創(chuàng)建一個 Surface 就是創(chuàng)建一個 Layer 。不得不說 Android 這些亂七八糟的名字,讓我繞了很久……

創(chuàng)建 Layer 的過程,首先是由這個應用程序的 Client 根據(jù)應用程序的 pid 生成一個唯一的 layer ID ,然后根據(jù)大小,位置,格式啊之類的信息創(chuàng)建出 Layer 。在 Layer 里面有一個嵌套的 Surface 類,它主要包含一個 ISurfaceFlingerClient::Surface_data_t ,包含了這個 Surace 的統(tǒng)一標識符以及 buffer信息等,提供給應用程序使用。最后應用程序會根據(jù)返回來的 ISurface 信息等創(chuàng)建自己的一個 Surface 。

Android中的SurfaceFlinger工作原理是什么

Android 提供了 4 種類型的 layer 供選擇,每個 layer 對應一種類型的窗口,并對應這種窗口相應的操作:

 Layer , LayerBlur , LayerBuffer ,LayerDim 。

 LayerBuffer 很容易讓人理解成是 Layer 的 Buffer ,它實際上是一種 Layer 類型。各個 Layer的效果大家可以參考 Surface.java 里面的描述: /frameworks/base/core/java/android/view/surface.java 。這里要重點說一下兩種 Layer ,一個是 Layer (norm layer) ,另一個是 LayerBuffer 。

Norm Layer 是 Android 種使用最多的一種 Layer ,一般的應用程序在創(chuàng)建 surface 的時候都是采用的這樣的 layer ,了解 Normal Layer 可以讓我們知道 Android 進行 display 過程中的一些基礎原理。 Normal Layer 為每個 Surface 分配兩個 buffer : front buffer 和 back buffer ,這個前后是相對的概念,他們是可以進行 Flip 的。 Front buffer 用于 SurfaceFlinger 進行顯示,而 Back buffer 用于應用程序進行畫圖,當 Back buffer 填滿數(shù)據(jù) (dirty) 以后,就會 flip, back buffer 就變成了 front buffer 用于顯示,而 front buffer 就變成了 back buffer 用來畫圖,這兩個 buffer 的大小是根據(jù) surface 的大小格式動態(tài)變化的。這個動態(tài)變化的實現(xiàn)我沒仔細看,可以參照 : /frameworks/base/lib/surfaceflinger/layer.cpp 中的 setbuffers() 。

兩個 buffer flip 的方式是 Android display 中的一個重要實現(xiàn)方式,不只是每個 Surface 這么實現(xiàn),最后寫入 FB 的 main surface 也是采用的這種方式。

LayerBuffer 也是將來必定會用到的一個 Layer ,個人覺得也是最復雜的一個 layer ,它不具備 render buffer ,主要用在 camera preview / video playback 上。它提供了兩種實現(xiàn)方式,一種就是 post buffer ,另外一種就是我們前面提到的 overlay , Overlay 的接口實際上就是在這個 layer 上實現(xiàn)的。不管是 overlay 還是 post buffer 都是指這個 layer 的數(shù)據(jù)來源自其他地方,只是 post buffer 是通過軟件的方式最后還是將這個 layer merge 主的 FB,而 overlay 則是通過硬件 merge 的方式來實現(xiàn)。與這個 layer 緊密聯(lián)系在一起的是 ISurface 這個接口,通過它來注冊數(shù)據(jù)來源,下面我舉個例子來說明這兩種方式的使用方法:

前面幾個步驟是通用的:

// 要使用 Surfaceflinger 的服務必須先創(chuàng)建一個 client

sp client = new SurfaceComposerClient();

// 然后向 Surfaceflinger 申請一個 Surface , surface 類型為 PushBuffers

sp surface = client->createSurface(getpid(), 0, 320, 240, PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);

// 然后取得 ISurface 這個接口, getISurface() 這個函數(shù)的調(diào)用時具有權(quán)限限制的,必須在Surface.h 中打開: /framewoks/base/include/ui/Surface.h

sp isurface = Test::getISurface(surface);

//overlay 方式下就創(chuàng)建 overlay ,然后就可以使用 overlay 的接口了

sp ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565);

sp verlay = new Overlay(ref);

//post buffer 方式下,首先要創(chuàng)建一個 buffer ,然后將 buffer 注冊到 ISurface 上

ISurface::BufferHeap buffers(w, h, w, h,

                                          PIXEL_FORMAT_YCbCr_420_SP,

                                         transform,

                                         0,

                                         mHardware->getPreviewHeap());

mSurface->registerBuffers(buffers);

3.2 、應用程序?qū)Υ翱诘目刂坪彤媹D

Surface 創(chuàng)建以后,應用程序就可以在 buffer 中畫圖了,這里就面對著下面幾個問題了:

  • a、是怎么知道在哪個 buffer 上來畫圖?

  • b、就是畫圖以后如何通知 SurfaceFlinger 來進行 flip ?

  • c、除了畫圖之外,如果我們移動窗口以及改變窗口大小的時候,如何告訴 SurfaceFlinger 來進行處理呢 ?

在明白這些問題之前,首先我們要了解 SurfaceFlinger 這個服務是如何運作的:

從類圖中可以看到 SurfaceFlinger 是一個線程類,它繼承了 Thread 類。當創(chuàng)建 SurfaceFlinger這個服務的時候會啟動一個 SurfaceFlinger 監(jiān)聽線程,這個線程會一直等待事件的發(fā)生,比如說需要進行 sruface flip ,或者說窗口位置大小發(fā)生了變化等等,一旦產(chǎn)生這些事件,SurfaceComposerClient 就會通過 IBinder 發(fā)出信號,這個線程就會結(jié)束等待處理這些事件,處理完成以后會繼續(xù)等待,如此循環(huán)。

SurfaceComposerClient 和 SurfaceFlinger 是通過 SurfaceFlingerSynchro 這個類來同步信號的,其實說穿了就是一個條件變量。監(jiān)聽線程等待條件的值變成 OPEN ,一旦變成 OPEN 就結(jié)束等待并將條件置成 CLOSE 然后進行事件處理,處理完成以后再繼續(xù)等待條件的值變成 OPEN ,而 Client 的Surface 一旦改變就通過 IBinder 通知 SurfaceFlinger 將條件變量的值變成 OPEN ,并喚醒等待的線程,這樣就通過線程類和條件變量實現(xiàn)了一個動態(tài)處理機制。

了解了 SurfaceFlinger 的事件機制我們再回頭看看前面提到的問題了。首先在對 Surface 進行畫圖之前必須鎖定 Surface 的 layer ,實際上就是鎖定了 Layer_cblk_t 里的 swapstate 這個變量。SurfaceComposerClient 通過 swapsate 的值來確定要使用哪個 buffer 畫圖,如果 swapstate 是下面的值就會阻塞Client ,就不翻譯了直接 copy 過來:

// We block the client if:

// eNextFlipPending:  we've used both buffers already, so we need to

//                    wait for one to become availlable.

// eResizeRequested:  the buffer we're going to acquire is being

//                    resized. Block until it is done.

// eFlipRequested && eBusy: the buffer we're going to acquire is

//                    currently in use by the server.

// eInvalidSurface:   this is a special case, we don't block in this

//                    case, we just return an error.

所以應用程序先調(diào)用 lockSurface() 鎖定 layer 的 swapstate ,并獲得畫圖的 buffer 然后就可以在上面進行畫圖了,完成以后就會調(diào)用unlockSurfaceAndPost() 來通知 SurfaceFlinger 進行 Flip?;蛘邇H僅調(diào)用 unlockSurface() 而不通知 SurfaceFlinger 。

一般來說畫圖的過程需要重繪 Surface 上的所有像素,因為一般情況下顯示過后的像素是不做保存的,不過也可以通過設定來保存一些像素,而只繪制部分像素,這里就涉及到像素的拷貝了,需要將 Front buffer 的內(nèi)容拷貝到 Back buffer 。在 SurfaceFlinger 服務實現(xiàn)中像素的拷貝是經(jīng)常需要進行的操作,而且還可能涉及拷貝過程的轉(zhuǎn)換,比如說屏幕的旋轉(zhuǎn),翻轉(zhuǎn)等一系列操作。因此 Android 提供了拷貝像素的 hal ,這個也可能是我們將來需要實現(xiàn)的,因為用硬件完成像素的拷貝,以及拷貝過程中可能的矩陣變換等操作,比用 memcpy 要有效率而且節(jié)省資源。這個 HAL 頭文件 在:

/hardware/libhardware/hardware/include/copybit.h

窗口狀態(tài)變化的處理是一個很復雜的過程,首先要說明一下, SurfaceFlinger 只是執(zhí)行 Windows manager 的指令,由 Windows manager 來決定什么是偶改變大小,位置,設置 透明度,以及如何調(diào)整 layer 之間的順序, SurfaceFlinger 僅僅只是執(zhí)行它的指令。 PS : Windows Manager 是java 層的一個服務,提供對所有窗口的管理 功能,這部分的內(nèi)容我沒細看過,覺得是將來需要了解的內(nèi)容。

窗口狀態(tài)的變化包括位置的移動,窗口大小,透明度, z-order 等等,首先我們來了解一下SurfaceComposerClient 是如何和 SurfaceFlinger 來交互這些信息的。當應用程序需要改變窗口狀態(tài)的時候它將所有的狀態(tài)改變信息打包,然后一起發(fā)送給 SurfaceFlinger , SurfaceFlinger 改變這些狀態(tài)信息以后,就會喚醒等待的監(jiān)聽線程,并設置一個標志位告訴監(jiān)聽線程窗口的狀態(tài)已經(jīng)改變了,必須要進行處理,在 Android 的實現(xiàn)中,這個打包的過程就是一個 Transaction ,所有對窗口狀態(tài)(layer_state_t) 的改變都必須在一個 Transaction 中。

到這里應用程序客戶端的處理過程已經(jīng)說完了,基本分為兩個部分,一個就是在窗口畫圖,還一個就是窗口狀態(tài)改變的處理。

4 、 SurfaceFlinger 的處理過程

了解了 Flinger 和客戶端的交互,我們再來仔細看看 SurfaceFlinger 的處理過程,前面已經(jīng)說過了SurfaceFlinger 這個服務在創(chuàng)建的時候會啟動一個監(jiān)聽的線程,這個線程負責每次窗口更新時候的處理,下面我們來仔細看看這個線程的事件的處理,大致就是下面的這個圖:

Android中的SurfaceFlinger工作原理是什么

先大致講一下 Android 組合各個窗口的原理 : Android 實際上是通過計算每一個窗口的可見區(qū)域,就是我們在屏幕上可見的窗口區(qū)域 ( 用 Android的詞匯來說就是 visibleRegionScreen ) ,然后將各個窗口的可見區(qū)域畫到一個主 layer 的相應部分,最后就拼接成了一個完整的屏幕,然后將主 layer 輸送到 FB 顯示。在將各個窗口可見區(qū)域畫到主 layer 過程中涉及到一個硬件實現(xiàn)和一個軟件實現(xiàn)的問題,如果是軟件實現(xiàn)則通過 Opengl 重新畫圖,其中還包括存在透明度的 alpha 計算;如果實現(xiàn)了 copybit hal 的話,可以直接將窗口的這部分數(shù)據(jù) 直接拷貝過來,并完成可能的旋轉(zhuǎn),翻轉(zhuǎn),以及 alhpa 計算等。

下面來看看 Android 組合各個 layer 并送到 FB 顯示的具體過程:

4.1 、 handleConsoleEvent

當接收到 signal 或者 singalEvent 事件以后,線程就停止等待開始對 Client 的請求進行處理,第一個步驟是 handleConsoleEvent ,這個步驟我看了下和 /dev/console 這個設備有關(guān),它會取得屏幕或者釋放屏幕,只有取得屏幕的時候才能夠在屏幕上畫圖。

4.2 、 handleTransaction

前面提到過,窗口狀態(tài)的改變只能在一個 Transaction 中進行。因為窗口狀態(tài)的改變可能造成本窗口和其他窗口的可見區(qū)域變化,所以就必須重新來計算窗口的可見區(qū)域。在這個處理子過程中 Android 會根據(jù)標志位來對所有 layer 進行遍歷,一旦發(fā)現(xiàn)哪個窗口的狀態(tài)發(fā)生了變化就設置標志位以在將來重新計算這個窗口的可見區(qū)域。在完成所有子 layer 的遍歷以后, Android 還會根據(jù)標志位來處理主 layer ,舉個例子,比如說傳感器感應到手機橫過來了,會將窗口橫向顯示,此時就要重新設置主 layer 的方向。

4.3 、 handlePageFlip

    這里會處理每個窗口 surface buffer 之間的翻轉(zhuǎn),根據(jù) layer_state_t 的 swapsate 來決定是否要翻轉(zhuǎn),當 swapsate 的值是 eNextFlipPending 是就會翻轉(zhuǎn)。處理完翻轉(zhuǎn)以后它會重新計算每個 layer的可見區(qū)域,這個重新計算的過程我還沒看太明白,但大致是一個這么的過程:

從 Z 值最大的 layer 開始計算,也就是說從最上層的 layer 計算,去掉本身的透明區(qū)域和覆蓋在它上面的不透明區(qū)域,得到的就是這個 layer 的可見區(qū)域。然后這個 layer 的不透明區(qū)域就會累加到不透明覆蓋區(qū)域,這個 layer 的可見區(qū)域會放入到主 layer 的可見區(qū)域,然后計算下一個 layer ,直到計算完所有的 layer 的可見區(qū)域。這中間的計算是通過定義在 skia 中的一種與或非的圖形邏輯運算實現(xiàn)的,類似我們數(shù)學中的與或非邏輯圖。

4.4 、 handleRepaint

計算出每個 layer 的可見區(qū)域以后,這一步就是將所有可見區(qū)域的內(nèi)容畫到主 layer 的相應部分了,也就是說將各個 surface buffer 里面相應的內(nèi)容拷貝到主 layer 相應的 buffer ,其中可能還涉及到alpha 運算,像素的翻轉(zhuǎn),旋轉(zhuǎn)等等操作,這里就像我前面說的可以用硬件來實現(xiàn)也可以用軟件來實現(xiàn)。在使用軟件的 opengl 做計算的過程中還會用到 PixFlinger 來做像素的合成,這部分內(nèi)容我還沒時間來細看。

4.5 、 postFrameBuffer

最后的任務就是翻轉(zhuǎn)主 layer 的兩個 buffer ,將剛剛寫入的內(nèi)容放入 FB 內(nèi)顯示了。

關(guān)于Android中的SurfaceFlinger工作原理是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI