【安卓12源码】WMS系列:addWindow 和 removeWindow流程

一、Window 的属性

Window的属性定义在WindowManager的内部类LayoutParams中,了解Window的属性能够更好的理解WMS的内部原理。Window的属性有很多种,与应用开发最密切的有三种,它们分别是Type(Window的类型)、Flag(Window的标志)和SoftInputMode(软键盘相关模式)

1. Window的类型 Type

Window的类型有很多种,比如应用程序窗口、系统错误窗口、输入法窗口、PopupWindow、Toast、Dialog等等。总来来说分为三大类分别是:Application Window(应用程序窗口)、Sub Windwow(子窗口)、System Window(系统窗口),每个大类又包含了很多种类型,它们都定义在WindowManager的静态内部类LayoutParams中

Window 窗口的显示次序:

当一个进程向WMS申请一个窗口时,WMS会为窗口确定显示次序。为了方便窗口显示次序的管理,手机屏幕可以虚拟的用X、Y、Z轴来表示,其中Z轴垂直于屏幕,从屏幕内指向屏幕外,这样确定窗口显示次序也就是确定窗口在Z轴上的次序,这个次序称为Z-Oder。Type值是Z-Oder排序的依据,我们知道Application应用程序窗口的Type值范围为1到99,Sub子窗口1000到1999 ,System系统窗口 2000到2999,,一般情况下,Type值越大则Z-Oder排序越靠前,就越靠近用户。当然窗口显示次序的逻辑不会这么简单,情况会比较多,举个常见的情况:当多个窗口的Type值都是TYPE_APPLICATION,这时WMS会结合各种情况给出最终的Z-Oder

/frameworks/base/core/java/android/view/WindowManager.java

  • 应用程序窗

应用程序的window 的值是从 1 到 99

// 在内部类 LayoutParams 中
    public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {

// 应用程序的window 的值是从 1 到 99
        public static final int FIRST_APPLICATION_WINDOW = 1;

        public static final int TYPE_BASE_APPLICATION   = 1;

// 应用窗口的值
        public static final int TYPE_APPLICATION        = 2;

//应用程序启动窗口类型,用于系统在应用程序窗口启动前显示的窗口
        public static final int TYPE_APPLICATION_STARTING = 3;

        public static final int LAST_APPLICATION_WINDOW = 99;
  • Sub子窗口

子窗口是不能独立的存在,需要附着在其他窗口才可以,PopupWindow属于子窗口 。type值是从 1000-1999

// 子窗口的type 值是从 1000 到 1999
        public static final int FIRST_SUB_WINDOW = 1000;

        public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;

        public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;

        public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;

        public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;

        public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;

        public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;

        public static final int LAST_SUB_WINDOW = 1999;

  • System系统窗口

Toast、输入法窗口、系统音量条窗口、系统错误窗口都属于系统窗口。type 值是从 2000-2999 

// 系统窗口的type值是从 2000 到 2999
        public static final int FIRST_SYSTEM_WINDOW     = 2000;
// 状态栏
        public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
// 搜索栏
        public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;

        @Deprecated
        public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;

        @Deprecated
        public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;

        public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;

        @Deprecated
        public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;

        @Deprecated
        public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;

        @Deprecated
        public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;

        public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;

        public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;

        @Deprecated
        public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;

        public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;

        public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
// 壁纸
        public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;

        public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;

        public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;

        public static final int TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16;

        public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;

        public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
// 导航栏
        public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
// 音量条
        public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;

        public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;

        public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22;

        public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;

        public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;

        public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;

        public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;

        public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;

        public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;

        public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;

        public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34;

        public static final int TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35;
// 截图
        public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;

        public static final int TYPE_PRESENTATION = FIRST_SYSTEM_WINDOW + 37;

        public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;

        public static final int TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39;
// 通知栏
        public static final int TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40;

        public static final int TYPE_STATUS_BAR_ADDITIONAL = FIRST_SYSTEM_WINDOW + 41;

        public static final int LAST_SYSTEM_WINDOW      = 2999;

2. Window的标志Flag

Flag描述
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON只要窗口可见,就允许在开启状态的屏幕上锁屏
FLAG_NOT_FOCUSABLE窗口不能获得输入焦点,设置该标志的同时,FLAG_NOT_TOUCH_MODAL也会被设置
FLAG_NOT_TOUCHABLE窗口不接收任何触摸事件
FLAG_NOT_TOUCH_MODAL在该窗口区域外的触摸事件传递给其他的Window,而自己只会处理窗口区域内的触摸事件
FLAG_KEEP_SCREEN_ON只要窗口可见,屏幕就会一直亮着
FLAG_LAYOUT_NO_LIMITS允许窗口超过屏幕之外
FLAG_FULLSCREEN隐藏所有的屏幕装饰窗口,比如在游戏、播放器中的全屏显示
FLAG_SHOW_WHEN_LOCKED窗口可以在锁屏的窗口之上显示
FLAG_IGNORE_CHEEK_PRESSES当用户的脸贴近屏幕时(比如打电话),不会去响应此事件
FLAG_TURN_SCREEN_ON窗口显示时将屏幕点亮

设置 flags  的 3 种方式:

// 1. 通过addFlags 方法
// getWindow 获取的是对象 PhoneWindow对象
Window mWindow =getWindow(); 
mWindow.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

// 2. 通过setFlags 方法
Window mWindow =getWindow();            
mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
,WindowManager.LayoutParams.FLAG_FULLSCREEN);

// 3. 通过创建 LayoutParams 对象赋值方式
WindowManager.LayoutParams mWindowLayoutParams =
              new WindowManager.LayoutParams();
      mWindowLayoutParams.flags=WindowManager.LayoutParams.FLAG_FULLSCREEN;
      WindowManager mWindowManager =(WindowManager) getSystemService(Context.WINDOW_SERVICE);  
      TextView mTextView=new TextView(this);
      mWindowManager.addView(mTextView,mWindowLayoutParams);
                                                                                                                     

3. Window 的软键盘相关模式SoftInputMode

窗口和窗口的叠加是非常常见的场景,但如果其中的窗口是软键盘窗口,可能就会出现一些问题,比如典型的用户登录界面,默认的情况弹出的软键盘窗口可能会盖住输入框下方的按钮,这样用户体验会非常糟糕。
为了使得软键盘窗口能够按照期望来显示,WindowManager的静态内部类LayoutParams中定义了软键盘相关模式,这里给出常用的几个:

SoftInputMode描述
SOFT_INPUT_STATE_UNSPECIFIED没有指定状态,系统会选择一个合适的状态或依赖于主题的设置
SOFT_INPUT_STATE_UNCHANGED不会改变软键盘状态
SOFT_INPUT_STATE_HIDDEN当用户进入该窗口时,软键盘默认隐藏
SOFT_INPUT_STATE_ALWAYS_HIDDEN当窗口获取焦点时,软键盘总是被隐藏
SOFT_INPUT_ADJUST_RESIZE当软键盘弹出时,窗口会调整大小
SOFT_INPUT_ADJUST_PAN当软键盘弹出时,窗口不需要调整大小,要确保输入焦点是可见的

从上面给出的SoftInputMode ,可以发现,它们与AndroidManifest中Activity的属性android:windowSoftInputMode是对应的。因此,除了在AndroidMainfest中为Activity设置android:windowSoftInputMode以外还可以在Java代码中为Window设置SoftInputMode:

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

Android解析WindowManager(二)Window的属性 | BATcoder - 刘望舒

二、WMS 窗口添加addWindow流程

有关于 WMS 的 一些重要类:

  • WindowManager

具体的实现是WindowManagerImpl 应用与窗口管理服务WindowManagerService交互的接口;

  • PhoneWindowManager

继承了WindowManagerPolicy,在UI线程创建的。实现了窗口的各种策略,定义了窗口相关策略,比如:告诉WMS某一个类型Window的Z-Order的值是多少,帮助WMS矫正不合理的窗口属性,为WMS监听屏幕旋转的状态,预处理一些系统按键事件;

  • Choreographer

用户控制窗口动画、屏幕选择等操作,它拥有从显示子系统获取Vsync同步事件的能力,从而可以在合适的时机通知渲染动作,避免在渲染的过程中因为发生屏幕重绘而导致的画面撕裂。WMS使用Choreographer负责驱动所有的窗口动画、屏幕旋转动画、墙纸动画的渲染;

  • DisplayContent

用于描述多屏输出相关信息;

根据窗口的显示位置将其分组。隶属于同一个DisplayContent的窗口将会被显示在同一个屏幕中。每个DisplayContent都对应着唯一ID,在添加窗口的时候可以通过指定这个ID决定其将显示在哪个屏幕中;

DisplayContent是一个非常具有隔离性的一个概念。处于不同DisplayContent的两个窗口在布局、显示顺序以及动画处理上不会产生任何耦合;

  • WindowState

描述窗口的状态信息以及和WindowManagerService进行通信,一般一个窗口对应一个WindowState。它用来表示一个窗口的所有属性;

  • WindowToken
  • 窗口Token,用来做Binder通信;同时也是一种标识;
  • 在进行窗口Zorder排序时,属于同一个WindowToken的窗口会被安排在一起,而且在其中定义的一些属性将会影响所有属于此WindowToken的窗口,这些都表明了属于同一个WindowToken的窗口之间的紧密联系;
  • 应用组件在需要新的窗口时,必须提供WindowToken以表明自己的身份,并且窗口的类型必须与所持有的WindowToken的类型一致;
  • 在创建系统类型的窗口时不需要提供一个有效的Token,WMS会隐式地为其声明一个WindowToken,看起来谁都可以添加个系统级的窗口。难道Android为了内部使用方便而置安全于不顾吗?非也,addWindow()函数一开始的mPolicy.checkAddPermission()的目的就是如此。它要求客户端必须拥有SYSTEM_ALERT_WINDOW或INTERNAL_SYSTEM_WINDOW权限才能创建系;
  • Session

App进程通过建立Session代理对象和Session对象通信,进而和WMS建立连接;

  • SurfaceFlinger

SurfaceFlinger负责管理Android系统的帧缓冲区(Frame Buffer),Android设备的显示屏被抽象为一个帧缓冲区,而Android系统中的SurfaceFlinger服务就是通过向这个帧缓冲区写入内容来绘制应用程序中的用户界面的;

  • InputManager

管理每个窗口的输入事件通道(InputChannel)以及向通道上派发事件;

  • Animator

所有窗口动画的总管(WindowStateAnimator对象)。在Choreographer的驱动下,逐个渲染所有的动画;

Window 的概念

  • 表示一个窗口的概念,是所有View的直接管理者,任何视图都通过Window呈现(点击事件由Window->DecorView->View;Activity的setContentView底层通过Window完成)
  • Window是一个抽象类,具体实现是PhoneWindow;
  • 创建Window需要通过WindowManager创建;
  • WindowManager是外界访问Window的入口;
  • Window的具体实现位于WindowManagerService中;
  • WindowManager和WindowManagerService的交互是通过IPC进程间通信完成的;
  • 定义窗口样式和行为的抽象基类,用于作为顶层的View加到WindowManager中,其实现类是PhoneWindow;
  • 每个Window都需要指定一个Type(应用窗口、子窗口、系统窗口)。Activity对应的窗口是应用窗口;PhoneWindow,ContextMenu,OptionMenu是常用的子窗口;像Toast和系统警告提示框(如ANR)就是系统窗口,还有很多应用的悬浮窗也属于系统窗口;

Surface 的作用

  • 在Android中,一个窗口会独占一个Surface,Surface其实就是一个画布,应用程序通过Canvas或者OpenGL在Surface上绘制内容;
  • 在Surface上绘制后,通过SurfaceFlinger将多块Surface的内容按照Z-order进行混合并输出到FrameBuffer,从而将Android页面展示给用户;
  • 每个窗口都有一块Surface用于显示自己的ui,必然需要一个角色对窗口进行统一管理,这个时候,WMS应运而生。WMS为所有窗口分配Surface,掌管z-order以及位置、尺寸、窗口的进场出场动画,并且还是输入系统的中转站;
  • 布局系统:计算管理窗口的位置和层次;
  • 动画系统:根据布局系统的计算渲染窗口动画;

Android进阶:深入理解Android窗口管理框架机制-android 窗口管理

我们在学习activity 的生命周期的时候,参考一些资料说 on_resume的时候,才真正去显示view,相信本文可以给个基础的解答。 

窗口的添加从Activity::makeVisible开始,由WindowManagerImpl委托给WindowManagerGlobal处理,WindowManagerGlobal内部的mViewsmRootsmParamsmDyingViews分别管理窗口的试图、主线程、布局参数以及死亡过程中的视图;ViewRootImpl持有Session的代理端与WMS通信;

/frameworks/base/core/java/android/app/ActivityThread.java

// 执行 handleResumeActivity 

    @Override
    public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, String reason) {

        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

// 先执行 performResumeActivity
        if (!performResumeActivity(r, finalStateRequest, reason)) {
            return;
        }


        final Activity a = r.activity;

        final int forwardBit = isForward
                ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

// mStartedActivity在 performResumeActivity 设置为 false
// willBeVisible  为 true
        boolean willBeVisible = !a.mStartedActivity;
        if (!willBeVisible) {
            willBeVisible = ActivityClient.getInstance().willActivityBeVisible(
                    a.getActivityToken());
        }
        if (r.window == null && !a.mFinished && willBeVisible) {

// 获取的对象是: PhoneWindow
            r.window = r.activity.getWindow();
// decor 是 new DecorView 对象
            View decor = r.window.getDecorView();

// DecorView 设置不可见
            decor.setVisibility(View.INVISIBLE);

// 在lauchactivity时候分析:activity.getWindowManager 是 WindowManagerImpl
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();

// 设置 activity 的 mDecor 为:DecorView 对象,先 install。。。
            a.mDecor = decor;

// 这里设置 layout 的类型为 TYPE_BASE_APPLICATION
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            if (r.mPreserveWindow) {
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                // Normally the ViewRoot sets up callbacks with the Activity
                // in addView->ViewRootImpl#setView. If we are instead reusing
                // the decor view we have to notify the view root that the
                // callbacks may have changed.
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
                    impl.notifyChildRebuilt();
                }
            }
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;

// addview 流程
                    wm.addView(decor, l);
                } else {
                    // The activity will get a callback for this {@link LayoutParams} change
                    // earlier. However, at that time the decor will not be set (this is set
                    // in this method), so no action will be taken. This call ensures the
                    // callback occurs with the decor set.
                    a.onWindowAttributesChanged(l);
                }
            }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
        } else if (!willBeVisible) {
            if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
            r.hideForNow = true;
        }

4870          if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {

4888              r.activity.mVisibleFromServer = true;
4889              mNumVisibleActivities++;
4890              if (r.activity.mVisibleFromClient) {
4891                  r.activity.makeVisible();
4892              }
4893          }

// 先执行 performResumeActivity

    @VisibleForTesting
    public boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            String reason) {

        if (r.getLifecycleState() == ON_RESUME) {
// finalStateRequest 为 true
            if (!finalStateRequest) {

            return false;
        }
        if (finalStateRequest) {
            r.hideForNow = false;
            r.activity.mStartedActivity = false;
        }
        try {
            r.activity.onStateNotSaved();
            r.activity.mFragments.noteStateNotSaved();
            checkAndBlockForNetworkAccess();
            if (r.pendingIntents != null) {
                deliverNewIntents(r, r.pendingIntents);
                r.pendingIntents = null;
            }
            if (r.pendingResults != null) {
                deliverResults(r, r.pendingResults, reason);
                r.pendingResults = null;
            }
// 回调 on_resume
            r.activity.performResume(r.startsNotResumed, reason);

            r.state = null;
            r.persistentState = null;
// 设置状态为 ON_RESUME
            r.setState(ON_RESUME);

            reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");
        } catch (Exception e) {
            if (!mInstrumentation.onException(r.activity, e)) {
                throw new RuntimeException("Unable to resume activity "
                        + r.intent.getComponent().toShortString() + ": " + e.toString(), e);
            }
        }
        return true;
    }

addView  相关的调用栈

WindowManagerImpl.addView()
    new ViewRoot
    // 保存到 mViews  mRoots  mParams
    ViewRoot.setView(xx)
        requestLayout // 检查主线程
            scheduleTraversals
                sendEmptyMessage
                handleMessage
                    performTraversals  // 2.11 测量 布局 绘制
                        ViewRoot.relayoutWindow
                            IWindowSession.relayout // 参考relayout的调用栈
                        draw
                            View.draw
                        scheduleTralScheduled // try again
        mWindowSession.addToDisplay // 2.15 与requestLayout同级
        // sWindowSession.add
            WMS.addWindow // 2.16
                new WindowState // 
                WindowState.attach // 
                    Session.windowAddedLocked
                        new SurfaceSession // 开辟一块内存,由SurfaceFlinger进行混合处理

 WindowManager是一个接口类,继承自接口ViewManager,从名称就知道它是用来管理Window的,它的实现类为WindowManagerImpl。如果我们想要对Window进行添加和删除就可以使用WindowManager

WindowManagerImpl 实现了 ViewManager  接口

public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);

 wm.addView(decor, l) 流程

 // WindowManagerImpl 增加 view ,mDecor为 DecorView

/frameworks/base/core/java/android/view/WindowManagerImpl.java

    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyTokens(params);

// WindowManagerGlobal 增加 view,mParentWindow 为 PhoneWindow
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }

// WindowManagerGlobal 增加 view,mParentWindow 为 PhoneWindow

/frameworks/base/core/java/android/view/WindowManagerGlobal.java

// WindowManagerGlobal  是单例模式
    @UnsupportedAppUsage
    public static WindowManagerGlobal getInstance() {
        synchronized (WindowManagerGlobal.class) {
            if (sDefaultWindowManager == null) {
                sDefaultWindowManager = new WindowManagerGlobal();
            }
            return sDefaultWindowManager;
        }
    }

=========
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
。。。。。

        ViewRootImpl root;
        View panelParentView = null;

....

            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
....

// 1-5-2-1-1)创建 ViewRootImpl 对象
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

// 将 DecorView 放到 mViews 数组中
            mViews.add(view);

// 将 ViewRootImpl 放到 mRoots 数组中
            mRoots.add(root);
            mParams.add(wparams);

            try {

// 1-5-2-2)ViewRootImpl 设置  view,为 DecorView,两者关联
                root.setView(view, wparams, panelParentView, userId);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

// 1-5-2-1-1)创建 ViewRootImpl 对象

/frameworks/base/core/java/android/view/ViewRootImpl.java

    public ViewRootImpl(Context context, Display display) {

// getWindowSession 获取为 IWindowSession ,与 wms 通信,对象为 wm/Session.java
// 不使用 useSfChoreographer 
        this(context, display, WindowManagerGlobal.getWindowSession(),
                false /* useSfChoreographer */);
    }


    public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
            boolean useSfChoreographer) {
        mContext = context;
// 缓存 session 与 wms 通信
        mWindowSession = session;
        mDisplay = display;
        mBasePackageName = context.getBasePackageName();
        mThread = Thread.currentThread();
        mLocation = new WindowLeaked(null);
        mLocation.fillInStackTrace();
        mWidth = -1;
        mHeight = -1;
        mDirty = new Rect();
        mTempRect = new Rect();
        mVisRect = new Rect();
        mWinFrame = new Rect();

// mWindow  为 W 对象
        mWindow = new W(this);
        mLeashToken = new Binder();
        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
        mViewVisibility = View.GONE;
        mTransparentRegion = new Region();
        mPreviousTransparentRegion = new Region();
        mFirst = true; // true for the first time the view is added
        mPerformContentCapture = true; // also true for the first time the view is added
        mAdded = false;

// 创建 View.AttachInfo 对象,传入 WindowSession,
        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                context);
        mCompatibleVisibilityInfo = new SystemUiVisibilityInfo();
        mAccessibilityManager = AccessibilityManager.getInstance(context);
        mAccessibilityManager.addAccessibilityStateChangeListener(
                mAccessibilityInteractionConnectionManager, mHandler);
        mHighContrastTextManager = new HighContrastTextManager();
        mAccessibilityManager.addHighTextContrastStateChangeListener(
                mHighContrastTextManager, mHandler);
        mViewConfiguration = ViewConfiguration.get(context);
        mDensity = context.getResources().getDisplayMetrics().densityDpi;
        mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
        mFallbackEventHandler = new PhoneFallbackEventHandler(context);

// 创建 Choreographer 对象
        mChoreographer = useSfChoreographer
                ? Choreographer.getSfInstance() : Choreographer.getInstance();
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
        mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));

。。。。

    }

ViewRootImp 与 Session 的关系:

ViewRootImpl获取Session的代理类,通过Binder::IPC通信;
Session持有WMS服务;
InputStage为事件传递相关的类,管理窗口焦点focus;
W代表当前操作的窗口, 是ViewRootImpl的内部类,且持有ViewRootImpl的弱引用

// 1-5-2-2)ViewRootImpl 设置  view,为 DecorView,两者关联

root.setView(view, wparams, panelParentView, userId)

/frameworks/base/core/java/android/view/ViewRootImpl.java

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
        synchronized (this) {
            if (mView == null) {
// 缓存 decorview
                mView = view;
。。。
                mSoftInputMode = attrs.softInputMode;
                mWindowAttributesChanged = true;

// 设置 mRootView 为 decorview
                mAttachInfo.mRootView = view;
                mAttachInfo.mScalingRequired = mTranslator != null;
                mAttachInfo.mApplicationScale =
                        mTranslator == null ? 1.0f : mTranslator.applicationScale;
                if (panelParentView != null) {
                    mAttachInfo.mPanelParentWindowToken
                            = panelParentView.getApplicationWindowToken();
                }
                mAdded = true;

。。。。。
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
// 1)请求vysnc,走绘制三大流程:requestLayout
                requestLayout();

。。。。
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    adjustLayoutParamsForCompatibility(mWindowAttributes);
                    controlInsetsForCompatibility(mWindowAttributes);

// 2)与wms 通信,增加 window:addToDisplayAsUser
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
                            mTempControls);

// 1)请求vysnc,走绘制三大流程:requestLayout

    @Override
    public void requestLayout() {

// 如果没有走 performLayout 流程
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

===========
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
// 消息同步屏障机制
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 给 Choreographer 编舞者发送 CALLBACK_TRAVERSAL 消息,请求一个 vsync,然后主线程走绘制三大流程
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

// 2)与wms 通信,增加 window:addToDisplayAsUser

/frameworks/base/services/core/java/com/android/server/wm/Session.java

// session 作为连接 wms 的中介
    @Override
    public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, int userId, InsetsState requestedVisibility,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls) {
        return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
                requestedVisibility, outInputChannel, outInsetsState, outActiveControls);
    }

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
            int displayId, int requestUserId, InsetsState requestedVisibility,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls) {
        Arrays.fill(outActiveControls, null);
        int[] appOp = new int[1];
        final boolean isRoundedCornerOverlay = (attrs.privateFlags
                & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;

// PhoneWindowManager 做权限检查,layout 的参数类型是 TYPE_BASE_APPLICATION
// PhoneWindowManager 也是个比较重要的类
        int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,
                appOp);
        if (res != ADD_OKAY) {
            return res;
        }

        WindowState parentWindow = null;
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        final int type = attrs.type;

        synchronized (mGlobalLock) {
            if (!mDisplayReady) {
                throw new IllegalStateException("Display has not been initialialized");
            }

// 2-1) 创建或者获取 DisplayContent 对象 getDisplayContentOrCreate
            final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);

.....
// type 为:TYPE_BASE_APPLICATION,不满足下列条件
            if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
                parentWindow = windowForClientLocked(null, attrs.token, false);

。。。
            ActivityRecord activity = null;

// hasParent  为false
            final boolean hasParent = parentWindow != null;

// 没有执行 addWindowToken,返回的 token 为null
            WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);

            final int rootType = hasParent ? parentWindow.mAttrs.type : type;
            boolean addToastWindowRequiresToken = false;
            final IBinder windowContextToken = attrs.mWindowContextToken;

            if (token == null) {
。。。
                } else if (mWindowContextListenerController.hasListener(windowContextToken)) {

//  2-2) 执行下列流程,创建 WindowToken 对象
                } else {
                    final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
                    token = new WindowToken.Builder(this, binder, type)
                            .setDisplayContent(displayContent)
                            .setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
                            .setRoundedCornerOverlay(isRoundedCornerOverlay)
                            .build();
                }

。。。。一些权限检查
。。。。

//  2-3) 创建 WindowState 对象
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], attrs, viewVisibility, session.mUid, userId,
                    session.mCanAddInternalSystemWindow);
            if (win.mDeathRecipient == null) {
                // Client has apparently died, so there is no reason to
                // continue.
                ProtoLog.w(WM_ERROR, "Adding window client %s"
                        + " that is dead, aborting.", client.asBinder());
                return WindowManagerGlobal.ADD_APP_EXITING;
            }

            if (win.getDisplayContent() == null) {
                ProtoLog.w(WM_ERROR, "Adding window to Display that has been removed.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }

            final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();

// DisplayPolicy  执行 adjustWindowParamsLw 调整 参数,为 TYPE_BASE_APPLICATION没有调整
            displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
            win.updateRequestedVisibility(requestedVisibility);

            res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
            if (res != ADD_OKAY) {
                return res;
            }

// 2-4) WinState去 打开InputChannel
            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
                win.openInputChannel(outInputChannel);
            }

            if (mUseBLAST) {
                res |= WindowManagerGlobal.ADD_FLAG_USE_BLAST;
            }

// 在 mWinAddedSinceNullFocus 数组增加这个 winstate
            if (displayContent.mCurrentFocus == null) {
                displayContent.mWinAddedSinceNullFocus.add(win);
            }

            if (excludeWindowTypeFromTapOutTask(type)) {
                displayContent.mTapExcludedWindows.add(win);
            }

// 2-5)调用WindowState 的attach 方法,其调用 Session 创建 SurfaceSession对象
            win.attach();
// 将 winstate 放到 map 中
            mWindowMap.put(client.asBinder(), win);
            win.initAppOpsState();

            final boolean suspended = mPmInternal.isPackageSuspended(win.getOwningPackage(),
                    UserHandle.getUserId(win.getOwningUid()));
            win.setHiddenWhileSuspended(suspended);

            final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
            win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);

            final ActivityRecord tokenActivity = token.asActivityRecord();
            if (type == TYPE_APPLICATION_STARTING && tokenActivity != null) {
                tokenActivity.mStartingWindow = win;
                ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
                        activity, win);
            }

            boolean imMayMove = true;
// 2-6) 在 winstate 的WinToken 中增加自己:addWindow
            win.mToken.addWindow(win);
            displayPolicy.addWindowLw(win, attrs);

            final WindowStateAnimator winAnimator = win.mWinAnimator;
// 设置为进入到动画
            winAnimator.mEnterAnimationPending = true;
            winAnimator.mEnteringAnimation = true;

// 看起来和动画相关
            if (activity != null && activity.isVisible()
                    && !prepareWindowReplacementTransition(activity)) {
                // If not, check if need to set up a dummy transition during display freeze
                // so that the unfreeze wait for the apps to draw. This might be needed if
                // the app is relaunching.
                prepareNoneTransitionForRelaunching(activity);
            }
。。。。

            boolean focusChanged = false;
            if (win.canReceiveKeys()) {

// 更新焦点
                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                        false /*updateInputWindows*/);
                if (focusChanged) {
                    imMayMove = false;
                }
            }

            win.getParent().assignChildLayers();

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

            ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
                    + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));

            if (win.isVisibleOrAdding() && displayContent.updateOrientation()) {
                displayContent.sendNewConfiguration();
            }

            // This window doesn't have a frame yet. Don't let this window cause the insets change.
            displayContent.getInsetsStateController().updateAboveInsetsState(
                    win, false /* notifyInsetsChanged */);

            getInsetsSourceControls(win, outActiveControls);
        }

addToDisplay方法中会调用了WMS的addWindow方法,并将自身也就是Session,作为参数传了进去,每个应用程序进程都会对应一个Session,WMS会用ArrayList来保存这些Session。这样剩下的工作就交给WMS来处理,在WMS中会为这个添加的窗口分配Surface,并确定窗口显示次序,可见负责显示界面的是画布Surface,而不是窗口本身。WMS会将它所管理的Surface交由SurfaceFlinger处理,SurfaceFlinger会将这些Surface混合并绘制到屏幕上。

// 2-1) 创建或者获取 DisplayContent 对象 getDisplayContentOrCreate

    RootWindowContainer mRoot;

    private DisplayContent getDisplayContentOrCreate(int displayId, IBinder token) {
        if (token != null) {
// mRoot 为 RootWindowContainer,这里返回是 null
            final WindowToken wToken = mRoot.getWindowToken(token);
            if (wToken != null) {
                return wToken.getDisplayContent();
            }
        }

// 调用 RootWindowContainer,返回 DisplayContent  对象
        return mRoot.getDisplayContentOrCreate(displayId);
    }

=======

    // TODO: Look into consolidating with getDisplayContent()
    @Nullable
    DisplayContent getDisplayContentOrCreate(int displayId) {
        DisplayContent displayContent = getDisplayContent(displayId);
        if (displayContent != null) {
            return displayContent;
        }

/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

    /** Returns the window token for the input binder if it exist in the system. */
    WindowToken getWindowToken(IBinder binder) {
        for (int i = mChildren.size() - 1; i >= 0; --i) {
// 如下分析,setWindowManager创建了DisplayContent, 获取到 DisplayContent
            final DisplayContent dc = mChildren.get(i);

// 需要调用 addWindowToken,才有对应的 WindowToken
            final WindowToken wtoken = dc.getWindowToken(binder);
            if (wtoken != null) {
                return wtoken;
            }
        }
        return null;
    }

=========
// mChildren 是再父类WindowContainer.java addChild 赋值的

514      protected void addChild(E child, Comparator<E> comparator) {
515          if (!child.mReparenting && child.getParent() != null) {
516              throw new IllegalArgumentException("addChild: container=" + child.getName()
517                      + " is already a child of container=" + child.getParent().getName()
518                      + " can't add to container=" + getName());
519          }
520  
521          int positionToAdd = -1;
522          if (comparator != null) {
523              final int count = mChildren.size();
524              for (int i = 0; i < count; i++) {
525                  if (comparator.compare(child, mChildren.get(i)) < 0) {
526                      positionToAdd = i;
527                      break;
528                  }
529              }
530          }
531  
532          if (positionToAdd == -1) {
533              mChildren.add(child);
534          } else {
535              mChildren.add(positionToAdd, child);
536          }

========
// 在 系统进程初始化的时候有 setWindowManager
    void setWindowManager(WindowManagerService wm) {
        mWindowManager = wm;
        mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);
        mDisplayManager.registerDisplayListener(this, mService.mUiHandler);
        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);

        final Display[] displays = mDisplayManager.getDisplays();
        for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {
            final Display display = displays[displayNdx];
// 创建 DisplayContent 对象
            final DisplayContent displayContent = new DisplayContent(display, this);
// 增加这个 child
            addChild(displayContent, POSITION_BOTTOM);
            if (displayContent.mDisplayId == DEFAULT_DISPLAY) {
                mDefaultDisplay = displayContent;
            }
        }

综上 // 调用 RootWindowContainer,返回 DisplayContent  对象,是在RootWindowContainer调用 setWindowManager创建的

//  2-2) 执行下列流程,创建 WindowToken 对象

/frameworks/base/services/core/java/com/android/server/wm/WindowToken.java

    static class Builder {
        private final WindowManagerService mService;
        private final IBinder mToken;
        @WindowType
        private final int mType;

        private boolean mPersistOnEmpty;
        private DisplayContent mDisplayContent;
        private boolean mOwnerCanManageAppTokens;
        private boolean mRoundedCornerOverlay;
        private boolean mFromClientToken;
        @Nullable
        private Bundle mOptions;

        Builder(WindowManagerService service, IBinder token, int type) {
            mService = service;
            mToken = token;
            mType = type;
        }
.。。。
        WindowToken build() {
            return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent,
                    mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions);
        }

//  2-3) 创建 WindowState 对象

/frameworks/base/services/core/java/com/android/server/wm/WindowState.java

IWindow c 为:ViewRootImpl 的 final W mWindow,与客户端通信

WindowToken token,: 为 WindowToken
WindowState parentWindow: 为null

    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
            int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow) {
        this(service, s, c, token, parentWindow, appOp, a, viewVisibility, ownerId, showUserId,
                ownerCanAddInternalSystemWindow, new PowerManagerWrapper() {
                    @Override
                    public void wakeUp(long time, @WakeReason int reason, String details) {
                        service.mPowerManager.wakeUp(time, reason, details);
                    }

                    @Override
                    public boolean isInteractive() {
                        return service.mPowerManager.isInteractive();
                    }
                });
    }

    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
            int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
            PowerManagerWrapper powerManagerWrapper) {
        super(service);
// SurfaceControl.Transaction 对象
        mTmpTransaction = service.mTransactionFactory.get();
        mSession = s;
// viewrootimpl 的 W
        mClient = c;
        mAppOp = appOp;
        mToken = token;
// 为 null
        mActivityRecord = mToken.asActivityRecord();
        mOwnerUid = ownerId;
        mShowUserId = showUserId;
        mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
        mWindowId = new WindowId(this);
        mAttrs.copyFrom(a);
        mLastSurfaceInsets.set(mAttrs.surfaceInsets);
        mViewVisibility = viewVisibility;

// policy是 PhoneWindowManager
        mPolicy = mWmService.mPolicy;
        mContext = mWmService.mContext;
        DeathRecipient deathRecipient = new DeathRecipient();
        mPowerManagerWrapper = powerManagerWrapper;
        mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
        mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
                mActivityRecord != null
                        ? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
                getDisplayId()));
        mInputWindowHandle.setOwnerPid(s.mPid);
        mInputWindowHandle.setOwnerUid(s.mUid);
        mInputWindowHandle.setName(getName());
        mInputWindowHandle.setPackageName(mAttrs.packageName);
        mInputWindowHandle.setLayoutParamsType(mAttrs.type);

// 。。。。。。。
        } else {
            // The multiplier here is to reserve space for multiple
            // windows in the same type layer.

// 这里乘以 10000 然后加 TYPE_LAYER_OFFSET = 1000==》 11000
            mBaseLayer = mPolicy.getWindowLayerLw(this)
                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
            mSubLayer = 0;
            mIsChildWindow = false;
            mLayoutAttached = false;
            mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
                    || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
            mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
        }
// 为 false
        mIsFloatingLayer = mIsImWindow || mIsWallpaper;

        if (mActivityRecord != null && mActivityRecord.mShowForAllUsers) {
            // Windows for apps that can show for all users should also show when the device is
            // locked.
            mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
        }

// 创建 WindowStateAnimator 对象
        mWinAnimator = new WindowStateAnimator(this);
        mWinAnimator.mAlpha = a.alpha;

        mRequestedWidth = 0;
        mRequestedHeight = 0;
        mLastRequestedWidth = 0;
        mLastRequestedHeight = 0;
        mLayer = 0;
        mOverrideScale = mWmService.mAtmService.mCompatModePackages.getCompatScale(
                mAttrs.packageName, s.mUid);

。。。。

// 2-4) WinState去 打开InputChannel

/frameworks/base/services/core/java/com/android/server/wm/WindowState.java

    void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
// 获取名字
        String name = getName();

// 调用 wms 的inputmanagerservice 去 创建channel: nativeCreateInputChannel
        mInputChannel = mWmService.mInputManager.createInputChannel(name);
        mInputChannelToken = mInputChannel.getToken();
        mInputWindowHandle.setToken(mInputChannelToken);

// 将其token 放入到 wms 的焦点map 中
        mWmService.mInputToWindowMap.put(mInputChannelToken, this);
        if (outInputChannel != null) {
            mInputChannel.copyTo(outInputChannel);
        } else {

// 2-5)调用WindowState 的attach 方法,其调用 Session 创建 SurfaceSession对象

    void attach() {
        if (DEBUG) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
        mSession.windowAddedLocked();
    }

调用 Session 的 windowAddedLocked

/frameworks/base/services/core/java/com/android/server/wm/Session.java

    SurfaceSession mSurfaceSession;

    void windowAddedLocked() {
        if (mPackageName == null) {
            final WindowProcessController wpc = mService.mAtmService.mProcessMap.getProcess(mPid);
            if (wpc != null) {

// 获取包名
                mPackageName = wpc.mInfo.packageName;
                mRelayoutTag = "relayoutWindow: " + mPackageName;
            } else {
                Slog.e(TAG_WM, "Unknown process pid=" + mPid);
            }
        }
        if (mSurfaceSession == null) {
// 创建 SurfaceSession 对象,mSurfaceSession 是public 方法,可以通过对象.mSurfaceSession 获取
            mSurfaceSession = new SurfaceSession();
            ProtoLog.i(WM_SHOW_TRANSACTIONS, "  NEW SURFACE SESSION %s", mSurfaceSession);
// 将这个应用进程创建的 session 添加到 wms 的 mSessions 数组中
            mService.mSessions.add(this);
            if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
                mService.dispatchNewAnimatorScaleLocked(this);
            }
        }
// 增加这个window 的数量
        mNumWindow++;
    }

// 创建 SurfaceSession 对象

/frameworks/base/core/java/android/view/SurfaceSession.java

// 创建一个链接与 surfaceflinger 通信
    /** Create a new connection with the surface flinger. */
    @UnsupportedAppUsage
    public SurfaceSession() {
        mNativeClient = nativeCreate();
    }

===========
/frameworks/base/core/jni/android_view_SurfaceSession.cpp

static jlong nativeCreate(JNIEnv* env, jclass clazz) {
// 创建 SurfaceComposerClient 对象
    SurfaceComposerClient* client = new SurfaceComposerClient();
    client->incStrong((void*)nativeCreate);
// 返回引用给java 层
    return reinterpret_cast<jlong>(client);
}

=========
// 创建 SurfaceComposerClient 对象

/frameworks/native/libs/gui/SurfaceComposerClient.cpp

SurfaceComposerClient::SurfaceComposerClient()
    : mStatus(NO_INIT)
{
}

// 初始化对象时会调用 onFirstRef
void SurfaceComposerClient::onFirstRef() {
// 获取与surfaceflinger 通信的客户端
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr && mStatus == NO_INIT) {
        sp<ISurfaceComposerClient> conn;

// 调用surfaceflinger 的 createConnection 方法
        conn = sf->createConnection();
        if (conn != nullptr) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

// 2-6) 在 winstate 的WinToken 中增加自己:addWindow

/frameworks/base/services/core/java/com/android/server/wm/WindowToken.java

    void addWindow(final WindowState win) {
        ProtoLog.d(WM_DEBUG_FOCUS,
                "addWindow: win=%s Callers=%s", win, Debug.getCallers(5));

// 这里为 false
        if (win.isChildWindow()) {
            // Child windows are added to their parent windows.
            return;
        }

// 先创建个 SurfaceControl,设置了 setSurfaceControl,SurfaceControl
        if (mSurfaceControl == null) {
            createSurfaceControl(true /* force */);
        }
        if (!mChildren.contains(win)) {
            ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", win, this);

// 调用父类将win 增加到 mChildren 中
            addChild(win, mWindowComparator);
            mWmService.mWindowsChanged = true;
            // TODO: Should we also be setting layout needed here and other places?
        }
    }

三、移除窗口操作 removeWindow

调用 WindowManagerGlobal 的removeView 方法

/frameworks/base/core/java/android/view/WindowManagerGlobal.java

431      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
432      public void removeView(View view, boolean immediate) {
433          if (view == null) {
434              throw new IllegalArgumentException("view must not be null");
435          }
436  
437          synchronized (mLock) {
438              int index = findViewLocked(view, true);
439              View curView = mRoots.get(index).getView();

// 加锁移除这个 view
440              removeViewLocked(index, immediate);
441              if (curView == view) {
442                  return;
443              }
444  
445              throw new IllegalStateException("Calling with view " + view
446                      + " but the ViewAncestor is attached to " + curView);
447          }
448      }

=============
492      private void removeViewLocked(int index, boolean immediate) {
493          ViewRootImpl root = mRoots.get(index);
494          View view = root.getView();
495  
496          if (root != null) {
497              root.getImeFocusController().onWindowDismissed();
498          }

// 通过 ViewRootImpl 的 die 方法去移除
499          boolean deferred = root.die(immediate);
500          if (view != null) {
501              view.assignParent(null);
502              if (deferred) {
503                  mDyingViews.add(view);
504              }
505          }
506      }

// 通过 ViewRootImpl 的 die 方法去移除

/frameworks/base/core/java/android/view/ViewRootImpl.java

8117      boolean die(boolean immediate) {
8118          // Make sure we do execute immediately if we are in the middle of a traversal or the damage
8119          // done by dispatchDetachedFromWindow will cause havoc on return.

// 如果是马上移除,并且没有在遍历绘制的话,处理Vsync 事件
8120          if (immediate && !mIsInTraversal) {
// 执行 dodie 方法
8121              doDie();
8122              return false;
8123          }
8124  
8125          if (!mIsDrawing) {
8126              destroyHardwareRenderer();
8127          } else {
8128              Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
8129                      "  window=" + this + ", title=" + mWindowAttributes.getTitle());
8130          }
// 这里其实也需要执行 dodie 方法
8131          mHandler.sendEmptyMessage(MSG_DIE);
8132          return true;
8133      }

==============
8135      void doDie() {
// 看是否在主线程中处理
8136          checkThread();
8137          if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
8138          synchronized (this) {
8139              if (mRemoved) {
8140                  return;
8141              }
8142              mRemoved = true;
// 在增加view 的时候,设置了 mAdded 为true
8143              if (mAdded) {
8144                  dispatchDetachedFromWindow();
8145              }
8146  
8147              if (mAdded && !mFirst) {
8148                  destroyHardwareRenderer();
8149  
。。。。
====================
4968      void dispatchDetachedFromWindow() {
4969          // Make sure we free-up insets resources if view never received onWindowFocusLost()
4970          // because of a die-signal
4971          mInsetsController.onWindowFocusLost();
4972          mFirstInputStage.onDetachedFromWindow();
4973          if (mView != null && mView.mAttachInfo != null) {
4974              mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
4975              mView.dispatchDetachedFromWindow();
4976          }
4977  
4978          mAccessibilityInteractionConnectionManager.ensureNoConnection();
4979          mAccessibilityManager.removeAccessibilityStateChangeListener(
4980                  mAccessibilityInteractionConnectionManager);
4981          mAccessibilityManager.removeHighTextContrastStateChangeListener(
4982                  mHighContrastTextManager);
4983          removeSendWindowContentChangedCallback();
4984  
// 销毁硬件渲染相关的对象
4985          destroyHardwareRenderer();
4986  
4987          setAccessibilityFocus(null, null);
4988  
4989          mInsetsController.cancelExistingAnimations();
4990  
4991          mView.assignParent(null);
4992          mView = null;
4993          mAttachInfo.mRootView = null;
4994  

// 销毁创建的surface
4995          destroySurface();
4996  
4997          if (mInputQueueCallback != null && mInputQueue != null) {
4998              mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
4999              mInputQueue.dispose();
5000              mInputQueueCallback = null;
5001              mInputQueue = null;
5002          }
5003          try {

// 与 wms 通信移除这个window
5004              mWindowSession.remove(mWindow);

// 与 wms 通信移除这个window

/frameworks/base/services/core/java/com/android/server/wm/Session.java

216      @Override
217      public void remove(IWindow window) {
218          mService.removeWindow(this, window);
219      }

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

2023  
2024      void removeWindow(Session session, IWindow client) {
2025          synchronized (mGlobalLock) {
2026              WindowState win = windowForClientLocked(session, client, false);
2027              if (win != null) {

// 通过 WindowState 去移除 removeIfPossible
2028                  win.removeIfPossible();
2029                  return;
2030              }

// 通过 WindowState 去移除 removeIfPossible

/frameworks/base/services/core/java/com/android/server/wm/WindowState.java

2417      @Override
2418      void removeIfPossible() {
2419          super.removeIfPossible();
2420          removeIfPossible(false /*keepVisibleDeadWindow*/);
2421      }

===========
2423      private void removeIfPossible(boolean keepVisibleDeadWindow) {
2424          mWindowRemovalAllowed = true;
2425          ProtoLog.v(WM_DEBUG_ADD_REMOVE,
2426                  "removeIfPossible: %s callers=%s", this, Debug.getCallers(5));
2427  
。。。。
2491                  // If we are not currently running the exit animation, we need to see about starting one

// 如果还在执行动画
2492                  wasVisible = isWinVisibleLw();
。。。
// 如果还是动画,这里去执行动画
2509                  if (wasVisible) {
2510                      final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
2511  
2512                      // Try starting an animation.
2513                      if (mWinAnimator.applyAnimationLocked(transit, false)) {
2514                          mAnimatingExit = true;
2515  
。。。。。。。
// 如果上面没有return,则立即执行移除方法 removeImmediately
2550              removeImmediately();

// 去更新焦点
2559              mWmService.updateFocusedWindowLocked(isFocused()
2560                              ? UPDATE_FOCUS_REMOVING_FOCUS
2561                              : UPDATE_FOCUS_NORMAL,
2562                      true /*updateInputWindows*/);

// 立即执行移除方法 removeImmediately

2361      @Override
2362      void removeImmediately() {

// 调用 WindowContainer ,移除创建的 mSurfaceControl
2363          super.removeImmediately();
2364  
2365          if (mRemoved) {
2366              // Nothing to do.
2367              ProtoLog.v(WM_DEBUG_ADD_REMOVE,
2368                      "WS.removeImmediately: %s Already removed...", this);
2369              return;
2370          }
2371  
2372          mRemoved = true;

// 移除input 相关的对象
2402          disposeInputChannel();
2403  

// WindowStateAnimator销毁 surface
2404          mWinAnimator.destroySurfaceLocked(mTmpTransaction);
// 提交事务
2405          mTmpTransaction.apply();
// 将与wms 通信的session 移除
2406          mSession.windowRemovedLocked();
2407          try {
2408              mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);

WindowStateAnimator销毁 surface

 /frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java

    void destroySurfaceLocked(SurfaceControl.Transaction t) {
        final ActivityRecord activity = mWin.mActivityRecord;
        if (activity != null) {
            if (mWin == activity.mStartingWindow) {
                activity.startingDisplayed = false;
            }
        }

        if (mSurfaceController == null) {
            return;
        }

// 设置 WindowState 的状态是隐藏的 mHidden
        mWin.mHidden = true;

        try {
            if (DEBUG_VISIBILITY) {
                logWithStack(TAG, "Window " + this + " destroying surface "
                        + mSurfaceController + ", session " + mSession);
            }
            ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "SURFACE DESTROY: %s. %s",
                    mWin, new RuntimeException().fillInStackTrace());
// 销毁surface
            destroySurface(t);

            mWallpaperControllerLocked.hideWallpapers(mWin);
        } catch (RuntimeException e) {
            Slog.w(TAG, "Exception thrown when destroying Window " + this
                    + " surface " + mSurfaceController + " session " + mSession + ": "
                    + e.toString());
        }

// windowstate 设置没有surface 
        mWin.setHasSurface(false);
        if (mSurfaceController != null) {

// WindowSurfaceController.java 设置显示状态为 false
            mSurfaceController.setShown(false);
        }

// 回收 mSurfaceController
        mSurfaceController = null;

// 设置绘制状态为 NO_SURFACE
        mDrawState = NO_SURFACE;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/220178.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

luceda ipkiss教程 39:修改版图text字体的粗细

通过修改font的line_width就可以修改版图中text字体的粗细&#xff1a; 代码如下&#xff1a; from si_fab import all as pdk import ipkiss3.all as i3class demo(i3.PCell):class Layout(i3.LayoutView):def _generate_elements(self, elems):elems i3.PolygonText(layer…

处理k8s中创建ingress失败

创建ingress&#xff1a; 如果在创建过程中出错了&#xff1a; 处理方法就是&#xff1a; kubectl get ValidatingWebhookConfiguration kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission 然后再次创建&#xff0c;发现可以&#xff1a;

AI封测需求强劲, AMD、英伟达等巨头将助推产业链增长 | 百能云芯

近期&#xff0c;超微&#xff08;AMD&#xff09;和英伟达&#xff08;NVIDIA&#xff09;相继发布了新一轮AI芯片&#xff0c;为封测产业链注入了新的活力。据业内人士透露&#xff0c;客户端对AI封测的需求愈发强劲&#xff0c;整体量能超过原先的估计&#xff0c;其中日月光…

【yolov8】与yolov5的区别及改进详解

图像识别技术在物联网、智能监控等领域广泛应用。而深度学习中的目标检测技术&#xff0c;能够帮助我们对图像中的目标进行识别&#xff0c;进而实现自动化控制。目前&#xff0c;Yolov8和Yolov5是目标检测领域热门的模型。 yolo目标检测原理yolov5详解yolov8yolov8结构图Conv模…

使用cpolar内网穿透实现内网SeaFile私有云盘的公网访问

文章目录 1. 前言2. SeaFile云盘设置2.1 Owncould的安装环境设置2.2 SeaFile下载安装2.3 SeaFile的配置 3. cpolar内网穿透3.1 Cpolar下载安装3.2 Cpolar的注册3.3 Cpolar云端设置3.4 Cpolar本地设置 4.公网访问测试5.结语 1. 前言 现在我们身边的只能设备越来越多&#xff0c…

解决cad找不到msvcr100.dll的有效方法,完美修复dll问题

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是由于找不到msvcr100.dll文件而导致CAD软件无法正常运行的情况&#xff0c;系统无法找到所需的动态链接库文件。但是通过一些简单的解决方法&#xff0c;我们可以快速解决这个问题并继续我们的…

深度学习|keras编程基础

使用 tensorflow.keras 接口&#xff0c;组装神经网络层次&#xff0c;训练并预测 参考链接&#xff1a;https://blog.csdn.net/March_A/article/details/129240390?ops_request_misc&request_id&biz_id102&utm_termtensorflow.keras%20&utm_mediumdistribute…

IOday3作业

1> 使用文件IO完成对图像的读写操作 #include<myhead.h>int main(int argc, const char *argv[]) {//只读打开图片int fd-1;if((fd open("./R-C.bmp",O_RDWR))-1){perror("open");return -1;}//向后便宜两个字节找到大小的起始地址lseek(fd,2,S…

全网最新最全面的Appium自动化:Appium常用操作之混合应用webview页面操作--待补充!

上下文操作&#xff1a; 在appium中&#xff0c;对于混合应用&#xff0c;需要进行WebView页面和原生应用的切换 常用的方法如下&#xff1a; 1、context(self) / current_context(self)&#xff1a;返回当前会话的当前上下文&#xff0c;context可以理解为可进入的窗口。对于…

智慧物联可视化大屏赋能设备管理和城市运行

在智慧物联的时代&#xff0c;万物互联的网络正在构筑起一个智能化的世界。无论是家居设备、汽车、还是工业设备&#xff0c;都能通过互联网实现智能化管理和控制。随着物联网技术的发展&#xff0c;我们迅速步入了一个千姿百态的智慧时代。智慧物联逐渐渗透进我们的日常生活&a…

【Maven】依赖管理

1. 依赖管理 1.1 依赖配置 依赖&#xff1a;指当前项目运行所需要的jar包。一个项目中可以引入多个依赖。 依赖引入步骤&#xff1a;在pom.xml中编写标签&#xff0c;在标签中使用引入坐标&#xff0c;定义坐标的 groupId、artifactId、version&#xff0c;最后点击刷新&…

搬运工让你分分钟了解Web接口测试

01、什么是接口 百度说&#xff1a;接口泛指实体把自己提供给外界的一种抽象化物&#xff08;可以为另一实体&#xff09;&#xff0c;用以由内部操作分离出外部沟通方法&#xff0c;使其能被内部修改而不影响外界其他实体与其交互的方式 上面这句有点抽象&#xff0c;网上的…

线程池,及7大参数,4大拒绝策略详解

线程池&#xff0c;及7大参数&#xff0c;4大拒绝策略详解 1. 前言 1.1 什么是线程池&#xff1f; 线程池是一种利用池化技术思想来实现的线程管理技术&#xff0c;主要是为了复用线程、便利地管理线程和任务、并将线程的创建和任务的执行解耦开来。我们可以创建线程池来复用…

Upload-Labs-Linux

打开后看到了一堆题目&#xff0c;试着做做吧&#xff01; 一 上传一句话木马&#xff0c;告诉我们不能传带这些后缀的文件 传个图片马试试 发现传上去了&#xff0c;抓包修改一下 复制图片地址 验证一下&#xff0c;然后拿去蚁剑去连接 回到根目录下就看到flag了

在vscode下将ipynb文件转成markdown(.md文件)的方法

这里写自定义目录标题 写在最前面安装nbconvert工具vscode界面 or cmd终端 写在最前面 正常情况下&#xff0c;可以在vscode的ipynb界面点击上面的三个点&#xff0c;里面有export导出&#xff0c;可以选择直接输出html和pdf 但是没有markdown&#xff08;.md文件&#xff09;…

30个Python小游戏,小白练手,我都能玩一天【内附源码】

给大家带来30个 Python 小游戏&#xff0c;一定要收藏&#xff01; 文末获取完整代码 有手就行 1、吃金币 import os import cfg import sys import pygame import random from modules import *游戏初始化 def initGame():# 初始化pygame, 设置展示窗口pygame.init()screen…

解决方案:Mac 安装 pip

python3 --version 通过以下命令来下载pip&#xff1a; curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py curl命令允许您指定一个直接下载链接。使用-o选项来设置下载文件的名称。 通过运行以下命令安装下载的包&#xff1a; python3 get-pip.py

102.套接字-Socket网络编程4(TCP通信流程)

目录 TCP编程流程 套接字函数 1.创建套接字 2.绑定地址 3.监听连接请求 4.接受连接 5. 连接到服务器 6. 发送数据 7. 接收数据 8.关闭套接字 服务器端通信流程 示例代码 客户端通信流程 代码示例 TCP编程流程 TCP是一个面向连接的&#xff0c;安全的&#xff0c;流…

深入学习Synchronized各种使用方法

文章目录 前言一、synchronized关键字通用在下面四个地方&#xff1a;1.1synchronized修饰实例方法1.2synchronized修饰静态方法&#xff1a;1.3synchronized修饰实例方法的代码块1.4synchronized修饰静态方法的代码块2.读入数据 二.Sychronized关键特性2.1互斥2.2 刷新内存2.3…

从零开始学习 JS APL(二):完整指南和实例解析

大家好&#xff01;这里是关于JS APL第二部分的知识点和笔记以及练习题 目录 大家好&#xff01;这里是关于JS APL第二部分的知识点和笔记以及练习题 我们分以下几点来说&#xff1a; 1、事件监听&#xff08;绑定&#xff09;&#xff1a; 目标&#xff1a;能够给 DOM元素…