本文基于Android 11.0源码分析
前言
Android系统中,WindowManagerService(以下简称WMS)负责一切窗口的管理,窗口可以理解为屏幕上的各种显示区域,如状态栏、Activity、锁屏等对于WMS来说,都是一个具体的窗口实例。从这篇文章开始,将会对WindowManagerService模块进行整理总结。WMS的职责可以简单总结为下图:
WMS04.PNG1.WMS架构
在WindowManagerService中,以容器+树结构的形式对窗口进行管理,最顶层容器为ConfigurationContainer,它是所有容器的父容器,各个容器继承关系如下:
WMS05.PNG上图中包含了WMS中的所有容器,各个子容器含义如下:
-
ConfigurationContainer:最顶层容器,定义了多个Configuration对象,以及提供了用来组织各容器层级的公共逻辑;
-
WindowProcessController:用于和AMS中的ProcessRecord进行通讯,当ProcessRecord中对应用进程作出调整后,通过WindowProcessController和WM进行通信;
-
WindowContainer:作为可以保存窗口类的父类,定义了用于操作窗口的所有公共方法;
-
RootWindowContainer:窗口容器在树结构中的根节点;
-
DisplayContent:作为RootWindowContainer的子节点,用于管理同一个逻辑屏的窗口;
-
DisplayChildWindowContainer:DisplayContent中的所有子节点的父类;
-
NonAppWindowContainers:继承于DisplayChildWindowContainer,主要保存非来自应用的WindowToken;
-
WindowContainers:只包含一个子节点——DisplayArea.Root,大部门窗口都会保存在这个容器中;
-
DisplayArea:用于对DisplayContent中的节点进行分组管理,主要分为了三类;
-
DisplayArea.Root:DisplayArea的子类,该容器作为DisplayContent中最顶层的显示区域,用来保存Tokens、TaskDisplayArea、ImeContainer容器;
-
TaskDisplayArea:DisplayArea的子类,此类容器用于管理Task;
-
TaskDisplayArea.Tokens:DisplayArea的子类,该容器用来保存正常窗口的WindowToken;
-
ImeContainer:Tokens的子类,该容器用来保存IME窗口的WindowToken;
-
Task:用来保存ActivityRecord,即我们常说的"任务";
-
ActivityStack:Task的子类,用来管理处于同一个栈的Activity,特殊栈可以保存Task;
-
WindowToken:用来管理窗口,多个窗口可以被一个WindowToken进行管理;
-
ActivityRecord:继承于WindowToken,表示ActivityStack中的一个Activity实例;
-
WallpaperWindowToken:继承于WindowToken,壁纸窗口比较特殊,因此由WallpaperWindowToken进行管理;
-
WindowState:窗口对象实例。
DisplayArea是Android R上新添加的容器,目的就是将复杂的窗口层级管理简单化、低耦合。
而在树结构中,各个容器结构如下:
WMS06.PNG可以看到,在树结构中,根节点为RootWindowContainer,叶子节点为WindowState。 正是通过这种结构,WMS中将系统中所有的窗口显示管理得井井有条,并将所有窗口以Surface的形式送到SurfacaFlinger中进行合成和显示。
2.WMS启动流程
接下来我们看下WMS的启动过程。WindowManagerService没有继承与SystemService,而是直接继承了IWindowManager.Stub接口,因此启动过程中,和SytemService的启动有区别。在system_server中,通过以下这些操作完成了WMS的启动:
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
// 2.1 创建WMS
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
// 2.2 进行初始化
wm.onInitReady();
// 2.3 设置InputCallback接口
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
// 2.4 进行Display配置更新
wm.displayReady();
// 2.5 系统启动完成
wm.systemReady();
// 2.6 计算Configuration
final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY);
DisplayMetrics metrics = new DisplayMetrics();
context.getDisplay().getMetrics(metrics);
context.getResources().updateConfiguration(config, metrics);
}
注:上面筛选出wm相关的操作,下面对这些操作分别进行分析。
2.1 WMS#main()创建WMS对象
在执行main()方法后,最终会在android.display线程去创建WMS的实例:
// 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,
SurfaceControl.Transaction::new, Surface::new, SurfaceControl.Builder::new);
}
/**
* Creates and returns an instance of the WindowManagerService. This call allows the caller
* to override factories that can be used to stub native calls during test.
*/
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
// DisplayThread就是android.display线程
// runWithScissors的执行会导致system_server线程等待android.display执行完再进行下一步操作。
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, transactionFactory, surfaceFactory, surfaceControlFactory), 0);
return sInstance;
}
------------------------
private WindowManagerService(Context context, InputManagerService inputManager,
boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
......
// Tranaction对象
mTransaction = mTransactionFactory.get();
// 创建WindowAnimator对象
mAnimator = new WindowAnimator(this);
// 创建RootWindowContainer对象
mRoot = new RootWindowContainer(this);
// 创建WindowSurfacePlacer对象
mWindowPlacerLocked = new WindowSurfacePlacer(this);
// 创建TaskSnapshotController对象
mTaskSnapshotController = new TaskSnapshotController(this);
// 创建DisplayWindowListenerController对象
mDisplayNotificationController = new DisplayWindowListenerController(this);
......
// 创建SurfaceAnimationRunner对象
mSurfaceAnimationRunner = new SurfaceAnimationRunner(mTransactionFactory,
mPowerManagerInternal);
// 创建TaskPositioningController
mTaskPositioningController = new TaskPositioningController(
this, mInputManager, mActivityTaskManager, mH.getLooper());
// 创建DragDropController对象
mDragDropController = new DragDropController(this, mH.getLooper());
// 创建EmbeddedWindowController
mEmbeddedWindowController = new EmbeddedWindowController(mAtmService);
// 创建 DisplayAreaPolicy.Provider对象
mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
mContext.getResources());
.....
}
构造方法中,创建了WMS所用到的多个对象。
2.2 WMS#onInitReady()对Policy进行初始化
接下来执行onInitReady()方法进行初始化:
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
public void onInitReady() {
initPolicy();//初始化policy
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
createWatermark();
showEmulatorDisplayOverlayIfNeeded();
}
-------------------------------------
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);
} // android.ui线程
}, 0);
}
在android.ui线程中调用WindowManagerPolicy#init()方法进行初始化,其中WindowManagerPolicy就是SystemServer.java中WindowManagerService.main()方法传进来的PhoneWindowManager。
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs) {
mContext = context;
mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
......
}
这个方法中做了大量的初始化操作。PhoneWindowManager继承于WindowManagerPolicy,是WMS中管理窗口过程中的一个策略类,窗口的显示、事件的派发等都受到PhoneWindowManager中的策略影响。mWindowManager和mWindowManagerFuncs都是WMS对象本身。
这里的initPolicy()方法最终执行在android.ui线程中,并且也是使用runWithScissors,所以中和前面的两个线程,有如下的线程执行关系:
WMS07.pnginitPolicy方法和此前讲的WMS的main方法的实现类似,它的具体实现在PhoneWindowManager(PWM)中。PWM的init方法运行在”android.ui”线程中,它的优先级要高于initPolicy方法所在的”android.display”线程,因此”android.display”线程要等PWM的init方法执行完毕后,处于等待状态的”android.display”线程才会被唤醒从而继续执行下面的代码:WMS.displayRead()。
2.3 IMS#setWindowManagerCallbacks()设置InputCallback回调
这个方法用来向IMS中设置InputManagerCallback回调:
// frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
mWindowManagerCallbacks = callbacks;
}
InputManagerCallback对象在WMS加载时完成创建:
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
// 创建InputManagerCallback对象
final InputManagerCallback mInputManagerCallback = new InputManagerCallback(this);
------------------------------
public InputManagerCallback getInputManagerCallback() {
return mInputManagerCallback;
}
InputManagerCallback接口用于接受IMS中的回调,如input事件派发过程中发生的ANR等,就是通过该接口向WMS中传递。
2.4 WMS#displayReady()更新DisplayContent配置
这个方法用来进行Display相关配置的第一次更新:
// 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();
// 告知WindowAnimator初始化完成
mAnimator.ready();
// 表示Display准备完成
mDisplayReady = true;
// Reconfigure all displays to make sure that forced properties and
// DisplayWindowSettings are applied.
// 更新Configuration
mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
}
try {
// 更新Configuration
mActivityTaskManager.updateConfiguration(null);
} catch (RemoteException e) {
}
}
这里通过DisplayContent#reconfigureDisplayLocked()更新DisplayContent相关配置。
2.5 WMS#systemReady()方法
这个方法的执行,表示system_server启动完成,WMS中会分别执行其他组件的systemReady()方法:
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
public void systemReady() {
// 系统
mSystemReady = true;
// PhoneWindowManager
mPolicy.systemReady();
// 执行DisplayPolicy#systemReady
mRoot.forAllDisplayPolicies(DisplayPolicy::systemReady);
mTaskSnapshotController.systemReady();
mHasWideColorGamutSupport = queryWideColorGamutSupport();
mHasHdrSupport = queryHdrSupport();
UiThread.getHandler().post(mSettingsObserver::loadSettings);
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
}
}
}
2.6 WMS#computeNewConfiguration()
这个方法是启动过程中执行的最后一个方法,用来更新全局配置状态:
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public Configuration computeNewConfiguration(int displayId) {
synchronized (mGlobalLock) {
return computeNewConfigurationLocked(displayId);
}
}
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;
}
在该方法中,会根据逻辑屏id,获得对应的DisplayContent对象来进行配置的更新,并在更新完成后,设置给对应Context的Resource对象。 关于DisplayContent中的更新配置更新流程,会在之后的文章中结合具体场景详细说明。
经过以上几个步骤,WMS启动完成。
网友评论