一、简介
WMS
全称WindowManagerService
,它作为一个系统服务负责管理着window
,对于应用层开发来讲,平时更多的接触是Activity
、Dialog
等组件,其实它们都对应着相关的window
对象,可以说Activity
和Dialog
最终能显示到屏幕上都是由于window
的存在。关于window
的定义文章就不具体描述了,想要从头到尾分析的比较彻底还是比较复杂的,文章将从WMS的启动
和WMS的应用
这两方面来分析WMS
在Android体系中所发挥的作用。
二、WMS的启动
WMS
与AMS
一样也是在SystemServer
进程中启动的,核心流程的代码都在SystemServer
的startOtherServices
方法中。
SystemServer#startOtherServices
private void startOtherServices() {
WindowManagerService wm = null;
//创建WMS对象
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
//将WMS注册到ServiceManager中,key为“window”
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
//WMS传给AMS
mActivityManagerService.setWindowManager(wm);
//WMS初始化完成
wm.onInitReady();
//WMS的Monitor传给InputManagerService
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
wm.displayReady();
从以上代码可以发现,在SystemServer
中首先调用WindowManagerService.main()
方法创建WindowManagerService
对象,然后将WindowManagerService
注册到ServiceManager
中,随后为 ActivityManagerService
设置WindowManagerService
引用,调用onInitReady
初始化完成方法,再将WindowManagerService
的InputMonitor
设置给InputManagerService
,最后调用displayReady
方法完成WindowManagerService
的核心流程。
WindowManagerService#main
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
WindowManagerPolicy policy) {
DisplayThread.getHandler().runWithScissors(() ->
//在DisplayThread中创建WindowManagerService对象
sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
onlyCore, policy), 0);
return sInstance;
}
WindowManagerService构造方法
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
installLock(this, INDEX_WINDOW);
...省略一些resource获取
//设置InputManagerService
mInputManager = inputManager;
//获取DisplayManager
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
//初始化Display相关设置
mDisplaySettings = new DisplaySettings();
mDisplaySettings.readSettingsLocked();
//WindowManagerPolicy
mPolicy = policy;
//管理Window对象的动画
mAnimator = new WindowAnimator(this);
....
//WindowManagerPolicy注册到LocalServices
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
if(mInputManager != null) {
//获取InputManagerService的InputChannel用于分发点击事件
final InputChannel inputChannel = mInputManager.monitorInput(TAG_WM);
mPointerEventDispatcher = inputChannel != null
? new PointerEventDispatcher(inputChannel) : null;
} else {
mPointerEventDispatcher = null;
}
//获取DisplayManager
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
//获取PowerManager
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
....
//获取ActivityManagerService
mActivityManager = ActivityManager.getService();
...
}
WindowManagerService
的构造方法中主要涉及Display
相关的设置、Window
动画对象的设置、InputChannel
的获取和一些其他服务的获取和注册。
三、WMS的应用
分析WindowManagerService
对window
的管理就需要来到多次提到的ViewRootImpl
这个类中了。
ViewRootImpl构造方法
public ViewRootImpl(Context context, Display display) {
....
//获取IWindowSession
mWindowSession = WindowManagerGlobal.getWindowSession();
....
//创建W对象
mWindow = new W(this);
....
}
ViewRootImpl
的构造方法和window
相关的主要流程是获取IWindowSession
和创建W
对象,这两个对象都是用于ViewRootImpl
和WMS
通信使用的。
WindowManagerGlobal#getWindowSession
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
//获取InputMethodManager
InputMethodManager imm = InputMethodManager.getInstance();
//获取WindowManagerService
IWindowManager windowManager = getWindowManagerService();
//调用openSession方法获取WindowSession
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
WindowManagerService#openSession
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
IInputContext inputContext) {
//创建Session
Session session = new Session(this, callback, client, inputContext);
return session;
}
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient
从以上代码可以看出session对象是通过WindowManagerGlobal
的getWindowSession
方法,经过WindowManagerService
的openSession
方法创建的。Session
这个类实现了IWindowSession
接口,IWindowSession
是一个AIDL
接口,可以用于进程间通信。
static class W extends IWindow.Stub {
private final WeakReference<ViewRootImpl> mViewAncestor;
private final IWindowSession mWindowSession;
W(ViewRootImpl viewAncestor) {
//软引用方式获取ViewRootImpl
mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
mWindowSession = viewAncestor.mWindowSession;
}
....省略一些方法,这些方法都是最终调用ViewRootImpl的方法
}
W
这个类是ViewRootImpl
的静态内部类,实现了IWindow
接口,IWindow
也是一个AIDL
接口,可以用于进程间通信,WindowManagerService
通过W
对象将逻辑调用到ViewRootImpl中。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
....
//调用addToDisplay方法,传入mWindow对象
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
....
}
Session#addToDisplay
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
//调用到了WindowManagerService的addWindow方法
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}
在ViewRootImpl
的setView
方法中mWindowSession调用addToDisplay
方法最后就调用到了WindowManagerService
的addWindow
方法。
注:以上分析基于API Level 28