基于Android 6.0源码, 分析WMS的启动过程。

一. 概述

  • Surface:代表画布
  • WMS: 添加window的过程主要功能是添加Surface,管理所有的Surface布局,以及Z轴排序问题;
  • SurfaceFinger: 将Surface按次序混合并显示到物理屏幕上;

1.1 WMS全貌

  • WMS继承于IWindowManager.Stub, 作为Binder服务端;
  • WMS的成员变量mSessions保存着所有的Session对象,Session继承于IWindowSession.Stub, 作为Binder服务端;
  • 成员变量mPolicy: 实例对象为PhoneWindowManager,用于实现各种窗口相关的策略;
  • 成员变量mChoreographer: 用于控制窗口动画,屏幕旋转等操作;
  • 成员变量mDisplayContents: 记录一组DisplayContent对象,这个跟多屏输出相关;
  • 成员变量mTokenMap: 保存所有的WindowToken对象; 以IBinder为key,可以是IAppWindowToken或者其他Binder的Bp端;
    • 另一端情况:ActivityRecord.Token extends IApplicationToken.Stub
  • 成员变量mWindowMap: 保存所有的WindowState对象;以IBinder为key, 是IWindow的Bp端;
    • 另一端情况: ViewRootImpl.W extends IWindow.Stub
  • 一般地,每一个窗口都对应一个WindowState对象, 该对象的成员变量mClient用于跟应用端交互,成员变量mToken用于跟AMS交互.

二. 启动过程

private void startOtherServices() {
...
// [见小节2.1]
WindowManagerService wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore); wm.displayReady(); // [见小节2.5]
...
wm.systemReady(); // [见小节2.6]
}

2.1 WMS.main

[-> WindowManagerService.java]

public static WindowManagerService main(final Context context, final InputManagerService im, final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore) {

    final WindowManagerService[] holder = new WindowManagerService[];

    DisplayThread.getHandler().runWithScissors(new Runnable() {

        public void run() {
//运行在"android.display"线程[见小节2.2]
holder[] = new WindowManagerService(context, im,
haveInputMethods, showBootMsgs, onlyCore);
}
}, );
return holder[];
}

2.2 WindowManagerService

 private WindowManagerService(Context context, InputManagerService inputManager, boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
mContext = context;
mHaveInputMethods = haveInputMethods;
mAllowBootMessages = showBootMsgs;
mOnlyCore = onlyCore;
...
mInputManager = inputManager;
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mDisplaySettings = new DisplaySettings();
mDisplaySettings.readSettingsLocked(); LocalServices.addService(WindowManagerPolicy.class, mPolicy);
mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG)); mFxSession = new SurfaceSession();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mDisplays = mDisplayManager.getDisplays(); for (Display display : mDisplays) {
//创建DisplayContent[见小节2.2.1]
createDisplayContentLocked(display);
} mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
... mAppTransition = new AppTransition(context, mH);
mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
mActivityManager = ActivityManagerNative.getDefault();
...
mAnimator = new WindowAnimator(this); LocalServices.addService(WindowManagerInternal.class, new LocalService());
//初始化策略[见小节2.3]
initPolicy(); Watchdog.getInstance().addMonitor(this); SurfaceControl.openTransaction();
try {
createWatermarkInTransaction();
mFocusedStackFrame = new FocusedStackFrame(
getDefaultDisplayContentLocked().getDisplay(), mFxSession);
} finally {
SurfaceControl.closeTransaction();
} updateCircularDisplayMaskIfNeeded();
showEmulatorDisplayOverlayIfNeeded();
}

在“android.display”线程中执行WindowManagerService对象的初始化过程,其中final H mH = new H();此处H继承于Handler,无参初始化的过程,便会采用当前所在线程 的Looper。那就是说WindowManagerService.H.handleMessage()方法运行在“android.display”线程。

2.2.1 WMS.createDisplayContentLocked

public DisplayContent getDisplayContentLocked(final int displayId) {
DisplayContent displayContent = mDisplayContents.get(displayId);
if (displayContent == null) {
final Display display = mDisplayManager.getDisplay(displayId);
if (display != null) {
displayContent = newDisplayContentLocked(display);
}
}
return displayContent;
}

创建DisplayContent,用于支持多屏幕的功能.比如目前除了本身真实的屏幕之外,还有Wifi display虚拟屏幕.

2.3 WMS.initPolicy

rivate void initPolicy() {
//运行在"android.ui"线程
UiThread.getHandler().runWithScissors(new Runnable() {
public void run() {
WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
//此处mPolicy为PhoneWindowManager.[见小节2.4]
mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
}
}, );
}

2.3.1 Handler.runWithScissors

[-> Handler.java]

public final boolean runWithScissors(final Runnable r, long timeout) {
//当前线程跟当前Handler都指向同一个Looper,则直接运行
if (Looper.myLooper() == mLooper) {
r.run();
return true;
} BlockingRunnable br = new BlockingRunnable(r);
//[见小节2.3.2]
return br.postAndWait(this, timeout);
}

2.3.2 postAndWait

[-> Handler.java ::BlockingRunnable]

 private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone; public BlockingRunnable(Runnable task) {
mTask = task;
} public void run() {
try {
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
} public boolean postAndWait(Handler handler, long timeout) {
if (!handler.post(this)) {
return false;
} synchronized (this) {
if (timeout > ) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= ) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}

由此可见, BlockingRunnable.postAndWait()方法是阻塞操作,就是先将消息放入Handler所指向的线程, 此处是指”android.ui”线程, 由于该方法本身运行在”android.display”线程. 也就意味着”android.display”线程会进入等待状态, 直到handler线程执行完成后再唤醒”android.display”线程. 那么PWM.init()便是运行在”android.ui”线程,属于同步阻塞操作.

2.4 PWM.init

[-> PhoneWindowManager.java]

 public void init(Context context, IWindowManager windowManager, WindowManagerFuncs windowManagerFuncs) {
mContext = context;
mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
... mHandler = new PolicyHandler(); //运行在"android.ui"线程
mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
mOrientationListener = new MyOrientationListener(mContext, mHandler);
... mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"PhoneWindowManager.mBroadcastWakeLock");
mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"PhoneWindowManager.mPowerKeyWakeLock");
... mGlobalKeyManager = new GlobalKeyManager(mContext);
... if (!mPowerManager.isInteractive()) {
startedGoingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
finishedGoingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
} mWindowManagerInternal.registerAppTransitionListener(
mStatusBarController.getAppTransitionListener());
}

前面小节[2.1 ~ 2.4]介绍了WMS.main()方法, 接下来便是开始执行WMS.displayReady().

2.5 WMS.displayReady

 public void displayReady() {
for (Display display : mDisplays) {
displayReady(display.getDisplayId());
} synchronized(mWindowMap) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
readForcedDisplayPropertiesLocked(displayContent);
mDisplayReady = true;
} mActivityManager.updateConfiguration(null); synchronized(mWindowMap) {
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
configureDisplayPolicyLocked(getDefaultDisplayContentLocked());
} mActivityManager.updateConfiguration(null);
}

2.6 WMS.systemReady

public void systemReady() {
mPolicy.systemReady();
}

2.6.1 PWM.systemReady

[-> PhoneWindowManager.java]

 public void systemReady() {
mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
mKeyguardDelegate.onSystemReady(); readCameraLensCoverState();
updateUiMode();
boolean bindKeyguardNow;
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true; mHandler.post(new Runnable() {
public void run() {
updateSettings();
}
}); bindKeyguardNow = mDeferBindKeyguard;
if (bindKeyguardNow) {
mDeferBindKeyguard = false;
}
} if (bindKeyguardNow) {
mKeyguardDelegate.bindService(mContext);
mKeyguardDelegate.onBootCompleted();
}
mSystemGestures.systemReady();
}

三. 总结

整个启动过程涉及3个线程: system_server主线程, “android.display”, “android.ui”, 整个过程是采用阻塞方式(利用Handler.runWithScissors)执行的. 其中WindowManagerService.mH的Looper运行在 “android.display”进程,也就意味着WMS.H.handleMessage()在该线程执行。 流程如下:

WMS—启动过程的更多相关文章

  1. Android10_原理机制系列_Window介绍及WMS的启动过程

    简介 Window简介 Android中,Window是一个重要部分,用户看到的界面.触摸显示界面进行一系列操作都涉及到Window.但实际上,Window本身并不具备绘制功能. 该篇简单介绍下Win ...

  2. Android 启动过程简析

    首先我们先来看android构架图: android系统是构建在linux系统上面的. 所以android设备启动经历3个过程. Boot Loader,Linux Kernel & Andr ...

  3. Zygote和System进程的启动过程

    ##init脚本的启动 +------------+ +-------+ +-----------+ |Linux Kernel+--> |init.rc+-> |app_process| ...

  4. Zygote和System进程的启动过程、Android应用进程启动过程

    1.基本过程 init脚本的启动Zygote Zygote进程的启动 System进程的启动 Android应用进程启动过程 2.init脚本的启动 +------------+ +-------+ ...

  5. google 分屏 横屏模式 按home键界面错乱故障分析(二) 分屏的启动过程

    google 进入分屏后在横屏模式按home键界面错乱(二) 你确定你了解分屏的整个流程? imageMogr2/auto-orient/strip%7CimageView2/2/w/1240&quo ...

  6. zookeeper源码分析之一服务端启动过程

    zookeeper简介 zookeeper是为分布式应用提供分布式协作服务的开源软件.它提供了一组简单的原子操作,分布式应用可以基于这些原子操作来实现更高层次的同步服务,配置维护,组管理和命名.zoo ...

  7. [原] KVM 虚拟化原理探究(2)— QEMU启动过程

    KVM 虚拟化原理探究- QEMU启动过程 标签(空格分隔): KVM [TOC] 虚拟机启动过程 第一步,获取到kvm句柄 kvmfd = open("/dev/kvm", O_ ...

  8. Openfire的启动过程与session管理

    说明   本文源码基于Openfire4.0.2.   Openfire的启动       Openfire的启动过程非常的简单,通过一个入口初始化lib目录下的openfire.jar包,并启动一个 ...

  9. 探索 Linux 系统的启动过程

    引言 之所以想到写这些东西,那是因为我确实想让大家也和我一样,把 Linux 桌面系统打造成真真正正日常使用的工具,而不是安装之后试用几把再删掉.我是真的在日常生活和工作中都使用 Linux,比如在 ...

随机推荐

  1. K:平衡二叉树(AVL)

    相关介绍:  二叉查找树的查找效率与二叉树的形状有关,对于按给定序列建立的二叉排序树,若其左.右子树均匀分布,则查找过程类似于有序表的二分查找,时间复杂度变为O(log2n).当若给定序列原来有序,则 ...

  2. visual core 运行 .net core bug处理

    launch: program 'launch: launch.json must be configured. Change 'program' to the path to the executa ...

  3. 一种数据与逻辑分离的Python单元测试工具

    一种数据与逻辑分离的Python单元测试工具 几个概念 TestCase TestCase是一个完整的测试单元,最小的测试执行实体,就是我们常说的测试用例. TestSuite 以某种特性将测试用例组 ...

  4. 基本命令行操作1(java编译)

    1. 设置环境变量,具体:https://www.cnblogs.com/shinge/p/5500002.html "cd + 文件名" 可进入指定文件,"cd..&q ...

  5. Hadoop(十)Hadoop IO之数据完整性

    前言 上一篇我分享了Hadoop的压缩和编解码器,在我们开发的过程中其实是经常会用到的,所以一定要去掌握.这一篇给大家介绍的是Hadoop的数据完整性! Hadoop用户在使用HDFS储存和处理数据不 ...

  6. lambdas了解

    Lambdas了解 功能接口的一个极其宝贵的特性是可以使用lambdas实例化它们.以下是一些关于lambdas的例子: 以逗号分隔的输入列表,左边是指定类型的输入,右边是返回的块:          ...

  7. 【Java学习笔记之十七】Java中普通代码块,构造代码块,静态代码块区别及代码示例分析

    //执行顺序:(优先级从高到低.)静态代码块>mian方法>构造代码块>构造方法. 其中静态代码块只执行一次.构造代码块在每次创建对象是都会执行. 1 普通代码块 //普通代码块:在 ...

  8. Codeforces Round #336 (Div. 2)【A.思维,暴力,B.字符串,暴搜,前缀和,C.暴力,D,区间dp,E,字符串,数学】

    A. Saitama Destroys Hotel time limit per test:1 second memory limit per test:256 megabytes input:sta ...

  9. [51nod1329]路径游戏

    Snuke与Sothe两个人在玩一个游戏.游戏在一个2*N的网格中进行(2行N列),这个网格中的2N个格子不是黑色就是白色.定义,一条有效路径是指一个完全由白色格子构成的序列,这个序列的第一个网格元素 ...

  10. [bzoj3702] 二叉树

    一个节点的儿子是否交换,不会影响到它和兄弟节点间的逆序对数. 所以每次合并线段树的时候算一下交换与不交换的逆序对数,然后选个较小值就行了. #include<cstdio> #includ ...