WindowManagerService理解与深入(Android Q)

一、WindowManagerService的基础概念

1、什么是WindowManagerServie?

首先,什么是Window?

从原理上来讲,Window是独自占有一个Surface实例的显示区域,用于绘制各种UI元素并可以响应用户输入。

什么是WindowManagerService

每个窗口都有一块Surface,就需要一个角色来协调管理所有的Surface。WindowManagerService就是这样的角色,它为所有窗口分配Surface、掌管Surface的显示顺序(Z序)以及大小尺寸、控制窗口动画,并且还是输入系统的中转站。

在客户端创建一个Window的步骤:

  1. 获取IWindowSession和WMS实例。IWindowSession是客户端向WMS请求窗口操作的中间代理,进程唯一。
  2. 创建并初始化WindowManager.LayoutParams,其继承自ViewGroup.LayoutParams。其扩展了一些窗口相关的属性,其中最重要的是type属性,描述了窗口的类型,是WMS对窗口排序的依据
  3. 向WMS添加一个窗口令牌,其描述了一个显示行为。WMS要求每一个窗口都必须隶属于某一个显示令牌
  4. 向WMS添加一个窗口,必须在LayoutParams中指明窗口所属的窗口令牌,否则会添加失败。但是系统窗口不用开发者担心,会自动添加令牌
  5. 向WMS申请对窗口重新布局(relayout)。重新布局指的是根据窗口新的属性去调整Surface相关的属性,或者重新创建一个Surface。向WMS中添加一个窗口,仅仅代表将它在WMS中进行了注册,只有经过重新布局,窗口才会拥有WMS为其创建的画布。有了画布,窗口才可以开始绘制工作。

窗口的绘制过程如下:

  • 通过Surface.lock获取可以在其上作画的Canvas实例
  • 使用Canvas实例作画
  • 通过Surface.unlockCanvasAndPost函数提交绘制结果

客户端除了使用以上标准作画流程,同样可以使用OpenGL作画。

窗口销毁只需要通过IWindowSession.remove方法将窗口从WMS中移除即可。如果客户端已经完成了工作并且不会再显示新的窗口,则需要从WMS中删除之前添加的显示令牌。

Android的显示系统可以根据Surface的操作分为三个层次:

  • UI框架层:在Surface上绘制UI元素以及响应输入事件
  • WMS:管理Surface的分配、层级顺序
  • SurfaceFlinger:负责将多个Surface混合输出

2、WMS的构成

a)WMS的创建过程

在这里插入图片描述

public static WindowManagerService main(
    final Context context,
    final InputManagerService im,
    final boolean showBootMsgs,
    final boolean onlyCore,
    WindowManagerPolicy policy,
    ActivityTaskManagerService atm,
    TransactionFactory transactionFactory){
   
    DisplayThread.getHandler().runWithScissors(()->
    	sInstance=new WindowManagerService(context,
                                          im,
                                          showBootMsgs,
                                          onlyCore,
                                          policy,
                                          atm,
                                          transactionFactory),0);
    return sInstance;
}

WindowManagerService.main的重要参数:

  • InputManagerService:对于C++InputManager类的包装,并且提供一些回调。

  • WindowManagerPolicy:一个提供Window Manager所有UI特定行为的接口。其实例在WindowManager启动的时候被创建。 因为它提供了与系统窗口管理器的深度交互,所以可以从各种上下文中调用这个接口上的特定方法,并对它们的功能进行各种限制。这些是通过方法末尾的一个后缀进行编码的,该后缀会编码方法调用的线程以及在调用该方法时持有的任何种类的锁。如果一个方法没有附加后缀,那么它不会被任何锁调用,可以从主窗口管理器线程调用,也可以从另一个调用窗口管理器的线程调用。

    后缀有:

    1. Ti:由输入线程调用,Input Thread负责分发输入事件到Window
    2. Tq:由低级的input queue thread调用,这个线程从原始的输入设备中读取数据然后将他们放入全局输入队列里。这个队列会由Ti线程读取。除了key driver以外,这个线程不应该被长时间锁住
    3. Lw:在持有主窗口管理器锁的情况下调用。因为WindowManager是非常低等级的System Service,所以拥有这个锁的时候,只有很少一部分系统服务可以调用。但是可以调用PackageManager和PowerManager。
    4. Li:在持有输入线程锁的时候调用,当WindowManager持有窗口锁的时候可以申请这个锁。所以这个后缀比Lw更加严格。
  • ActivityTaskManagerSerivce:管理Activities以及它们的容器的系统服务。

  • TransactionFactory:为WindowManager注入定制的transaction对象的辅助类。transcation对象为SurfaceControl中关于变化的一组原子集合。通过使用SurfaceControl.Transaction,我们可以操作很多属性来控制缓冲内容如何显示在显示屏上。

DisplayThread:所有跟系统前景有关的操作都集中到这个线程类中,这个类只能用来处理低时延的显示相关操作,只能由WindowManager、DispalyManager和InputManager用来实时显示的快速操作。这也就是说WMS的创建在Android5.0之后改成了运行在DisplayThread的Handler中(android.display)。 WMS创建完成之后还是运行在“systemServer”线程中。

runWithScissors:这个函数会在Hanadler所在的线程中执行传入的Runnable对象,同时阻塞调用线程的执行,直到Runnable对象的run()函数执行完毕。

传入给runWithScissors的Runnable对象中的函数为WindowManagerService,这个函数主要进行如下操作:

  • 创建DisplayManager:这个类用来管理添加的显示器,初始化DisplayContent列表,一个DisplayContent指代一个屏幕,屏幕可以是手机自身的屏幕,也可以是虚拟屏幕。

    从API26开始增加了WindowContainer来定义那些可以直接在层次结构表单中保存窗口或者通过其子窗体保存窗口的类的公共功能,比如以前在WindowManagerService中使用DisplayContent列表来遍历所有窗口的操作被放在了继承了WindowContainer的RootWindowContainer中使用forAllWindow来完成。其中又会交给WindowState来完成。(之前逻辑全在WMS中)

    而WindowContainer的管理又交给了WindowContainerController来完成。这个类提供了方法使得WindowContainer的拥有者/创建者能够直接与WindowContainer交流以及做出变更。

    会在IWindowSession调用reparentDisplayContent的时候调用checkCallerOwnDisplay,在这个方法中获取display,然后在getDisplayContentOrCreate中获取displayContent。

  • 保存InputManagerService:输入事件最终要分发给具有焦点的窗口,WMS是窗口管理者,所以WMS是输入系统中的重要一环

  • 创建WidowAnimator:管理着所有窗口的动画

  • 初始化WindowManagerPolicy:

     private void initPolicy() {
         
            UiThread.getHandler().runWithScissors(new Runnable() {
         
                @Override
                public void run() {
         
                    WindowManagerPolicyThread.set(Thread.currentThread(), 													Looper.myLooper());
                    mPolicy.init(mContext, WindowManagerService.this, 											WindowManagerService.this)
  • 13
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值