SurfaceFlinger 原理分析

SurfaceFlinger是Android multimedia的一個(gè)部分惰帽,在Android 的實(shí)現(xiàn)中它是一個(gè)service憨降,提供系統(tǒng)范圍內(nèi)的surface composer功能,它能夠?qū)⒏鞣N應(yīng)用程序的2D该酗、3D surface進(jìn)行組合授药。

背景

屏幕應(yīng)用程序window組成

每個(gè)應(yīng)用程序可能對(duì)應(yīng)著一個(gè)或者多個(gè)圖形界面,而每個(gè)界面我們就稱(chēng)之為一個(gè)surface 呜魄,或者說(shuō)是window 悔叽,在上面的圖中我們能看到4 個(gè)surface ,一個(gè)是home 界面爵嗅,還有就是紅娇澎、綠、藍(lán)分別代表的3個(gè)surface 睹晒,而兩個(gè)button 實(shí)際是home surface 里面的內(nèi)容趟庄。我們需要考慮一下情況:

  • 每個(gè)surface 在屏幕上有它的位置、大小册招,然后每個(gè)surface 里面還有要顯示的內(nèi)容
  • 各個(gè)surface 之間可能有重疊
  1. 我們可以想象在屏幕平面的垂直方向還有一個(gè)Z 軸岔激,所有的surface 根據(jù)在Z 軸上的坐標(biāo)來(lái)確定前后,這樣就可以描述各個(gè)surface 之間的上下覆蓋關(guān)系了是掰,而這個(gè)在Z 軸上的順序虑鼎,圖形上有個(gè)專(zhuān)業(yè)術(shù)語(yǔ)叫Z-order 。
    2.我們需要一個(gè)結(jié)構(gòu)來(lái)記錄應(yīng)用程序界面的位置键痛,大小炫彩,以及一個(gè)buffer 來(lái)記錄需要顯示的內(nèi)容,所以這就是我們 surface 的概念絮短,surface 實(shí)際我們可以把它理解成一個(gè)容器江兢,這個(gè)容器記錄著應(yīng)用程序界面的控制信息,比如說(shuō)大小丁频、位置杉允,而它還有buffer 來(lái)專(zhuān)門(mén)存儲(chǔ)需要顯示的內(nèi)容邑贴。
  2. 當(dāng)存在圖形重合或者有些surface 還帶有透明信息的時(shí)候,就需要 SurfaceFlinger 來(lái)解決問(wèn)題叔磷,它要把各個(gè)surface 組合(compose/merge)成一個(gè)main Surface 拢驾,最后將Main Surface 的內(nèi)容發(fā)送給FB/V4l2 Output ,這樣屏幕上就能看到我們想要的效果改基。

在實(shí)際中對(duì)這些Surface 進(jìn)行merge 可以采用兩種方式繁疤,一種就是采用軟件的形式來(lái)merge ,還一種就是采用硬件的方式秕狰,軟件的方式就是我們的SurfaceFlinger 稠腊,而硬件的方式就是Overlay

Overlay

因?yàn)橛布erge 內(nèi)容相對(duì)簡(jiǎn)單鸣哀,我們首先來(lái)看overlay 架忌。以IMX51 為例子,當(dāng)IPU 向內(nèi)核申請(qǐng)F(tuán)B 的時(shí)候它會(huì)申請(qǐng)3 個(gè)FB 诺舔,一個(gè)是主屏的鳖昌,還一個(gè)是副屏的,還一個(gè)就是Overlay 的低飒。 簡(jiǎn)單地來(lái)說(shuō)许昨,Overlay就是我們將硬件所能接受的格式數(shù)據(jù)和控制信息送到這個(gè)Overlay FrameBuffer,由硬件驅(qū)動(dòng)來(lái)負(fù)責(zé)merge Overlay buffer和主屏buffer中的內(nèi)容褥赊。

一般來(lái)說(shuō)現(xiàn)在的硬件都只支持一個(gè)Overlay糕档,主要用在視頻播放以及camera preview上,因?yàn)橐曨l內(nèi)容的不斷變化用硬件Merge比用軟件Merge要有效率得多拌喉,下面就是使用Overlay和不使用Overlay的過(guò)程:


對(duì)比圖
SurfaceFlinger

surfaceFlinger 只是負(fù)責(zé) merge Surface 的控制速那,比如說(shuō)計(jì)算出兩個(gè) Surface 重疊的區(qū)域,至于 Surface 需要顯示的內(nèi)容尿背,則通過(guò) skia端仰,opengl 和 pixflinger 來(lái)計(jì)算。
創(chuàng)建過(guò)程

創(chuàng)建類(lèi)圖

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

  1. 創(chuàng)建Client
    因?yàn)镾urfaceFlinger 要管理多個(gè)應(yīng)用程序的多個(gè)窗口界面臀稚,為了進(jìn)行管理它提供了一個(gè)Client 類(lèi),每個(gè)來(lái)請(qǐng)求服務(wù)的應(yīng)用程序就對(duì)應(yīng)了一個(gè) Client 三痰。因?yàn)?surface 是在 SurfaceFlinger 創(chuàng)建的吧寺,必須返回一個(gè)結(jié)構(gòu)讓?xiě)?yīng)用程序知道自己申請(qǐng)的 surface 信息窜管,因此 SurfaceFlinger 將 Client 創(chuàng)建的控制結(jié)構(gòu)per_client_cblk_t 經(jīng)過(guò) BClient 的封裝以后返回給 SurfaceComposerClient ,并向應(yīng)用程序提供了一組創(chuàng)建和銷(xiāo)毀 surface 的接口:


    Client稚机、BClient 與 SurfaceFlinger

    Flinger 為每個(gè) Client 提供了 8M 的空間微峰,包括控制信息和存儲(chǔ)內(nèi)容的 buffer 。
    為應(yīng)用程序創(chuàng)建一個(gè) Client 以后抒钱,下面需要做的就是為這個(gè) Client 分配 Surface , 可以理解為創(chuàng)建一個(gè) Surface 就是創(chuàng)建一個(gè) Layer 颜凯。

  2. 創(chuàng)建 Layer
    創(chuàng)建 Layer 的過(guò)程谋币,首先是由這個(gè)應(yīng)用程序的 Client 根據(jù)應(yīng)用程序的 pid 生成一個(gè)唯一的 layer ID ,然后根據(jù)大小症概、位置蕾额、格式等信息創(chuàng)建出 Layer 。在 Layer 里面有一個(gè)嵌套的 Surface 類(lèi)彼城,它主要包含一個(gè) ISurfaceFlingerClient::Surface_data_t 诅蝶,包含了這個(gè) Surace 的統(tǒng)一標(biāo)識(shí)符以及 buffer 信息等,提供給應(yīng)用程序使用募壕。最后應(yīng)用程序會(huì)根據(jù)返回來(lái)的 ISurface 創(chuàng)建一個(gè)自己的 Surface 调炬。


    Layer 創(chuàng)建過(guò)程

    Android 提供了 4 種類(lèi)型的 layer 供選擇: Layer , LayerBlur 舱馅, LayerBuffer 缰泡, LayerDim ,每個(gè) layer 對(duì)應(yīng)一種類(lèi)型的窗口代嗤,并對(duì)應(yīng)這種窗口相應(yīng)的操作

  • Normal Layer
    它是 Android 種使用最多的一種 Layer 棘钞,一般的應(yīng)用程序在創(chuàng)建 surface 的時(shí)候都是采用的這樣的 layer , Normal Layer 為每個(gè) Surface 分配兩個(gè) buffer : front buffer 和 back buffer 干毅, Front buffer 用于 SurfaceFlinger 進(jìn)行顯示宜猜,而 Back buffer 用于應(yīng)用程序進(jìn)行畫(huà)圖,當(dāng) Back buffer 填滿(mǎn)數(shù)據(jù) (dirty) 以后硝逢,就會(huì) flip 姨拥, back buffer 就變成了 front buffer 用于顯示,而 front buffer 就變成了 back buffer 用來(lái)畫(huà)圖趴捅。
  • LayerBuffer
    最復(fù)雜的一個(gè) layer垫毙,它不具備 render buffer ,主要用在 camera preview / video playback 上拱绑。它提供了兩種實(shí)現(xiàn)方式综芥,一種就是 post buffer ,另外一種就是我們前面提到的 overlay 猎拨, Overlay 的接口實(shí)際上就是在這個(gè) layer 上實(shí)現(xiàn)的膀藐。不管是 overlay 還是 post buffer 都是指這個(gè) layer 的數(shù)據(jù)來(lái)源自其他地方屠阻,只是 post buffer 是通過(guò)軟件的方式最后還是將這個(gè) layer merge 主的 FB ,而 overlay 則是通過(guò)硬件 merge 的方式來(lái)實(shí)現(xiàn)额各。與這個(gè) layer 緊密聯(lián)系在一起的是 ISurface 這個(gè)接口国觉,通過(guò)它來(lái)注冊(cè)數(shù)據(jù)來(lái)源。用法如下:
// 要使用 Surfaceflinger 的服務(wù)必須先創(chuàng)建一個(gè) client
sp<SurfaceComposerClient> client = new SurfaceComposerClient();

// 然后向 Surfaceflinger 申請(qǐng)一個(gè) Surface 虾啦, surface 類(lèi)型為 PushBuffers
sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240,
            PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);

// 然后取得 ISurface 這個(gè)接口麻诀, getISurface() 這個(gè)函數(shù)的調(diào)用時(shí)具有權(quán)限限制的,
// 必須在Surface.h 中打開(kāi): /framewoks/base/include/ui/Surface.h
sp<ISurface> isurface = Test::getISurface(surface);

//overlay 方式下就創(chuàng)建 overlay 傲醉,然后就可以使用 overlay 的接口了
sp<OverlayRef> ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565);
sp<Overlay> verlay = new Overlay(ref);

//post buffer 方式下蝇闭,首先要?jiǎng)?chuàng)建一個(gè) buffer ,然后將 buffer 注冊(cè)到 ISurface 上
ISurface::BufferHeap buffers(w, h, w, h,
                                          PIXEL_FORMAT_YCbCr_420_SP,
                                         transform,
                                         0,
                                         mHardware->getPreviewHeap());
mSurface->registerBuffers(buffers);
  1. 硬毕、應(yīng)用程序?qū)Υ翱诘目刂埔约爱?huà)圖
    首先了解一下 SurfaceFlinger 這個(gè)服務(wù)的運(yùn)作方式:

SurfaceFlinger 是一個(gè)線程類(lèi)呻引,它繼承了 Thread 類(lèi)。當(dāng)創(chuàng)建 SurfaceFlinger 這個(gè)服務(wù)的時(shí)候會(huì)啟動(dòng)一個(gè) SurfaceFlinger 監(jiān)聽(tīng)線程吐咳,這個(gè)線程會(huì)一直等待事件的發(fā)生逻悠,比如說(shuō)需要進(jìn)行 sruface flip ,或者說(shuō)窗口位置大小發(fā)生了變化等韭脊,一旦產(chǎn)生這些事件童谒,SurfaceComposerClient 就會(huì)通過(guò) IBinder 發(fā)出信號(hào),這個(gè)線程就會(huì)結(jié)束等待處理這些事件沪羔,處理完成以后會(huì)繼續(xù)等待惠啄,如此循環(huán)。
SurfaceComposerClient 和 SurfaceFlinger 是通過(guò) SurfaceFlingerSynchro 這個(gè)類(lèi)來(lái)同步信號(hào)的任内,其實(shí)說(shuō)穿了就是一個(gè)條件變量撵渡。監(jiān)聽(tīng)線程等待條件的值一旦變成 OPEN 就結(jié)束等待并將條件置成 CLOSE 然后進(jìn)行事件處理,處理完成以后再繼續(xù)等待條件的值變成 OPEN 死嗦,而 Client 的Surface 一旦改變就通過(guò) IBinder 通知 SurfaceFlinger 將條件變量的值變成 OPEN 趋距,并喚醒等待的線程,這樣就通過(guò)線程類(lèi)和條件變量實(shí)現(xiàn)了一個(gè)動(dòng)態(tài)處理機(jī)制越除。

  • 在對(duì) Surface 進(jìn)行畫(huà)圖之前必須鎖定 Surface 的 layer 节腐,實(shí)際上就是鎖定了 Layer_cblk_t 里的 swapstate 這個(gè)變量。SurfaceComposerClient 通過(guò)調(diào)用 lockSurface() 來(lái)鎖定 swapsate 的值來(lái)確定要使用哪個(gè) buffer 畫(huà)圖摘盆,如果 swapstate 是下面的值就會(huì)阻塞 Client 翼雀,
    | value | usages |
    | ------ | ------ |
    | 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: | he 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)用 unlockSurfaceAndPost() 來(lái)通知 SurfaceFlinger 進(jìn)行Flip『⒗蓿或者僅僅調(diào)用 unlockSurface() 而不通知 SurfaceFlinger 狼渊。
    一般來(lái)說(shuō)畫(huà)圖的過(guò)程需要重繪 Surface 上的所有像素,因?yàn)橐话闱闆r下顯示過(guò)后的像素是不做保存的,不過(guò)也可以通過(guò)設(shè)定來(lái)保存一些像素狈邑,而只繪制部分像素城须,這里就涉及到像素的拷貝了,需要將Front buffer 的內(nèi)容拷貝到 Back buffer 米苹。在 SurfaceFlinger 服務(wù)實(shí)現(xiàn)中像素的拷貝是經(jīng)常需要進(jìn)行的操作糕伐,而且還可能涉及拷貝過(guò)程的轉(zhuǎn)換,比如說(shuō)屏幕的旋轉(zhuǎn)蘸嘶,翻轉(zhuǎn)等一系列操作良瞧。因此 Android 提供了拷貝像素的 hal ,這個(gè)也可能是我們將來(lái)需要實(shí)現(xiàn)的训唱,因?yàn)橛糜布瓿上袼氐目截愝喊约翱截愡^(guò)程中可能的矩陣變換等操作,比用 memcpy 要有效率而且節(jié)省資源雪情。這個(gè) HAL 頭文件在:/hardware/libhardware/hardware/include/copybit.h

窗口狀態(tài)變化的處理是一個(gè)很復(fù)雜的過(guò)程,SurfaceFlinger 只是執(zhí)行 Windows Manager 的指令你辣,由 Windows manager 來(lái)決定什么是偶改變大小巡通、位置、透明度舍哄、以及如何調(diào)整layer 之間的順序宴凉, SurfaceFlinger 僅僅只是執(zhí)行它的指令。

  1. SurfaceFlinger 的處理過(guò)程
    監(jiān)聽(tīng)的處理過(guò)程

    前面已經(jīng)說(shuō)過(guò)了SurfaceFlinger 這個(gè)服務(wù)在創(chuàng)建的時(shí)候會(huì)啟動(dòng)一個(gè)監(jiān)聽(tīng)的線程表悬,這個(gè)線程負(fù)責(zé)每次窗口更新時(shí)候的處理弥锄。
    Android 組合各個(gè)窗口的原理: Android 實(shí)際上是通過(guò)計(jì)算每一個(gè)窗口的可見(jiàn)區(qū)域,就是我們?cè)谄聊簧峡梢?jiàn)的窗口區(qū)域 ( 用 Android 的詞匯來(lái)說(shuō)就是 visibleRegionScreen ) 蟆沫,然后將各個(gè)窗口的可見(jiàn)區(qū)域畫(huà)到一個(gè)主 layer 的相應(yīng)部分籽暇,最后就拼接成了一個(gè)完整的屏幕,然后將主 layer 輸送到 FB 顯示饭庞。在將各個(gè)窗口可見(jiàn)區(qū)域畫(huà)到主 layer 過(guò)程中涉及到一個(gè)硬件實(shí)現(xiàn)和一個(gè)軟件實(shí)現(xiàn)的問(wèn)題戒悠,如果是軟件實(shí)現(xiàn)則通過(guò) Opengl 重新畫(huà)圖,其中還包括存在透明度的 alpha 計(jì)算舟山;如果實(shí)現(xiàn)了 copybit hal 的話绸狐,可以直接將窗口的這部分?jǐn)?shù)據(jù)直接拷貝過(guò)來(lái),并完成可能的旋轉(zhuǎn)累盗,翻轉(zhuǎn)寒矿,以及 alhpa計(jì)算等。
  • handleConsoleEvent
    當(dāng)接收到 signal 或者 singalEvent 事件以后若债,線程就停止等待開(kāi)始對(duì) Client 的請(qǐng)求進(jìn)行處理符相,第一個(gè)步驟是 handleConsoleEvent ,它會(huì)取得屏幕或者釋放屏幕蠢琳,只有取得屏幕的時(shí)候才能夠在屏幕上畫(huà)圖主巍。
  • handleTransaction
    因?yàn)?strong>窗口狀態(tài)的改變只能在一個(gè) Transaction 中進(jìn)行冠息。而窗口狀態(tài)的改變可能造成本窗口和其他窗口的可見(jiàn)區(qū)域變化,所以就必須重新來(lái)計(jì)算窗口的可見(jiàn)區(qū)域孕索。在這個(gè)處理子過(guò)程中 Android會(huì)根據(jù)標(biāo)志位來(lái)對(duì)所有 layer 進(jìn)行遍歷逛艰,一旦發(fā)現(xiàn)哪個(gè)窗口的狀態(tài)發(fā)生了變化就設(shè)置標(biāo)志位以在將來(lái)重新計(jì)算這個(gè)窗口的可見(jiàn)區(qū)域。在完成所有子 layer 的遍歷以后搞旭, Android 還會(huì)根據(jù)標(biāo)志位來(lái)處理主layer 散怖,舉個(gè)例子,比如說(shuō)傳感器感應(yīng)到手機(jī)橫過(guò)來(lái)了肄渗,會(huì)將窗口橫向顯示镇眷,此時(shí)就要重新設(shè)置主 layer 的方向。
  • handlePageFlip
    處理每個(gè)窗口 surface buffer 之間的翻轉(zhuǎn)翎嫡,根據(jù) layer_state_t 的 swapsate 來(lái)決定是否要翻轉(zhuǎn)欠动,當(dāng) swapsate 的值是 eNextFlipPending 是就會(huì)翻轉(zhuǎn)。處理完翻轉(zhuǎn)以后它會(huì)重新計(jì)算每個(gè) layer的可見(jiàn)區(qū)域惑申。
  • handleRepaint
    計(jì)算出每個(gè) layer 的可見(jiàn)區(qū)域以后具伍,這一步就是將所有可見(jiàn)區(qū)域的內(nèi)容畫(huà)到主 layer 的相應(yīng)部分了,也就是說(shuō)將各個(gè) surface buffer 里面相應(yīng)的內(nèi)容拷貝到主 layer 相應(yīng)的 buffer 圈驼,其中可能還涉及到alpha 運(yùn)算人芽,像素的翻轉(zhuǎn),旋轉(zhuǎn)等等操作绩脆,這里就像我前面說(shuō)的可以用硬件來(lái)實(shí)現(xiàn)也可以用軟件來(lái)實(shí)現(xiàn)萤厅。在使用軟件的 opengl 做計(jì)算的過(guò)程中還會(huì)用到 PixFlinger 來(lái)做像素的合成,
  • postFrameBuffer
    翻轉(zhuǎn)主 layer 的兩個(gè) buffer 靴迫,將剛剛寫(xiě)入的內(nèi)容放入 FB 內(nèi)顯示了惕味。

共享內(nèi)存

普通的Android控件,例如TextView玉锌、Button和CheckBox等赦拘,它們都是將自己的UI繪制在宿主窗口的繪圖表面之上,這意味著它們的UI是在應(yīng)用程序的主線程中進(jìn)行繪制的。由于應(yīng)用程序的主線程除了要繪制UI之外,還需要及時(shí)地響應(yīng)用戶(hù)輸入系羞,否則系統(tǒng)就會(huì)認(rèn)為應(yīng)用程序沒(méi)有響應(yīng)了扭屁。而對(duì)于一些游戲畫(huà)面,或者攝像頭預(yù)覽、視頻播放來(lái)說(shuō),它們的UI都比較復(fù)雜,而且要求能夠進(jìn)行高效的繪制捎谨。這時(shí)候就必須要給那些需要復(fù)雜而高效UI的視圖生成一個(gè)獨(dú)立的繪圖表面,以及使用一個(gè)獨(dú)立的線程來(lái)繪制這些視圖的UI。

SurfaceFlinger服務(wù)運(yùn)行在Android系統(tǒng)的System進(jìn)程中涛救,它負(fù)責(zé)管理Android系統(tǒng)的幀緩沖區(qū)(Frame Buffer)畏邢。Android應(yīng)用程序?yàn)榱四軌驅(qū)⒆约旱腢I繪制在系統(tǒng)的幀緩沖區(qū)上,它們就必須要與SurfaceFlinger服務(wù)進(jìn)行通信检吆。

在APP端執(zhí)行draw的時(shí)候舒萎,數(shù)據(jù)很明顯是要繪制到APP的進(jìn)程空間,但是視圖窗口要經(jīng)過(guò)SurfaceFlinger圖層混排才會(huì)生成最終的幀蹭沛,而SurfaceFlinger又運(yùn)行在另一個(gè)獨(dú)立的服務(wù)進(jìn)程臂寝,那么View視圖的數(shù)據(jù)是如何在兩個(gè)進(jìn)程間傳遞的呢,普通的Binder通信肯定不行摊灭,因?yàn)锽inder不太適合這種數(shù)據(jù)量較大的通信咆贬,那么View數(shù)據(jù)的通信采用的是什么IPC手段呢?答案就是共享內(nèi)存帚呼,更精確的說(shuō)是匿名共享內(nèi)存掏缎。共享內(nèi)存是Linux自帶的一種IPC機(jī)制,Android直接使用了該模型煤杀,不過(guò)做出了自己的改進(jìn)眷蜈,進(jìn)而形成了Android的匿名共享內(nèi)存(Anonymous Shared Memory-Ashmem)。通過(guò)Ashmem怜珍,APP進(jìn)程同SurfaceFlinger共用一塊內(nèi)存,如此凤粗,就不需要進(jìn)行數(shù)據(jù)拷貝酥泛,APP端繪制完畢嫌拣,通知SurfaceFlinger端合成捶索,再輸出到硬件進(jìn)行顯示即可。


View繪制與共享內(nèi)存

在每一個(gè)Android應(yīng)用程序與SurfaceFlinger服務(wù)之間的連接上加上一塊用來(lái)傳遞UI元數(shù)據(jù)的匿名共享內(nèi)存燎竖,這個(gè)共享內(nèi)存就是 SharedClient


shareClient.jpg

在每一個(gè)SharedClient里面构回,有至多31個(gè)SharedBufferStack纤掸。SharedBufferStack就是Android應(yīng)用程序和SurfaceFlinger 的緩沖區(qū)堆棧政己。用來(lái)緩沖 UI 元數(shù)據(jù)。
一般我們就繪制UI的時(shí)候,都會(huì)采用一種稱(chēng)為“雙緩沖”的技術(shù)京腥。雙緩沖意味著要使用兩個(gè)緩沖區(qū),其中一個(gè)稱(chēng)為Front Buffer,另外一個(gè)稱(chēng)為Back Buffer。UI總是先在Back Buffer中繪制宜鸯,然后再和Front Buffer交換鸿市,渲染到顯示設(shè)備中剥懒。這下就可以理解SharedBufferStack的含義了吧谒获?SurfaceFlinger服務(wù)只不過(guò)是將傳統(tǒng)的“雙緩沖”技術(shù)升華和抽象為了一個(gè)SharedBufferStack∽Σ玻可別小看了這個(gè)升華和抽象榔昔,有了SharedBufferStack之后瘪菌,SurfaceFlinger 服務(wù)就可以使用N個(gè)緩沖區(qū)技術(shù)來(lái)繪制UI了撒会。N值的取值范圍為2到16。例如师妙,在Android 2.3中诵肛,N的值等于2,而在Android 4.1中默穴,據(jù)說(shuō)就等于3了怔檩。

在SurfaceFlinger服務(wù)中,每一個(gè)SharedBufferStack都對(duì)應(yīng)一個(gè)Surface壁顶,即一個(gè)窗口珠洗。這樣溜歪,我們就可以知道為什么每一個(gè)SharedClient里面包含的是一系列SharedBufferStack而不是單個(gè)SharedBufferStack:一個(gè)SharedClient對(duì)應(yīng)一個(gè)Android應(yīng)用程序若专,而一個(gè)Android應(yīng)用程序可能包含有多個(gè)窗口,即Surface蝴猪。從這里也可以看出调衰,一個(gè)Android應(yīng)用程序至多可以包含31個(gè)Surface。

SharedBufferStack

我們假設(shè)圖中的SharedBufferStack有5個(gè)Buffer自阱,其中嚎莉,Buffer-1和Buffer-2是已經(jīng)使用了的,而B(niǎo)uffer-3沛豌、Buffer-4和Buffer-5是空閑的趋箩。指針head和tail分別指向空閑緩沖區(qū)列表的頭部和尾部赃额,而指針queue_head指向已經(jīng)使用了的緩沖區(qū)列表的頭部。從這里就可以看出叫确,從指針tail到head之間的Buffer即為空閑緩沖區(qū)表跳芳,而從指針head到queue_head之間的Buffer即為已經(jīng)使用了的緩沖區(qū)列表。注意竹勉,圖中的5個(gè)Buffer是循環(huán)使用的飞盆。

SharedBufferStack中的緩沖區(qū)只是用來(lái)描述UI元數(shù)據(jù)的,這意味著它們不包含真正的UI數(shù)據(jù)次乓。真正的UI數(shù)據(jù)保存在GraphicBuffer中吓歇,后面我們?cè)倜枋鯣aphicBuffer。因此票腰,為了完整地描述一個(gè)UI城看,SharedBufferStack中的每一個(gè)已經(jīng)使用了的緩沖區(qū)都對(duì)應(yīng)有一個(gè)GraphicBuffer,用來(lái)描述真正的UI數(shù)據(jù)丧慈。當(dāng)SurfaceFlinger服務(wù)緩制Buffer-1和Buffer-2的時(shí)候析命,就會(huì)找到與它們所對(duì)應(yīng)的GraphicBuffer,這樣就可以將對(duì)應(yīng)的UI繪制出來(lái)了逃默。

當(dāng)Android應(yīng)用程序需要更新一個(gè)Surface的時(shí)候鹃愤,它就會(huì)找到與它所對(duì)應(yīng)的SharedBufferStack,并且從它的空閑緩沖區(qū)列表的尾部取出一個(gè)空閑的Buffer完域。我們假設(shè)這個(gè)取出來(lái)的空閑Buffer的編號(hào)為index软吐。接下來(lái)Android應(yīng)用程序就請(qǐng)求SurfaceFlinger服務(wù)為這個(gè)編號(hào)為index的Buffer分配一個(gè)圖形緩沖區(qū)GraphicBuffer

SurfaceFlinger 服務(wù)分配好圖形緩沖區(qū) GraphicBuffer 之后吟税,會(huì)將它的編號(hào)設(shè)置為 index凹耙,然后再將這個(gè)圖形緩沖區(qū) GraphicBuffer 返回給 Android 應(yīng)用程序訪問(wèn)。Android應(yīng)用程序得到了 SurfaceFlinger 服務(wù)返回的圖形緩沖區(qū) GraphicBuffer 之后肠仪,就在里面寫(xiě)入U(xiǎn)I數(shù)據(jù)肖抱。寫(xiě)完之后,就將與它所對(duì)應(yīng)的緩沖區(qū)异旧,即編號(hào)為 index 的 Buffer意述,插入到對(duì)應(yīng)的 SharedBufferStack 的已經(jīng)使用了的緩沖區(qū)列表的頭部去。這一步完成了之后吮蛹,Android 應(yīng)用程序就通知 SurfaceFlinger 服務(wù)去繪制那些保存在已經(jīng)使用了的緩沖區(qū)所描述的圖形緩沖區(qū)GraphicBuffer了荤崇。用上面例子來(lái)說(shuō),SurfaceFlinger服務(wù)需要繪制的是編號(hào)為1和2的Buffer所對(duì)應(yīng)的圖形緩沖區(qū)GraphicBuffer潮针。由于SurfaceFlinger服務(wù)知道編號(hào)為1和2的 Buffer 所對(duì)應(yīng)的圖形緩沖區(qū) GraphicBuffer 在哪里术荤,因此,Android 應(yīng)用程序只需要告訴 SurfaceFlinger 服務(wù)要繪制的 Buffer 的編號(hào)就OK了每篷。當(dāng)一個(gè)已經(jīng)被使用了的Buffer被繪制了之后瓣戚,它就重新變成一個(gè)空閑的 Buffer 了端圈。

SharedBufferStack 是在 Android 應(yīng)用程序和 SurfaceFlinger 服務(wù)之間共享的,但是子库,Android 應(yīng)用程序和 SurfaceFlinger 服務(wù)使用 SharedBufferStack 的方式是不一樣的枫笛,具體來(lái)說(shuō),就是 Android 應(yīng)用程序關(guān)心的是它里面的空閑緩沖區(qū)列表刚照,而 SurfaceFlinger 服務(wù)關(guān)心的是它里面的已經(jīng)使用了的緩沖區(qū)列表刑巧。從SurfaceFlinger服務(wù)的角度來(lái)看,保存在 SharedBufferStack中 的已經(jīng)使用了的緩沖區(qū)其實(shí)就是在排隊(duì)等待渲染无畔。

為了方便 SharedBufferStack 在 Android 應(yīng)用程序和 SurfaceFlinger 服務(wù)中的訪問(wèn)啊楚,Android 系統(tǒng)分別使用 SharedBufferClient 和 SharedBufferServer 來(lái)描述 SharedBufferStack ,其中浑彰,SharedBufferClient 用來(lái)在Android 應(yīng)用程序這一側(cè)訪問(wèn) SharedBufferStack 的空閑緩沖區(qū)列表恭理,而 SharedBufferServer 用來(lái)在SurfaceFlinger 服務(wù)這一側(cè)訪問(wèn) SharedBufferStack 的排隊(duì)緩沖區(qū)列表。


SharedBufferClient眼中的SharedBufferStack

只要 SharedBufferStack 中的 available 的 buffer 的數(shù)量大于0郭变, SharedBufferClient 就會(huì)將指針 tail 往前移一步颜价,并且減少 available 的值,以便可以獲得一個(gè)空閑的 Buffer诉濒。當(dāng) Android 應(yīng)用程序往這個(gè)空閑的 Buffer 寫(xiě)入好數(shù)據(jù)之后周伦,它就會(huì)通過(guò) SharedBufferClient 來(lái)將它添加到 SharedBufferStack 中的排隊(duì)緩沖區(qū)列表的尾部去,即指針 queue_head 的下一個(gè)位置上未荒。


SharedBufferServer眼中的SharedBufferStack.jpg

當(dāng) Android 應(yīng)用程序通知 SurfaceFlinger 服務(wù)更新UI的時(shí)候专挪,只要對(duì)應(yīng)的 SharedBufferStack 中的 queued 的緩沖區(qū)的數(shù)量大于0,SharedBufferServer 就會(huì)將指針 head 的下一個(gè)Buffer繪制出來(lái)片排,并且將指針 head 向前移一步寨腔,以及將 queued 的值減1。

參考:
https://blog.csdn.net/luoshengyang/article/details/7846923

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末率寡,一起剝皮案震驚了整個(gè)濱河市迫卢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冶共,老刑警劉巖乾蛤,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異比默,居然都是意外死亡幻捏,警方通過(guò)查閱死者的電腦和手機(jī)盆犁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)命咐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人谐岁,你說(shuō)我怎么就攤上這事醋奠¢痪剩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵窜司,是天一觀的道長(zhǎng)沛善。 經(jīng)常有香客問(wèn)我,道長(zhǎng)塞祈,這世上最難降的妖魔是什么金刁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮议薪,結(jié)果婚禮上尤蛮,老公的妹妹穿的比我還像新娘。我一直安慰自己斯议,他們只是感情好产捞,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著哼御,像睡著了一般坯临。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恋昼,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天看靠,我揣著相機(jī)與錄音,去河邊找鬼液肌。 笑死衷笋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的矩屁。 我是一名探鬼主播辟宗,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吝秕!你這毒婦竟也來(lái)了泊脐?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤烁峭,失蹤者是張志新(化名)和其女友劉穎容客,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體约郁,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缩挑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鬓梅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片供置。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绽快,靈堂內(nèi)的尸體忽然破棺而出芥丧,到底是詐尸還是另有隱情紧阔,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布续担,位于F島的核電站擅耽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏物遇。R本人自食惡果不足惜乖仇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望询兴。 院中可真熱鬧这敬,春花似錦、人聲如沸蕉朵。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)始衅。三九已至冷蚂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間汛闸,已是汗流浹背蝙茶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诸老,地道東北人隆夯。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像别伏,于是被迫代替她去往敵國(guó)和親蹄衷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348