一、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
内部的mViews
、mRoots
、mParams
、mDyingViews
分别管理窗口的试图、主线程、布局参数以及死亡过程中的视图;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;}