窗口管理可以說(shuō)是Android系統(tǒng)中最復(fù)雜的一部分,主要是它涉及的模塊比較多,雖然籠統(tǒng)的說(shuō)是窗口管理,其實(shí),除了WindowManagerService還包括SurfaceFlinger服務(wù)、Linux的共享內(nèi)存及tmpfs文件系統(tǒng)、Binder通信、InputManagerService、動(dòng)畫、VSYNC同步技術(shù)等,一篇文章不可能分析完全,但是可以首先對(duì)于窗口的顯示與管理有一個(gè)大概的輪廓,再分塊分解,涉及的知識(shí)點(diǎn)大概如下:

WMS的作用是窗口管理 不負(fù)責(zé)View繪制
既然是概述,我們不妨直觀的思考一個(gè)問(wèn)題,Activity是如何呈現(xiàn)到屏幕上的,或者說(shuō)View是如何被繪制到屏幕上來(lái)的?或多或少,開發(fā)者都知道WindowManagerService是負(fù)責(zé)Android的窗口管理,但是它其實(shí)只負(fù)責(zé)管理,比如窗口的添加、移除、調(diào)整順序等,至于圖像的繪制與合成之類的都不是WMS管理的范疇,WMS更像在更高的層面對(duì)于Android窗口的一個(gè)抽象,真正完成圖像繪制的是APP端,而完成圖層合成的是SurfaceFlinger服務(wù)。這里通過(guò)一個(gè)簡(jiǎn)單的懸浮窗口來(lái)探索一下大概流程:
TextView mview=new TextView(context);
...<!--設(shè)置顏色 樣式-->
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);
以上代碼可以在主屏幕上添加一個(gè)TextView并展示,并且這個(gè)TextView獨(dú)占一個(gè)窗口。在利用WindowManager.addView添加窗口之前,TextView的onDraw不會(huì)被調(diào)用,也就說(shuō)View必須被添加到窗口中,才會(huì)被繪制,或者可以這樣理解,只有申請(qǐng)了依附窗口,View才會(huì)有可以繪制的目標(biāo)內(nèi)存。當(dāng)APP通過(guò)WindowManagerService的代理向其添加窗口的時(shí)候,WindowManagerService除了自己進(jìn)行登記整理,還需要向SurfaceFlinger服務(wù)申請(qǐng)一塊Surface畫布,其實(shí)主要是畫布背后所對(duì)應(yīng)的一塊內(nèi)存,只有這一塊內(nèi)存申請(qǐng)成功之后,APP端才有繪圖的目標(biāo),并且這塊內(nèi)存是APP端同SurfaceFlinger服務(wù)端共享的,這就省去了繪圖資源的拷貝,示意圖如下:

以上是抽象的圖層對(duì)應(yīng)關(guān)系,可以看到,APP端是可以通過(guò)unLockCanvasAndPost直接同SurfaceFlinger通信進(jìn)行重繪的,就是說(shuō)圖形的繪制同WMS沒有關(guān)系,WMS只是負(fù)責(zé)窗口的管理,并不負(fù)責(zé)窗口的繪制,這一點(diǎn)其實(shí)也可以從IWindowSession的binder通信接口看出來(lái):
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);
...
}
從參數(shù)就可以看出,APP與WindowManagerService通信的時(shí)候沒有任何View相關(guān)的信息,更不會(huì)說(shuō)將視圖的數(shù)據(jù)傳遞給WMS,基本都是以IWindow為基本單位進(jìn)行通信的,所以涉及的操作也都是針對(duì)窗口的,比如整個(gè)窗口的添加、移除、大小調(diào)整、分組等,單單從窗口顯示來(lái)看,WMS的作用確實(shí)很明確,就是在服務(wù)端登記當(dāng)前存活窗口,后面還會(huì)看到,這會(huì)影響SurfaceFlinger的圖層混合,可以說(shuō)是為SurfaceFlinger服務(wù)的。
在對(duì)于日常開發(fā)來(lái)說(shuō),WMS的窗口分組有時(shí)候會(huì)對(duì)開發(fā)帶來(lái)影響,如果不知道窗口分組管理,可能有點(diǎn)忙迷惑,比如Dialog必須使用Activity的Context,PopupWindow不能作為父窗口,尤其要避免作為Webview的容器等,這些都跟WMS窗口的組織有關(guān)系。PopupWindow、Dialog、Activity三者都有窗口的概念,但又各有不同,Activity屬于應(yīng)用窗口、PopupWindow屬于子窗口,而Dialog位于兩者之間,從性質(zhì)上說(shuō)屬于應(yīng)用窗口,但是從直觀理解上,比較像子窗口(其實(shí)不是)。Android中的窗口主要分為三種:系統(tǒng)窗口、應(yīng)用窗口、子窗口,Toast就屬于系統(tǒng)窗口,而Dialog、Activity屬于應(yīng)用窗口,不過(guò)Dialog必須依附Activity才能存在。PopupWindow算是子窗口,必須依附到其他窗口,依附的窗口可以使應(yīng)用窗口也可以是系統(tǒng)窗口,但是不能是子窗口。

當(dāng)然,WMS的作用不僅只是管理窗口,它還負(fù)責(zé)窗口動(dòng)畫、Touch事件等,后面會(huì)逐個(gè)模塊分析。
View繪制與數(shù)據(jù)傳遞
既然WMS的作用只是窗口管理,那么圖形是怎么繪制的呢?并且這些繪制信息是如何傳遞給SurfaceFlinger服務(wù)的呢?每個(gè)View都有自己的onDraw回調(diào),開發(fā)者可以在onDraw里繪制自己想要繪制的圖像,很明顯View的繪制是在APP端,直觀上理解,View的繪制也不會(huì)交給服務(wù)端,不然也太不獨(dú)立了,可是View繪制的內(nèi)存是什么時(shí)候分配的呢?是誰(shuí)分配的呢?我們知道每個(gè)Activity可以看做是一個(gè)圖層,其對(duì)應(yīng)一塊繪圖表面其實(shí)就是Surface,Surface繪圖表面對(duì)應(yīng)的內(nèi)存其實(shí)是由SurfaceFlinger申請(qǐng)的,并且,內(nèi)存是APP與SurfaceFlinger間進(jìn)程共享的。實(shí)現(xiàn)機(jī)制是基于Linux的共享內(nèi)存,其實(shí)就是MAP+tmpfs文件系統(tǒng),你可以理解成SF為APP申請(qǐng)一塊內(nèi)存,然后通過(guò)binder將這塊內(nèi)存相關(guān)的信息傳遞APP端,APP端往這塊內(nèi)存中繪制內(nèi)容,繪制完畢,通知SF圖層混排,之后,SF再將數(shù)據(jù)渲染到屏幕。其實(shí)這樣做也很合理,因?yàn)閳D像內(nèi)存比較大,普通的binder與socket都無(wú)法滿足需求,內(nèi)存共享的示意圖如下:

總結(jié)
其實(shí)整個(gè)Android窗口管理簡(jiǎn)化的話可以分為以下三部分
- WindowManagerService:WMS控制著Surface畫布的添加與次序,動(dòng)畫還有觸摸事件
- SurfaceFlinger:SF負(fù)責(zé)圖層的混合,并且將結(jié)果傳輸給硬件顯示
- APP端:每個(gè)APP負(fù)責(zé)相應(yīng)圖層的繪制,
- APP與SurfaceFlinger通信:APP與SF圖層之間數(shù)據(jù)的共享是通過(guò)匿名內(nèi)存來(lái)實(shí)現(xiàn)的。
作者:看書的小蝸牛
原文鏈接: Android窗口管理分析(1):窗口管理及主觀理解
僅供參考,歡迎指正