目录

WindowManagerService

目录

前一节, 对WindowWindowManager进行了分析, blog, 其中的WMS是不容忽视的角色

关于Android的framework层主要就是由它与另外一个系统服务ActivityManagerServiceView构成, 这三个模块穿插在整个framework中.

和其他系统服务一样, WMS也是由SystemServer启动的. 调用了WMS#main()静态方法来构建的对象. 之后其他进程就可以通过ServiceManger查询window来获取WMS. main()比较简单就是通过Handler#runWithScissors()方法执行一个特殊的同步Task并在其中构造WMS的实例

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

private WindowManagerService(Context context, InputManagerService inputManager,
  boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
   // 成员变量的赋值
   mContext = context;
   // ....
   // 获取显示服务
   mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);

   // 构造APP事务对象
   mAppTransition = new AppTransition(context, mH);
   
   // 获取IActivityManager对象
   mActivityManager = ActivityManagerNative.getDefault();
   
   // 构造Window对象
   mAnimator = new WindowAnimator(this);
   
   // 初始化窗口管理策略
   initPolicy();
   
   // 开启Surface事务
   SurfaceControl.openTransaction();    
}

WMS主要功能可以分为两方面, 一是对窗口的管理, 二是对事件的管理和分发. 其接口方法以AIDL的方式定义在IWindowManager.aidl文件中, 编译后生成一个对应的IWindowManager.java接口文件, 这个接口文件定义了WMS绝大部分的功能方法.

作为窗口管理承担者, WMS中定义了许多不同的窗口, 他们都被定义在WMS的成员变量中.

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    // 已经完成启动的应用
    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>();

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

    // 为了释放内存需要关闭的窗口
    ArrayList<WindowState> mForceRemoves;
    
    // 正在打开的应用
    final ArraySet<AppWindowToken> mOpeningApps = new ArraySet<AppWindowToken>();
    
    // 正在关闭的应用
    final ArraySet<AppWindowToken> mClosingApps = new ArraySet<AppWindowToken>();
    
    // 当前获得焦点的窗口
    WindowState mCurrentFocus = null;
    
    // 上一个获得焦点的窗口
    WindowState mLastFocus = null;
    
    // 输入法窗口下方的窗口
    WindowState mInputMethodTarget = null;
    
    // 输入法窗口
    WindowState mInputMethodWindow = null;
    
    // 墙纸窗口
    WindowState mWallpaperTarget = null;
    
    // 在切换过程中位于墙纸z-order下方的窗口
    WindowState mLowerWallpaperTarget = null;
    
    // 在切换过程中位于墙纸z-order上方的窗口
    WindowState mUpperWallpaperTarget = null;
    
    // 得到焦点的窗口
    AppWindowToken mFocusedApp = null; 
}

可以看到大量的线性表应用, 不同的窗口或同一个窗口在不同的状态下可能位于不同的表中. 虽然状态较多, 但是对于Android来讲窗口可以用两种粗略的概括为应用窗口,系统窗口.

  • 应用窗口: 就是常见的Activity,dialog,popup等都属于该类. 也可以继续分为子窗口(比如子窗口AlertDialog的常规创建需要使用activity的context). 而与应用相关的Window类主要是PhoneWindow,主要应用于手机,PhoneWindow继承与Window,核心是DecorView, 通过WindowManager进行DecorView的操作.
  • 系统窗口: 常见的屏幕顶部的状态栏, 底部的导航栏, 桌面窗口等都是系统窗口. 系统窗口没有针对性的封装类, 只需要直接通过WindowManager直接进行View的操作即可.

WMS是运行在系统进程中, 那么一个应用需要创建窗口时必然需要跨进程通信通知WMS生成一个窗口, 然后再由WMS向应用返回和窗口交互的消息. 上一篇说过, WindowManger的操作是桥接到了WindowMangerGlobal实现的具体逻辑, 最后会调用ViewRootImpl#setView()函数, 在该方法中通过addToDisplay()函数向WMS发起了一个Session请求. 最终会调用到Session#addToDisplay()函数.

@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);
}

最后还是回到了WMS中建立连接, addToDisplay()最终返回的就是WMS#addWindow()的返回结果.

WMS#addWindow()逻辑主要是先检查权限, 区分系统权限应用权限通过PhoneWindowManager#checkAddPermission()判断窗口类型是否是系统级的. 如果不是系统级则返回一个ADD_OKAY值表示允许, 否则就需要SYSTEM_ALERT_WINDOW或者INTERNAL_SYSTEM_WINDOW的权限. 权限之后则相关Display显示信息以及窗口信息进行校队, 然后在WMS中获取对应的WindowToken, 之后根据不同的窗口类型检查窗口的有效性.

窗口的有效性检查完之后, 就会为该窗口创建一个WindowState对象类, 维护窗口的状态以及根据适当的机制来调整窗口的状态.

WindowState对象构建完之后, 会通过mPolicy本质上就是PhoneWindowManageradjustWindowParamsLw()函数决定该窗口是否需要获取焦点. 判断逻辑就是只要是TYPE_SYSTEM_OVERLAY或者TYPE_SECURE_SYSTEM_OVERLAY就不获取.

最后将窗口与其他相关组件关联.

addWindow方法的最后一部分, 最重要的一步就是通过WindowState#attach()函数创建了一个关联SurfaceSession的对象以与SurfaceFlinger通信, 而SurfaceSession实际对应的就是native层中的SurfaceComposerClient对象. SurfaceComposerClient主要作用就是在应用进程与SurfaceFlinger服务之间建立连接.

以上就是一个系统窗口的添加的主要逻辑.