WMS浅析

171 阅读3分钟

一、简介

WMS全称WindowManagerService,它作为一个系统服务负责管理着window,对于应用层开发来讲,平时更多的接触是ActivityDialog等组件,其实它们都对应着相关的window对象,可以说ActivityDialog最终能显示到屏幕上都是由于window的存在。关于window的定义文章就不具体描述了,想要从头到尾分析的比较彻底还是比较复杂的,文章将从WMS的启动WMS的应用这两方面来分析WMS在Android体系中所发挥的作用。

二、WMS的启动

WMSAMS一样也是在SystemServer进程中启动的,核心流程的代码都在SystemServerstartOtherServices方法中。

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初始化完成方法,再将WindowManagerServiceInputMonitor设置给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的应用

分析WindowManagerServicewindow的管理就需要来到多次提到的ViewRootImpl这个类中了。

ViewRootImpl构造方法
public ViewRootImpl(Context context, Display display) {
    ....
    //获取IWindowSession
    mWindowSession = WindowManagerGlobal.getWindowSession();
    ....
    //创建W对象
    mWindow = new W(this);
    ....
}

ViewRootImpl的构造方法和window相关的主要流程是获取IWindowSession和创建W对象,这两个对象都是用于ViewRootImplWMS通信使用的。

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对象是通过WindowManagerGlobalgetWindowSession方法,经过WindowManagerServiceopenSession方法创建的。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);
}

ViewRootImplsetView方法中mWindowSession调用addToDisplay方法最后就调用到了WindowManagerServiceaddWindow方法。

注:以上分析基于API Level 28

参考文章
深入理解 WindowManagerService