Android窗口管理分析(1):View如何繪製到屏幕上的主觀理解

窗口管理能夠說是Android系統中最複雜的一部分,主要是它涉及的模塊比較多,雖說是窗口管理,但除了WindowManagerService還包括SurfaceFlinger服務、Linux的共享內存及tmpfs文件系統、Binder通訊、InputManagerService、動畫、VSYNC同步技術等,一篇文章不可能分析徹底,可是能夠首先對於窗口的顯示與管理有一個大概的輪廓,再分塊分解,涉及的知識點大概以下:bash

窗口管理知識圖譜.png
窗口管理知識圖譜.png

WMS的做用是窗口管理 不負責View繪製

既然是概述,咱們不妨直觀的思考一個問題,Activity是如何呈現到屏幕上的,或者說View是如何被繪製到屏幕上來的?或多或少,開發者都知道WindowManagerService是負責Android的窗口管理,可是它其實只負責管理,好比窗口的添加、移除、調整順序等,至於圖像的繪製與合成之類的都不是WMS管理的範疇,WMS更像在更高的層面對於Android窗口的一個抽象,真正完成圖像繪製的是APP端,而完成圖層合成的是SurfaceFlinger服務。這裏經過一個簡單的懸浮窗口來探索一下大概流程:socket

TextView mview=new TextView(context);
    ...<!--設置顏色 樣式-->
    WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();
    wmParams.type = WindowManager.LayoutParams.TYPE_TOAST;
    wmParams.format = PixelFormat.RGBA_8888;
    wmParams.width = 800;
    wmParams.height = 800;
    mWindowManager.addView(mview, wmParams);複製代碼

以上代碼能夠在主屏幕上添加一個TextView並展現,而且這個TextView獨佔一個窗口。在利用WindowManager.addView添加窗口以前,TextView的onDraw不會被調用,也就說View必須被添加到窗口中,纔會被繪製,或者能夠這樣理解,只有申請了依附窗口,View纔會有能夠繪製的目標內存。當APP經過WindowManagerService的代理向其添加窗口的時候,WindowManagerService除了本身進行登記整理,還須要向SurfaceFlinger服務申請一塊Surface畫布,其實主要是畫布背後所對應的一塊內存,只有這一塊內存申請成功以後,APP端纔有繪圖的目標,而且這塊內存是APP端同SurfaceFlinger服務端共享的,這就省去了繪圖資源的拷貝,示意圖以下:動畫

繪圖原理.jpg
繪圖原理.jpg

以上是抽象的圖層對應關係,能夠看到,APP端是能夠經過unLockCanvasAndPost直接同SurfaceFlinger通訊進行重繪的,就是說圖形的繪製同WMS沒有關係,WMS只是負責窗口的管理,並不負責窗口的繪製,這一點其實也能夠從IWindowSession的binder通訊接口看出來:spa

interface IWindowSession {

    int add(IWindow window, int seq, in WindowManager.LayoutParams attrs,
            in int viewVisibility, out Rect outContentInsets,
            out InputChannel outInputChannel);

    int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
            in int viewVisibility, in int layerStackId, out Rect outContentInsets,
            out InputChannel outInputChannel);

    int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility,
            int flags, out Rect outFrame, out Rect outOverscanInsets,
            out Rect outContentInsets, out Rect outVisibleInsets,
            out Configuration outConfig, out Surface outSurface);

    void remove(IWindow window);
...
}複製代碼

從參數就能夠看出,APP與WindowManagerService通訊的時候沒有任何View相關的信息,更不會說將視圖的數據傳遞給WMS,基本都是以IWindow爲基本單位進行通訊的,因此涉及的操做也都是針對窗口的,好比整個窗口的添加、移除、大小調整、分組等,單單從窗口顯示來看,WMS的做用確實很明確,就是在服務端登記當前存活窗口,後面還會看到,這會影響SurfaceFlinger的圖層混合,能夠說是爲SurfaceFlinger服務的。3d

在對於平常開發來講,WMS的窗口分組有時候會對開發帶來影響,若是不知道窗口分組管理,可能有點忙迷惑,好比Dialog必須使用Activity的Context,PopupWindow不能做爲父窗口,尤爲要避免做爲Webview的容器等,這些都跟WMS窗口的組織有關係。PopupWindow、Dialog、Activity三者都有窗口的概念,但又各有不一樣,Activity屬於應用窗口、PopupWindow屬於子窗口,而Dialog位於二者之間,從性質上說屬於應用窗口,可是從直觀理解上,比較像子窗口(其實不是)。Android中的窗口主要分爲三種:系統窗口、應用窗口、子窗口,Toast就屬於系統窗口,而Dialog、Activity屬於應用窗口,不過Dialog必須依附Activity才能存在。PopupWindow算是子窗口,必須依附到其餘窗口,依附的窗口可使應用窗口也能夠是系統窗口,可是不能是子窗口。代理

窗口組織形式.jpg
窗口組織形式.jpg

固然,WMS的做用不只只是管理窗口,它還負責窗口動畫、Touch事件等,後面會逐個模塊分析。code

View繪製與數據傳遞

既然WMS的做用只是窗口管理,那麼圖形是怎麼繪製的呢?而且這些繪製信息是如何傳遞給SurfaceFlinger服務的呢?每一個View都有本身的onDraw回調,開發者能夠在onDraw裏繪製本身想要繪製的圖像,很明顯View的繪製是在APP端,直觀上理解,View的繪製也不會交給服務端,否則也太不獨立了,但是View繪製的內存是何時分配的呢?是誰分配的呢?咱們知道每一個Activity能夠看作是一個圖層,其對應一塊繪圖表面其實就是Surface,Surface繪圖表面對應的內存實際上是由SurfaceFlinger申請的,而且,內存是APP與SurfaceFlinger間進程共享的。實現機制是基於Linux的共享內存,其實就是MAP+tmpfs文件系統,你能夠理解成SF爲APP申請一塊內存,而後經過binder將這塊內存相關的信息傳遞APP端,APP端往這塊內存中繪製內容,繪製完畢,通知SF圖層混排,以後,SF再將數據渲染到屏幕。其實這樣作也很合理,由於圖像內存比較大,普通的binder與socket都沒法知足需求,內存共享的示意圖以下:orm

View繪製與共享內存.jpg
View繪製與共享內存.jpg

總結

其實整個Android窗口管理簡化的話能夠分爲如下三部分cdn

  • WindowManagerService:WMS控制着Surface畫布的添加與次序,動畫還有觸摸事件
  • SurfaceFlinger:SF負責圖層的混合,而且將結果傳輸給硬件顯示
  • APP端:每一個APP負責相應圖層的繪製,
  • APP與SurfaceFlinger通訊:APP與SF圖層之間數據的共享是經過匿名內存來實現的。

做者:看書的小蝸牛
原文連接: Android窗口管理分析(1):窗口管理及主觀理解blog

僅供參考,歡迎指正

相關文章
相關標籤/搜索