【安卓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 到 99public 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 到 1999public 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 到 2999public 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;@Deprecatedpublic static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;@Deprecatedpublic static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;@Deprecatedpublic static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;@Deprecatedpublic static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;@Deprecatedpublic 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;@Deprecatedpublic 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 

    @Overridepublic void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) {unscheduleGcIdler();mSomeActivitiesChanged = true;// 先执行 performResumeActivityif (!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  为 trueboolean willBeVisible = !a.mStartedActivity;if (!willBeVisible) {willBeVisible = ActivityClient.getInstance().willActivityBeVisible(a.getActivityToken());}if (r.window == null && !a.mFinished && willBeVisible) {// 获取的对象是: PhoneWindowr.window = r.activity.getWindow();
// decor 是 new DecorView 对象View decor = r.window.getDecorView();// DecorView 设置不可见decor.setVisibility(View.INVISIBLE);// 在lauchactivity时候分析:activity.getWindowManager 是 WindowManagerImplViewManager wm = a.getWindowManager();WindowManager.LayoutParams l = r.window.getAttributes();// 设置 activity 的 mDecor 为:DecorView 对象,先 install。。。a.mDecor = decor;// 这里设置 layout 的类型为 TYPE_BASE_APPLICATIONl.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

    @VisibleForTestingpublic boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest,String reason) {if (r.getLifecycleState() == ON_RESUME) {
// finalStateRequest 为 trueif (!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_resumer.activity.performResume(r.startsNotResumed, reason);r.state = null;r.persistentState = null;
// 设置状态为 ON_RESUMEr.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  mParamsViewRoot.setView(xx)requestLayout // 检查主线程scheduleTraversalssendEmptyMessagehandleMessageperformTraversals  // 2.11 测量 布局 绘制ViewRoot.relayoutWindowIWindowSession.relayout // 参考relayout的调用栈drawView.drawscheduleTralScheduled // try againmWindowSession.addToDisplay // 2.15 与requestLayout同级// sWindowSession.addWMS.addWindow // 2.16new WindowState // WindowState.attach // Session.windowAddedLockednew 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();@Overridepublic void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {applyTokens(params);// WindowManagerGlobal 增加 view,mParentWindow 为 PhoneWindowmGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,mContext.getUserId());}

// WindowManagerGlobal 增加 view,mParentWindow 为 PhoneWindow

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

// WindowManagerGlobal  是单例模式@UnsupportedAppUsagepublic 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 addedmPerformContentCapture = true; // also true for the first time the view is addedmAdded = 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) {
// 缓存 decorviewmView = view;
。。。mSoftInputMode = attrs.softInputMode;mWindowAttributesChanged = true;// 设置 mRootView 为 decorviewmAttachInfo.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,走绘制三大流程:requestLayoutrequestLayout();。。。。try {mOrigWindowType = mWindowAttributes.type;mAttachInfo.mRecomputeGlobalAttributes = true;collectViewAttributes();adjustLayoutParamsForCompatibility(mWindowAttributes);controlInsetsForCompatibility(mWindowAttributes);// 2)与wms 通信,增加 window:addToDisplayAsUserres = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), userId,mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,mTempControls);

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

    @Overridepublic 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 的中介@Overridepublic 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 对象 getDisplayContentOrCreatefinal 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  为falsefinal boolean hasParent = parentWindow != null;// 没有执行 addWindowToken,返回的 token 为nullWindowToken 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去 打开InputChannelfinal 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 数组增加这个 winstateif (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 中增加自己:addWindowwin.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,这里返回是 nullfinal WindowToken wToken = mRoot.getWindowToken(token);if (wToken != null) {return wToken.getDisplayContent();}}// 调用 RootWindowContainer,返回 DisplayContent  对象return mRoot.getDisplayContentOrCreate(displayId);}=======// TODO: Look into consolidating with getDisplayContent()@NullableDisplayContent 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, 获取到 DisplayContentfinal DisplayContent dc = mChildren.get(i);// 需要调用 addWindowToken,才有对应的 WindowTokenfinal 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          }========
// 在 系统进程初始化的时候有 setWindowManagervoid 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);
// 增加这个 childaddChild(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;@WindowTypeprivate final int mType;private boolean mPersistOnEmpty;private DisplayContent mDisplayContent;private boolean mOwnerCanManageAppTokens;private boolean mRoundedCornerOverlay;private boolean mFromClientToken;@Nullableprivate 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() {@Overridepublic void wakeUp(long time, @WakeReason int reason, String details) {service.mPowerManager.wakeUp(time, reason, details);}@Overridepublic 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 的 WmClient = c;mAppOp = appOp;mToken = token;
// 为 nullmActivityRecord = mToken.asActivityRecord();mOwnerUid = ownerId;mShowUserId = showUserId;mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;mWindowId = new WindowId(this);mAttrs.copyFrom(a);mLastSurfaceInsets.set(mAttrs.surfaceInsets);mViewVisibility = viewVisibility;// policy是 PhoneWindowManagermPolicy = 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==》 11000mBaseLayer = 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;}
// 为 falsemIsFloatingLayer = 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: nativeCreateInputChannelmInputChannel = 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. */@UnsupportedAppUsagepublic SurfaceSession() {mNativeClient = nativeCreate();}===========
/frameworks/base/core/jni/android_view_SurfaceSession.cppstatic 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.cppSurfaceComposerClient::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));// 这里为 falseif (win.isChildWindow()) {// Child windows are added to their parent windows.return;}// 先创建个 SurfaceControl,设置了 setSurfaceControl,SurfaceControlif (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 的状态是隐藏的 mHiddenmWin.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());
// 销毁surfacedestroySurface(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 设置显示状态为 falsemSurfaceController.setShown(false);}// 回收 mSurfaceControllermSurfaceController = null;// 设置绘制状态为 NO_SURFACEmDrawState = NO_SURFACE;}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SMART PLC温度采集模块温度转换FC(梯形图+SCL代码)

对于模拟量输入采集,温度变送器等我们可以利用线性转换功能块完成温度采集,西门子PLC有温度采集模块,利用温度采集模块采集温度我们的转换关系无需进行线性变换,下面我们具体介绍。温度采集线性转换功能块请参考下面的文章链接: https://rxxw-control.blog.csdn.net/arti…

Hadoop学习笔记(HDP)-Part.06 安装OracleJDK

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

外包干了8个月,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

HarmonyOS带大家创建自己的第一个Page页面并实现路由跳转

我们 在开发过程中 经常会看到 被 艾特修饰的代码 有限像 java中的注解 在 harmonyOS 中 这叫 装饰器 被关键字装饰取来的代码 会具备某某功能 我们这里先来创建一个新的界面 在pages 目录下 右键 如下图 选择page创建 这里 我们取名叫 AppView 然后点击右下角 Finish 这样…

P1006 [NOIP2008 提高组] 传纸条

洛谷的题 网址&#xff1a;P1006 [NOIP2008 提高组] 传纸条 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 还是动态规划&#xff0c;这题和我上一篇博客写的题差不多 区别在于&#xff0c;这个地图不再是方阵&#xff0c;路线不能交叉&#xff0c;而且地图的大小可能大得多…

IDEA中,光标移动快捷键(Shift + 滚轮前后滚动:当前文件的横向滚动轴滚动。)

除此之外&#xff0c;其他常用的光标移动快捷键包括&#xff1a; Shift 滚轮前后滚动&#xff1a;当前文件的横向滚动轴滚动。Shiftenter&#xff1a;快速将鼠标移动到下一行。Ctrl ]&#xff1a;移动光标到当前所在代码的花括号结束位置。Ctrl 左方向键&#xff1a;光标跳转…

内衣迷你洗衣机什么牌子好?好用不贵的内衣洗衣机推荐

由于内衣洗衣机在目前的市场上越来越受欢迎&#xff0c;使得不少的小伙伴都在犹豫要不要为自己入手一台专用的内衣洗衣机&#xff0c;专门来清洗一些内衣裤等等贴身衣物&#xff0c;这个问题的答案是很有必要的&#xff0c;因为目前市场上的家用大型洗衣机对衣物只能够起到清洁…

SpringBoot_02

Web后端开发_07 SpringBoot_02 SpringBoot原理 1.配置优先级 1.1配置 SpringBoot中支持三种格式的配置文件&#xff1a; application.propertiesapplication.ymlapplication.yaml properties、yaml、yml三种配置文件&#xff0c;优先级最高的是properties 配置文件优先级…

前端又出新轮子Nue.js,但还是低代码更香!

前言 别TM卷了&#xff01;&#xff01;&#xff01; 自从前后端分离以来&#xff0c;前端前端的车轮滚滚向前&#xff0c;轮子造的越来越圆。每个人都在适应这个轮子的节奏&#xff0c;稍微不注意就会被甩出车轮之外。 调侃归调侃&#xff0c;既然口子已经开了&#xff0c;…

一键抠图2:C/C++实现人像抠图 (Portrait Matting)

一键抠图2&#xff1a;C/C实现人像抠图 (Portrait Matting) 目录 一键抠图2&#xff1a;C/C实现人像抠图 (Portrait Matting) 1. 前言 2. 抠图算法 3. 人像抠图算法MODNet &#xff08;1&#xff09;模型训练 &#xff08;2&#xff09;将Pytorch模型转换ONNX模型 &…

作业12.5

1.定义一个基类 Animal&#xff0c;其中有一个虛函数perform&#xff08;)&#xff0c;用于在子类中实现不同的表演行为。 #include <iostream>using namespace std; class Animal { private:int weight; public:Animal(){}Animal(int weight):weight(weight){}virtual …

全网最新最牛的Appium自动化:Appium常用操作之TouchAction操作

TouchAction操作 Appium的辅助类&#xff0c;主要针对手势操作&#xff0c;比如滑动、长按、拖动等。其原理是将一系列的动作放在一个链条中&#xff0c;然后将该链条传递给服务器。服务器接受到该链条后&#xff0c;解析各个动作&#xff0c;逐个执行。 TouchAction类支持的动…

如何销售汽车之 汽车销售技巧和话术

如何销售汽车之 汽车销售技巧和话术 当前&#xff0c;汽车销售市场的竞争日益激烈&#xff0c;消费者对汽车的需求和要求也越来越高。但是市场竞争车型也非常多&#xff0c;如何更好的做好销售业绩突破&#xff0c;提高汽车销量&#xff0c;创造汽车销售佳绩&#xff0c;就需要…

什么是网络爬虫?有什么用?怎么爬?

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 【导读】 网络爬虫也叫做网络机器人&#xff0c;可以代替人们自动地在互联网中进行数据信息的采集与整理。 在大数据时代&#xff0c;信息的采集是一项重要的工作&#xff0c;如果单纯靠人力进行信息采集&#xff0c;不仅低…

k8s 安装部署

一&#xff0c;准备3台机器&#xff0c;安装docker&#xff0c;kubelet、kubeadm、kubectl firewall-cmd --state 使用下面命令改hostname的值&#xff1a;(改为k8s-master01)另外两台改为相应的名字。 172.188.32.43 hostnamectl set-hostname k8s-master01 172.188.32.4…

Matlab 生成license

参考下面两个帖子 https://ww2.mathworks.cn/matlabcentral/answers/389888-matlab https://www.mathworks.com/matlabcentral/answers/131749-id-id-id-id 登陆 https://ww2.mathworks.cn/licensecenter 针对R2020b版本,点击下面红框生成 ip addr | grep ether看第一行 根据…

Geodesic in Heat: 一种测地线计算方法

在之前的博客中&#xff0c;我已经介绍过了使用Fast Marching算法计算测地线。Fast Marching的好处是实现简单&#xff0c;方便扩展在点云上。但是缺点是精度不够&#xff0c;求解不平滑。早在2013年&#xff0c;Crane et al. [1]就已经提出利用热流来估算测地距离。我很早就知…

Hadoop学习笔记(HDP)-Part.14 安装YARN+MR

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

一文7个步骤教你搭建测试web测试项目实战环境,

​今天小编&#xff0c;给大家总结下web 测试实战的相关内容&#xff0c;一起来学习下吧&#xff01; web项目实战可按顺序依次为&#xff1a;【搭建测试环境】、【需求评审】、【编写测试计划】、【分析测试点.编写测试用例】、【用例评审】、【执行用例提bug】、【测试报告】…

编写并调试运行一个简单的 Java 应用程序,显示自己的学号、姓名、兴趣爱好等。

源代码&#xff1a; public class Main { public static void main(String[] args) { System.out.println("学号是:""0233217821"); System.out.println("姓名是:""赵港"); System.out.println("兴趣爱好是:""运动&qu…