Android | WMS 解析(一)(上)

简介: Android | WMS 解析(一)(上)

前言


前段时间分析了 Window 的添加、更新和删除流程,也知晓了 Activity 、Dialog 和 Toast 中 Window 的创建过程,今天就接着上篇文章,看一下 WMS 的创建 以及WindowManager 添加 WIndow 后 WMS 是怎样进行操作的。上篇文章点这里直达;


WindowManagerService 简称 WMS ,是系统的核心服务,主要分为四大部分,风别是 窗口管理,窗口动画,输入系统中转站,Surface 管理 。


了解 WMS


WMS 的职责很多,主要的就是下面这几点:


窗口管理:WMS是窗口的管理者,负责窗口的启动,添加和删除,另外窗口的大小也时有 WMS 管理的,管理窗口的核心成员有DisplayContent,WindowToken 和 WindowState

窗口动画:窗口间进行切换时,使用窗口动画可以更好看一些,窗口动画由 WMS 动画子系统来负责,动画的管理系统为 WindowAnimator

输入系统的中转站:通过对窗口触摸而产生的触摸事件,InputManagerServer(IMS) 会对触摸事件进行处理,他会寻找一个最合适的窗口来处理触摸反馈信息,WMS 是窗口的管理者,因此理所当然的就成为了输入系统的中转站。

Surface 管理:窗口并不具备绘制的功能,因此每个窗口都需要有一个块 Surface 来供自己绘制,为每个窗口分配 Surface 是由 WMS 来完成的。

WMS 的职责可以总结为下图:


0a2653c851af460fa595bd959398a8f1.png


WMS 的启动


WMS 是在 SystemServer 内部启动的


Android 系统在启动的时候,会启动两个重要的进程,一个是 Aygote 进程,两一个是由 Zygote 进程 fork 出来的 system_server 进程,SystemServer 会启动我们在系统中所需要的一系列 Service。


//#SystemServer.java
private void startOtherServices() {
    //.....
    //1
    WindowManagerService wm = null;
    InputManagerService inputManager = null;
  //2
    traceBeginAndSlog("StartInputManagerService");
    inputManager = new InputManagerService(context);
    traceEnd();
    traceBeginAndSlog("StartWindowManagerService");
    //WMS needs sensor service ready
    ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
    mSensorServiceStart = null;
    //3
    wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
            new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
    // WMS 初创建完成后调用,后面会讲到
    wm.onInitReady();
    //4
    ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
                DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
    //5
    ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
            /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
    traceEnd();
  //...
    try {
        //6 
        wm.displayReady();
    } catch (Throwable e) {
        reportWtf("making display ready", e);
    }
    traceEnd();
    try {
        //7
        wm.systemReady();
    } catch (Throwable e) {
        reportWtf("making Window Manager Service ready", e);
    }
    traceEnd();
  ///...
}


startOtherServer 用于启动其他服务,大概有70多个,上面列出了 WMS 和 IMS 的启动逻辑。


在注释1的地方声明了 WMS 和 IMS, 这里值列出了两个,其实非常多。


注释2处创建了 IMS ,


注释 3 调用了 WMS 的 main 方法,并且传入了 IMS,因为 WMS 是 IMS 的中转站。观察 WindowManagerService.main 方法可以知道他是运行在 SystemServer 的 run 方法中,换句话说就是运行在 system_server 线程中。


注释4和5处将 WMS 和 IMS 注册到 ServerManager 里面,这样客户端想要使用 WMS 就需要先去 ServiceManager 中查询信息,然后与 WMS 所在的进程建立通信,这样客户端就可以使用 WMS 了。


注释 6 用来初始化显示信息,注释 7 处用来通知 WMS 系统初始化工作已经完成,内部调用了 WindowManagerPolicy 的 systemReady 方法。


接着,我们看看 WMS 的 maain 方法:


public static WindowManagerService main(final Context context, final InputManagerService im,
        final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
        ActivityTaskManagerService atm) {
    return main(context, im, showBootMsgs, onlyCore, policy, atm,
            SurfaceControl.Transaction::new, Surface::new, SurfaceControl.Builder::new);
}
public static WindowManagerService main(final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,Supplier<Surface> surfaceFactory,
            Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
        DisplayThread.getHandler().runWithScissors(() ->
                sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
                        atm, transactionFactory, surfaceFactory, surfaceControlFactory), 0);
        return sInstance;
    }


上面通过 DisplayThread 的 getHandler 方法获取到了 DisplayThread 的 Handler 实例。


DisplayThread 是一个单例的前台线程,用来处理需要低延时显示的相关操作,并且只能由 WindowManager,DisplayManager 和 INputManager 试试执行快速操作。


runWithScissors 表达式中创建了 WMS 对象。至于 Handler.runWithScissors 方法,有兴趣的可以看一下这篇文章。


到这里我们就知道 WMS 是从何处启动的了,下面我们来看一下 WMS 的构造方法


WMS构造方法


private WindowManagerService(Context context, InputManagerService inputManager,
            boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
       ...
        //1
        mInputManager = inputManager; // Must be before createDisplayContentLocked.
      //2
      mPolicy = policy;
        //3
        mAnimator = new WindowAnimator(this);
      //4
        mRoot = new RootWindowContainer(this);
    //5
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    //6
        mActivityManager = ActivityManager.getService();
    //7
        LocalServices.addService(WindowManagerInternal.class, new LocalService());
    ...
    }


保存 IMS ,这样就持有了 IMS 的引用。

初始化 WindowManagerPolicy ,它用来定义一个窗口测量所需要遵循的规范。

创建了 WindowAnimator,它用于管理所有的窗口动画。

创建 RootWindowContainer 对象,根窗口容器

获取 DisplayManager 服务

获取 AMS,并持有他的引用

将 LocalService 添加到 LocalServices 中

在上面 WMS的启动中 WMS 创建完成后会调用 wm.onInitReady 方法,下面我们来看一下这个方法:


public void onInitReady() {
   initPolicy();
   //将 WMS 添加到 Watchdog 中,Watchdog 用来监控一下系统关键服务的运行情况。
   //这些被监控的服务都会实现 Watchdog.Monitor 接口,Watchdog 每分钟都会对
   //被监控的服务进行检测,如果被监控的服务出现了死锁,则会杀死 Watchdog 所在的进程
   Watchdog.getInstance().addMonitor(this);
   ......
}
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);
        }
    }, 0);
}


上面的和 WMS 的 main 方法类似,WindowManagerPolicy (简称 WMP) 是一个接口,init 的具体实现在 PhoneWindowManager(PWM) 中,并且通过上面代码我们知道,init 方法运行在 android.ui线程中。因此他的线程优先级要高于 android.display 线程,必须等 init 方法执行完成后,android.display线程才会被唤醒从而继续执行下面的代码。


WindowManagerPolicy 用来定义一个窗口策略所要遵循的通用规范,,并提供了 WindowManager 所有的特定 UI 行为

他的具体实现类为 PhoneWindowManager


在上面的文章中,一共提供了三个线程,分别是 system_server,android.display ,android.ui,他们之间的关系如下图所示:


0a2653c851af460fa595bd959398a8f1.png


system_server 线程中会调用 main 方法,mian 方法中会创建 WMS,创建的过程实在 android.display 线程中,他的优先级会高一些,创建完成后才会唤醒处于 system_server 线程。


WMS 创建完成后会调用 onInitReady 中的 initPolicy 方法,该方法中会调用 PWM 的 init() 方法,init 方法调用完成之后就会唤醒 system_server 线程。init 方法运行中 android.ui 线程中。


之后就会接着执行 system_server 中的代码,例如 displayReady 等。


WIMS 窗口管理


Window 的操作有两大部分,一部分是 WindowManager 来处理,一部分是 WMS 来处理,如下图所示:


0a2653c851af460fa595bd959398a8f1.png


WindowManager 中,通过 WindowManagerGlobal 创建 ViewRootImpl ,也就是 View 的根。在 ViewRootImpl 中完成对 View 的绘制等操作,然后通过 IPC 获取到 Session ,最终通过 WMS 来进行处理。在理解 Window 和 WindowManager 这篇文章中,讲解了 WIndow 的创建,添加和删除部分,有兴趣的可以看一下。

WMS 来处理后面的部分,具体见下文


WindowManager -> WMS


我们都知道 Window 的添加最后是通过 ViewRootImpl.addTodisplay 方法来完成的,我们先来看一下:


public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {
    synchronized (this) {
        if (mView == null) {
          ....
            try {
                res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mDisplayCutout, inputChannel,
                        mTempInsets, mTempControls);
            }
            ...
    }
}


这里调用了 mWindowSession.addToDisplayAsUser 来完成最后的添加,我们先看看 mWindowSession 是个啥东西。


public ViewRootImpl(Context context, Display display) {
    this(context, display, WindowManagerGlobal.getWindowSession(),
            false /* useSfChoreographer */);
}


//WindowManagerGlobal.java
public static IWindowSession getWindowSession() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
            try {
        ....
                IWindowManager windowManager = getWindowManagerService();
                //通过 windowManager 创建一个 IWindowSession 
                sWindowSession = windowManager.openSession(
                        new IWindowSessionCallback.Stub() {
                            @Override
                            public void onAnimatorScaleChanged(float scale) {
                                ValueAnimator.setDurationScale(scale);
                            }
                        });
            }
        return sWindowSession;
    }
}
public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                // 通过 AIDL 获取 IWindowManager 
                sWindowManagerService = IWindowManager.Stub.asInterface(
                    //获取 WindowManagerService 的 IBinder 
                    ServiceManager.getService("window"));
    //...
            }
            return sWindowManagerService;
        }
    }
// WindowManagerService.java    
@Override
public IWindowSession openSession(IWindowSessionCallback callback) {
    return new Session(this, callback);//传入了 this,将 Session 就会持有 WindowManagerService 的引用
}


mWindowSession 是 IwindowSession 的对象,实现类是 Session。


上面代码中,在 VIewRootImpl 初始化的时候,通过IPC 获取到 IWindowManager,然后通过 IPC 的调用创建了 Session 对象。


接着我们来看一下 mWindowSession.addToDisplayAsUser 方法,也就是在 Session 类中


@Override
public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, int userId, Rect outFrame,
        Rect outContentInsets, Rect outStableInsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
        InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
            outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
            outInsetsState, outActiveControls, userId);
}


可以看到,最终是通过 mService 来完成添加的,


需要注意的是,WMS 并不关系 View 的具体内容,他只关心各个应用显示的界面大小,层级值等,这些数据到包含在 WindowManager.LayoutParams 中。也就是上面的 atrs 属性。


注意 addWindow 的第二个参数是一个 IWindow 类型,这是 App 暴露给 WMS 的抽象实例,在 ViewRootImp 中实例化,与 ViewRootImpl 一一对应,同事也是 WMS 向 App 端发送消息的 Binder 通道。


从 WindowManager 到 WMS 的具体流程如下所示:


WMS 重要成员


final WindowManagerPolicy mPolicy;
final IActivityManager mActivityManager;
final ActivityManagerInternal mAmInternal;
final AppOpsManager mAppOps;
final DisplaySettings mDisplaySettings;
...
final ArraySet<Session> mSessions = new ArraySet<>();
final WindowHashMap mWindowMap = new WindowHashMap();
final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>();
final ArrayList<AppWindowToken> mFinishedEarlyAnim = new ArrayList<>();
final ArrayList<AppWindowToken> mWindowReplacementTimeouts = new ArrayList<>();
final ArrayList<WindowState> mResizingWindows = new ArrayList<>();
final ArrayList<WindowState> mPendingRemove = new ArrayList<>();
WindowState[] mPendingRemoveTmp = new WindowState[20];
final ArrayList<WindowState> mDestroySurface = new ArrayList<>();
final ArrayList<WindowState> mDestroyPreservedSurface = new ArrayList<>();
...
final H mH = new H();
...
final WindowAnimator mAnimator;
...
 final InputManagerService mInputManager


WindowManagerPolicy mPolicy


窗口管理策略的接口类,用来定义一个窗口策略所要遵循的通用规范,并提供了 WindowManager 所有的特定 UI 行为

他的具体实现类为 PhoneWindowManager,这个实现类在 WMS 创建时被创建。WMP 允许定制窗口层级和特殊窗口类型以及关键字的调度和布局


ArraySet mSessions


ArraySet 类型的变量,元素类型为 Session,他主要用于进程间的通信。并且每个应用程序都会对应一个 Session,WMS 保存这些 Session 用来记录所有向 WMS 提出窗口管理服务的客户端


WindowHashMap mWindowMap


继承自 HashMap,它限制 key 为 IBinder,value 的值类型为 WindowState,WindowState 用于保存窗口信息,在 WMS 中用来描述一个窗口。所以 mWindowMap 就是用来保存 WMS 中各种窗口的集合。


ArrayList mFinishedStarting


元素类型是 AppWindowToken,他是 WindowToken 的子类,想要了解 mFinishedStarting 的含义,需要先了解 WindowToken 是什么,WindowToken 主要由两个作用:


可以理解为窗口令牌,当应用程序想要向 WMS 申请创建一个窗口,则需要向 WMS 出示有效的 WindowToken。AppWindowToken 作为 WindowToken 的子类,主要用来描述应用程序的 WindowToken 结构。

WindowToken 会将相同组件(例如 Activity)的窗口(WindowState)集合在一起,方便管理。

mFinishedStarting 就是用于存储已经完成启动的应用窗口程序窗口(比如Activity) 的 AppWindowToken 的列表。


除了 mFinishedStarting,还有类似的 mFinishedEarlyAnim和 mWindowReplacementTimeouts


其中 mFinishedEarlyAnim 存储了已经完成窗口绘制并且不需要再展示任何已经保存 surface 的应用程序窗口的 AppWindowToken


mWindowReplacementTimeout 存储了等待更换的应用程序窗口的 AppWindowToken,如果更换不及时,旧窗口就需要被处理


ArrayList mResizingWindow


用来存储正在调整大小的窗口列表。与 mResizingWindows 类似的还有个 mPendingRemove,mDestorySurface 和 mDestoryPreservedSurface 等等。


其中 mPendingRemove 是在内存耗尽时设置的,里面存有需要强制删除的窗口。


mDestorySurface 里面存有需要被 Destory 的 Surface ,mDestoryPreservedSurface 里面存有窗口需要保存的等等销毁的 Surface ,为什么窗口需要保存这些 Surface ?这是因为当窗口经历 Surface 变化时,窗口需要一直保持旧 Surface,直到新 Surface 的第一帧绘制完成。


WindowAnimator mAnimator


WindowAnimator 类型的变量,用于管理窗口的动画以及特效动画


H mH


继承自 Hnadler 类,用于将任务加入到主线程的消息队列中,这样代码逻辑就会在主线程执行


InputManagerService mINputManager


IMS ,输入系统的管理者。IMS 会对触摸事件进行处理,他会寻找一个最合适的窗口来处理触摸反馈信息,WMS 是窗口管理者,因此 WMS 理所应当的成为了输入系统的中转站,WMS 包含了 IMS 的引用不足为怪。


相关文章
|
24天前
|
XML Java Android开发
Android实现自定义进度条(源码+解析)
Android实现自定义进度条(源码+解析)
51 1
|
3月前
|
存储 算法 安全
AVB数据解析:Android verified boot 2.0 vbmeta 数据结构解析
AVB数据解析:Android verified boot 2.0 vbmeta 数据结构解析
142 0
|
1月前
|
编译器 开发工具 Android开发
Android 12 新特性深度解析
【2月更文挑战第15天】 随着移动操作系统的不断进化,Android 12带来了一系列创新功能与性能提升。本文将深入剖析Android 12的核心新特性,包括隐私仪表盘、通知管理、设备控制以及性能优化等方面,为开发者和用户提供全面的更新指南。
|
3月前
|
JSON Java Android开发
Android网络和数据交互: 请解释Android中的JSON解析库,如Gson。
Android网络和数据交互: 请解释Android中的JSON解析库,如Gson。
24 0
|
4月前
|
Android开发 容器
[Android]View的事件分发机制(源码解析)
[Android]View的事件分发机制(源码解析)
36 0
|
1天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
9天前
yolo-world 源码解析(六)(2)
yolo-world 源码解析(六)
18 0
|
9天前
yolo-world 源码解析(六)(1)
yolo-world 源码解析(六)
13 0
|
9天前
yolo-world 源码解析(五)(4)
yolo-world 源码解析(五)
22 0
|
9天前
yolo-world 源码解析(五)(1)
yolo-world 源码解析(五)
31 0

推荐镜像

更多