Android10_原理机制系列_Window介绍及WMS的启动过程
简介
Window简介
Android中,Window是一个重要部分,用户看到的界面、触摸显示界面进行一系列操作都涉及到Window。但实际上,Window本身并不具备绘制功能。
该篇简单介绍下Window的一点内容,同时总结下WMS的启动过程。在下篇会逐步介绍一个Activity是如何创建出窗口 并 添加到WMS中的。
该篇基于Andorid10的代码。
窗口涉及到一下几个功能:
-
窗口管理-WMS
WMS管理窗口的创建、添加、删除、大小、层级等等。 -
输入中转-IMS(InputManagerService)
触摸窗口产生触摸事件,IMS对触摸事件进行处理,最后寻找一个最合适窗口进行反馈处理。 -
窗口动画 —WindowAnimator
窗口间进行切换时,使用窗口动画可以实现更好的效果,窗口动画主要由WindowAnimator管理。可以在开发者模式菜单找到相应设置。 -
Surface管理 —SurfaceFlinger
窗口不具备有绘制的功能,因此每个窗口都需要有一块Surface来供自己绘制。为每个窗口分配Surface是由WMS来完成的。
Surface就像画布,然后通过Canvas或OpenGL绘制。
SurfaceFlinger的作用主要是merge Surface,它接受多个来源的Surface图形显示数据(所有Surface:所有Window的Surface,特殊情况 有些Surface跟Window无关,如StrictMode),然后将他们合并(根据特定顺序Z-order),然后发送到显示设备。如最常见的界面是3层,顶部的statusbar,底部的导航栏,应用界面。
WMS简介
WMS同之前总结过的AMS、PMS一样(链接:AMS的启动 、AMS之应用的第一次启动过程、PMS的启动及应用的安装过程),是系统服务,作为Binder的服务端。 下表简单对比列出下:
系统服务 | binder服务端 | binder客户端 | 服务名 |
---|---|---|---|
AMS | ActivityManagerService(extends IActivityManager.Stub) | ActivityManager | activity(Context.ACTIVITY_SERVICE) |
PMS | PackageManagerService(extends IPackageManager.Stub) | PackageManager | package |
WMS | WindowManagerService(extends IWindowManager.Stub) | WindowManager | window(Context.WINDOW_SERVICE) |
一般获取方法:
获取binder客户端,与服务通信,类似:
ActivityManager am = (ActivityManager) context.getSystemService(“activity”);
ActivityManager am = context.getSystemService(ActivityManager.class);
从ServiceManager获取服务的Binder,类似:
IBinder binder = ServiceManager.getService(Context.ACTIVITY_SERVICE);
下面两个也是用的ServiceManager.getService():
IActivityManager mgr = ActivityManager.getService();
PackageManagerService pm = (PackageManagerService) ServiceManager.getService(“package”);
WMS的启动过程
之前总结了 AMS的启动 、AMS之应用的第一次启动过程、PMS的启动及应用的安装过程。 这里WMS的启动类似,下面会简单介绍下。
WMS是在system server启动后的startOtherServices()中启动。下面截取了其中关于WMS相关的代码。
//SystemServer.java
private void startOtherServices() {
final Context context = mSystemContext;
WindowManagerService wm = null;
try {
// WMS 依赖 sensor service
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
//标记1:StartWindowManagerService
//创建WMS实例
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
//注册WINDOW_SERVICE 服务到 ServiceManager。
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
//标记2:SetWindowManagerService
//WMS设置到AMS/ATMS中。
mActivityManagerService.setWindowManager(wm);
//标记3:WindowManagerServiceOnInitReady
//WMS初始化完成。
wm.onInitReady();
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
inputManager.start();
mDisplayManagerService.windowManagerAndInputReady();
}
// Before things start rolling, be sure we have decided whether
// we are in safe mode.
final boolean safeMode = wm.detectSafeMode();
try {
//标记4:MakeDisplayReady
//初始化显示信息
wm.displayReady();
}
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
if (!isWatch) {
try {
statusBar = new StatusBarManagerService(context, wm);
ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
}
}
}
try {
//标记5:MakeWindowManagerServiceReady
//通知WMS系统准备好了,初始化完成了。
wm.systemReady();
}
final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY);
DisplayMetrics metrics = new DisplayMetrics();
WindowManager w = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
w.getDefaultDisplay().getMetrics(metrics);
context.getResources().updateConfiguration(config, metrics);
final WindowManagerService windowManagerF = wm;
mActivityManagerService.systemReady(() -> {
try {
startSystemUi(context, windowManagerF);
}
}, BOOT_TIMINGS_TRACE_LOG);
}
startOtherServices()中,创建了WindowManagerService对象 并 注册了服务Context.WINDOW_SERVICE。然后进行了各种初始化等操作。
注意上面的注释,下面主要看下其中的5行代码(标记1-标记5)。
标记1:wm = WindowManagerService.main(…)
//public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
//WindowManagerService.java
private static WindowManagerService sInstance;
static WindowManagerService getInstance() {
return sInstance;
}
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);
}
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
//android.display线程中执行
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, transactionFactory), 0);
return sInstance;
}
private WindowManagerService(Context context, InputManagerService inputManager,
boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
......
//ActivityTaskManagerService
mAtmService = atm;
//context是mSystemContext system server进程上下文
mContext = context;
mOnlyCore = onlyCore;
mInTouchMode = context.getResources().getBoolean(
com.android.internal.R.bool.config_defaultInTouchMode);
mMaxUiWidth = context.getResources().getInteger(
com.android.internal.R.integer.config_maxUiWidth);
mLowRamTaskSnapshotsAndRecents = context.getResources().getBoolean(
com.android.internal.R.bool.config_lowRamTaskSnapshotsAndRecents);
//输入法管理
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mDisplayWindowSettings = new DisplayWindowSettings(this);
mPolicy = policy;
//管理窗口动画
mAnimator = new WindowAnimator(this);
mRoot = new RootWindowContainer(this);
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mActivityManager = ActivityManager.getService();
mActivityTaskManager = ActivityTaskManager.getService();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
......
}
WindowManagerService.main()主要就是创建了WindowManagerService对象。
WindowManagerService的构造方法没有完整附上了,没什么特别的,基本是初始化并保存 WMS中需要用到的各种对象等数据。上面列出了几个常见的。DisplayThread.getHandler().runWithScissors()
,注意这里是DisplayThread(继承ServiceThread),是在android.display线程上执行。
题外话 :DisplayThread.getHandler().runWithScissors(() -> sInstance = new WindowManagerService(...),0);
是 lambda表达式 ,这里相当于:
DisplayThread.getHandler().runWithScissors(
new Runnable() {
@Override
public void run() {
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, transactionFactory)
}
}, 0);
标记2:mActivityManagerService.setWindowManager(wm)
这个很简单,wm被设置的到AMS和ATMS中。
//ActivityManagerService.java
public void setWindowManager(WindowManagerService wm) {
synchronized (this) {
mWindowManager = wm;
mActivityTaskManager.setWindowManager(wm);
}
}
标记3:wm.onInitReady()
//WindowManagerService.java
public void onInitReady() {
//初始化PhoneWindowManager (PhoneWindowManager implements WindowManagerPolicy)
initPolicy();
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
//SurfaceControl.openTransaction();
openSurfaceTransaction();
try {
//水印,这里了解了下
createWatermarkInTransaction();
} finally {
closeSurfaceTransaction("createWatermarkInTransaction");
}
showEmulatorDisplayOverlayIfNeeded();
}
private void initPolicy() {
//android.ui线程上执行
UiThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
}
}, 0);
}
void createWatermarkInTransaction() {
...
File file = new File("/system/etc/setup.conf");
...
try {
...
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);
}
}
}
...
}
onInitReady()这里几个地方记录下,个人觉得比较值得注意的:
-
initPolicy()中,mPolicy即PhoneWindowManager对象,从开始处startOtherServices()中可以看到。startOtherServices()创建了PhoneWindowManager,这里完成了PhoneWindowManager的init()操作。
-
initPolicy()中,是运行在UiThread,也是继承的ServiceThread。执行mPolicy.init()。
-
createWatermarkInTransaction():这个可以看一下。这是在window manager的窗口上添加水印。这个功能几乎没有用过,尝试了下,效果如下图。
往后跟踪,可以看到:显示的字符配置到/system/etc/setup.conf里的,Watermark有个解析过程(类似解密),详细的可以自己看下Watermark的构造方法。如下图中显示的字符串“WMS”,我在setup.conf配置的是“A8B2A<%30”,%后面是字体大小。“A8B2A<”即“WMS”。
标记4:wm.displayReady()
//WindowManagerService.java
public void displayReady() {
synchronized (mGlobalLock) {
if (mMaxUiWidth > 0) {
mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));
}
//全局设置仅适用于默认显示。设置Display size、Display density、Display scaling mode。
//getDefaultDisplayContentLocked()。
final boolean changed = applyForcedPropertiesForDefaultDisplay();
mAnimator.ready();
mDisplayReady = true;
if (changed) {
reconfigureDisplayLocked(getDefaultDisplayContentLocked());
}
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
}
try {
//初始化配置完成,ATMS完成第一次Configuration更新
mActivityTaskManager.updateConfiguration(null);
} catch (RemoteException e) {
}
updateCircularDisplayMaskIfNeeded();
}
看下注释。这里主要是初始化显示信息。初始化配置完成,ATMS完成第一次Configuration更新。
标记5:wm.systemReady()
//WindowManagerService.java
public void systemReady() {
mSystemReady = true;
mPolicy.systemReady();
...
}
系统初始化完成,通知WMS系统准备好了。这里主要完成:mPolicy.systemReady()
。
在标记3 时,有在android.ui线程执行的mPolicy.init()
,这里有mPolicy.systemReady()
。
mPolicy是PhoneWindowManager,关于这两个方法这里不关注,在后续类似事件传递时应该会再触及。