Android 9.0WMS启动浅析

2019-02-20  本文已影响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的诞生

上一篇下一篇

猜你喜欢

热点阅读