美文网首页
Android8.0源码解析之理解WindowManagerSe

Android8.0源码解析之理解WindowManagerSe

作者: AFinalStone | 来源:发表于2022-10-20 19:59 被阅读0次

    一、WMS的职责

    WMS是Android中重要的服务,它是WindowManager的管理者,WMS无论对于应用开发还是Framework开发都是重要的知识点,究其原因是因为WMS有很多职责,每个职责都会涉及重要且复杂的系统,这使得WMS就像一个十字路口的交通灯一样,没有了这个交通灯,十字路口就无法正常通车,WMS的职责只要有以下几点。

    1、窗口管理
    WMS是窗口的管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由WMS进行管理的。窗口管理的核心成员由DisplayContent、WindowToken和WindowState。
    2、窗口动画
    窗口间进行切换时,使用窗口动画可以显得更炫一些,窗口动画由WMS的动画子系统来负责,动画子系统的管理者为WindowAnimator。
    3、输入系统的中转站
    通过对窗口的触摸从而产生触摸事件,InputManagerService(IMS)会对触摸事件进行处理,它会寻找一个最合适的窗口来处理触摸反馈信息,WMS是窗口的管理者,它作为输入系统的中转站再合适不过。
    4、Surface管理
    窗口并不具备绘制的功能,因此每个窗口都需要有一块Surface来供自己绘制,为每个窗口分配Surface时由WMS来完成的。

    WMS的职责

    从上图可以看出WMS很复杂,与它关联的由窗口管理、窗口动画、输入系统和Surface,它们每一个都是重要且负责的系统。

    二、WMS的创建过程

    1)WMS涉及的知识点非常多,但是无论这些知识点如何多,我们还是十分有必要先知道WMS时如何创建的。WMS时在SystemServer进程中创建的,SystemServer的run方法关键代码如下所示:

    frameworks/base/services/java/com/android/server/SystemServer.java

     private void run() {
            try {
                ...代码省略...
                Looper.prepareMainLooper();//1创建消息Looper
                System.loadLibrary("android_servers");//2加载动态库libandroid_servers.so
                performPendingShutdown();
                createSystemContext();//3初始化系统的Context
                mSystemServiceManager = new SystemServiceManager(mSystemContext);//4创建系统服务管理者
                mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
                LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
                SystemServerInitThreadPool.get();
            } finally {
                traceEnd();
            }
            // 开启服务
            try {
                traceBeginAndSlog("StartServices");
                startBootstrapServices();//5启动引导服务
                startCoreServices();//6启动核心服务
                startOtherServices();//7启动其他服务,WMS在该方法中被启动
                SystemServerInitThreadPool.shutdown();
            } catch (Throwable ex) {
                Slog.e("System", "******************************************");
                Slog.e("System", "************ Failure starting system services", ex);
                throw ex;
            } finally {
                traceEnd();
            }
          ...代码省略...
        }
    

    SystemServer的run方法中会调用startOtherServices方法,WMS就是在该方法中被启动的。

    2)SystemServer的startOtherServices方法如下所示:

      private void startOtherServices() {
               ...代码省略...
                traceBeginAndSlog("InitWatchdog");
                final Watchdog watchdog = Watchdog.getInstance();//1得到Watchdog实例,该对象可以用来监视系统的一些关键服务的运行状况。
                watchdog.init(context, mActivityManagerService);//2对Watchdog实例进行初始化
                traceEnd();
                traceBeginAndSlog("StartInputManagerService");
                inputManager = new InputManagerService(context);//3创建InputManagerService
                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执行WMS的main方法,其内部会创建WMS,
                ServiceManager.addService(Context.WINDOW_SERVICE, wm);//5将WMS注册到服务管理器中
                ServiceManager.addService(Context.INPUT_SERVICE, inputManager);//6将IMS注册到服务管理器中
                traceEnd();
               ...代码省略...        
            try {
                wm.displayReady();//7初始化屏幕显示信息
            } catch (Throwable e) {
                reportWtf("making display ready", e);
            }
               ...代码省略...       
            try {
                wm.systemReady();//8通知WMS,系统的初始化工作已经完成,其内部调用了WindowManagerPolicy的systemReady方法
            } catch (Throwable e) {
                reportWtf("making Window Manager Service ready", e);
            }
                 ...代码省略...       
        }
    

    startOtherServices会获取Watchdog实例并对实例进行初始化,创建InputManagerService实例,并在注释4处将该实例作为参数传递给WindowManagerService的main方法。

    3)WindowManagerService 的main方法如下:

       public static WindowManagerService main(final Context context, final InputManagerService im,
                final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
                WindowManagerPolicy policy) {
               //1这里使用了java8中的Lambda表达式
               DisplayThread.getHandler().runWithScissors(() ->
               sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs, onlyCore, policy)
                , 0);//2创建WMS实例对象
            return sInstance;
        }
    

    DisplayThread是一个单例的前台线程,这个线程用来处理需要低延时显示的相关操作,并只能由WindowManager、DisplayManager和InputManager实时执行快速操作。正是在DisplayThread的run方法中创建了WMS的实例,这就意味着WMS的创建时运行在android.display线程中的。
    4)来看下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) {
                r.run();
                return true;
            }
            BlockingRunnable br = new BlockingRunnable(r);
            return br.postAndWait(this, timeout);
        }
    
    • 对传入的Runnable的timeout进行判断,如果Runnable为null或者timeout小于0则抛出异常。
    • 根据每个线程只有一个Looper的原理来判断当前线程(system_server线程)是否是Handler所指向的线程(android.display线程),如果是则直接执行Runnable的run方法,否则调用BlockingRunnable的postAndWait方法,并将当前线程的Runnable作为参数传递进去。

    5)BlockingRunnable是Handler的内部类。

     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的任务队列中,上面第3步我们知道runWithScissors方法的第二个参数为0,因此timeout等于0,这样如果mDone为false的话会一直调用注释3处的wait方法使得当前线程(system_server线程)进入等待状态。
    • 在注释1处执行了传入的Runnable的run方法(运行在android.display线程中),执行完毕后finally代码块中将mDone设置为true,并调用noifyAll方法唤醒处于等待状态的线程,这样就不会继续调用注释3处的wait方法。

    结合以上两点我们可以得出一个结论,system_server线程会一直等待android.display线程执行完毕才开始执行system_server线程,这是因为android.display线程内部执行了WMS的创建,而WMS的创建优先级要更高。

    6)接下来我们来查看一下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
            ...代码省略...
            mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
            ...代码省略...
            mAnimator = new WindowAnimator(this); // 注释5
            mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
    com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
    
            LocalServices.addService(WindowManagerInternal.class, new LocalService());
            initPolicy(); // 注释6
            Watchdog.getInstance().addMonitor(this); // 注释7
            ...代码省略...
        }
    
    
    • 注释1处保存传递进来的IMS,这样WMS就持有了IMS的引用。
    • 注释2处通过DisplayManager的getDisplay方法得到Display数组(每个显示设备都有一个Display实例),接着遍历Display数组。
    • 注释3处的createDisplayContentLocked方法将Display封装成DisplayContent,DisplayContent用来描述一块屏幕。
    • 注释4处得到AMS实例,并赋值给mActivityManager,这样WMS就持有了AMS的引用。
    • 注释5处创建WindowAnimator,用于管理所有的窗口动画。
    • 注释6处初始化了窗口管理策略的接口类WindowManagerPolicy(WMP),它用来定义一个窗口策略所要遵循的通用规范。
    • 注释7处调用addMonitor方法将自身添加到watchdog中,Watchdog用来监控系统的一些关键服务的运行状况,这些被监控的服务都会实现Watchdog.Monitor接口。Watchdog每分钟都会对被监控的系统服务进行检查,如果被监控的系统服务出现了死锁,就会杀死Watchdog所在的进程,也就是SystemServer进程。

    6)继续来看注释6处的initPolicy方法。

        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线程才会被唤醒从而继续执行下面的代码。

    三、WMS的创建过程的3个线程

    上面WMS创建的过程中有提到3个线程,分别是system_server、android.display和android.ui,下图是关于这三个线程的三个步骤。


    三个线程之间的关系

    1)首先在system_server线程中执行了SystemServer的startOtherServices方法,在startOtherServices方法中会调用WMS的main方,main方法会创建WMS,创建的过程是在android.display线程中实现的,由于创建WMS的优先级更高,因此system_server线程要等WMS创建完成后,处于等待状态的system_server线程才会被唤醒从而继续执行下面的代码。

    2)在WMS的构造方法中会调用WMS的initPolicy方法,在initPolicy方法中又会调用PWM的init方法,PWM的init方法在android.ui线程中运行,它的优先级要高于android.display线程,因此"android.display"线程要等PWM的init方法执行完毕后,处于等待状态的android.display线程才会被唤醒从而继续执行下面的代码。

    3)PWM的init方法执行完毕后,android.display线程就完成了WMS的创建,等待的system_server线程被唤醒后继续执行WMS的main方法后的代码逻辑,比如在前面第二部分第2步的注释7的地方,WMS的displayReady方法用来初始化屏幕显示信息。

    相关文章

      网友评论

          本文标题:Android8.0源码解析之理解WindowManagerSe

          本文链接:https://www.haomeiwen.com/subject/kixyzrtx.html