Android窗口管理分析(1):View如何绘制到屏幕上的主观理解

窗口管理可以说是Android系统中最复杂的一部分,主要是它涉及的模块比较多,虽然笼统的说是窗口管理,其实,除了WindowManagerService还包括SurfaceFlinger服务、Linux的共享内存及tmpfs文件系统、Binder通信、InputManagerService、动画、VSYNC同步技术等,一篇文章不可能分析完全,但是可以首先对于窗口的显示与管理有一个大概的轮廓,再分块分解,涉及的知识点大概如下:

窗口管理知识图谱.png

WMS的作用是窗口管理 不负责View绘制

既然是概述,我们不妨直观的思考一个问题,Activity是如何呈现到屏幕上的,或者说View是如何被绘制到屏幕上来的?或多或少,开发者都知道WindowManagerService是负责Android的窗口管理,但是它其实只负责管理,比如窗口的添加、移除、调整顺序等,至于图像的绘制与合成之类的都不是WMS管理的范畴,WMS更像在更高的层面对于Android窗口的一个抽象,真正完成图像绘制的是APP端,而完成图层合成的是SurfaceFlinger服务。这里通过一个简单的悬浮窗口来探索一下大概流程:

    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

以上是抽象的图层对应关系,可以看到,APP端是可以通过unLockCanvasAndPost直接同SurfaceFlinger通信进行重绘的,就是说图形的绘制同WMS没有关系,WMS只是负责窗口的管理,并不负责窗口的绘制,这一点其实也可以从IWindowSession的binder通信接口看出来:

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服务的。

在对于日常开发来说,WMS的窗口分组有时候会对开发带来影响,如果不知道窗口分组管理,可能有点忙迷惑,比如Dialog必须使用Activity的Context,PopupWindow不能作为父窗口,尤其要避免作为Webview的容器等,这些都跟WMS窗口的组织有关系。PopupWindow、Dialog、Activity三者都有窗口的概念,但又各有不同,Activity属于应用窗口、PopupWindow属于子窗口,而Dialog位于两者之间,从性质上说属于应用窗口,但是从直观理解上,比较像子窗口(其实不是)。Android中的窗口主要分为三种:系统窗口、应用窗口、子窗口,Toast就属于系统窗口,而Dialog、Activity属于应用窗口,不过Dialog必须依附Activity才能存在。PopupWindow算是子窗口,必须依附到其他窗口,依附的窗口可以使应用窗口也可以是系统窗口,但是不能是子窗口。

窗口组织形式.jpg

当然,WMS的作用不仅只是管理窗口,它还负责窗口动画、Touch事件等,后面会逐个模块分析。

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都无法满足需求,内存共享的示意图如下:

View绘制与共享内存.jpg

总结

其实整个Android窗口管理简化的话可以分为以下三部分

  • WindowManagerService:WMS控制着Surface画布的添加与次序,动画还有触摸事件
  • SurfaceFlinger:SF负责图层的混合,并且将结果传输给硬件显示
  • APP端:每个APP负责相应图层的绘制,
  • APP与SurfaceFlinger通信:APP与SF图层之间数据的共享是通过匿名内存来实现的。

作者:看书的小蜗牛
原文链接: Android窗口管理分析(1):窗口管理及主观理解

仅供参考,欢迎指正

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容