美文网首页
Android 9.0WMS启动浅析

Android 9.0WMS启动浅析

作者: 呆萌的中二青年 | 来源:发表于2019-02-20 18:17 被阅读0次

    在讲解AMS 的时候我们提到SystemServer在执行systemServer.run()方法的时候会启动三类服务,而我们的wms是在startOtherServices()中启动的,看代码:

    SystemServer::startOtherServices()
    
    private void startOtherServices() {
      ......
      1.wm = WindowManagerService.main(context, inputManager,
         mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
         !mFirstBoot, mOnlyCore, new PhoneWindowManager());
        ServiceManager.addService(Context.WINDOW_SERVICE, wm, /*                            allowIsolated= */ false,
      ......
      2.wm.onInitReady();
      ......
      try {
        3.wm.displayReady();
      } catch (Throwable e) {
        reportWtf("making display ready", e);
      }
      ......
      try {
        4.wm.systemReady();
      } catch (Throwable e) {
        reportWtf("making Window Manager Service ready", e);
      }
      ......
    }
    

    这里我将9.0的WMS启动流程分为4步,先看看第一步。

    WMS::main()
    public static WindowManagerService main(final Context context, final InputManagerService im,
                final boolean haveInputMethods, final boolean showBootMsgs, final boolean               onlyCore,WindowManagerPolicy policy) {
        DisplayThread.getHandler().runWithScissors(() ->
            sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,onlyCore, policy), 0);
        return sInstance;
    }
    

    我们可以看到上面用于jdk8中的Lambda表达式,等驾驭执行了一个run方法,这里可以看出我们WMS.main()方法很简单,在runnable的run()中获取WMS的实例,而我们的runnable对象则传入了DisplayThread.getHandler().runWithScissors()中,同时我们也可以看出在调用WMS.main过程中我们从”system_server”线程进入了线程”android.display”中,需要注意的是我们在执行runWithScissors传入了一个”0”的参数,下面我们看看handle中的runWithScissors所做的功能。

    Handle::runWithScissors()
    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");
            }
            //1
            if (Looper.myLooper() == mLooper) {
                r.run();
                return true;
            }
            //2
            BlockingRunnable br = new BlockingRunnable(r);
            return br.postAndWait(this, timeout);
    }
    

    可以看出,当runnable为null或者timtout<0时,均会抛出异常,注释1中采用了每个线程只有一个looper的原理来判断当前线程(system_server)是否是Handle所指向的线(android.display),如果是则直接执行Runnable的run(),如果不是,则执行注释2中 BlockingRunnable的postAndWait,并把runnable当做参数传入,BlockingRunnable是handle的内部类,代码如下:

    Handle->BlockingRunnable
    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();
                            } 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的构造方法:

    WMS::WindowManagerService()
    private WindowManagerService(Context context, InputManagerService inputManager,
                boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
                WindowManagerPolicy policy) {
        ....
        //1.
        mInputManager = inputManager; // Must be before createDisplayContentLocked.
        .....
        //2.
        mAnimator = new WindowAnimator(this);
        .....
        //3.
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
        //这段代码在9.0后没有了,为了区分,贴出
        /*mDisplays = mDisplayManager.getDisplays();
        for (Display display : mDisplays) {
                createDisplayContentLocked(display);
        }*/
        ....
        //4.
        mActivityManager = ActivityManager.getService();
        ....
    }
    

    注释1:获取IMS的引用。看看系统对他的注释,说这个要在createDisplayContentLocked前调用.
    注释2:创建WindowAnimator,用于管理所有的窗口动画。
    注释3:在9.0之前的版本,获取DisplayManager对象后通过getDisplays方法得到Displays数组,然后遍历这个数组,并执行createDisplayContentLocked方法,这个方法会将数组中的Display封装成displayContent。displayContent是android4.2支持多屏幕输出所引入的一个概念,目前这个已经在9.0被移除,为什么?不太清楚。后续补充。
    注释4:获取AMS实例。

    一直到这里我们WMS的构造方法所做的事情差不多结束了,我们上文中提到等到”android.display”线程结束后会执行”system_server”线程。那么第二步,接下来看看wms的onInitReady(),因此我们这个函数也就运行在”system_server”线程中。

    WMS::onInitReady()
    
    public void onInitReady() {
    
            //5.
            initPolicy();
    
            // Add ourself to the Watchdog monitors.
    
            //6.
            Watchdog.getInstance().addMonitor(this);
    
            openSurfaceTransaction();
    
            try {
    
                createWatermarkInTransaction();
    
            } finally {
    
                closeSurfaceTransaction("createWatermarkInTransaction");
    
            }
    
            showEmulatorDisplayOverlayIfNeeded();
    
    }
    

    onInitReady这个方法在9.0之前是不存在的,而我们这个方法所做的功能,在9.0之前我们是放在WMS的构造方法里面,也就是说在9.0之前我们这个方法所做的事情是在”android.display”线程中。

    注释5:初始化WindowManagerPolicy(WMP),他是窗口管理策略的接口类,继承自WindowManagerPolicyConstants,调用这个方法,我们会调用WindowManagerPolicy的init方法,这个方法会运行在新的”android.ui”线程中,而WindowManagerPolicy的实现类是我们熟悉的PhoneWindowManager。

     WMS::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);
                }
            }, 0);
        }
    

    initPolicy方法和此前讲的WMS的main方法的实现类似,这个方法执行了WMP的init方法,WMP是一个接口,init方法的具体实现在PhoneWindowManager(PWM)中。PWM的init方法运行在"android.ui"线程中,它的优先级要高于initPolicy方法所在的"system_server"线程,因此"system_server"线程要等PWM的init方法执行完毕后,处于等待状态的"system_server"线程才会被唤醒从而继续执行下面的代码。

    注释6:将WMS自己加入Watchdog中。WatchDog用来监控系统一些关键服务的运行状况。

    第三步,调用wms的displayReady(),这个方法主要是初始化尺寸信息,在这个方法执行后,WMS会要求AMS进行Configuration的更新。

    WMS::displayReady()
    
    public void displayReady() {
            final int displayCount = mRoot.mChildren.size();
            for (int i = 0; i < displayCount; ++i) {
                final DisplayContent display = mRoot.mChildren.get(i);
                displayReady(display.getDisplayId());
            }
    
    
            synchronized(mWindowMap) {
                final DisplayContent displayContent = getDefaultDisplayContentLocked();
                if (mMaxUiWidth > 0) {
                    displayContent.setMaxUiWidth(mMaxUiWidth);
                }
                readForcedDisplayPropertiesLocked(displayContent);
                mDisplayReady = true;
            }
    
            try {
                mActivityManager.updateConfiguration(null);
            } catch (RemoteException e) {
            }
    
            synchronized(mWindowMap) {
                mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
                        PackageManager.FEATURE_TOUCHSCREEN);
                getDefaultDisplayContentLocked().configureDisplayPolicy();
            }
    
            try {
                mActivityManager.updateConfiguration(null);
            } catch (RemoteException e) {
            }
    
            updateCircularDisplayMaskIfNeeded();
    }
    

    第四步,调用systemReady(),这里面WMS本身没做太多操作,调用了WMP.systemReady(),O版系统新增了任务快照TaskSnapshot,并在这里调用了TaskSnapshotController.systemReady,这是一个新的调用,O版之前没有的。queryWideColorGamutSupport则是与surfaceFlinger有关的函数,也是O版以后加入的,这里不做分析。

    WMS::systemReady()
    public void systemReady() {
            mPolicy.systemReady();
            mTaskSnapshotController.systemReady();
            mHasWideColorGamutSupport = queryWideColorGamutSupport();
    }
    

    9.0 WMS启动流程图如下:

    图片1.png

    参考资料:
    《深入理解Android:卷III》
    https://www.jianshu.com/p/143bdc5363ca刘望舒大神的Android解析WindowManagerService(一)WMS的诞生

    相关文章

      网友评论

          本文标题:Android 9.0WMS启动浅析

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