Android 9.0WMS启动浅析
在讲解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的诞生