1. 程式人生 > >Android應用程式與SurfaceFlinger服務的關係概述

Android應用程式與SurfaceFlinger服務的關係概述

        SurfaceFlinger服務負責繪製Android應用程式的UI,它的實現相當複雜,要從正面分析它的實現不是一件容易的事。既然不能從正面分析,我們就想辦法從側面分析。說到底,無論SurfaceFlinger服務有多複雜,它都是為Android應用程式服務的,因此,我們就從Android應用程式與SurfaceFlinger服務的關係入手,來概述和制定SurfaceFlinger服務的學習計劃。

        SurfaceFlinger服務執行在Android系統的System程序中,它負責管理Android系統的幀緩衝區(Frame Buffer)。Android系統的幀緩衝區的相關知識,可以參考前面兩篇文章

Android系統的開機畫面顯示過程分析Android幀緩衝區(Frame Buffer)硬體抽象層(HAL)模組Gralloc的實現原理分析。Android應用程式為了能夠將自己的UI繪製在系統的幀緩衝區上,它們就必須要與SurfaceFlinger服務進行通訊,如圖1所示:


圖1 Android應用程式與SurfaceFlinger服務的關係

        注意,Android應用程式與SurfaceFlinger服務是執行在不同的程序中的,因此,它們採用Binder程序間通訊機制來進行通訊。Android系統的Binder程序間通訊機制的相關知識,可以參考Android程序間通訊(IPC)機制Binder簡要介紹和學習計劃

這一系列的文章。

        在圖1中,每一個Android應用程式與SurfaceFlinger服務都有一個連線,這個連線都是通過一個型別為Client的Binder物件來描述的。這些Client物件是Android應用程式連線到SurfaceFlinger服務的時候由SurfaceFlinger服務建立的,而當Android應用程式成功連線到SurfaceFlinger服務之後,就可以獲得一個對應的Client物件的Binder代理介面了。有了這些Binder代理介面之後,Android應用程式就可以通知SurfaceFlinger服務來繪製自己的UI了。

        Android應用程式在通知SurfaceFlinger服務來繪製自己的UI的時候,需要將UI元資料傳遞給SurfaceFlinger服務,例如,要繪製UI的區域、位置等資訊。一個Android應用程式可能會有很多個視窗,而每一個視窗都有自己的UI元資料,因此,Android應用程式需要傳遞給SurfaceFlinger服務的UI元資料是相當可觀的。在這種情況下,通過Binder程序間通訊機制來在Android應用程式與SurfaceFlinger服務之間傳遞UI元資料是不合適的,這時候Android系統的匿名共享記憶體機制(Anonymous Shared Memory)就派上用場了。Android系統的匿名共享記憶體機制的相關知識,可以參考

Android系統匿名共享記憶體Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃這一系列的文章。

       在每一個Android應用程式與SurfaceFlinger服務之間的連線上加上一塊用來傳遞UI元資料的匿名共享記憶體,我們就得到了圖2,如下所示:


圖2 用來在Android應用程式與SurfaceFlinger服務之間傳遞UI元資料的匿名共享記憶體

        在Application和Client這兩個高富帥看來,它們之間的原生匿名共享記憶體塊就一個活脫脫的土肥圓。因此,Application和Client是看不上這塊原生的匿名共享記憶體的。於是,這塊原生的匿名共享記憶體當時就怒了,立志要逆襲變成白富美,如圖3所示:


圖3 結構化後的用來傳遞UI元資料的匿名共享記憶體塊

       土肥圓逆襲後,就變成了一個名字為SharedClient的白富美,從此,它就和Application、Client過上幸福的啪啪啪生活了。

       SharedClient到底有多白多富多美?參見圖4:


圖4 用來描述Android應用程式的UI元資料的SharedClient

        在每一個SharedClient裡面,有至多31個SharedBufferStack。字面上來看,SharedBufferStack就是共享緩衝區堆疊。怎麼理解呢?首先,Shared表明這個堆疊共享的。那麼由誰來共享呢?當然就是Android應用程式和SurfaceFlinger服務了。其次,Buffer表明這個堆疊的內容是緩衝區。什麼樣的緩衝區呢?當然就是用來描述UI元資料的緩衝區了。再者,Stack表明用來描述UI元資料的緩衝區是需要按照一定的規則來訪問的。綜合起來,我們就可以認為每一個SharedBufferStack就是用來描述一系列需要按照一定規則來訪問的緩衝區。

        好像還是不能理解SharedBufferStack?好吧,回憶一下,一般我們就繪製UI的時候,都會採用一種稱為“雙緩衝”的技術。雙緩衝意味著要使用兩個緩衝區,其中一個稱為Front Buffer,另外一個稱為Back Buffer。UI總是先在Back Buffer中繪製,然後再和Front Buffer交換,渲染到顯示裝置中。這下就可以理解SharedBufferStack的含義了吧?SurfaceFlinger服務只不過是將傳統的“雙緩衝”技術昇華和抽象為了一個SharedBufferStack。可別小看了這個昇華和抽象,有了SharedBufferStack之後,SurfaceFlinger服務就可以使用N個緩衝區技術來繪製UI了。N值的取值範圍為2到16。例如,在Android 2.3中,N的值等於2,而在Android 4.1中,據說就等於3了。

        我們還可以再進一步地理解SharedBufferStack。在SurfaceFlinger服務中,每一個SharedBufferStack都對應一個Surface,即一個視窗。這樣,我們就可以知道為什麼每一個SharedClient裡面包含的是一系列SharedBufferStack而不是單個SharedBufferStack:一個SharedClient對應一個Android應用程式,而一個Android應用程式可能包含有多個視窗,即Surface。從這裡也可以看出,一個Android應用程式至多可以包含31個Surface。

        SharedBufferStack長什麼樣子呢?看圖5:

 

圖 5 SharedBufferStack的結構示意圖

       在圖5中,為了方便描述,我們假設圖中的SharedBufferStack有5個Buffer,其中,Buffer-1和Buffer-2是已經使用了的,而Buffer-3、Buffer-4和Buffer-5是空閒的。指標head和tail分別指向空閒緩衝區列表的頭部和尾部,而指標queue_head指向已經使用了的緩衝區列表的頭部。從這裡就可以看出,從指標tail到head之間的Buffer即為空閒緩衝區表,而從指標head到queue_head之間的Buffer即為已經使用了的緩衝區列表。注意,圖中的5個Buffer是迴圈使用的。

       空閒緩衝區比較好理解,接下來我們重點解釋一下那些已經被使用了的緩衝區,即圖5中的Buffer-1和Buffer-2。

       前面我們說過,SharedBufferStack中的緩衝區只是用來描述UI元資料的,這意味著它們不包含真正的UI資料。真正的UI資料儲存在GraphicBuffer中,後面我們再描述GaphicBuffer。因此,為了完整地描述一個UI,SharedBufferStack中的每一個已經使用了的緩衝區都對應有一個GraphicBuffer,用來描述真正的UI資料。當SurfaceFlinger服務緩制Buffer-1和Buffer-2的時候,就會找到與它們所對應的GraphicBuffer,這樣就可以將對應的UI繪製出來了。

       當Android應用程式需要更新一個Surface的時候,它就會找到與它所對應的SharedBufferStack,並且從它的空閒緩衝區列表的尾部取出一個空閒的Buffer。我們假設這個取出來的空閒Buffer的編號為index。接下來Android應用程式就請求SurfaceFlinger服務為這個編號為index的Buffer分配一個圖形緩衝區GraphicBuffer。SurfaceFlinger服務分配好圖形緩衝區GraphicBuffer之後,會將它的編號設定為index,然後再將這個圖形緩衝區GraphicBuffer返回給Android應用程式訪問。Android應用程式得到了SurfaceFlinger服務返回的圖形緩衝區GraphicBuffer之後,就在裡面寫入UI資料。寫完之後,就將與它所對應的緩衝區,即編號為index的Buffer,插入到對應的SharedBufferStack的已經使用了的緩衝區列表的頭部去。這一步完成了之後,Android應用程式就通知SurfaceFlinger服務去繪製那些儲存在已經使用了的緩衝區所描述的圖形緩衝區GraphicBuffer了。用圖5的例子來說,SurfaceFlinger服務需要繪製的是編號為1和2的Buffer所對應的圖形緩衝區GraphicBuffer。由於SurfaceFlinger服務知道編號為1和2的Buffer所對應的圖形緩衝區GraphicBuffer在哪裡,因此,Android應用程式只需要告訴SurfaceFlinger服務要繪製的Buffer的編號就OK了。當一個已經被使用了的Buffer被繪製了之後,它就重新變成一個空閒的Buffer了。

        上面描述的過程比較複雜,後面我們再用幾篇文章來詳細描述。

        SharedBufferStack是在Android應用程式和SurfaceFlinger服務之間共享的,但是,Android應用程式和SurfaceFlinger服務使用SharedBufferStack的方式是不一樣的,具體來說,就是Android應用程式關心的是它裡面的空閒緩衝區列表,而SurfaceFlinger服務關心的是它裡面的已經使用了的緩衝區列表。從SurfaceFlinger服務的角度來看,儲存在SharedBufferStack中的已經使用了的緩衝區其實就是在排隊等待渲染。

        為了方便SharedBufferStack在Android應用程式和SurfaceFlinger服務中的訪問,Android系統分別使用SharedBufferClient和SharedBufferServer來描述SharedBufferStack,其中,SharedBufferClient用來在Android應用程式這一側訪問SharedBufferStack的空閒緩衝區列表,而SharedBufferServer用來在SurfaceFlinger服務這一側訪問SharedBufferStack的排隊緩衝區列表。

         在SharedBufferClient看來,SharedBufferStack的樣子如圖6所示:


圖6 SharedBufferClient眼中的SharedBufferStack 

        只要SharedBufferStack中的available的buffer的數量大於0,SharedBufferClient就會將指標tail往前移一步,並且減少available的值,以便可以獲得一個空閒的Buffer。當Android應用程式往這個空閒的Buffer寫入好資料之後,它就會通過SharedBufferClient來將它新增到SharedBufferStack中的排隊緩衝區緩衝區列表的尾部去,即指標queue_head的下一個位置上。

        在SharedBufferServer看來,SharedBufferStack的樣子如圖7所示:


圖7 SharedBufferServer眼中的SharedBufferStack

        當Android應用程式通知SurfaceFlinger服務更新UI的時候,只要對應的SharedBufferStack中的queued的緩衝區的數量大於0,SharedBufferServer就會將指標head的下一個Buffer繪製出來,並且將指標head向前移一步,以及將queued的值減1。

        上面我們多次提到了圖形緩衝區GraphicBuffer,它是什麼東東呢?我們看圖8:


圖8 圖形緩衝區Graphic的結構示意圖

        每一個GraphicBuffer內部都包含有一塊用來儲存UI資料的緩衝區,這塊緩衝區使用一個buffer_handle_t物件來描述。看到buffer_handle_t,是不是有點眼熟?在前面Android幀緩衝區(Frame Buffer)硬體抽象層(HAL)模組Gralloc的實現原理分析一文中,我們說過,由HAL層的Gralloc模組分配的圖形緩衝區的是使用一個buffer_handle_t物件來描述的,而由buffer_handle_t物件所描述的圖形緩衝區要麼是在系統幀緩衝區(Frame Buffer)或者匿名共享記憶體(Anonymous Shared Memory)中分配的。這樣,我們就可以將SurfaceFlinger服務與HAL層中的Gralloc模組關聯起來了。

        至此,ndroid應用程式與SurfaceFlinger服務的關係就概述完畢了,但是我們的任務還沒有完成,我們還要進一步去具體地學習它,例如:

        回答了這4個問題之後,相信我們就可以對SurfaceFlinger服務有一個深刻的認識,進而可以幫助我們從正面去分析SurfaceFlinger服務的實現。後面我們將以Android系統的開機動畫為例子,用4篇文章來回答這4個問題,敬請關注!

相關推薦

Android應用程式SurfaceFlinger服務關係概述

        SurfaceFlinger服務負責繪製Android應用程式的UI,它的實現相當複雜,要從正面分析它的實現不是一件容易的事。既然不能從正面分析,我們就想辦法從側面分析。說到底,無論SurfaceFlinger服務有多複雜,它都是為Android應用程式服務的,因此,我們就從Android應

Android應用程式SurfaceFlinger服務關係概述和學習計劃

        SurfaceFlinger服務負責繪製Android應用程式的UI,它的實現相當複雜,要從正面分析它的實現不是一件容易的事。既然不能從正面分析,我們就想辦法從側面分析。說到底,無論SurfaceFlinger服務有多複雜,它都是為Android應用程式服務的

Android應用程式請求SurfaceFlinger服務渲染Surface的過程分析

                        在前面一篇文章中,我們分析了Android應用程式請求SurfaceFlinger服務建立Surface的過程。有了Surface之後,Android應用程式就可以在上面繪製自己的UI了,接著再請求SurfaceFlinger服務將這個已經繪製好了UI的Surf

ASP.NET Web應用程式ASP.NET Web服務應用程式有什麼區別

ASP.NET Web應用程式就是一個網站,B/S架構,客戶通過瀏覽器獲取伺服器上執行的該應用程式上的業務功能。 ASP.NET Web服務應用程式是一個遠端服務,必須被其他網站引用才可以正常被使用者使用,相當於一個被遠端呼叫的方法,一般是隻提供資料,不提供修改。如我們在各

android應用程式fps meter[幀數顯示]的分析 —— SurfaceFlinger被注入統計程式碼 (1)

fps meter是常用的檢測幀率的軟體,該軟體需要root許可權才能工作,一直比較好奇它一個apk是如何知道系統當前的幀率情況的,就針對此apk分析了一下其工作原理。 Apk組成 首先看一下apk的組成,apk檔案就是一個壓縮包,可以解壓縮軟體如winrar解壓檢視,也可

android應用程式元件概述

元件是一個Android程式至關重要的構建模組。每一個元件都是系統進入你的應用的不同途徑。但並不是所有的元件都是使用者進入程式的真實入口,其中一些要依賴於其它元件, 但是每一個元件都以自己獨有的形式存在,併發揮特殊的作用;每一個元件都是一個唯一的模組,幫助你實現

讀書筆記之應用程式作業系統之間的關係——《作業系統之真相還原》

這個知識點很好的解釋了為什麼一些程式不能跨平臺使用,比如windows與linux之間的應用程式一般不能通用,底層庫不同,可執行程式的格式也不同,後面章節中作者也點明瞭這個問題。此問題可見知乎上的討論:主要的原因是格式不同和API不同,前者更重要一些。http://www.

Android應用程式概述

一.    android應用程式開發方式         Android應用程式可以基於兩種方式開發:Android SDK和Android 原始碼 二、  Android應用程式概念性描述 1.     Android應用程式包含了工程檔案、程式碼和各種資源,主要有Jav

Android應用程式管理服務啟動過程淺析(PackageManagerService)

       我們知道安卓應用程式的安裝最終都是通過應用程式管理服務PackageManagerService來管理安裝的,系統在啟動時就會啟動該服務,在之前的 Android應用程式安裝過程淺析文章中分析了應用程式的安裝的過程,當時只是使用該服務,並沒有講到該

Android客戶端本地服務器Socket通信

msg 初始化 ips print rmi listener 個數 myeclips 開啟 Android客戶端與本地服務器Socket通信 Socket服務器運行結果圖?? 一.客戶端和服務器端的選擇: 客戶端是我們手機端,關於服務器端,只要安裝了JDK,自然就擁有通

瀏覽器判別下載安裝/開啟Android應用程式

摘要: 通過手機瀏覽器直接開啟Android應用程式。 如果本地已經安裝了指定Android應用,就直接開啟它; 如果沒有安裝,則直接下載該應用的安裝檔案(也可以跳轉到下載頁面)。 之前寫過一篇blog,介紹如何通過點選手機瀏覽器中的連結,直接開啟本地Android App。 實現方式

Android應用程式框架講解

在我們的android的程式中會有很多的檔案,那麼這些檔案到底是有什麼作用呢? 我們編譯android專案,可以使用eclipse和AS,首先介紹一下eclipse中的框架 1、src檔案:存放的是應用程式使用到的java檔案 2、gen檔案:系統自動生成的目錄。不需要程式設計師進行

android應用程式的介面程式設計

要點 android的介面與view元件 view元件和viewgroup元件 android控制程式的三種方式 通過繼承view開發自定義view android常見的佈局管理器 文字框元件:textview和edittext 按鈕元件:button 特殊按鈕元件:radiobut

Android應用程式進行系統簽名

有時寫一個程式需要呼叫系統的庫,如果許可權不夠,是用不了庫裡面一些方法的 。這時就需要將apk進行系統簽名。  簡單常用的方法:                 1,在apk的AndroidMani

Android應用程式簽名打包(AS)

使用Android studio對Android應用簽名步驟: 第一步: 第二步: 第三步: 第四步: 數字證書建立完成後,點選OK----->點選Next------>Finish。 注意:生成後的數字證書千萬不能丟失,還有密碼也不能忘記了

怎麼獲取Android應用程式的上下文

前面我做了一個類似於騰訊QQ一樣的聊天應用,在這個應用裡面,有很多activity,而這些activity之間經常要進行互相啟動、往復跳轉、還有就是通過Notification啟動。當activity多了之後,如果設定他的模式為單例模式,或者不設定模式。在反覆啟動後會出現數據不同步、fc等各種未知的

Android 應用程式崩潰日誌捕捉

程式崩潰是應用迭代中不可避免的問題,即使有著5年或者10年經驗的程式猿也無法完全保證自己的程式碼沒有任何的bug導致崩潰,現在有一些第三方平臺可以幫助我們蒐集應用程式的崩潰,比如友盟,詳情如下圖 雖然能夠看到崩潰的日誌以及機型等,但還是不是很方便,如果需要精確定位的話需要使用者提供崩潰的時間點、機型

轉老羅 Android應用程式資源的查詢過程分析

原文地址  http://blog.csdn.net/luoshengyang/article/details/8806798   轉載請說明     我們知道,在Android系統中,每一個應用程式一般都會配置很多資源,用來適配不同密

轉自老羅 Android應用程式資源的編譯和打包過程分析

原文地址   http://blog.csdn.net/luoshengyang/article/details/8744683 轉載自老羅,轉載請說明   我們知道,在一個APK檔案中,除了有程式碼檔案之外,還有很多資原始檔。這些資原始檔是通過An

轉自 老羅 Android應用程式資源管理器(Asset Manager)的建立過程分析

原文地址在 http://blog.csdn.net/luoshengyang/article/details/8791064 原創老羅,轉載請說明     在前面一篇文章中,我們分析了Android應用程式資源的編譯和打包過程,最終得到的應用程式資源就與