WMS工作原理分析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/english2888/article/details/79362338


Wms管理着所有的窗口,包括创建、删除和修改,以及将某个窗口设置为焦点窗口。

一、窗口、Window和View的区别

窗口由两部分构成,一部分是描述该窗口的类WindowState,另一部分是该窗口在屏幕上对应的界面Surface。

window是一个类,其实现类是PhoneWindow类,Activity类实现Window.Callback接口,从而成了具有通用操作方式的窗口。

View也是一个视图,是一个独立的交互元素。

二、Wms接口结构

交互过程如下:

  1. 应用程序在Activity中添加、删除窗口。具体实现就是通过调用WindowManager类的addView()和removeView()函数完成,转而调用ViewRoot类的相关方法,然后通过IPC调用到Wms中的相关方法完成添加、删除过程。

  2. AmS通知ActivityThread销毁某个Actviity时,ActivityThread会直接调用WindowManager中的removeView()方法删除窗口。

  3. AmS中直接调用WmS,告诉Wms一些信息,比如某个新的Activity要启动了,从而Wms保存一个该Activity记录的引用。

  4. 在Wms内部,全权接管输入消息的处理和屏幕的绘制。输入消息由InputManager类完成,屏幕绘制由SurfaceFlinger模块完成,SurfaceFlings是Linux的一个驱动,内部使用芯片的图形加速引擎完成界面的绘制。

三、窗口的创建时机和过程

时机:第一种是开发者主动调用WindowManager类的addView()方法;第二种是当用户启动新的Activity或者显示一个对话框的时候,由类内部间接调用addView()函数。

以第二种窗口创建为例,activity启动执行performLaunchActivity函数,创建activity对象、ContextImpl对象和Application对象,然后调用activity.attach()函数,创建Window实现类PhoneWindow对象,回调Activity的onCreate()函数,setContentView(view)初始化DecorView。接着调用handleResumeActivity函数,调用windowManage.addView(decor)。windowManager的实现类是windowManagerImpl类,看下它的addView()方法。

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

调用到WindowManagerGlobal.addView()函数。

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
           ...
    ViewRootImpl root;
    View panelParentView = null;
         ...

        root = new ViewRootImpl(view.getContext(), display);

        view.setLayoutParams(wparams);

        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
    }

    // do this last because it fires off messages to start doing things
    try {
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
        // BadTokenException or InvalidDisplayException, clean up.
        synchronized (mLock) {
            final int index = findViewLocked(view, false);
            if (index >= 0) {
                removeViewLocked(index, true);
            }
        }
        throw e;
    }
}

初始化调用到ViewRootImpl对象,在构造函数中获取WindowSession对象,windowSession会通过IPC创建Session对象。它是一个SurfaceSession对象的包装类,直接和SurfaceFlinger对象直接打交道,SurfaceFlinger对象是底层界面绘制类。接着看ViewRootImpl.setView()方法。setView函数主要做两件事情,一是requestLayout(),请求绘制界面scheduleTraversals()。二是创建InputChannel消息传输渠道对象,他是对Unxi Socket对的封装,在系统server和程序中各有一个,作用是对消息的读取。三是调用session.addToDisplay(),继而调用wms.addWindow()函数。

addWindow方法的执行流程分为三个小过程,第一个是进行前置处理,即首先判断参数的合法性,二是具体添加和窗口相关的数据,第三是后置处理,即添加窗口会引起相关状态的变化。

  1. 判断mDisplay是否为空,该变量为全局变量,代表当前屏幕的Display属性,该代码当系统启动后仅被执行一次。

  2. 判断目标窗口是否已经存在mWindowMap列表中,此时目标是IWindow类型,其对应是ViewRoot类中的W对象。如果已经存在,抛出异常提示重复添加。

  3. 如果目标窗口参数attr.type=SUB_WINDOW,即子窗口类型,那么目标窗口所隶属的父窗口必须存在,否则添加无效。

当前置检查完成后,没什么错误,就开始真正窗口的添加。

  1. 新建一个windowState对象,窗口都是由WindowState类表示,每个窗口对应一个WindowState对象。

  2. 调用mPolicy.adjustWindowParamsLw()对窗口参数进行调整,对TOAST窗口限制其获得输入焦点的功能。

  3. 创建一对pipe,一个赋值给输出参数outchannel变量中,另一个赋值给InputDispatcher中,管道将用于输入消息的传递。

  4. 调用win.attach()方法,内部初始化和创建真正的Surface相关的变量,主要是SurfaceSession变量,该类直接和SurfaceFlinger交互的类,用于向SurfaceFlinger中添加、删除、变换窗口。SurfaceSession构造函数中调用了nativeCreate(),属于native层方法,主要是创建爱你一块共享内存,通过writeParcel返回给ViewRootImlp.mSurface

  5. 将新建的windowState对象那个添加到mWindowMap列表中。

后置处理:

展开阅读全文

没有更多推荐了,返回首页