Android | WMS 解析(一)(上)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 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 的引用不足为怪。


相关文章
|
4月前
|
Java 开发工具 Android开发
Android与iOS开发环境搭建全解析####
本文深入探讨了Android与iOS两大移动操作系统的开发环境搭建流程,旨在为初学者及有一定基础的开发者提供详尽指南。我们将从开发工具的选择、环境配置到第一个简单应用的创建,一步步引导读者步入移动应用开发的殿堂。无论你是Android Studio的新手还是Xcode的探索者,本文都将为你扫清开发道路上的障碍,助你快速上手并享受跨平台移动开发的乐趣。 ####
|
3月前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
3月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
4月前
|
开发框架 Dart Android开发
安卓与iOS的跨平台开发:Flutter框架深度解析
在移动应用开发的海洋中,Flutter作为一艘灵活的帆船,正引领着开发者们驶向跨平台开发的新纪元。本文将揭开Flutter神秘的面纱,从其架构到核心特性,再到实际应用案例,我们将一同探索这个由谷歌打造的开源UI工具包如何让安卓与iOS应用开发变得更加高效而统一。你将看到,借助Flutter,打造精美、高性能的应用不再是难题,而是变成了一场创造性的旅程。
|
4月前
|
安全 Java Linux
深入解析Android系统架构及其对开发者的意义####
【10月更文挑战第21天】 本文旨在为读者揭开Android操作系统架构的神秘面纱,探讨其如何塑造现代移动应用开发格局。通过剖析Linux内核、硬件抽象层、运行时环境及应用程序框架等关键组件,揭示Android平台的强大功能与灵活性。文章强调了理解Android架构对于开发者优化应用性能、提升用户体验的重要性,并展望了未来技术趋势下Android的发展方向。 ####
109 0
|
5月前
|
开发工具 Android开发 iOS开发
深入解析安卓与iOS开发环境的优劣
【10月更文挑战第4天】 本文将深入探讨安卓和iOS两大主流移动操作系统的开发环境,从技术架构、开发工具、用户体验等方面进行详细比较。通过分析各自的优势和不足,帮助开发者更好地理解这两个平台的异同,从而为项目选择最合适的开发平台提供参考。
64 3
|
4月前
|
安全 5G Android开发
安卓与iOS的较量:技术深度解析
【10月更文挑战第24天】 在移动操作系统领域,安卓和iOS无疑是两大巨头。本文将深入探讨这两个系统的技术特点、优势和不足,以及它们在未来可能的发展方向。我们将通过对比分析,帮助读者更好地理解这两个系统的本质和内涵,从而引发对移动操作系统未来发展的深思。
96 0
|
2天前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
41 29
|
4月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
145 2
|
10天前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。

热门文章

最新文章

  • 1
    Android历史版本与APK文件结构
  • 2
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 3
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 4
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 5
    【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
  • 6
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 8
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
  • 9
    Android实战经验之Kotlin中快速实现MVI架构
  • 10
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
  • 推荐镜像

    更多