本篇對Android圖形顯示框架做一個(gè)概述,內(nèi)容主要包含:SurfaceSession創(chuàng)建和銷毀(添加/刪除窗口),Surface創(chuàng)建和銷毀,BufferQueue創(chuàng)建,以及BufferQueue的dequeueBuffer和queueBuffer、acquire和release大致流程梳理。
顯示框架概述
Android與用戶進(jìn)行圖形界面的交互,例如各個(gè)應(yīng)用程序,他們的對話框、按鈕、菜單等圖形窗口。
這些窗口的管理都是由WindowManager負(fù)責(zé),窗口管理位于Java層,真正的實(shí)現(xiàn)者是運(yùn)行在System_server進(jìn)程空間中的WindowManagerService。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /** |
應(yīng)用程序負(fù)責(zé)修改繪制窗口中的內(nèi)容,而WindowManager負(fù)責(zé)窗口的生命周期、幾何屬性、坐標(biāo)變換信息、用戶輸入焦點(diǎn)、動畫等功能。
他還管理著窗口狀態(tài)的變化,如窗口位置、大小、透明度以及Z-order(前后遮蓋順序)等一系列的邏輯判斷。
這些WindowManager功能由一系列接口或類構(gòu)成,包括ViewManager、WindowManager、WindowManagerImpl、WindowManagerService等。
SurfaceFlinger負(fù)責(zé)分配應(yīng)用程序所需的圖形緩沖區(qū),并對系統(tǒng)中的整個(gè)圖形窗口進(jìn)行composition(合成)。
最終,圖形窗口會更新顯示到Display顯示器上。
顯示過程的三個(gè)進(jìn)程
Android顯示的整個(gè)過程由 App 進(jìn)程、System_server 進(jìn)程、SurfaceFlinger進(jìn)程一起配合完成。
App進(jìn)程:App需要將自己的內(nèi)容顯示在屏幕上,所以需要負(fù)責(zé)發(fā)起Surface創(chuàng)建的請求。同時(shí)觸發(fā)對控件的測量、布局、繪制以及輸入事件的派發(fā)處理,這些主要在ViewRootImpl中觸發(fā);
System_server進(jìn)程:主要是WindowManagerService,負(fù)責(zé)接收App請求,同時(shí)和SurfaceFlinger建立連接,向SurfaceFlinger發(fā)起具體請求創(chuàng)建Surface,并且創(chuàng)建Surace的輔助管理類SurfaceControl(和window一一對應(yīng))(AMS作用是統(tǒng)一調(diào)度所有App的Activity);
SurfaceFlinger:為App創(chuàng)建具體的Surface,在SurfaceFLinger對應(yīng)成Layer,然后負(fù)責(zé)管理、合成所有圖層,最終顯示。
Activity、Window、PhoneWindow、DecorView、View的對應(yīng)關(guān)系
Window:每一個(gè)Activity都包含一個(gè)Window對象(抽象類,提供了繪制窗口的一組通用API),通常由PhoneWindow實(shí)現(xiàn)。
在Activity.java中定義:private Window mWindow;
一個(gè)Activity對應(yīng)創(chuàng)建一個(gè)Surface
PhoneWindow:繼承于Window,是Window類的具體實(shí)現(xiàn)。該類內(nèi)部包含了一個(gè)DecorView對象,該DecorView對象是所有應(yīng)用窗口(Activity界面)的根View。
簡而言之,PhoneWindow類是把一個(gè)FrameLayout類,即DecorView對象進(jìn)行一定的包裝,將他作為應(yīng)用窗口的根View,并提供一組通用的窗口操作接口。
PhoneWindow是Android中最基本的窗口系統(tǒng),每個(gè)Activity都會創(chuàng)建一個(gè)PhoneWindow對象,是Activity和整個(gè)View系統(tǒng)交互的接口。
在Activity.java的attach函數(shù)實(shí)例化:mWindow = new PhoneWindow(this, window, activityConfigCallback);
DecorView:PhoneWindow構(gòu)造函數(shù)中定義,繼承FrameLayout類,是所有應(yīng)用窗口的根View。
在PhoneWindow.java中定義,構(gòu)造函數(shù)中初始化:private DecorView mDecor;
相關(guān)debug方法:
adb shell dumpsys activity
adb shell dumpsys window
![window包含關(guān)系]](phonewindow.png)
Activity生命周期
Activity onResume添加窗口
onCreate方法中調(diào)用setContentView來設(shè)置布局,此時(shí)只是完成了View Tree的創(chuàng)建。此處參考HWUI繪制文章
真正通知WMS添加窗口,是在回調(diào)onResume完成的。
調(diào)用onResume的方法在ActivityThread.java中是handleResumeActivity
。之后調(diào)用到WMS.java的addWindow。
App進(jìn)程中完成添加窗口操作
當(dāng)一個(gè)新窗口(Window)被創(chuàng)建的時(shí)候,在ActivityThread.java的
handleResumeActivity
中調(diào)用addView(),然后調(diào)用到WindowManagerImpl
的addView()函數(shù)。
1 2 3 4 5 | @Override |
這個(gè)函數(shù)將實(shí)際操作委托給mGlobal成員完成,這個(gè)成員隨著WindowManagerImpl的創(chuàng)建而被初始化:
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
WindowManagerGlobal是一個(gè)單例模式,即一個(gè)進(jìn)程中最多僅有一個(gè)WindowManagerGlobal實(shí)例。
調(diào)用mGlobal的addView函數(shù)后,將會創(chuàng)建一個(gè)ViewRootImpl對象,并且將窗口的控件、布局參數(shù)、ViewRootImpl對象入?yún)⒌絪etView函數(shù)中,這個(gè)動作將導(dǎo)致ViewRootImpl向WMS添加新的窗口、申請Surface創(chuàng)建、繪制動作等。這才真正意義的完成了窗口的添加操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public void addView(View view, ViewGroup.LayoutParams params, |
窗口移除序列圖(Activity destroy)
窗口被刪除,Activity執(zhí)行了handleDestroyActivity函數(shù):
Surface Destroy(Activity pause或者stop狀態(tài))
可以結(jié)合以下
Surface創(chuàng)建部分
一起梳理,針對的情況是Surface被destroy,從framework/base到SurfaceFlinger模塊Layer析構(gòu)的流程。
但是就Activity而言,并沒有被銷毀,而是類似按了home鍵返回桌面,或者在后臺運(yùn)行的狀態(tài),具體可以通過日志觀察。
SurfaceSession創(chuàng)建
此處是接著上面添加窗口的流程,分為以下兩部分。
mGlobal.addView中創(chuàng)建ViewRootImpl對象
新建ViewRootImpl對象的時(shí)候,調(diào)用構(gòu)造函數(shù),會從WindowManagerGlobal中獲取一個(gè)窗口session。
mWindowSession = WindowManagerGlobal.getWindowSession();
在WindowManagerGlobal中會通過Binder IPC跨進(jìn)程創(chuàng)建一個(gè)session。
Session主要用于進(jìn)程間通信,其他應(yīng)用程序想要和WMS通信就需要經(jīng)過Session,每個(gè)應(yīng)用程序進(jìn)程都會對應(yīng)一個(gè)Session,WMS保存這些Session用來記錄所有向WMS提出窗口管理服務(wù)的客戶端。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | @UnsupportedAppUsage |
WMS繼承IWindowManager.Stub,調(diào)用到openSessio函數(shù),創(chuàng)建一個(gè)新的session對象, 返回值是IWindowSession類型。用于在APP進(jìn)程和WMS之間建立聯(lián)系。
1 2 3 4 5 6 7 |
|
mGlobal.addView中調(diào)用ViewRootImpl.setView
在前面mGlobal創(chuàng)建ViewRootImpl對象之后,會調(diào)用ViewRootImpl對象的setView,然后通知到WMS創(chuàng)建一個(gè)SurfaceSession,建立WindowManagerService和Surfacelinger的連接。
一個(gè)SurfaceSession代表著一個(gè)到SurfaceFlinger的連接會話,在這個(gè)連接會話里,可以創(chuàng)建一個(gè)或多個(gè)surface,最后這些surface被合成送到Display上顯示。
大致過程:(查看下面的序列圖)
在setView()中調(diào)用mWindowSession.addToDisplay, mWindowSession是IWindowSession接口類型,而Session.java實(shí)現(xiàn)了該接口;
Session.java 中調(diào)用mService.addWindow(…), mService是WMS類型;
WMS.java的addWindow()創(chuàng)建WindowState對象win,調(diào)用win.attach()
frameworks/base/services/core/java/com/android/server/wm/WindowState.java 調(diào)用attach
frameworks/base/services/core/java/com/android/server/wm/Session.java 調(diào)用windowAddedocked,創(chuàng)建SurfaceSession類型的mSurfaceSession
frameworks/base/core/java/android/view/SurfaceSession.java 構(gòu)造函數(shù)調(diào)用JNI,然后在android_view_SurfaceSession.cpp中的nativeCreate創(chuàng)建SurfaceComposerClient, 調(diào)用Refase的incStrong然后實(shí)現(xiàn)onFirstRef,通過調(diào)用CreateConnection()建立和SF的連接;
SF.cpp 調(diào)用CreateConnection()返回SF的Client類的Binder代理BpSurfaceComposerClient;
Surface創(chuàng)建
App進(jìn)程請求創(chuàng)建Surface
Surface是Android圖形系統(tǒng)的核心部分,圖形界面上的一個(gè)窗口或?qū)υ捒虻榷紝?yīng)著一個(gè)Surface。
而這個(gè)Surface是一塊繪制區(qū)域的抽象,它對應(yīng)著Server服務(wù)端Surfacelinger中的一個(gè)圖層Layer,這個(gè)圖層的背后是一塊圖形緩沖區(qū)GraphicBuffer,Client客戶端的應(yīng)用程序的UI使用軟件繪制、硬件繪制在Surface上各種渲染操作時(shí),繪制操作的結(jié)果其實(shí)也就是在該圖形緩沖區(qū)中。
這部分的內(nèi)容是梳理Surface創(chuàng)建的過程。
在ViewRootImpl對象中,
setView到requestLayout函數(shù)請求布局,到調(diào)用scheduleTraversals
,該函數(shù)里面在Choreographer.java層層調(diào)用到Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
此處的action即是新的線程啟動。
啟動ViewRootImp中單獨(dú)的線程TraversalRunnable,然后調(diào)用到關(guān)鍵函數(shù)
performTraversals()
。
這個(gè)關(guān)鍵函數(shù)有兩個(gè)主要的函數(shù):
relayoutWindow() ->布局窗口
performDraw() ->繪制渲染
請求創(chuàng)建Surface就從relayoutWindow函數(shù)開始。
在這個(gè)方法中調(diào)用IWindowSession的relayout,會調(diào)用到Session.java,然后調(diào)用到WMS的relayoutWindow從而達(dá)到跨進(jìn)程:(流程圖查看下面單獨(dú)章節(jié)的序列圖)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, |
System_server進(jìn)程 —— WMS
跨進(jìn)程到WMS后,從relayoutWindow函數(shù)調(diào)用到
createSurfaceControl(outSurfaceControl)
。
(1)然后先是在WindowStateAnimator創(chuàng)建一個(gè)WindowSurfaceController對象,作為調(diào)用到WindowStateAnimator.java的createSurfaceLocked
函數(shù)的返回值。
在createSurfaceLocked函數(shù)中,會new一個(gè)WindowSurfaceController對象,從而調(diào)用他的構(gòu)造函數(shù)。
在他的構(gòu)造函數(shù)中會創(chuàng)建一個(gè)SurfaceControl內(nèi)部類Builder對象,調(diào)用該對象的build函數(shù);
(2) WMS.java中調(diào)用WindowStateAnimator.java的createSurfaceLocked
函數(shù)之后,會執(zhí)行以下邏輯:
a. 如果surfaceController不為空,調(diào)用WindowSurfaceController的getSurfaceControl;
b. WindowSurfaceController.java調(diào)用
getSurfaceControl, outSurfaceControl.copyFrom(mSurfaceControl);
,而mSurfaceControl就是之前的構(gòu)造函數(shù)創(chuàng)建的。此處的copyFrom會經(jīng)過JNI調(diào)用到Native層, 然后讀取SurfaeControl。
在Builder內(nèi)部類的build函數(shù)中
創(chuàng)建Java層的SurfaceControl對象
,在SurfaceControl的構(gòu)造函數(shù)中調(diào)用JNI層的nativeCreate函數(shù);android_view_SurfaceControl.cpp的nativeCreate函數(shù)會調(diào)用SurfaceComposerClient.cpp的
createSurfaceChecked
函數(shù),創(chuàng)建一個(gè)surface(實(shí)際上是SurfaceControl)
,然后將surface返回。
SurfaceFlinger進(jìn)程
SurfaceComposerClinet.cpp位于frameworks/native/libs/gui模塊。
而libgui庫主要被JNI層中的代碼調(diào)用,從而和Surfacelinger進(jìn)程進(jìn)行交互
,可以看做是Java層的Bn端,是SurfaceFlinger的Bp端。
比如此處的SurfaceComposerClinet通過Binder IPC(ISurfaceComposerClinet.cpp),跨進(jìn)程到SurfaceFlinger進(jìn)程。
SurfaceComposerClinet作為Bp客戶端調(diào)用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h, |
Bn服務(wù)端是surfaceflinger模塊的Client.cpp,此時(shí)跨進(jìn)程到SurfaceFlinger進(jìn)程,調(diào)用createSurface,從而請求到SurfaceFlinger創(chuàng)建Surface:
1 2 3 4 5 6 7 8 | status_t Client::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, |
在SurfaceFlinger::createLayer中創(chuàng)建Layer(創(chuàng)建surface的請求到SurfaceFlinger進(jìn)程中就是創(chuàng)建Layer),創(chuàng)建的Layer有四種:
(1)createBufferQueueLayer
(2)createBufferStateLayer
(3)createColorLayer
(4)createContainerLayer
通常情況下創(chuàng)建的是第一種Layer——BufferQueueLayer(在P中是BufferLayer),會創(chuàng)建一個(gè)<sp>BufferQueueLayer強(qiáng)指針對象
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, const String8& name, |
序列圖
該序列圖包含上面部分的流程,包含APP進(jìn)程和WMS進(jìn)程之間的Session創(chuàng)建、SurfaceSession創(chuàng)建、Surface創(chuàng)建。
BufferQueue
關(guān)于BufferQueue只大致梳理他的創(chuàng)建流程,以及在渲染過程中的dequeuebuffer和queuebuffer流程、在合成過程中的acquire和release流程。
關(guān)于和GraphicsBuffer和再底層的邏輯,暫時(shí)不梳理。
BufferQueue概述
創(chuàng)建BuffeQueueLayer對象的onFirstRef中會創(chuàng)建一個(gè)BufferQueue。
BufferQueue是buffer流轉(zhuǎn)的中轉(zhuǎn)站。具體分成四個(gè)步驟:
生產(chǎn)者dequeue一塊buffer,buffer狀態(tài)->DEQUEUED,持有者->Producer,之后生產(chǎn)者可以填充數(shù)據(jù)(渲染繪制)。在dequeueBuffer之前,buffer狀態(tài)是free,持有者是BufferQueue;
生產(chǎn)者填充完數(shù)據(jù)后,進(jìn)行queue操作,buffer->QUEUED,持有者->BufferQueue。操作后producer會回調(diào)BufferQueue的onFrameAvailable函數(shù),通知消費(fèi)者有可用的buffer;
消費(fèi)者進(jìn)行acquire取出Buffer,buffer->ACQUIRED,持有者->Consumer;
消費(fèi)者消費(fèi)完這塊buffer(已經(jīng)合成),進(jìn)行release操作釋放,歸還給BufferQueue
BufferQueue狀態(tài)
DEQUEUED 狀態(tài):
Producer dequeue一個(gè)Buffer后,這個(gè)Buffer就變?yōu)?DEQUEUED 狀態(tài),release Fence發(fā)信號后,Producer就可以修改Buffer的內(nèi)容,我們稱為release Fence。
此時(shí)Buffer被Producer占用。
DEQUEUED狀態(tài)的Buffer可以遷移到 QUEUED 狀態(tài),通過queueBuffer或attachBuffer流程。也可以遷移到FREE裝,通過cancelBuffer或detachBuffer流程。
QUEUED 狀態(tài):
Buffer繪制完后,queue到BufferQueue中,給Consumer進(jìn)行消費(fèi)。此時(shí)Buffer可能還沒有真正繪制完成,必現(xiàn)要等對應(yīng)的Fence發(fā)信號出來后,才真正完成。
此時(shí)Buffer是BufferQueue持有,可以遷移到ACQUIRED狀態(tài),通過acquireBuffer流程。而且可以遷移到FREE狀態(tài),如果另外一個(gè)Buffer被異步的queue進(jìn)來。
ACQUIRED 狀態(tài):
Buffer已經(jīng)被Consumer獲取,但是也必須要等對應(yīng)的Fence發(fā)信號才能被Consumer讀寫,找個(gè)Fence是從Producer那邊,queueBuffer的時(shí)候傳過來的。
我們將其稱為acquire fence。此時(shí),Buffer被Consumer持有。狀態(tài)可以遷移到FREE狀態(tài),通過releaseBuffer或detachBuffer流程。
除了從acquireBuffer流程可以遷移到ACQUIRED狀態(tài),attachBuffer流程也可以遷移到ACQUIRED狀態(tài)。
FREE 狀態(tài):
FREE狀態(tài),說明Buffer被BufferQueue持有,可以被Producer dequeue,它將遷移到DEQUEUED狀態(tài),通過dequeueBuffer流程。
SHARED狀態(tài):
SHARED狀態(tài)是一個(gè)特殊的狀態(tài),SHARED的Buffer并不參與前面所說的狀態(tài)遷移。它說明Buffer被用與共享Buffer模式。
除了FREE狀態(tài),它可以是其他的任何狀態(tài)。它可以被多次dequeued, queued, 或者 acquired。這中共享Buffer的模式,主要用于VR等低延遲要求的場合。
BufferQueue創(chuàng)建以及創(chuàng)建一個(gè)監(jiān)聽
在BufferQueueLayer::onFirstRef
調(diào)用BufferQueue::createBufferQueue()創(chuàng)建了bufferQueue、生產(chǎn)者、消費(fèi)者,在創(chuàng)建生產(chǎn)者和消費(fèi)者的過程中,將他們綁定到同一個(gè)BufferQueue上。
之后會創(chuàng)建一個(gè)BufferLayerConsumer對象mConsumer,這個(gè)對象繼承了ConsumerBase類,所以會回調(diào)基類的構(gòu)造函數(shù),注冊一個(gè)監(jiān)聽對象到BufferQueue(空對象)。
真正的監(jiān)聽是在mConsumer->setContentsChangedListener(this)
基類構(gòu)造函數(shù)中還會調(diào)用consumerConnect將消費(fèi)者關(guān)聯(lián)到BufferQueue中。
此時(shí)監(jiān)聽對象就賦給了BufferQueue的mConsumerListener成員(調(diào)用BufferQueueConsumer的connect函數(shù))。
這個(gè)監(jiān)聽對象會在queueBuffer是觸發(fā),由生產(chǎn)者回調(diào)注冊到BufferQueue的幀可用通知。
DequeuBuffer
BufferQueue創(chuàng)建后,首先由生產(chǎn)者執(zhí)行 dequeueBuffer 請求一塊Buffer。
Dequeue和Queue的操作都是在硬件渲染(軟件繪制暫不考慮)的過程中,在ThreadedRenderer::draw
函數(shù)中,updateRootDisplayList創(chuàng)建好一個(gè)RootDisplayList后,開始渲染一幀,在這時(shí)調(diào)用父類的syncAndDrawFrame函數(shù),這個(gè)函數(shù)層層調(diào)到CanvasContext::draw函數(shù),然后依次調(diào)用三個(gè)函數(shù):
mRenderPipeline->getFrame 執(zhí)行dequeueBuffer請求一塊buffer
draw 填充buffer
mRenderPipeline->swapBuffers 執(zhí)行queueBuffer送到BufferQueue
在此處dequeuBuffer和queueBuffer兩個(gè)操作調(diào)到gui/Surface.cpp的兩個(gè)對應(yīng)函數(shù),這個(gè)流程基本一樣。
大致都從SkiaOpenPipeline.cpp -> EglManager.cpp -> eglApi.cpp -> ANativeWindow.cpp
,之后到Bp客戶端libgui庫的Surface.cpp,執(zhí)行具體操作。
Surface::dequeueBuffer中調(diào)用IGraphicBufferProducer::dequeueBuffer。然后remote()->transact(DEQUEUE_BUFFER,data,&reply)
調(diào)用到Bn端BufferQueueProducer::dequeueBuffer函數(shù)。
首先查找mSlots[found]的序列號found,mSlots是存放Buffer的地方,他的數(shù)量是64。即至多存放64個(gè)buffer。
found是從waitForFreeSlotThenRelock中獲取:
從非Free的buffer中統(tǒng)計(jì)dequeue和acquire的數(shù)量;
判斷dequeueBufferCount數(shù)量不能大于最大允許dequeueBuffer的數(shù)量;
slot的獲取主要來自兩個(gè)集合,mFreeSlots和mFreeBuffers;兩者包含的所有狀態(tài)都是free,區(qū)別在于前者沒有attached,后者以及attached;如果調(diào)用來自dequeueBuffer優(yōu)先選擇前者,如果調(diào)用來自attachBuffer,優(yōu)先選擇后者;
如果沒找到符合要求的buffer或者queue的buffer還有太多沒有完成,就要等待這個(gè)buffer被acquired或者released,或者修改最大的buffer數(shù)量。
找到可用的slot,還要判斷是否重新分配空間:如果Buffer(本質(zhì)上是GraphicBuffer)是空,并且需要重新分配空間,則對這個(gè)mSlots[found]初始化;
new GraphicBuffer為mSlots分配一個(gè)GraphicBuffer,賦值給BufferQueueCore中的變量mSlots[]的mGraphicBuffer;
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
Surface::dequeueBuffer
從服務(wù)端申請到Buffer后,通過requestBuffer
將客戶端的buffer和服務(wù)端的buffer指向同一塊物理內(nèi)存。
具體是IGraphicBufferPruducer代理中通過REQUEST_BUFFER狀態(tài),在onTransact中將申請的GraphicBuffer,即mSlots[slot].mGraphicBuffer
。將其寫入reply,等待客戶端讀取。
QueueBuffer
queueBuffer是在渲染一幀后通過mRenderPipeline->swapBuffers
調(diào)用到Surface::queueBuffer。將填充完數(shù)據(jù)的buffer放入BufferQueue,并且通過監(jiān)聽者通知消費(fèi)者對象開始消費(fèi)。
在Bn端BufferQueueProducer::queueBuffer L977中調(diào)用:frameAvailableListener->onFrameAvailable(item);
通知消費(fèi)者,在BufferQueueLayer::onFrameAvailable中調(diào)用:mFlinger->signalLayerUpdate();
觸發(fā)SurfaceFlinger的消息循環(huán)機(jī)制,開始處理SurfaceFlinger合成事件。
序列圖
acquire & release
消費(fèi)者SurfaceFlinger通過acquire從BufferQueue取出一塊buffer消費(fèi)。消費(fèi)(合成)之后釋放。