WindowManagerService源码学习

WindowManagerService 源码

Android 的framework 层主要是由 WindowManagerService 与 ActivityManagerService 以及 View 所构成,这三个模块穿插交互在 framework中。

WMS 和其他很多服务一样, 都是由 SystemServer 启动。

在SystemServer 中,有如下代码:

wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore);
            ServiceManager.addService(Context.WINDOW_SERVICE, wm);

addService中 key 是 window。 那么在其他进程就可以通过 ServiceManager 以key 为 window 来获取到 WMS。

下面是WMS 中的 main 方法。 通过 Handler 的 runWithScissors 方法执行一个特殊的同步 Task. 并构建了 WMS 的实例。

public static WindowManagerService main(final Context context,
            final InputManagerService im,
            final boolean haveInputMethods, final boolean showBootMsgs,
            final boolean onlyCore) {
        final WindowManagerService[] holder = new WindowManagerService[1];
        //执行同步 task 
        DisplayThread.getHandler().runWithScissors(new Runnable() {
            @Override
            public void run() {
                   //构建实例
                holder[0] = new WindowManagerService(context, im,
                        haveInputMethods, showBootMsgs, onlyCore);
            }
        }, 0);
        return holder[0];
    }

Handler 的 runWithScissors 方法中 第一行注释说明这是一个同步 task。如下:

  • Runs the specified task synchronously.

WMS 的构造方法中主要是对一些窗口管理将要用到的成员变量 进行初始化:

    private WindowManagerService(Context context, InputManagerService inputManager,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
        mContext = context;
        mHaveInputMethods = haveInputMethods;
        mAllowBootMessages = showBootMsgs;
        mOnlyCore = onlyCore;
        mLimitedAlphaCompositing = context.getResources().getBoolean(
                com.android.internal.R.bool.config_sf_limitedAlpha);
        mHasPermanentDpad = context.getResources().getBoolean(
                com.android.internal.R.bool.config_hasPermanentDpad);
        mInputManager = inputManager; // Must be before createDisplayContentLocked.
        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
        mDisplaySettings = new DisplaySettings(context);

        // ... 省略几行代码
        //获取显示服务
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
        Display[] displays = mDisplayManager.getDisplays();
        //为每一个 Display 分配一个 Content
        for (Display display : displays) {
            createDisplayContentLocked(display);
        }
         // ... 省略几行代码

         //构建App 事务
        mAppTransition = new AppTransition(context, mH);
         //获取 IActivityManager 对象
        mActivityManager = ActivityManagerNative.getDefault();
        // ... 省略几行代码
        //构造 Window 动画对象
        mAnimator = new WindowAnimator(this);

         // 初始化窗口策略
        initPolicy();

         //开启绘制事务
        SurfaceControl.openTransaction();
        // ... 省略几行代码
    }

WMS 主要功能有两个方面, 一是 对窗口的管理; 二是 对事件的管理和分发。

接口方法定义在 IWindowManager.aidl。 编译后会生成 IWindowManager.java接口文件。 里面定义了 WMS 绝大部分的功能和方法。

WMS 定义了许多各种不同的窗口。

     //已经完成启动的应用
    final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>();

     //渐变窗口
    final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<FakeWindowImpl>();

     //尺寸正在改变的窗口
    final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>();

     //动画正在结束的窗口
    final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();

     //即将释放的Surface窗口
    final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>();

     // 失去焦点的Window
    ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>();

    //为了释放内存需要强制关闭的Window
    ArrayList<WindowState> mForceRemoves;

    //正在打开的应用
    final ArraySet<AppWindowToken> mOpeningApps = new ArraySet<AppWindowToken>();    

     //正在关闭的应用 
    final ArraySet<AppWindowToken> mClosingApps = new ArraySet<AppWindowToken>();

     //得到焦点的应用 
    AppWindowToken mFocusedApp = null;

    ... //省略代码 还有很多。

不同的窗口或者同一个窗口在不同的阶段可能会位于不同的表中。

Android 中主要由两种窗口类型:

1.应用窗口。

如 Activity所处的窗口,对话框窗口、弹出的窗口等等。 与应用相关的 Window类的 PhoneWindow。 核心是DecorView, 通过 addView 将一个DecorView 添加到 WindowManager.

2.系统窗口。

如 屏幕顶部的状态栏 、 底部的导航栏、桌面的窗口等。 系统窗口没有针对的封装类, 只需要通过 WindwoManager的 addView方法 添加到WindowManager 即可。

比如PhoneStatusBar 中。 createAndAddWindows() -> StatusBarWindowManager.java -> add()中:

mWindowManager.addView(mStatusBarView, mLp);

客户端添加一个窗口

WindowManager.addView() -> WindowManagerImpl.addView() -> WindowMangerGlobal.addView() -> ViewRootImpl.setView() -> IWindowSession.addToDisplay() -> Session.addToDisplay() -> WMS.addWindow().

Sesson中:

@Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets,
            InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outInputChannel);
    }

ok 。我们来看 WMS 中 addWindow 的实现:

    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, InputChannel outInputChannel) {
        int[] appOp = new int[1];
        int res = mPolicy.checkAddPermission(attrs, appOp);
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }
        ...// 省略一堆代码...
    }

这里的 mPolicy 实际上是 PhoneWindowManager. Policy 中的实现。

 public WindowManagerPolicy makeNewWindowManager() {
     return new PhoneWindowManager();
}

PhoneWindowManager 的 checkAddPermission 中会先判断窗口的 type 是否是系统级别。 如果不是 则返回 WindowManagerGlobal.ADD_OKAY. 如果是,就会进行相关权限等的校验 SYSTEM_ALERT_WINDOWINTERNAL_SYSTEM_WINDOW. 如果没有权限就会 返回 ADD_PERMISSION_DENIED. 校验完毕权限 会校验窗口的有效性。


            boolean addToken = false;
            WindowToken token = mTokenMap.get(attrs.token);
            if (token == null) {
                    //如果窗口是子窗口
                if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                //如果是输入法窗口
                if (type == TYPE_INPUT_METHOD) {
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
               ...// 省略一堆 if else.

检查窗口的有效性完毕,接下来就是为该窗口创建一个 WindowState对象。维护窗口的状态以及更加适当的机制来调整窗口状态。

        synchronized(mWindowMap) {

              // ...省略代码

              //构建WindowState对象
            win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
            //如果客户端已经被销毁        
            if (win.mDeathRecipient == null) {
                return WindowManagerGlobal.ADD_APP_EXITING;
            }
              //根据窗口类型调整属性
            mPolicy.adjustWindowParamsLw(win.mAttrs);

            //设置该窗口是否只对自己的 uid 可见
            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
              //根据窗口类型判定权限
            res = mPolicy.prepareAddWindowLw(win, attrs);
            if (res != WindowManagerGlobal.ADD_OKAY) {
                return res;
            }
              //如果输出 Channel 的通道为空
            if (outInputChannel != null && (attrs.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                //创建通道    
                String name = win.makeInputChannelName();
                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
                win.setInputChannel(inputChannels[0]);
                inputChannels[1].transferTo(outInputChannel);
                   //向 InputManager 中注册该通道,以便当前窗口可以接受到事件。
                mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
            }

            //...省略一些代码

mPolicy 实质上就是 PhoneWindowManager。 对用它的 adjustWindowParamsLw 方法。里面判断如果是 TYPE_SYSTEM_OVERLAY 和 TYPE_SECURE_SYSTEM_OVERLAY 类型 的窗口,不要获取焦点即可。

addWindow 最后部分的逻辑

    ... 省略大量代码
   res = WindowManagerGlobal.ADD_OKAY;
              //重置当前线程 IPC 的 ID
            origId = Binder.clearCallingIdentity();
              是否需要token
            if (addToken) {
                mTokenMap.put(attrs.token, token);
            }
            //将窗口添加至Session
            win.attach();
            //将窗口添加至 WMS
            mWindowMap.put(client.asBinder(), win);

              //省略几行代码...

              //顺序排列窗口
            if (type == TYPE_INPUT_METHOD) {
                    //如果是输入法窗口
                win.mGivenInsetsPending = true;
                mInputMethodWindow = win;
                addInputMethodWindowToListLocked(win);
                imMayMove = false;
            } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                  //如果是输入法对话框窗口
                mInputMethodDialogs.add(win);
                addWindowToListInOrderLocked(win, true);
                moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
                imMayMove = false;
            } else {
                  //如果是其他窗口
                addWindowToListInOrderLocked(win, true);
                if (type == TYPE_WALLPAPER) {
                    mLastWallpaperTimeoutTime = 0;
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if (mWallpaperTarget != null
                        && mWallpaperTarget.mLayer >= win.mBaseLayer) {
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                }
            }

            win.mWinAnimator.mEnterAnimationPending = true;
              //如果displayContent 是默认的显示
            if (displayContent.isDefaultDisplay) {
                   //获取系统窗口区域的inserts
                mPolicy.getContentInsetHintLw(attrs, outContentInsets);
            } else {
                    //否则将 outContentInsets 置为空
                outContentInsets.setEmpty();
            }

            if (mInTouchMode) {
                    //标识用户直接触摸的窗口
                res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
            }
            if (win.mAppToken == null || !win.mAppToken.clientHidden) {
                    //标识应用窗口
                res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
            }

            mInputMonitor.setUpdateInputWindowsNeededLw();

            boolean focusChanged = false;
            //如果当前窗口可以接收按键事件
            if (win.canReceiveKeys()) {
                   //那么更新焦点将窗口信息存入 InputDispatcher
                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                        false /*updateInputWindows*/);
                if (focusChanged) {
                    imMayMove = false;
                }
            }

            if (imMayMove) {
                moveInputMethodWindowsIfNeededLocked(false);
            }

              //分配最终层级
            assignLayersLocked(displayContent.getWindowList());

            if (focusChanged) {
                mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
            }
            mInputMonitor.updateInputWindowsLw(false /*force*/);

            if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                reportNewConfig = true;
            }
        }

        if (reportNewConfig) {
            sendNewConfiguration();
        }

        Binder.restoreCallingIdentity(origId);

        return res;
    }

这部分逻辑中,最重要的一步就是通过 WindowState的 attach方法 创建一个关联的 SurfaceSession的对象 用以与 SurfaceFlinger通信。 而 SurfaceSession实际对应的是 native层中的 SurfaceComposerClient对象。 SurfaceComposerClient 主要作用就是在 应用进程与 SurfaceFlinger 服务之间建立连接。(这块不是很明白。很多知识都不理解)。

mSurfaceSession = new SurfaceSession();
    原文作者:派派的生活
    原文地址: https://blog.csdn.net/mike_Cui_LS/article/details/81299278
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞