一 概述
今天,我们介绍 WindowManagerService(后续简称 WMS)的启动流程,WMS 是 Android 系统中,负责窗口显示的的服务。在 Android 中它也起着承上启下的作用。
如下图,就是《深入理解 Android》书籍中的一张图。
图中展示了,WMS 在 Android 系统的地位,它作为中间层,连接了上层的 View 框架和下层的 SurfaceFingler。了解了 WMS 的工作机制,我们就彻底打通了上层 VIew 到底层 Surface,甚至到显示器如何显示的逻辑。
接下来,我们依旧从 WMS 的启动开始,来看 WMS 是如何启动的。
二 从 SystemServer 开始
2.1 startOtherServices
[frameworks/base/services/java/com/android/server/SystemServer.java]
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
WindowManagerService wm = null;
// 这里传入的 PhoneWindowManager 就是 WMS 中的 WindowManagerPolicy
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
// 将 WMS 设置到 AMS 中
mActivityManagerService.setWindowManager(wm);
wm.onInitReady();
...
try {
wm.displayReady();
} catch (Throwable e) {
reportWtf("making display ready", e);
}
...
try {
wm.systemReady();
} catch (Throwable e) {
reportWtf("making Window Manager Service ready", e);
}
...
// 更新上下文中,关于显示窗口相关的属性
final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY);
DisplayMetrics metrics = new DisplayMetrics();
context.getDisplay().getMetrics(metrics);
context.getResources().updateConfiguration(config, metrics);
}
和 AMS 不同的是,WMS 的启动是在 SystemServer 的 startOtherServices 中,启动过程依旧是我们之前提过的构造、注册,只是少了 onStart 这个步骤。
并且,在 WMS 启动之后,还会陆续调用一些其他的函数
- onInitReady
- displayReady
- systemReady
- updateConfiguration
接下来,我们会根据 WMS 启动过程中调用的函数,以此查看它们具体的实现原理。
从 AMS 和 WMS 的启动,我们可以看出来,它们都是隶属于 SystemServer 进程的,根据之前我们对应用和 AMS 的了解,也经常看到它们交互的流程中,有 WMS 的身影,所以虽然说是应用和 AMS,WMS 的通信,实际上就是应用和 SystemServer 进程的通信。
2.2 main
[frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java]
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
return main(context, im, showBootMsgs, onlyCore, policy, atm,
new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new,
SurfaceControl.Builder::new);
}
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, DisplayWindowSettingsProvider
displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,
surfaceControlFactory), 0);
return sInstance;
}
在 WMS 的 main 函数中主要做了两件事
- 创建了一个 WMS 对象
- 将这个 WMS 对象传递给了 DisplayThread
我们首先看这个 WMS 对象的构造函数
三 WindowManagerService
3.1 WMS 的构造函数
private WindowManagerService(Context context, InputManagerService inputManager,
boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, DisplayWindowSettingsProvider
displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
installLock(this, INDEX_WINDOW);
// ActivityTaskManagerService
mGlobalLock = atm.getGlobalLock();
mAtmService = atm;
mContext = context;
mIsPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
mAllowBootMessages = showBootMsgs;
...
// 输入法管理
mInputManager = inputManager; // Must be before createDisplayContentLocked.
// 显示管理
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
// Surface 图像相关
mSurfaceControlFactory = surfaceControlFactory;
mTransactionFactory = transactionFactory;
mSurfaceFactory = surfaceFactory;
mTransaction = mTransactionFactory.get();
mPolicy = policy;
// 窗口动画
mAnimator = new WindowAnimator(this);
// 根窗口容器
mRoot = new RootWindowContainer(this);
final ContentResolver resolver = context.getContentResolver();
mUseBLAST = Settings.Global.getInt(resolver,
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR, 1) == 1;
mSyncEngine = new BLASTSyncEngine(this);
mWindowPlacerLocked = new WindowSurfacePlacer(this);
mTaskSnapshotController = new TaskSnapshotController(this);
mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,
Choreographer.getInstance());
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mKeyguardDisableHandler = KeyguardDisableHandler.create(mContext, mPolicy, mH);
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
if (mPowerManagerInternal != null) {
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
public int getServiceType() {
return ServiceType.ANIMATION;
}
@Override
public void onLowPowerModeChanged(PowerSaveState result) {
synchronized (mGlobalLock) {
final boolean enabled = result.batterySaverEnabled;
if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {
mAnimationsDisabled = enabled;
dispatchNewAnimatorScaleLocked(null);
}
}
}
});
mAnimationsDisabled = mPowerManagerInternal
.getLowPowerState(ServiceType.ANIMATION).batterySaverEnabled;
}
mScreenFrozenLock = mPowerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
mScreenFrozenLock.setReferenceCounted(false);
mDisplayNotificationController = new DisplayWindowListenerController(this);
// AMS 相关
mActivityManager = ActivityManager.getService();
mActivityTaskManager = ActivityTaskManager.getService();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
...
}
WMS 的构造函数的代码非常长,其中有包含各种服务,我们这里只关注和我们应用 Activity 相关的,还有和显示相关的窗口容器 RootWindowContainer,还有和刷新相关的 Surface。
3.2 runWithScissors
另外,在 main 函数中,还调用了一个 runWithScissors,这个函数是 Handler 中定义的函数,这里我们简单看一下。
public final boolean runWithScissors(@NonNull 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");
}
if (Looper.myLooper() == mLooper) {
r.run();
return true;
}
BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}
runWithScissors 是 Handler 中的函数,用一句话概括就是,如果发送消息的线程与 Handler 处理的线程相同,就直接调用。如果不同,就阻塞调用。
3.3 onInitReady
public void onInitReady() {
initPolicy();
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
createWatermark();
showEmulatorDisplayOverlayIfNeeded();
}
3.4 initPolicy
private void initPolicy() {
UiThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
// mPolicy 其实就是 PhoneWindowManager【5.1】
mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
}
}, 0);
}
mPolicy 其实是 PhoneWindowManager,runWithScissors 前面介绍过了,如果是当前线程,就直接运行,如果不是当前线程,就阻塞运行。
所以这里是在 android.ui 线程中,运行 mPolicy 的初始化逻辑。
3.5 createWatermark
void createWatermark() {
if (mWatermark != null) {
return;
}
File file = new File("/system/etc/setup.conf");
FileInputStream in = null;
DataInputStream ind = null;
try {
in = new FileInputStream(file);
ind = new DataInputStream(in);
String line = ind.readLine();
if (line != null) {
String[] toks = line.split("%");
if (toks != null && toks.length > 0) {
// TODO(multi-display): Show watermarks on secondary displays.
final DisplayContent displayContent = getDefaultDisplayContentLocked();
mWatermark = new Watermark(displayContent, displayContent.mRealDisplayMetrics,
toks, mTransaction);
mTransaction.apply();
}
}
} ...
}
createWatermark 创建系统水印(只能显示文字)。
3.6 displayReady
[frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java]
public void displayReady() {
synchronized (mGlobalLock) {
if (mMaxUiWidth > 0) {
mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));
}
applyForcedPropertiesForDefaultDisplay();
mAnimator.ready();
mDisplayReady = true;
// createWatermark重新配置所有显示器大小
mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
// 是否触屏
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
mIsFakeTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_FAKETOUCH);
}
try {
// ATMS
mActivityTaskManager.updateConfiguration(null);
} catch (RemoteException e) {
}
}
displayReady 就是初始化显示器大小。
3.7 systemReady
[frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java]
public void systemReady() {
mSystemReady = true;
// 调用 PhoneWindowManager 的 systemReady
mPolicy.systemReady();
// 调用 DisplayPolicy 的 systemReady
mRoot.forAllDisplayPolicies(DisplayPolicy::systemReady);
// 调用 TaskSnapshotController 的 systemReady
mTaskSnapshotController.systemReady();
mHasWideColorGamutSupport = queryWideColorGamutSupport();
mHasHdrSupport = queryHdrSupport();
// 加载系统设置
UiThread.getHandler().post(mSettingsObserver::loadSettings);
// VR
IVrManager vrManager = IVrManager.Stub.asInterface(
ServiceManager.getService(Context.VR_SERVICE));
if (vrManager != null) {
try {
final boolean vrModeEnabled = vrManager.getVrModeState();
synchronized (mGlobalLock) {
vrManager.registerListener(mVrStateCallbacks);
if (vrModeEnabled) {
mVrModeEnabled = vrModeEnabled;
mVrStateCallbacks.onVrStateChanged(vrModeEnabled);
}
}
} catch (RemoteException e) {
// Ignore, we cannot do anything if we failed to register VR mode listener
}
}
}
3.8 computeNewConfiguration
public Configuration computeNewConfiguration(int displayId) {
synchronized (mGlobalLock) {
return computeNewConfigurationLocked(displayId);
}
}
3.9 computeNewConfigurationLocked
private Configuration computeNewConfigurationLocked(int displayId) {
if (!mDisplayReady) {
return null;
}
final Configuration config = new Configuration();
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
displayContent.computeScreenConfiguration(config);
return config;
}
displayId 表示的是显示设备的 id,这两段代码,就是通过 mRoot(RootWindowContainer)获取显示指定设备的 DisplayContent。说人话就是,通过显示器的 id,获取显示器对应的实例类 DisplayContent。
四 DisplayThread
[frameworks/base/services/core/java/com/android/server/DisplayThread.java]
public final class DisplayThread extends ServiceThread {
private static DisplayThread sInstance;
private static Handler sHandler;
private DisplayThread() {
// DisplayThread 运行重要的东西,但 AnimationThread 更重要。因此,优先级设置为 THREAD_PRIORITY_DISPLAY + 1
// THREAD_PRIORITY_DISPLAY 的值为 -4,
super("android.display", Process.THREAD_PRIORITY_DISPLAY + 1, false /*allowIo*/);
}
DisplayThread 就是 Android 中的 android.display 线程,它的优先级为 THREAD_PRIORITY_DISPLAY + 1,THREAD_PRIORITY_DISPLAY 值为 -4,所以 android.display 线程的优先级是 -3。
再回到 【2.2】中,WMS 的 main 函数是通过 android.display 线程完成的,并且在 android.display 线程中,对 android.ui 线程进行了初始化。
五 UIThread
public final class UiThread extends ServiceThread {
private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
private static UiThread sInstance;
private static Handler sHandler;
private UiThread() {
super("android.ui", Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
}
@Override
public void run() {
// Make sure UiThread is in the fg stune boost group
Process.setThreadGroup(Process.myTid(), Process.THREAD_GROUP_TOP_APP);
super.run();
}
UiThread 和 DisplayThread 一样,也是继承自 ServiceThread,它的线程名是 android.ui,优先级是 THREAD_PRIORITY_FOREGROUND,值为-2,所以 android.ui 线程的优先级是 -2。
六 PhoneWindowManager
PhoneWindowManager 是 WindowManagerPolicy 的实现类,它定义了手机窗口、处理输入事件以及与系统 UI 交互的策略和行为。
PhoneWindowManager 中的函数有很多,这里我们列举一个,其中的按键分发的函数 interceptKeyBeforeQueueing。
6.1 interceptKeyBeforeQueueing
[frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java]
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
final int keyCode = event.getKeyCode();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
|| event.isWakeKey();
if (!mSystemBooted) {
// 系统启动前,只监听电源按键
if (down && (keyCode == KeyEvent.KEYCODE_POWER
|| keyCode == KeyEvent.KEYCODE_TV_POWER)) {
wakeUpFromPowerKey(event.getDownTime());
} else if (down && (isWakeKey || keyCode == KeyEvent.KEYCODE_WAKEUP)
&& isWakeKeyWhenScreenOff(keyCode)) {
wakeUpFromWakeKey(event);
}
// 拦截掉电源键
return 0;
}
// interceptKeyBeforeQueueing 主要就是对手机按键的事件拦截,这里我们简单列举几个
// 返回键,音量键等等。
switch (keyCode) {
case KeyEvent.KEYCODE_BACK: {
if (down) {
mBackKeyHandled = false;
} else {
if (!hasLongPressOnBackBehavior()) {
mBackKeyHandled |= backKeyPress();
}
// Don't pass back press to app if we've already handled it via long press
if (mBackKeyHandled) {
result &= ~ACTION_PASS_TO_USER;
}
}
break;
}
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
返回值是一个整型,如果是 0 就表示被拦截,一开始的电源按键我们就看到了,在系统没有启动前,电源按键只能用于系统启动,但是系统启动后,电源按键就可以用于其他的作用了,例如语音助手。
PhoneWindowManager 这个类主要的作用有:
- 按键的分发
- 窗口的管理
这里我们就不扩展了,后面遇到实际的场景再来说明。
七 总结
WMS 的启动流程比较简单,主要就是启动了两个线程 "android.display"
和 "android.ui"
如果你还没有掌握Framework,现在想要在最短的时间里吃透它,可以参考一下《Android Framework核心知识点》,里面内容包含了:Init、Zygote、SystemServer、Binder、Handler、AMS、PMS、Launcher……等知识点记录。
《Framework 核心知识点汇总手册》:https://qr18.cn/AQpN4J
Handler 机制实现原理部分:
1.宏观理论分析与Message源码分析
2.MessageQueue的源码分析
3.Looper的源码分析
4.handler的源码分析
5.总结
Binder 原理:
1.学习Binder前必须要了解的知识点
2.ServiceManager中的Binder机制
3.系统服务的注册过程
4.ServiceManager的启动过程
5.系统服务的获取过程
6.Java Binder的初始化
7.Java Binder中系统服务的注册过程
Zygote :
- Android系统的启动过程及Zygote的启动过程
- 应用进程的启动过程
AMS源码分析 :
- Activity生命周期管理
- onActivityResult执行过程
- AMS中Activity栈管理详解
深入PMS源码:
1.PMS的启动过程和执行流程
2.APK的安装和卸载源码分析
3.PMS中intent-filter的匹配架构
WMS:
1.WMS的诞生
2.WMS的重要成员和Window的添加过程
3.Window的删除过程
《Android Framework学习手册》:https://qr18.cn/AQpN4J
- 开机Init 进程
- 开机启动 Zygote 进程
- 开机启动 SystemServer 进程
- Binder 驱动
- AMS 的启动过程
- PMS 的启动过程
- Launcher 的启动过程
- Android 四大组件
- Android 系统服务 - Input 事件的分发过程
- Android 底层渲染 - 屏幕刷新机制源码分析
- Android 源码分析实战