Android 系统启动系列
Android 深入四大组件系列
Android 应用进程启动过程系列
Android 解析 WindowManager 系列
前言
此前我用多篇文章介绍了 WindowManager, 这个系列我们来介绍 WindowManager 的管理者 WMS, 首先我们先来学习 WMS 是如何产生的本文源码基于 Android 8.0, 与 Android 7.1.2 相比有一个比较直观的变化就是 Java FrameWork 采用了 Lambda 表达式
1.WMS 概述
WMS 是系统的其他服务, 无论对于应用开发还是 Framework 开发都是重点的知识, 它的职责有很多, 主要有以下几点:
窗口管理
WMS 是窗口的管理者, 它负责窗口的启动添加和删除, 另外窗口的大小和层级也是由 WMS 进行管理的窗口管理的核心成员有 DisplayContentWindowToken 和 WindowState
窗口动画
窗口间进行切换时, 使用窗口动画可以显得更炫一些, 窗口动画由 WMS 的动画子系统来负责, 动画子系统的管理者为 WindowAnimator
输入系统的中转站
通过对窗口的触摸从而产生触摸事件, InputManagerService(IMS)会对触摸事件进行处理, 它会寻找一个最合适的窗口来处理触摸反馈信息, WMS 是窗口的管理者, 因此, WMS 理所应当的成为了输入系统的中转站
Surface 管理
窗口并不具备有绘制的功能, 因此每个窗口都需要有一块 Surface 来供自己绘制为每个窗口分配 Surface 是由 WMS 来完成的
WMS 的职责可以简单总结为下图
2.WMS 的诞生
WMS 的知识点非常多, 在了解这些知识点前, 我们十分有必要知道 WMS 是如何产生的 WMS 是在 SyetemServer 进程中启动的, 不了解 SyetemServer 进程的可以查看在 Android 系统启动流程 (三) 解析 SyetemServer 进程启动过程这篇文章
先来查看 SyetemServer 的 main 方法:
- frameworks/base/services/java/com/android/server/SystemServer.java
- public static void main(String[] args) {
- new SystemServer().run();
- }
main 方法中只调用了 SystemServer 的 run 方法, 如下所示
- frameworks/base/services/java/com/android/server/SystemServer.java
- private void run() {
- try {
- System.loadLibrary("android_servers");//1
- ...
- mSystemServiceManager = new SystemServiceManager(mSystemContext);//2
- mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
- LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
- // Prepare the thread pool for init tasks that can be parallelized
- SystemServerInitThreadPool.get();
- } finally {
- traceEnd(); // InitBeforeStartServices
- }
- try {
- traceBeginAndSlog("StartServices");
- startBootstrapServices();//3
- startCoreServices();//4
- startOtherServices();//5
- SystemServerInitThreadPool.shutdown();
- } catch (Throwable ex) {
- Slog.e("System", "******************************************");
- Slog.e("System", "************ Failure starting system services", ex);
- throw ex;
- } finally {
- traceEnd();
- }
- ...
- }
run 方法代码很多, 这里截取了关键的部分, 在注释 1 处加载了 libandroid_servers.so 在注释 2 处创建 SystemServiceManager, 它会对系统的服务进行创建启动和生命周期管理接下来的代码会启动系统的各种服务, 在注释 3 中的 startBootstrapServices 方法中用 SystemServiceManager 启动了 ActivityManagerServicePowerManagerServicePackageManagerService 等服务在注释 4 处的方法中则启动了 BatteryServiceUsageStatsService 和 webViewUpdateService 注释 5 处的 startOtherServices 方法中则启动了 CameraServiceAlarmManagerServiceVrManagerService 等服务, 这些服务的父类为 SystemService 从注释 345 的方法名称可以看出, 官方把大概 100 多个系统服务分为了三种类型, 分别是引导服务核心服务和其他服务, 其中其他服务为一些非紧要和一些不需要立即启动的服务, WMS 就是其他服务的一种
我们来查看 startOtherServices 方法是如何启动 WMS 的:
- frameworks/base/services/java/com/android/server/SystemServer.java
- private void startOtherServices() {
- ...
- traceBeginAndSlog("InitWatchdog");
- final Watchdog watchdog = Watchdog.getInstance();//1
- watchdog.init(context, mActivityManagerService);//2
- traceEnd();
- traceBeginAndSlog("StartInputManagerService");
- inputManager = new InputManagerService(context);//3
- traceEnd();
- traceBeginAndSlog("StartWindowManagerService");
- ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
- mSensorServiceStart = null;
- wm = WindowManagerService.main(context, inputManager,
- mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
- !mFirstBoot, mOnlyCore, new PhoneWindowManager());//4
- ServiceManager.addService(Context.WINDOW_SERVICE, wm);//5
- ServiceManager.addService(Context.INPUT_SERVICE, inputManager);//6
- traceEnd();
- ...
- try {
- wm.displayReady();//7
- } catch (Throwable e) {
- reportWtf("making display ready", e);
- }
- ...
- try {
- wm.systemReady();//8
- } catch (Throwable e) {
- reportWtf("making Window Manager Service ready", e);
- }
- ...
- }
startOtherServices 方法用于启动其他服务, 其他服务大概有 70 多个, 上面的代码只列出了 WMS 以及和它相关的 IMS 的启动逻辑, 剩余的其他服务的启动逻辑也都大同小异
在注释 12 处分别得到 Watchdog 实例并对它进行初始化, Watchdog 用来监控系统的一些关键服务的运行状况, 后文会再次提到它在注释 3 处创建了 IMS, 并赋值给 IMS 类型的 inputManager 对象注释 4 处执行了 WMS 的 main 方法, 其内部会创建 WMS, 需要注意的是 main 方法其中一个传入的参数就是注释 1 处创建的 IMS,WMS 是输入事件的中转站, 其内部包含了 IMS 引用并不意外结合上文, 我们可以得知 WMS 的 main 方法是运行在 SystemServer 的 run 方法中, 换句话说就是运行在 system_server 线程中, 后面会再次提到 system_server 线程
注释 5 和注释 6 处分别将 WMS 和 IMS 注册到 ServiceManager 中, 这样如果某个客户端想要使用 WMS, 就需要先去 ServiceManager 中查询信息, 然后根据信息与 WMS 所在的进程建立通信通路, 客户端就可以使用 WMS 了注释 7 处用来初始化显示信息, 注释 8 处则用来通知 WMS, 系统的初始化工作已经完成, 其内部调用了 WindowManagerPolicy 的 systemReady 方法
我们来查看注释 4 处 WMS 的 main 方法, 如下所示
- frameworks/base/services/core/java/com/android/server/wm/WindowManagerService .java
- public static WindowManagerService main(final Context context, final InputManagerService im,
- final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
- WindowManagerPolicy policy) {
- DisplayThread.getHandler().runWithScissors(() ->//1
- sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
- onlyCore, policy), 0);
- return sInstance;
- }
在注释 1 处调用了 DisplayThread 的 getHandler 方法, 用来得到 DisplayThread 的 Handler 实例 DisplayThread 是一个单例的前台线程, 这个线程用来处理需要低延时显示的相关操作, 并只能由 WindowManagerDisplayManager 和 InputManager 实时执行快速操作注释 1 处的 runWithScissors 方法中使用了 Java8 中的 Lambda 表达式, 它等价于如下代码:
- DisplayThread.getHandler().runWithScissors(new Runnable() {
- @Override
- public void run() {
- sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
- onlyCore, policy);//2
- }
- }, 0);
在注释 2 处创建了 WMS 的实例, 这个过程运行在 Runnable 的 run 方法中, 而 Runnable 则传入到了 DisplayThread 对应 Handler 的 runWithScissors 方法中, 说明 WMS 的创建是运行在 android.display 线程中需要注意的是, runWithScissors 方法的第二个参数传入的是 0, 后面会提到来查看 Handler 的 runWithScissors 方法里做了什么:
- frameworks/base/core/java/android/os/Handler.java
- public final boolean runWithScissors(final Runnable r, long timeout) {
- if (r == null) {
- throw new IllegalArgumentException("runnable must not be null");
- }
- if (timeout < 0) {
- throw new IllegalArgumentException("timeout must be non-negative");
- }
- if (Looper.myLooper() == mLooper) {//1
- r.run();
- return true;
- }
- BlockingRunnable br = new BlockingRunnable(r);
- return br.postAndWait(this, timeout);
- }
开头对传入的 Runnable 和 timeout 进行了判断, 如果 Runnable 为 null 或者 timeout 小于 0 则抛出异常注释 1 处根据每个线程只有一个 Looper 的原理来判断当前的线程 (system_server 线程) 是否是 Handler 所指向的线程(android.display 线程), 如果是则直接执行 Runnable 的 run 方法, 如果不是则调用 BlockingRunnable 的 postAndWait 方法, 并将当前线程的 Runnable 作为参数传进去 ,BlockingRunnable 是 Handler 的内部类, 代码如下所示
- frameworks/base/core/java/android/os/Handler.java
- private static final class BlockingRunnable implements Runnable {
- private final Runnable mTask;
- private boolean mDone;
- public BlockingRunnable(Runnable task) {
- mTask = task;
- }
- @Override
- public void run() {
- try {
- mTask.run();//1
- } finally {
- synchronized (this) {
- mDone = true;
- notifyAll();
- }
- }
- }
- public boolean postAndWait(Handler handler, long timeout) {
- if (!handler.post(this)) {//2
- return false;
- }
- synchronized (this) {
- if (timeout > 0) {
- final long expirationTime = SystemClock.uptimeMillis() + timeout;
- while (!mDone) {
- long delay = expirationTime - SystemClock.uptimeMillis();
- if (delay <= 0) {
- return false; // timeout
- }
- try {
- wait(delay);
- } catch (InterruptedException ex) {
- }
- }
- } else {
- while (!mDone) {
- try {
- wait();//3
- } catch (InterruptedException ex) {
- }
- }
- }
- }
- return true;
- }
- }
注释 2 处将当前的 BlockingRunnable 添加到 Handler 的任务队列中前面 runWithScissors 方法的第二个参数为 0, 因此 timeout 等于 0, 这样如果 mDone 为 false 的话会一直调用注释 3 处的 wait 方法使得当前线程 (system_server 线程) 进入等待状态, 那么等待的是哪个线程呢? 我们往上看, 注释 1 处, 执行了传入的 Runnable 的 run 方法(运行在 android.display 线程), 执行完毕后在 finally 代码块中将 mDone 设置为 true, 并调用 notifyAll 方法唤醒处于等待状态的线程, 这样就不会继续调用注释 3 处的 wait 方法因此得出结论, system_server 线程线程等待的就是 android.display 线程, 一直到 android.display 线程执行完毕再执行 system_server 线程, 这是因为 android.display 线程内部执行了 WMS 的创建, 显然 WMS 的创建优先级更高些
WMS 的创建就讲到这, 最后我们来查看 WMS 的构造方法:
- frameworks/base/services/core/java/com/android/server/wm/WindowManagerService .java
- private WindowManagerService(Context context, InputManagerService inputManager,
- boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy) {
- ...
- mInputManager = inputManager;//1
- ...
- mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
- mDisplays = mDisplayManager.getDisplays();//2
- for (Display display : mDisplays) {
- createDisplayContentLocked(display);//3
- }
- ...
- mActivityManager = ActivityManager.getService();//4
- ...
- mAnimator = new WindowAnimator(this);//5
- mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
- com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
- LocalServices.addService(WindowManagerInternal.class, new LocalService());
- initPolicy();//6
- // Add ourself to the Watchdog monitors.
- Watchdog.getInstance().addMonitor(this);//7
- ...
- }
注释 1 处用来保存传进来的 IMS, 这样 WMS 就持有了 IMS 的引用注释 2 处通过 DisplayManager 的 getDisplays 方法得到 Display 数组(每个显示设备都有一个 Display 实例), 接着遍历 Display 数组, 在注释 3 处的 createDisplayContentLocked 方法会将 Display 封装成 DisplayContent,DisplayContent 用来描述一快屏幕
注释 4 处得到 AMS 实例, 并赋值给 mActivityManager , 这样 WMS 就持有了 AMS 的引用注释 5 处创建了 WindowAnimator, 它用于管理所有的窗口动画注释 6 处初始化了窗口管理策略的接口类 WindowManagerPolicy(WMP), 它用来定义一个窗口策略所要遵循的通用规范注释 7 处将自身也就是 WMS 通过 addMonitor 方法添加到 Watchdog 中, Watchdog 用来监控系统的一些关键服务的运行状况(比如传入的 WMS 的运行状况), 这些被监控的服务都会实现 Watchdog.Monitor 接口 Watchdog 每分钟都会对被监控的系统服务进行检查, 如果被监控的系统服务出现了死锁, 则会杀死 Watchdog 所在的进程, 也就是 SystemServer 进程
查看注释 6 处的 initPolicy 方法, 如下所示
- frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
- 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);//1
- }
- }, 0);
- }
initPolicy 方法和此前讲的 WMS 的 main 方法的实现类似, 注释 1 处执行了 WMP 的 init 方法, WMP 是一个接口, init 方法的具体实现在 PhoneWindowManager(PWM)中 PWM 的 init 方法运行在 android.ui 线程中, 它的优先级要高于 initPolicy 方法所在的 android.display 线程, 因此 android.display 线程要等 PWM 的 init 方法执行完毕后, 处于等待状态的 android.display 线程才会被唤醒从而继续执行下面的代码
在本文中共提到了 3 个线程, 分别是 system_serverandroid.display 和 android.ui, 为了便于理解, 下面给出这三个线程之间的关系
system_server 线程中会调用 WMS 的 main 方法, main 方法中会创建 WMS, 创建 WMS 的过程运行在 android.display 线程中, 它的优先级更高一些, 因此要等创建 WMS 完毕后才会唤醒处于等待状态的 system_server 线程
WMS 初始化时会执行 initPolicy 方法, initPolicy 方法会调用 PWM 的 init 方法, 这个 init 方法运行在 android.ui 线程, 并且优先级更高, 因此要先执行完 PWM 的 init 方法后, 才会唤醒处于等待状态的 android.display 线程
PWM 的 init 方法执行完毕后会接着执行运行在 system_server 线程的代码, 比如本文前部分提到 WMS 的
systemReady 方法
参考资料
深入理解 Android 内核设计思想第二版
深入理解 Android: 卷 III
WMS 启动过程
Android Watchdog 源码简析 Based on Android 6.0.1
Watchdog 实现分析
来源: http://liuwangshu.cn/framework/wms/1-wms-produce.html