WMS—启动过程
基于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—启动过程的更多相关文章
- Android10_原理机制系列_Window介绍及WMS的启动过程
简介 Window简介 Android中,Window是一个重要部分,用户看到的界面.触摸显示界面进行一系列操作都涉及到Window.但实际上,Window本身并不具备绘制功能. 该篇简单介绍下Win ...
- Android 启动过程简析
首先我们先来看android构架图: android系统是构建在linux系统上面的. 所以android设备启动经历3个过程. Boot Loader,Linux Kernel & Andr ...
- Zygote和System进程的启动过程
##init脚本的启动 +------------+ +-------+ +-----------+ |Linux Kernel+--> |init.rc+-> |app_process| ...
- Zygote和System进程的启动过程、Android应用进程启动过程
1.基本过程 init脚本的启动Zygote Zygote进程的启动 System进程的启动 Android应用进程启动过程 2.init脚本的启动 +------------+ +-------+ ...
- google 分屏 横屏模式 按home键界面错乱故障分析(二) 分屏的启动过程
google 进入分屏后在横屏模式按home键界面错乱(二) 你确定你了解分屏的整个流程? imageMogr2/auto-orient/strip%7CimageView2/2/w/1240&quo ...
- zookeeper源码分析之一服务端启动过程
zookeeper简介 zookeeper是为分布式应用提供分布式协作服务的开源软件.它提供了一组简单的原子操作,分布式应用可以基于这些原子操作来实现更高层次的同步服务,配置维护,组管理和命名.zoo ...
- [原] KVM 虚拟化原理探究(2)— QEMU启动过程
KVM 虚拟化原理探究- QEMU启动过程 标签(空格分隔): KVM [TOC] 虚拟机启动过程 第一步,获取到kvm句柄 kvmfd = open("/dev/kvm", O_ ...
- Openfire的启动过程与session管理
说明 本文源码基于Openfire4.0.2. Openfire的启动 Openfire的启动过程非常的简单,通过一个入口初始化lib目录下的openfire.jar包,并启动一个 ...
- 探索 Linux 系统的启动过程
引言 之所以想到写这些东西,那是因为我确实想让大家也和我一样,把 Linux 桌面系统打造成真真正正日常使用的工具,而不是安装之后试用几把再删掉.我是真的在日常生活和工作中都使用 Linux,比如在 ...
随机推荐
- Django_'utf-8' codec can't decode 问题解决
最近用vs2017新建django模板项目时,页面输入中文时导致编码错误,如下图: 几经排查,原来是对应的html文件保存的编码错误,重新用utf-8保存即可
- Python => ValueError: unsupported format character 'Y' (0x59)
产生问题的原因是:SQL语句的'%Y-%m-%d'部分被再次解释为字符串格式,并抛出错误 解决方案一:字符串%形式进行替换 '%string' % string. '%Y-%m-%d'改写为'%%%% ...
- deeplearning.ai 卷积神经网络 Week 2 深度卷积网络:实例研究 听课笔记
1. Case study:学习经典网络的原因是它们可以被迁移到其他任务中. 1.1)几种经典的网络: a)LeNet-5(LeCun et al., 1998. Gradient-based lea ...
- AtCoder Regular Contest 069 D
D - Menagerie Time limit : 2sec / Memory limit : 256MB Score : 500 points Problem Statement Snuke, w ...
- 2329: [HNOI2011]括号修复
传送魔法 一开始以为可以直接线段树的,好像还是不行……还是得用Spaly,然后就没啥了. #include<cstdio> #include<algorithm> #defin ...
- 常见 Java 异常解释(恶搞版)
常见 Java 异常解释:(译者注:非技术角度分析.阅读有风险,理解需谨慎o(╯□╰)o) java.lang ArithmeticException 你正在试图使用电脑解决一个自己解决不了的数学问题 ...
- 51Nod 1289 大鱼吃小鱼(模拟,经典好题)
1289 大鱼吃小鱼 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: ...
- python写一个邮箱伪造脚本
前言: 原本打算学php MVC的思路然后写一个项目.但是贼恶心, 写不出来.然后就还是用python写了个邮箱伪造. 0x01 第一步先去搜狐注册一个邮箱 然后,点开设置,开启SMTP服务. 当然你 ...
- Linux 权限、磁盘操作命令-Linux基础环境命令学习笔记
1.创建用户和用户组 1)用户和用户组 /etc/passwd 保存系统用户的基本信息 /etc/group 保存用户组信息 用户名:x:UID:GID 2)基本命令 useradd 增加用户 gro ...
- python基础1 day2
一.上节课回顾1. 编译型: 将源码一次性全部编译成二进制. C 优点:执行效率高. 缺点:开发效率慢,不可跨平台使用. 解释型: 当程序执行时,代码一行一行的去解释成二进制. python 优点:开 ...