基于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. Java的参数传递是值传递还是引用传递

    当一个对象被当作参数传递到一个方法后,在此方法内可以改变这个对象的属性,那么这里到底是值传递还是引用传递?  答:是值传递.Java 语言的参数传递只有值传递.当一个对象实例作为一个参数被传递到方法中 ...

  2. Two Sum(两个数的相加)

    2017.11.10题目描述:Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9, retur ...

  3. 有关java里,nextLine()无法输入的问题

    在课后习题中用到了以下代码 public static void main(String[] args) { System.out.print("输入学生人数:"); int st ...

  4. Ubuntu下配置ShadowS + Chrome

    // 这是一篇导入进来的旧博客,可能有时效性问题. 题目和全文中的ShadowS指代以ShadowS开头名字的某工具,以预防文章被和谐.本机Ubuntu 14.04 LTS.在apt-get upda ...

  5. 51Nod 1182 完美字符串(字符串处理 贪心 Facebook Hacker Cup选拔)

    1182 完美字符串             题目来源:                         Facebook Hacker Cup选拔         基准时间限制:1 秒 空间限制:1 ...

  6. [bzoj1587] [Usaco2009 Mar]Cleaning Up 打扫卫生

    首先(看题解)可得...分成的任意一段中的不同颜色个数都<=根号n...不然的话直接分成n段会更优= = 然后就好做多了.. 先预处理出对于每头牛i,和它颜色相同的前一头和后一头牛的位置. 假设 ...

  7. [国嵌笔记][028][Bootloader设计蓝图]

    Bootloader的作用就是启动Linux内核 U-Boot简介 1.U-Boot是用于多种嵌入式CPU(ARM.x86.MIPS等)的bootloader程序,U-Boot不仅支持嵌入式Linux ...

  8. 豹哥嵌入式讲堂:ARM Cortex-M开发之文件详解(8)- 镜像文件(.bin/.hex/.s19)

    大家好,我是豹哥,猎豹的豹,犀利哥的哥.今天豹哥给大家讲的是嵌入式开发里的image文件(.bin, .hex, .s19). 今天这节课是豹哥<ARM Cortex-M开发之文件详解>主 ...

  9. Web API (四) 特性路由(Attribute Route)

    特性路由 是Web API 2 中提出的一种新的类型的路由,正如其名称那样,它是通过特性(Attribute) 来定义路由的,相比之前的基于模式(Convertion Based)的路由,特性路由 能 ...

  10. MyBatis的关于批量数据操作的测试

    摘录自:http://www.linuxidc.com/Linux/2012-05/60863.htm MyBatis的前身就是著名的Ibatis,不知何故脱离了Apache改名为MyBatis.My ...