Window管理深入了解WindowManagerService

Posted 丶笑看退场

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Window管理深入了解WindowManagerService相关的知识,希望对你有一定的参考价值。

前文已经介绍过WindowManage(全方面来认识WindowManager),今天就让我们来认识下WindowManager的管理者WMS,在android系统中,对系统中的所有窗口进行管理是窗口管理服务WindowManagerService的职责。

可以知道App从启动到主窗口显示出来,主要需要AppActivityManagerServiceWindowManagerServiceSurfaceFlinger等这几个模块相互合作。

在这几个中App主要负责业务逻辑,绘制视图,AMS负责管理组件和进程信息以及堆栈信息,WMS负责管理Activity的窗口以及子窗口和系统窗口,SF则是在用于管理图形缓冲区,进行屏幕渲染。本文分析就基于Android 10.0上。

一、WMS的诞生

正如AMS一样,WMS也是在SystemServermain()中诞生:

public static void main(String[] args) 
        new SystemServer().run();
    

private void run() 
  ......
  // 开启服务.
        try 
            traceBeginAndSlog("StartServices");
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
         catch (Throwable ex) 
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
         finally 
            traceEnd();
        
  ......

从上面可以看出,创建了个SystemServer对象后就会调用run方法。在方法里会开启三种类型的系统服务,分别是引导服务,核心服务和其他服务,而WMS是其他服务的一种。

接着我们来看下WMS在startOtherService中是如何产生的:

private void startOtherServices() 
 ......
  //代码1
  wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                    new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
  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);
    traceEnd();

    traceBeginAndSlog("SetWindowManagerService");
  //代码2
    mActivityManagerService.setWindowManager(wm);
    traceEnd();

    traceBeginAndSlog("WindowManagerServiceOnInitReady");
  //代码3
            wm.onInitReady();
  ......
    //代码4
    try 
            wm.displayReady();
         catch (Throwable e) 
            reportWtf("making display ready", e);
        
  ......
    //代码5
    try 
            wm.systemReady();
         catch (Throwable e) 
            reportWtf("making Window Manager Service ready", e);
        


在代码1处,调用WindowManagerServiice.main()创建wms对象,并将该对象加入到ServiceManager中,代码2处,为AMS设置了wms,之后在代码3和代码4中初始化显示信息,在代码5处红藕你过来痛殴感知wms,系统的初始化已经完成,内部会调用mPolicy.systemReady方法。

从上面可以看到当调用了wms的main方法的时候,会创建wms实例出来:

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

 public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, TransactionFactory transactionFactory) 
        DisplayThread.getHandler().runWithScissors(() ->
                sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
                        atm, transactionFactory), 0);
        return sInstance;
    

main方法中,会用DisplayThread.getHandlerunWithSciissors方法,说明WMS的创建是运行在android.display线程中。

DisplayThread 线程是一个系统前台线程,用于执行一些延时要非常小的关于显示的操作

HandlerunWithScissors方法中:

public final boolean runWithScissors(final Runnable r, long timeout) 
        ......

        if (Looper.myLooper() == mLooper) 
            r.run();
            return true;
        

        BlockingRunnable br = new BlockingRunnable(r);
        return br.postAndWait(this, timeout);
    

在这里会判断是否是当前的looper,这里的looper也是指是不是处在android.display中。当如果不是的时候,就会将runnable传入到BlockingRunnable,并执行postAndWait方法。

    private static final class BlockingRunnable implements Runnable 
        private final Runnable mTask;
        private boolean mDone;

        public BlockingRunnable(Runnable task) 
            mTask = task;
        

        @Override
        public void run() 
            try 
                mTask.run();
             finally 
                synchronized (this) 
                    mDone = true;
                    notifyAll();
                
            
        

        public boolean postAndWait(Handler handler, long timeout) 
            if (!handler.post(this)) 
                return false;
            

            synchronized (this) 
                if (timeout > 0) 
                    final long expirationTime = SystemClock.uptimeMillis() + timeout;
                    while (!mDone) 
                        long delay = expirationTime - SystemClock.uptimeMillis();
                        if (delay <= 0) 
                            return false; // timeout
                        
                        try 
                            wait(delay);
                         catch (InterruptedException ex) 
                        
                    
                 else 
                    while (!mDone) 
                        try 
                            wait();
                         catch (InterruptedException ex) 
                        
                    
                
            
            return true;
        
    

postAndWait方法里,在mDone没有设置为trrue时,一直会让线程处于等待状态,直到run方法被执行。在这个时候会设置爱mDone为true,并同时notifyAll唤醒线程。从这里也可以看出wms的创建的优先级会高点。

接着就会执行到wms的构造方法,构造方法很长我们就截取一些关键点:

private WindowManagerService(Context context, InputManagerService inputManager,
            boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, TransactionFactory transactionFactory) 
  			......   
        //代码1
  			mPolicy = policy;
  
  			//代码2
        mAnimator = new WindowAnimator(this);
        mRoot = new RootWindowContainer(this);

        mWindowPlacerLocked = new WindowSurfacePlacer(this);
        mTaskSnapshotController = new TaskSnapshotController(this);

        mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,
                Choreographer.getInstance());

        LocalServices.addService(WindowManagerPolicy.class, mPolicy);
  
  			......
  			//代码3
  		  mActivityManager = ActivityManager.getService();
        mActivityTaskManager = ActivityTaskManager.getService();
  
  

在代码1处,mPolicy对象在wms中占有了很重要的作用,是一个接口,WMS中的操作都是wmp所处理。而它真正的实现类是PhoneWindowManagerPhoneWindowManager处理线程是在ui线程中。

二、WMS重要成员

名字含义
mPolicy: WiindoowMangerPolicy是窗口管理策略的接口类,用来定义一个窗口所要遵循的通用规范
mSessions: ArraySet主要用于进程间通信,其他的应用程序进程需要和WMS进程通信就需要经过Session,每个应用进程都会对应一个Session,保存它就是用来记录所有向WMS提出窗口管理服务的客户端。
mWindowMap:WindowHashMapkey对应的值是IBinder,value对应的值是WindowState。Window则是在窗口管理中的一个窗口
mAnimator:WindowAnimatorwindowAnimatoor类型的变量,用于管理窗口的动画以及特效动画
mH:H系统的Handler,用于将任务加入到主线程的消息队列中

三、WMS的添加过程

从上文ViewRootImpl在调用setView方法时会执行addToDisplay方法,内部又会调用了WMSaddWindow方法并将自身也就是Session传入了进去,我们直接来看下WindowManagerServiceaddWindow方法:

 public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
            InsetsState outInsetsState) 
       ......
   
         synchronized (mGlobalLock) 
         //WindowToken转换为专门针对应用程序窗口的AppWindowToken
            AppWindowToken atoken = null;
         //对子窗口使用现有的父窗口令牌,因为它们与父窗口具有相同的令牌,因此我们可以对它们应用相同的策略
         		WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);
         
         //如果不存在token
         if (token == null) 
           //如果是Appliation类型的窗口,  不允许WindowToken为null
           if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) 
                    Slog.w(TAG_WM, "Attempted to add application window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                
           .......
         
         
         //创建WindowState
          final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
         
         //创建InputChanel,用来Input信息的接收和传递
         final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) 
                win.openInputChannel(outInputChannel);
            
         
         //将WindowState加入到windowMap中
         		win.attach();
            mWindowMap.put(client.asBinder(), win);

            win.initAppOpsState();
         //将WindowState对象添加到WindowToken中,WindowToken将作为WindowState的父容器
         win.mToken.addWindow(win);
        .....
          //创建窗口动画
           final WindowStateAnimator winAnimator = win.mWinAnimator;
            winAnimator.mEnterAnimationPending = true;
            winAnimator.mEnteringAnimation = true;
         
         //如果能获取到焦点,则更新焦点窗口
         		boolean focusChanged = false;
            if (win.canReceiveKeys()) 
                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                        false /*updateInputWindows*/);
                if (focusChanged) 
                    imMayMove = false;
                
            
         
         //更新输入 Window
         if (focusChanged) 
                displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
                        false /*updateInputWindows*/);
            
         
            displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);

            ......
              
					//如果方向有更新,则更新全局配置
            if (win.isVisibleOrAdding() && displayContent.updateOrientationFromAppTokens()) 
                reportNewConfig = true;
            
         ......
       
   
 

addWindow中做了大量的检查,主要做了如下工作:

  1. 对所有窗口类型进行检查,不满足就不会去执行
  2. windowToken迹进行处理,获取不到则会创建新的WindowToken
  3. 创建windowState对象,并将其与WindowToken相关联,让WindowToken成为WindowStae对象的父容器
  4. 更新焦点窗口以及更新InputWindow

3.1 WindowToken创建

​ WindowToken在里面的作用是作为WindowState的父容器,负责管理一组Window。而它的构造方法如下:

WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
            DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) 
        super(service);
  //赋值IBinder对象
        token = _token;
  //窗口类型
        windowType = type;  
  //是否是显式添加的WindowToken
        mPersistOnEmpty = persistOnEmpty;  
        mOwnerCanManageAppTokens = ownerCanManageAppTokens;
        mRoundedCornerOverlay = roundedCornerOverlay;
        onDisplayChanged(dc);
    

void onDisplayChanged(DisplayContent dc) 
  //将该对象添加到DisplayContent中
        dc.reParentWindowToken(this);
        super.onDisplayChanged(dc);
    

做了些属性初始化工作后,将WindowToken传递给了DisplayContent,最终把token保存到了DisplayContent#mToken中。

//DisplayContent.java
void reParentWindowToken(WindowToken token) 
        final DisplayContent prevDc = token.getDisplayContent();
        if (prevDc == this) 
            return;
        
        ......

        addWindowToken(token.token, token);
    

private void addWindowToken(IBinder binder, WindowToken token) 
  // 如果该WindowToken已经关联有DisplayContent对象,则不能再关联其他DisplayContent对象
        final DisplayContent dc = mWmService.mRoot.getWindowTokenDisplay(token);
        if (dc != null) 
            // We currently don't support adding a window token to the display if the display
            // already has the binder mapped to another token. If there is a use case for supporting
            // this moving forward we will either need to merge the WindowTokens some how or have
            // the binder map to a list of window tokens.
            throw new IllegalArgumentException("Can't map token=" + token + " to display="
                    + getName() + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
        
        if (binder == null) 
            throw new IllegalArgumentException("Can't map token=" + token + " to display="
                    + getName() + " binder is null");
        
        if (token == null) 
            throw new IllegalArgumentException("Can't map null token to display="
                    + getName() + " binder=" + binder);
        

  //将WindowToken添加到哦DisplayContent的TokenMap中
        mTokenMap.put(binder, token);

  //对于不是Activity类型的窗口,会根据Window类型添加到对应三个container中国
        if (token.asAppWindowToken() == null) 
            switch (token.windowType) 
                case TYPE_WALLPAPER:
                    mBelowAppWindowsContainers.addChild(token);
                    break;
                case TYPE_INPUT_METHOD:
                case TYPE_INPUT_METHOD_DIALOG:
                    mImeWindowsContainers.addChild(token);
                    break;
                default:
                    mAboveAppWindowsContainers.addChild(token);
                    break;
            
        
    

到这里WindowToken对象就创建完毕了。

3.2 WindowState创建

WindowToken管理着windowState,每个WindowState代表了一个具体的Window,每次添加个Window就会创建出对应的一个windowState,其构造方法如下:

//WindowStae 
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
            int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
            Window管理深入了解WindowManagerService

Android 设计模式 笔记 - 深入了解WindowManager

Andoird WindowManager管理Window的流程

Android-Window和WindowManager

深入Android系统Android图形显示系统-1-显示原理与Surface

Android Framework 之 Window / WindowManager基本概念及addView源码分析