【Android Framework系列】第7章 WMS原理

1 前言

前面【Android Framework系列】第5章 AMS启动流程【Android Framework系列】第6章 AMS原理之Launcer启动流程我们分析了AMS启动以及Launcher启动的整体流程,那Launcher(Activity启动)后UI是如何渲染到屏幕并且展示出来的呢?我们这章节来探讨一下。

2 WMS简介

2.1 WMS的主要职责

WindowManagerService简称WMS,是系统的核心服务,主要分为四大部分,分别是窗口管理窗口动画输入系统中转站Surface管理

1.窗口管理:WMS是窗口的管理者,负责窗口的启动,添加和删除,另外窗口的大小也是由WMS管理的,管理窗口的核心成员有DisplayContent,WindowToken和WindowState。窗口的显示顺序、尺寸、位置, 最终都会反馈SurfaceFlinger。

2.窗口动画:窗口间进行切换时,使用窗口动画可以更好看一些,窗口动画由WMS动画子系统来负责,动画的管理系统为WindowAnimator。

3.输入系统的中转站:通过对窗口触摸而产生的触摸事件,InputManagerServer(IMS)会对触摸事件进行处理,他会寻找一个最合适的窗口来处理触摸反馈信息,WMS是窗口的管理者,因此理所当然的就成为了输入系统的中转站。

4.Surface管理:窗口并不具备绘制的功能,因此每个窗口都需要有一个块Surface来供自己绘制,为每个窗口分配Surface是由WMS来完成。

WMS的职责图:

2.2 什么是Window

2.2.1 Window是什么?

表示一个窗口的概念,是所有View的直接管理者,任何视图都通过Window呈现,由Window->DecorView->View,Activity的setContentView()底层通过Window完成。

Window是一个抽象类,具体实现是PhoneWindow。这个可以看Activity#attach()方法源码

创建Window需要通过WindowManager创建,WindowManager是外界访问Window的入口,Window具体实现位于WindowManagerService中,WindowManagerWindowManagerService的交互是通过IPC完成。

2.2.2 Window和View关系

Window和View通过ViewRootImpl建立联系,View是视图的呈现方式,但是不能单独存在,必须依附在Window这个抽象的概念上。
WMS把所有的用户消息发给View/ViewGroup,但是在View/ViewGroup处理消息的过程中,有一些操作是公共的, Window把这些公共行为抽象出来, 这就是Window。

2.2.3 Activity、View、Window三者之间的关系

Activity启动过程其中的attach()方法中初始化了PhoneWindow,而PhoneWindowWindow的唯一实现类。

然后Activity通过setContentViewView设置到了PhoneWindow上,而View通过WindowManageraddView()removeView()updateViewLayout()View进行管理。

2.3 WMS整体框架

3 WMS启动流程

WMSPMSAMS的启动都是在SystemServer进程,系统启动后Zygote进程第一个fork出SystemServer进程,进入到SystemServer:main()->run()->startBootstrapServices()启动引导服务,进而完成WMSPMSAMS等核心服务的启动。

在Android系统所有的核心服务都会经过SystemServer启动,WMSPMSAMS都是一样。SystemServer会在手机开机时启动运行。关于SystemServer是如何启动的可以查看文章【Android Framework系列】第3章 Zygote进程相关【Android车载系列】第10章 系统服务-SystemServer源码分析(API28)

本文基于Android10(Q)的源码做分析

3.1 SystemServer启动WMS

我们知道WMS是在SystemServer进程中被启动,下面我们来看看具体是怎么启动的WMS:

/frameworks/base/services/java/com/android/server/SystemServer.java

java 复制代码
877      private void startOtherServices() {
......
			  // 1.IMS、WMS服务创建,并add到ServiceManager中
1016          inputManager = new InputManagerService(context);
1023          wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
1024                      new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);

1025          ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
1026                      DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
1027          ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
1028                      /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
......
			  // 2.将WMS设置到AMS中
1032          mActivityManagerService.setWindowManager(wm);
......
			  // 3.WMS创建完成后调用
1036          wm.onInitReady();
			  // 4.IMS启动
1057              inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
1058          inputManager.start();
......
			  // 5.WMS初始化显示信息
1138          wm.displayReady();
			  // 6.通知WMS初始化工作已经完成,内部调用了WindowManagerPolicy#systemReady()
1942          wm.systemReady();

由于WMSIMS有着比较强的关联,所以这里我们分析WMS,会顺带简单分析一下IMS。

从上面代码,关于WMS、IMS启动相关的核心两个点:

  1. SystemServer#WindowManagerService.main(),传入了IMS,因为WMSIMS的中转站。观察WindowManagerService.main()方法可以知道他是运行在SystemServerrun()方法中,换句话说就是运行在system_server线程中。
  2. SystemServer#ServiceManager.addService(),将WMSIMS注册到ServerManager里面,这样客户端想要使用WMS就需要先去ServiceManager中查询信息,然后与WMS所在的进程建立通信,这样客户端就可以使用WMS

下面我们先来看看1中调用WMS的main()方法创建WMS

3.2 WMS的main()

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

java 复制代码
963      public static WindowManagerService main(final Context context, final InputManagerService im,
964              final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
965              ActivityTaskManagerService atm) {
966          return main(context, im, showBootMsgs, onlyCore, policy, atm,
967                  SurfaceControl.Transaction::new);
968      }
......
975      public static WindowManagerService main(final Context context, final InputManagerService im,
976              final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
977              ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
			 // 创建WMS
978          DisplayThread.getHandler().runWithScissors(() ->
979                  sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
980                          atm, transactionFactory), 0);
981          return sInstance;
982      }

通过DisplayThread.getHandler()方法获取到了DisplayThreadHandler实例。用来处理需要低延时显示的相关操作,runWithScissors表达式中创建了WMS对象。
runWithScissors方法中,WMS的创建是运行在android.display线程中的。需要注意的是,runWithScissors方法的第二个参数timeout传入的是0

HandlerrunWithScissors()方法:A线程向B线程发送一个消息,使A线程进入阻塞,等待B线程处理完消息后再继续执行

我们来简单看一下Handler的这个runWithScissors方法:

/frameworks/base/core/java/android/os/Handler.java

java 复制代码
568      public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
569          if (r == null) {
570              throw new IllegalArgumentException("runnable must not be null");
571          }
572          if (timeout < 0) {
573              throw new IllegalArgumentException("timeout must be non-negative");
574          }
575  
			 // 判断当前调用该方法的线程,是否该handler创建时的线程
576          if (Looper.myLooper() == mLooper) {
577              r.run();
578              return true;
579          }
580  
581          BlockingRunnable br = new BlockingRunnable(r);
582          return br.postAndWait(this, timeout);
583      }

根据每个线程只有一个Looper 的原理来判断当前system_server线程,是否Handler所指向的android.display线程,如果是则直接执行Runnable#run()方法,如果不是则调用BlockingRunnable#postAndWait()方法,并将当前线程的Runnable作为参数传进去。

我们继续看WindowManagerService的构造方法:

3.3 WMS的构造方法

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

java 复制代码
1000      private WindowManagerService(Context context, InputManagerService inputManager,
1001              boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
1002              ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
......
			  // 保存IMS, 持有了IMS引用。
1027          mInputManager = inputManager; // Must be before createDisplayContentLocked.
......
			  // 初始化WindowManagerPolicy,它用来定义一个窗口测量所需要遵循的规范。
1033          mPolicy = policy;
			  // 创建了WindowAnimator,它用于管理所有的窗口动画。
1034          mAnimator = new WindowAnimator(this);
			  // 创建RootWindowContainer对象,根窗口容器
1035          mRoot = new RootWindowContainer(this);
1036  
1037          mWindowPlacerLocked = new WindowSurfacePlacer(this);
1038          mTaskSnapshotController = new TaskSnapshotController(this);
1039  
1040          mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,
1041                  Choreographer.getInstance());
1042  
1043          LocalServices.addService(WindowManagerPolicy.class, mPolicy);
			  // 获取DisplayManager服务
1045          mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);

			  // 获取AMS、ATMS,并持有其引用
1078          mActivityManager = ActivityManager.getService();
1079          mActivityTaskManager = ActivityTaskManager.getService();
1080          mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
1081          mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
......
			  // 将LocalService添加到LocalServices中
1168          LocalServices.addService(WindowManagerInternal.class, new LocalService());
1169      }

WMS构造函数主要完成以下几点核心操作:

  1. 获取AMSATMSIMSDisplayManager,并持有其引用
  2. 初始化WindowManagerPolicy,它用来定义一个窗口测量所需要遵循的规范。
  3. 创建了WindowAnimator,它用于管理所有的窗口动画。
  4. 创建RootWindowContainer对象,根窗口容器
  5. 获取DisplayManager服务
  6. 创建WMSLocalService添加到LocalServices

到这里我们的WMS已经被创建完成,我们继续看3.1中WMS创建完成后调用WMSonInitReady()方法:

3.4 WMS的onInitReady()

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

java 复制代码
984      private void initPolicy() {
985          UiThread.getHandler().runWithScissors(new Runnable() {
986              @Override
987              public void run() {
988                  WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
989                  mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
990              }
991          }, 0);
992      }
......
1175      public void onInitReady() {
1176          initPolicy();
1177  
1178          // Add ourself to the Watchdog monitors.
1179          Watchdog.getInstance().addMonitor(this);
1180  
1181          openSurfaceTransaction();
1182          try {
1183              createWatermarkInTransaction();
1184          } finally {
1185              closeSurfaceTransaction("createWatermarkInTransaction");
1186          }
1187  
1188          showEmulatorDisplayOverlayIfNeeded();
1189      }

WMSmain()方法类似,WindowManagerPolicy(简称WMP)是一个接口,init()的具体实现在PhoneWindowManager(PWM)中,init()方法运行在android.ui线程中。因此他的线程优先级要高于android.display线程,必须等init()方法执行完成后,android.display线程才会被唤醒从而继续执行下面的代码。

3.5 三个线程的执行

一共提供了三个线程,分别是system_serverandroid.displayandroid.ui,他们之间的关系如下图所示:

  1. system_server线程中会调用main()方法,main()方法中会创建WMS,创建的过程是在android.display线程中,他的优先级会高一些,创建完成后才会唤醒system_server线程

  2. WMS创建完成后会调用onInitReady()中的initPolicy()方法,该方法中调用PWMinit()方法,init()android.ui线程,方法调用完成之后就会唤醒system_server线程

  3. 之后就会接着执行system_server中的代码,例如displayReady()等。

线程的执行顺序如下:
system_server线程->android.display线程->system_server线程->android.ui线程->system_server线程

到这里,WMS已被创建并启动完成,下面我们继续看运行中的WMS,到底是怎么完成窗体管理:

4 WMS原理

Window的操作有两大部分:一部分是WindowManager来处理,一部分是WMS来处理。WMS并不关心View的具体内容,WMS只关心各个应用显示的界面大小层级值等,这些数据都包含在WindowManager.LayoutParams中。

WindowManager通过WindowManagerGlobal创建ViewRootImpl,也就是View的根。在ViewRootImpl中完成对View的绘制等操作,然后通过IPC获取到Session,最终通过WMS来进行处理。

WindowManager三大方法,最后都是通过Binder跨进程调用AMS对应的增加更新删除方法。下面我们来详细分析:

4.1 添加、更新、删除View的三大方法

WindowManager 所提供的功能很简单,常用的只有三个方法:
1. 添加 View: addView()
2. 更新 View: updateViewLayout()
3. 删除 View: removeView()

这三个方法定义在 ViewManager 接口中,而 WindowManager 继承了ViewManager

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

java 复制代码
22  public interface ViewManager
23  {
......
34      public void addView(View view, ViewGroup.LayoutParams params);
35      public void updateViewLayout(View view, ViewGroup.LayoutParams params);
36      public void removeView(View view);
37  }

由此看来**WindowManager操作Window的过程更像是在操作Window中的View**,我们平常简单的那种可以拖动的Window效果其实是很好实现的,只需要修改LayoutParams中的x,y值就可以改变Window的位置。首先给View设置onTouchListener,然后在onTouch方法中不断的更新View的位置即可。

Window的添加需要通过WindowManager的addViewupdateViewLayoutremoveView来实现,WindowManager是一个接口,他的真正实现是WindowManageImpl。如下:

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

java 复制代码
92      @Override
93      public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
94          applyDefaultToken(params);
95          mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
96      }
97  
98      @Override
99      public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
100          applyDefaultToken(params);
101          mGlobal.updateViewLayout(view, params);
102      }
......
119      @Override
120      public void removeView(View view) {
121          mGlobal.removeView(view, false);
122      }

可以看到WindowManagerImpl并没有直接实现Window三大操作,而是全部交给了WindowManagerGlobal来处理。

下面我们先来看看WindowManagerGlobal#addView()

4.2 View的添加addView()

4.2.1 WindowManagerGlobal#addView()

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

java 复制代码
309      public void addView(View view, ViewGroup.LayoutParams params,
310              Display display, Window parentWindow) {
......
			 // 大小、位置等信息
321          final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
......
335          ViewRootImpl root;
336          View panelParentView = null;
......
			 // 创建 ViewRootImpl,并赋值给 root
377          root = new ViewRootImpl(view.getContext(), display);
			 // 设置 View 的params
379          view.setLayoutParams(wparams);
			 // 将 view,RootRootImpl,wparams 添加到列表中
			 // mViews 所有 Window 对应的 View
			 // mRoots 所有 Window 对应的 ViewRootImpl
			 // mParams 所有 Window 所对应的布局参数
381          mViews.add(view);
382          mRoots.add(root);
383          mParams.add(wparams);
384  
385          // do this last because it fires off messages to start doing things
386          try {
				//调用 ViewRootImpl 来更新界面并完成 Window 的添加过程
387          	root.setView(view, wparams, panelParentView);
388          } catch (RuntimeException e) {
......
394          }
396		}
397  
398      public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
399          if (view == null) {
400              throw new IllegalArgumentException("view must not be null");
401          }
402          if (!(params instanceof WindowManager.LayoutParams)) {
403              throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
404          }
405  
406          final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
407  
408          view.setLayoutParams(wparams);
409  
410          synchronized (mLock) {
411              int index = findViewLocked(view, true);
412              ViewRootImpl root = mRoots.get(index);
413              mParams.remove(index);
414              mParams.add(index, wparams);
415              root.setLayoutParams(wparams, false);
416          }
417      }
418  
419      @UnsupportedAppUsage
420      public void removeView(View view, boolean immediate) {
421          if (view == null) {
422              throw new IllegalArgumentException("view must not be null");
423          }
424  
425          synchronized (mLock) {
426              int index = findViewLocked(view, true);
427              View curView = mRoots.get(index).getView();
428              removeViewLocked(index, immediate);
429              if (curView == view) {
430                  return;
431              }
432  
433              throw new IllegalStateException("Calling with view " + view
434                      + " but the ViewAncestor is attached to " + curView);
435          }
436      }

我们看到addView中最终调用的是ViewRootImpl#setView(),先来看一下这个方法:

4.2.2 ViewRootImpl#setView()

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

java 复制代码
760      public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
761          synchronized (this) {
762              if (mView == null) {
763                  mView = view;
......
850                  // Schedule the first layout -before- adding to the window
851                  // manager, to make sure we do the relayout before receiving
852                  // any other events from the system.
853                  requestLayout();
......
860                  try {
861                      mOrigWindowType = mWindowAttributes.type;
862                      mAttachInfo.mRecomputeGlobalAttributes = true;
863                      collectViewAttributes();
864                      res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
865                              getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
866                              mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
867                              mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
868                              mTempInsets);
869                      setFrame(mTmpFrame);
......
883                  }
......
987              }
988          }
989      }
......
1417      @Override
1418      public void requestLayout() {
1419          if (!mHandlingLayoutInLayoutRequest) {
1420              checkThread();
1421              mLayoutRequested = true;
1422              scheduleTraversals();
1423          }
1424      }

这个方法首先会调用requestLayout()来进行一次刷新请求,其中scheduleTraversals()是View绘制的入口
requestLayout()调用之后,调用了mWindowSession.addToDisplay()方法,来完成最终的Window的添加过程。

在上面代码中,mWindowSession的类型是IWindowSession,他是一个Binder对象,真正的实现是Session,也就是Window的添加过程是一次IPC调用。

Session内部会通过WindowManagerService#addWindow()来实现Window的添加,如下所示:

4.2.3 Session#addToDisplay()

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

java 复制代码
153      @Override
154      public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
155              int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
156              Rect outStableInsets, Rect outOutsets,
157              DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
158              InsetsState outInsetsState) {
			 // 这里的mService是WMS
159          return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
160                  outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
161                  outInsetsState);
162      }

4.2.4 WindowManagerService#addWindow()

从上面可以知道,添加View最后调用的是AMS的addWindow()方法,我们来看看这个方法到底做了什么:

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

java 复制代码
1220      public int addWindow(Session session, IWindow client, int seq,
1221              LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
1222              Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
1223              DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
1224              InsetsState outInsetsState) {
1225          int[] appOp = new int[1];
			  // 检查权限,mPolicy 的实现类是 PhoneWindowManager
1226          int res = mPolicy.checkAddPermission(attrs, appOp);
1227          if (res != WindowManagerGlobal.ADD_OKAY) {
1228              return res;
1229          }
......
1237          synchronized (mGlobalLock) {
				  // displayId 来获得 Window 要添加到那个 DisplayContent,
				  // 如果没有找到,则返回 WindowManagerGlobal.ADD_INVALID_DISPLAY 状态。
				  // 其中`DisplayContent` 用来描述一块屏幕。
1242              final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
......
				  // 判断 type 的窗口类型(100 - 1999),如果是子类型,
				  // 必须要有父窗口,并且父窗口不能是子窗口类型
1260              if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
1261                  parentWindow = windowForClientLocked(null, attrs.token, false);
1262                  if (parentWindow == null) {
1263                      Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
1264                            + attrs.token + ".  Aborting.");
1265                      return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
1266                  }
1267                  if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
1268                          && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
1269                      Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
1270                              + attrs.token + ".  Aborting.");
1271                      return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
1272                  }
1273              }
......
1287              AppWindowToken atoken = null;
1288              final boolean hasParent = parentWindow != null;
				  // 通过 displayContent 的 getWindowToken 方法
				  // 得到父窗口的 WindowToken 或者是当前窗口的 WindowToken。
1291              WindowToken token = displayContent.getWindowToken(
1292                      hasParent ? parentWindow.mAttrs.token : attrs.token);
1293              // If this is a child window, we want to apply the same type checking rules as the
1294              // parent window type.
1295              final int rootType = hasParent ? parentWindow.mAttrs.type : type;
1296  
1297              boolean addToastWindowRequiresToken = false;
1298  
1299              if (token == null) {
......
					 // 如果 token 等于 null,并且不是应用窗口或者是其他类型的窗口,
				  	 // 则窗口就是系统类型(例如 Toast),就进行隐式创建WindowToken,
				  	 // 这说明我们添加窗口时是可以不向WMS提供WindowToken的,
				  	 // WindowToken的隐式和显式创建是需要区分,第四个参数false表示隐式创建。
				  	 // 一般系统窗口都不需要添加token,WMS 会隐式创建。例如 Toast 类型的窗口。
1347                  token = new WindowToken(this, binder, type, false, displayContent,
1348                          session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
1349              } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
					  // 断是否为 应用窗口,如果是 应用窗口,
					  // 就会将WindowToken转换为针对于应用程序窗口的AppWindowToken,
					  // 然后再继续进行判断
1350                  atoken = token.asAppWindowToken();
1351                  if (atoken == null) {
......
1354                      return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
1355                  }
......
1364              } 
......
				  // 创建了WindowState,保存了窗口的所有状态信息(例如 WMS ,Session,WindowToken等),
				  // 在 WMS 中它代表一个窗口。WindowState 与窗口是一一对应的关系。
1418              final WindowState win = new WindowState(this, session, client, token, parentWindow,
1419                      appOp[0], seq, attrs, viewVisibility, session.mUid,
1420                      session.mCanAddInternalSystemWindow);
				  // 判断请求添加窗口的客户端是否已经死亡,如果死亡则不会执行下面逻辑。
1421              if (win.mDeathRecipient == null) {
1422                  // Client has apparently died, so there is no reason to
1423                  // continue.
1424                  Slog.w(TAG_WM, "Adding window client " + client.asBinder()
1425                          + " that is dead, aborting.");
1426                  return WindowManagerGlobal.ADD_APP_EXITING;
1427              }
1428  
1429              if (win.getDisplayContent() == null) {
1430                  Slog.w(TAG_WM, "Adding window to Display that has been removed.");
1431                  return WindowManagerGlobal.ADD_INVALID_DISPLAY;
1432              }
1433  
				  // 调用了 adjustWindowParamsLw 方法,这里会根据窗口的 type 类型
				  // 对窗口的 LayoutParams 的一些成员变量进行修改。
				  // 源码注释信息为 清理来自客户端的布局参数。
				  // 允许策略做一些事情,比如确保特定类型的窗口不能输入焦点。
1434              final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
1435              displayPolicy.adjustWindowParamsLw(win, win.mAttrs, Binder.getCallingPid(),
1436                      Binder.getCallingUid());
1437              win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
1438  
				  // 调用了 prepareAddWindowLw 方法用于准备将窗口添加到系统中。
1439              res = displayPolicy.prepareAddWindowLw(win, attrs);
......
				  // 当前APP申请建立SurfaceFlinger的链接
1493              win.attach();
				  // 将 WindowState 添加到 mWindowMap 中,mWindowMap 是各种窗口的集合。
1494              mWindowMap.put(client.asBinder(), win);
				  // 将 WindowState 添加到对应的 WindowToken 中
				  //(实际上就是保存在 WindowToken 的父类 WindowContainer),
				  // 这样 WindowToken 就包含了相同组件的 WindowState。
1514              win.mToken.addWindow(win);
......
1616          }
......
1624          return res;
1625      }
......
 		  // 如下面代码,从 mRoot(RootWindowContainer)对应的 DisplayContent,
		  // 如果没有,则创建一个再返回,RootWindowContainer 是用来管理 DisplayContent 的。
1641      private DisplayContent getDisplayContentOrCreate(int displayId, IBinder token) {
1642          if (token != null) {
1643              final WindowToken wToken = mRoot.getWindowToken(token);
1644              if (wToken != null) {
1645                  return wToken.getDisplayContent();
1646              }
1647          }
1648  
1649          DisplayContent displayContent = mRoot.getDisplayContent(displayId);
1650  
1651          // Create an instance if possible instead of waiting for the ActivityManagerService to drive
1652          // the creation.
1653          if (displayContent == null) {
1654              final Display display = mDisplayManager.getDisplay(displayId);
1655  
1656              if (display != null) {
1657                  displayContent = mRoot.createDisplayContent(display, null /* controller */);
1658              }
1659          }
1660  
1661          return displayContent;
1662      }

WMSaddWindow方法返回各种状态,例如添加成功失败无效的display等,这些状态定义在WindowManagerGloabl中。主要做了这几件事:

  1. 检查参数等设置
  2. 检查Token
  3. 将Token、Window保存到WMS中
  4. 将WindowState保存到Session中

4.2.5 addView()总结

如此一来,Window的添加过程就交给了WMS去处理。WMS会为其分配Surface,确定窗口显示的次序,最终通过SurfaceFlinger将这些Surface绘制到屏幕上,WindowManagerService#addWindow()这部分我们后面再做分析。

我们先来梳理一下WindowManager#addView()流程:

  1. 首先调用的是WindowManagerImpl.addView()

    在addView中将实现委托给了WindowManagerGlobal.addView()

  2. WindowManagerGlobal.addView()

    在addView中创建了ViewRootImpl赋值给了root。然后将view,params,root全部存入了各自的列表中。最后调用了ViewRootImpl.setView()

  3. ViewRootImpl.setView()

    setView()中通过调用requestLayout()完成刷新的请求,接着会通过IWindowSession的addToDisplay()来完成最终的Window添加的过程,IWindowSession是一个Binder对象,真正的实现类是Session,也就是说Window的添加过程试一次IPC的调用。

  4. Session.addToDisplay():

    通过WindowManagerService#addWindow()来实现Window的添加。

我们继续看第二大方法WindowManagerGlobal#updateViewLayout()

4.3 View的更新updateViewLayout()

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

java 复制代码
......
398      public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
399          if (view == null) {
400              throw new IllegalArgumentException("view must not be null");
401          }
402          if (!(params instanceof WindowManager.LayoutParams)) {
403              throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
404          }
405  
406          final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
407  
			 // 将更新的参数设置到 view 中
408          view.setLayoutParams(wparams);
409  
410          synchronized (mLock) {
				 // 获取到 view 在列表中的索引
411              int index = findViewLocked(view, true);
				 // 拿到 view 对应的 ViewRootImpl
412              ViewRootImpl root = mRoots.get(index);
				 // 从参数列表中移除旧的参数
413              mParams.remove(index);
				 // 将新的参数添加到指定的位置中
414              mParams.add(index, wparams);
				 // 调用 ViewRootImpl.setLayoutPrams 对参数进行更新
415              root.setLayoutParams(wparams, false);
416          }
417      }
.......

WindowManagerGlobal#updateViewLayout实际上调用ViewRootImpl.setLayoutPrams()对参数进行更新

4.3.1 ViewRootImpl#setLayoutParams()

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

java 复制代码
1215      void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
1216          synchronized (this) {
......
1271              if (newView) {
1272                  mSoftInputMode = attrs.softInputMode;
1273                  requestLayout();
1274              }
......
1285              scheduleTraversals();
1286          }
1287      }
......
1689      void scheduleTraversals() {
1690          if (!mTraversalScheduled) {
1691              mTraversalScheduled = true;
1692              mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
				  // 刷新布局
1693              mChoreographer.postCallback(
1694                      Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1695              if (!mUnbufferedInputDispatch) {
1696                  scheduleConsumeBatchedInput();
1697              }
1698              notifyRendererOfFramePending();
1699              pokeDrawLockIfNeeded();
1700          }
1701      }
......
1712      void doTraversal() {
1713          if (mTraversalScheduled) {
1714              mTraversalScheduled = false;
1715              mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
1716  
1717              if (mProfile) {
1718                  Debug.startMethodTracing("ViewAncestor");
1719              }
1720  
1721              performTraversals();
1722  
1723              if (mProfile) {
1724                  Debug.stopMethodTracing();
1725                  mProfile = false;
1726              }
1727          }
1728      }
......
		  // 后面重点分析这个方法
1944      private void performTraversals() {
......
2264      	  relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
......
2769	  }
......
		  private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
6902              boolean insetsPending) throws RemoteException {
......
			  // 通过Binder调用Session的relayout()方法,
			  // 内部实际上调用了AMS的relayoutWindow()方法
6930          int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
6931                  (int) (mView.getMeasuredWidth() * appScale + 0.5f),
6932                  (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
6933                  insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
6934                  mTmpFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
6935                  mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
6936                  mPendingMergedConfiguration, mSurfaceControl, mTempInsets);
......
6959          return relayoutResult;
6960      }
......
7595      final class TraversalRunnable implements Runnable {
7596          @Override
7597          public void run() {
7598              doTraversal();
7599          }
7600      }
7601      final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
......

上面的ViewRootImpl#setLayoutParams方法中主要做了两件事:

  1. 调用了scheduleTraversals方法来对View重新策略,布局,重绘。
  2. 通过WindowSession来更新Window视图,这个过程是由WMSrelayoutWindow()来实现,这同样也是一个IPC过程。

注意:这里的mTraversalRunnablemChoreographer对象的回调,实际上是请求VSYNC信号后,返回VSYNC信号的回调。

4.3.2 Choreographer 编舞者

上面我们看到调用了Choreographer#postCallback()绘制请求,进入消息队列发送,在Choreographer创建阶段我们可以看到他的绘制节奏固定是16.63ms每帧,帧率存储在框架层面的系统属性文件当中。

java 复制代码
		 // 回调(回调函数控制)
149      private static final int MSG_DO_FRAME = 0;
		 // 向底层请求垂直同步信号
150      private static final int MSG_DO_SCHEDULE_VSYNC = 1;
		 // 帧绘制(具体开始绘制)
151      private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
......
254      private Choreographer(Looper looper, int vsyncSource) {
255          mLooper = looper;
256          mHandler = new FrameHandler(looper);
257          mDisplayEventReceiver = USE_VSYNC
258                  ? new FrameDisplayEventReceiver(looper, vsyncSource)
259                  : null;
			 // 指上一次帧绘制时间点
260          mLastFrameTimeNanos = Long.MIN_VALUE;
261  
			 // 帧间时长,一般等于16.63ms
262          mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
263  
264          mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
265          for (int i = 0; i <= CALLBACK_LAST; i++) {
266              mCallbackQueues[i] = new CallbackQueue();
267          }
268          // b/68769804: For low FPS experiments.
269          setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
270      }
......
		 // 进入postCallback后发现该线程接口对象进入一个队列
		 // 以数组+列表形成存储,然后进行一组消息发送
447      private void postCallbackDelayedInternal(int callbackType,
448              Object action, Object token, long delayMillis) {
449          if (DEBUG_FRAMES) {
450              Log.d(TAG, "PostCallback: type=" + callbackType
451                      + ", action=" + action + ", token=" + token
452                      + ", delayMillis=" + delayMillis);
453          }
454  
455          synchronized (mLock) {
456              final long now = SystemClock.uptimeMillis();
457              final long dueTime = now + delayMillis;
458              mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
459  
460              if (dueTime <= now) {
461                  scheduleFrameLocked(now);
462              } else {
463                  Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
464                  msg.arg1 = callbackType;
465                  msg.setAsynchronous(true);
466                  mHandler.sendMessageAtTime(msg, dueTime);
467              }
468          }
469      }
......
885      private final class FrameHandler extends Handler {
886          public FrameHandler(Looper looper) {
887              super(looper);
888          }
889  
890          @Override
891          public void handleMessage(Message msg) {
892              switch (msg.what) {
893                  case MSG_DO_FRAME:
894                      doFrame(System.nanoTime(), 0);
895                      break;
896                  case MSG_DO_SCHEDULE_VSYNC:
897                      doScheduleVsync();
898                      break;
899                  case MSG_DO_SCHEDULE_CALLBACK:
900                      doScheduleCallback(msg.arg1);
901                      break;
902              }
903          }
904      }

4.3.2.1 Choreographer#doScheduleCallback()

java 复制代码
813      void doScheduleCallback(int callbackType) {
814          synchronized (mLock) {
815              if (!mFrameScheduled) {
816                  final long now = SystemClock.uptimeMillis();
817                  if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
						 // 是否是延迟时间内,是则调用帧锁
818                      scheduleFrameLocked(now);
819                  }
820              }
821          }
822      }
......
620      private void scheduleFrameLocked(long now) {
621          if (!mFrameScheduled) {
622              mFrameScheduled = true;
623              if (USE_VSYNC) {
624                  if (DEBUG_FRAMES) {
625                      Log.d(TAG, "Scheduling next frame on vsync.");
626                  }
					 // 如果是在主线程上,则向底层请求同步信号
					 // 如果是在子线程的绘制消息,则通过消息发送执行
					 // 两者最终都是走到scheduleVsyncLocked()
631                  if (isRunningOnLooperThreadLocked()) {
632                      scheduleVsyncLocked();
633                  } else {
634                      Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
635                      msg.setAsynchronous(true);
636                      mHandler.sendMessageAtFrontOfQueue(msg);
637                  }
638              } else {
639                  final long nextFrameTime = Math.max(
640                          mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
641                  if (DEBUG_FRAMES) {
642                      Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
643                  }
644                  Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
645                  msg.setAsynchronous(true);
646                  mHandler.sendMessageAtTime(msg, nextFrameTime);
647              }
648          }
649      }

如果是在主线程上,则向底层请求同步信号,

如果是在子线程的绘制消息,则通过消息发送执行,

两者最终都是走到scheduleVsyncLocked()

4.3.2.2 Choreographer#doScheduleVsync()

java 复制代码
805      void doScheduleVsync() {
806          synchronized (mLock) {
807              if (mFrameScheduled) {
808                  scheduleVsyncLocked();
809              }
810          }
811      }

这里被触发只有一种状况就是在子线程中调用的绘制

4.3.2.3 Choreographer#scheduleVsyncLocked()

java 复制代码
824      @UnsupportedAppUsage
825      private void scheduleVsyncLocked() {
826          mDisplayEventReceiver.scheduleVsync();
827      }

4.3.2.3 DisplayEventReceiver#scheduleVsync()

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

java 复制代码
174      public void scheduleVsync() {
175          if (mReceiverPtr == 0) {
176              Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
177                      + "receiver has already been disposed.");
178          } else {
179              nativeScheduleVsync(mReceiverPtr);
180          }
181      }
......

4.3.2.3 DisplayEventReceiver#onVsync()

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

java 复制代码
		 // vsync来的时候底层会通过JNI回调这个方法
		 // 这里是屏幕刷新机制重点,应用必须向底层请求vsync信号
		 // 然后下一次vsync信号来的时候,会通过JNI通知到应用
		 // 然后接下来才到应用绘制逻辑
186      private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
187          onVsync(timestampNanos, physicalDisplayId, frame);
188      }

最后调用native方法nativeScheduleVsync()向底层Surfacefilnger请求垂直同步信号,

底层Surfacefilnger信号同步发送过来后会回调onVsync()

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

java 复制代码
906      private final class FrameDisplayEventReceiver extends DisplayEventReceiver
907              implements Runnable {
908          private boolean mHavePendingVsync;
909          private long mTimestampNanos;
910          private int mFrame;
911  
912          public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
913              super(looper, vsyncSource);
914          }
915  
916          // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
917          // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
918          // for the internal display implicitly.
919          @Override
920          public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
......
926              long now = System.nanoTime();
927              if (timestampNanos > now) {
928                  Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
929                          + " ms in the future!  Check that graphics HAL is generating vsync "
930                          + "timestamps using the correct timebase.");
931                  timestampNanos = now;
932              }
933  
934              if (mHavePendingVsync) {
935                  Log.w(TAG, "Already have a pending vsync event.  There should only be "
936                          + "one at a time.");
937              } else {
938                  mHavePendingVsync = true;
939              }
940  
941              mTimestampNanos = timestampNanos;
942              mFrame = frame;
943              Message msg = Message.obtain(mHandler, this);
944              msg.setAsynchronous(true);
945              mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
946          }
947  
948          @Override
949          public void run() {
950              mHavePendingVsync = false;
				 // 这里最终触发到doFrame进行具体绘制
951              doFrame(mTimestampNanos, mFrame);
952          }
953      }

这里最终触发到doFrame()进行具体绘制

4.3.2.3 Choreographer#doFrame()

java 复制代码
657      @UnsupportedAppUsage
658      void doFrame(long frameTimeNanos, int frame) {
659          final long startNanos;
660          synchronized (mLock) {
661              if (!mFrameScheduled) {
662                  return; // no work to do
663              }
664  
665              if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
666                  mDebugPrintNextFrameTimeDelta = false;
667                  Log.d(TAG, "Frame time delta: "
668                          + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
669              }
670  
671              long intendedFrameTimeNanos = frameTimeNanos;
672              startNanos = System.nanoTime();
673              final long jitterNanos = startNanos - frameTimeNanos;
674              if (jitterNanos >= mFrameIntervalNanos) {
675                  final long skippedFrames = jitterNanos / mFrameIntervalNanos;
676                  if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
677                      Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
678                              + "The application may be doing too much work on its main thread.");
679                  }
680                  final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
681                  if (DEBUG_JANK) {
682                      Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
683                              + "which is more than the frame interval of "
684                              + (mFrameIntervalNanos * 0.000001f) + " ms!  "
685                              + "Skipping " + skippedFrames + " frames and setting frame "
686                              + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
687                  }
688                  frameTimeNanos = startNanos - lastFrameOffset;
689              }
690  
691              if (frameTimeNanos < mLastFrameTimeNanos) {
692                  if (DEBUG_JANK) {
693                      Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
694                              + "previously skipped frame.  Waiting for next vsync.");
695                  }
696                  scheduleVsyncLocked();
697                  return;
698              }
699  
700              if (mFPSDivisor > 1) {
701                  long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
702                  if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
703                      scheduleVsyncLocked();
704                      return;
705                  }
706              }
707  
708              mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
709              mFrameScheduled = false;
710              mLastFrameTimeNanos = frameTimeNanos;
711          }
712  
713          try {
714              Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
715              AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
716  
717              mFrameInfo.markInputHandlingStart();
718              doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
719  
720              mFrameInfo.markAnimationsStart();
721              doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
722              doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
723  
724              mFrameInfo.markPerformTraversalsStart();
725              doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
726  
727              doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
728          } finally {
729              AnimationUtils.unlockAnimationClock();
730              Trace.traceEnd(Trace.TRACE_TAG_VIEW);
731          }
732  
733          if (DEBUG_FRAMES) {
734              final long endNanos = System.nanoTime();
735              Log.d(TAG, "Frame " + frame + ": Finished, took "
736                      + (endNanos - startNanos) * 0.000001f + " ms, latency "
737                      + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
738          }
739      }

callback中最终调用的是CallbackRecord对象的run,也就是前文在postCallback中传入的runnble对象,调用该对象就是调用doTraversal

下面我们先来看看重点方法ViewRootImpl#performTraversals()

4.3.3 ViewRootImpl#performTraversals()

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

java 复制代码
1944      private void performTraversals() {
1945          // cache mView since it is used so much below...
1946          final View host = mView;
......
			  // mAdded指DecorView是否被成功加入到window中,在setView()中被赋值为true
1954          if (host == null || !mAdded)
1955              return;
......
1961          WindowManager.LayoutParams lp = mWindowAttributes;
......
1999          Rect frame = mWinFrame;
			  // mFirst在构造器中被赋值true,表示第一次traversals
			  // 在后面的代码中被赋值false
2000          if (mFirst) {
				  // 设置需要全部重新draw并且重新layout
2001              mFullRedrawNeeded = true;
2002              mLayoutRequested = true;
2003  
2004              final Configuration config = mContext.getResources().getConfiguration();
				  // 初始化期望窗口长宽,根据窗口类型来判断是否需要使用屏幕宽高,包含状态栏区域
2005              if (shouldUseDisplaySize(lp)) {
2006                  // NOTE -- system code, won't try to do compat mode.
2007                  Point size = new Point();
					  // 获取屏幕的真实尺寸,存储到size中
2008                  mDisplay.getRealSize(size);
					  // 将设备宽、高作为期望的窗口宽度和高度
2009                  desiredWindowWidth = size.x;
2010                  desiredWindowHeight = size.y;
2011              } else {
					  // 使用屏幕的可用宽高,是去除掉装饰区的
					  // 如果含有状态栏、导航栏,那就需要把这部分去除掉
2012                  desiredWindowWidth = mWinFrame.width();
2013                  desiredWindowHeight = mWinFrame.height();
2014              }
......
2031          } else {
				  // 如果不是第一次traversals,就直接使用之前存储的mWinFrame的宽高
2032              desiredWindowWidth = frame.width();
2033              desiredWindowHeight = frame.height();
				  // mWidth和mHeight是上一次traversals时赋frame的值的。
				  // 如果现在的值不一样了,那么就需要重新draw和layout
2034              if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
2035                  if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
2036                  mFullRedrawNeeded = true;
2037                  mLayoutRequested = true;
2038                  windowSizeMayChange = true;
2039              }
2040          }
......
2067          boolean insetsChanged = false;
2068  
2069          boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
2070          if (layoutRequested) {
2071  
2072              final Resources res = mView.getContext().getResources();
2073  
				  // 如果是第一次
2074              if (mFirst) {
					  // 确保window的触摸模式已经打开
2077                  mAttachInfo.mInTouchMode = !mAddedTouchMode;
					  // 内部 mAttachInfo.mInTouchMode = inTouchMode
2078                  ensureTouchModeLocally(mAddedTouchMode);
2079              } else {
					  // mPending...Insets是这一次请求traversals还未生效的值
					  // mAttachInfo中的值是上一次traversals时保存的值
					  // 比较两者看是否有变化,如果有变化就将insetsChanged置为true。
2080                  if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
2081                      insetsChanged = true;
2082                  }
2083                  if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
2084                      insetsChanged = true;
2085                  }
2086                  if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
2087                      insetsChanged = true;
2088                  }
2089                  if (!mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout)) {
2090                      insetsChanged = true;
2091                  }
2092                  if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
2093                      mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
2094                      if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
2095                              + mAttachInfo.mVisibleInsets);
2096                  }
2097                  if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
2098                      insetsChanged = true;
2099                  }
2100                  if (mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars) {
2101                      insetsChanged = true;
2102                  }
					  // 如果将窗口的宽或高设置为wrap_content了,最终还是会变为屏幕大小
2103                  if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
2104                          || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
						  // 窗口大小可能改变,windowSizeMayChange设置为true
2105                      windowSizeMayChange = true;
						  // 和前面一样,判断Activity是否含有状态栏,相应的赋值窗口的期望宽高
2107                      if (shouldUseDisplaySize(lp)) {
2108                          // NOTE -- system code, won't try to do compat mode.
2109                          Point size = new Point();
2110                          mDisplay.getRealSize(size);
2111                          desiredWindowWidth = size.x;
2112                          desiredWindowHeight = size.y;
2113                      } else {
2114                          Configuration config = res.getConfiguration();
2115                          desiredWindowWidth = dipToPx(config.screenWidthDp);
2116                          desiredWindowHeight = dipToPx(config.screenHeightDp);
2117                      }
2118                  }
2119              }
    			  // 会调用performMeasure()去确定window的大小,返回窗口大小是否会改变
    			  // 这里其实就是测量流程的入口
    			  // host: Decor   lp: window attr   rs: decor res
    			  // desiredWindowWidth/Height: 上面初始的窗口期望宽高
2122              windowSizeMayChange |= measureHierarchy(host, lp, res,
2123                      desiredWindowWidth, desiredWindowHeight);
2124          }
...
2184          if (layoutRequested) {
2185              // Clear this now, so that if anything requests a layout in the
2186              // rest of this function we will catch it and re-run a full
2187              // layout pass.
2188              mLayoutRequested = false;
2189          }
			  // 同时满足三个条件
			  // layoutRequested为true,已经发起了一次新的layout。
			  // 上面赋值的窗口尺寸可能发生改变
			  // 上面measureHierarchy()中测量的值和上一次保存的值不同    或
			  // 宽或高设置为wrap_content并且这次请求WMS的值和期望值、上次的值都不同
2191          boolean windowShouldResize = layoutRequested && windowSizeMayChange
2192              && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
2193                  || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
2194                          frame.width() < desiredWindowWidth && frame.width() != mWidth)
2195                  || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
2196                          frame.height() < desiredWindowHeight && frame.height() != mHeight));
2197          windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
			  // 如果activity重新启动
2202          windowShouldResize |= mActivityRelaunched;
			  // 设置是否需要计算insets,设置了监听或存在需要重新设置的空insets
2207          final boolean computesInternalInsets =
2208                  mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
2209                  || mAttachInfo.mHasNonEmptyGivenInternalInsets;
			  // 第一次traversals 或 窗口尺寸有变化 或 insets有变化 或 窗口visibility有变化
			  // 或 窗口属性有变化 或 强迫窗口下一次重新layout
2221          if (mFirst || windowShouldResize || insetsChanged ||
2222                  viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
				  // 清空这个标记位
2223              mForceNextWindowRelayout = false;
2224  
2225              if (isViewVisible) {
					  // 如果insets发生改变 并且 是第一次traversals或窗口从不可见变为可见
					  // 就置insetsPending为true
2235                  insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
2236              }
......
2247              try {
......
    				  // 调用relayoutWindow()重新计算窗口尺寸以及insets大小
    				  // 会使用IPC去请求 WMS
    				  // params: window attr   view可见性 是否有额外的insets
2264                  relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
......
					  // 比较这次计算和上次计算的值是否发生了改变
2288                  final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
2289                          mAttachInfo.mOverscanInsets);
2290                  contentInsetsChanged = !mPendingContentInsets.equals(
2291                          mAttachInfo.mContentInsets);
2292                  final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
2293                          mAttachInfo.mVisibleInsets);
2294                  final boolean stableInsetsChanged = !mPendingStableInsets.equals(
2295                          mAttachInfo.mStableInsets);
2296                  final boolean cutoutChanged = !mPendingDisplayCutout.equals(
2297                          mAttachInfo.mDisplayCutout);
2298                  final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
2299                  surfaceSizeChanged = (relayoutResult
2300                          & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
2301                  surfaceChanged |= surfaceSizeChanged;
2302                  final boolean alwaysConsumeSystemBarsChanged =
2303                          mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
2304                  final boolean colorModeChanged = hasColorModeChanged(lp.getColorMode());
					  // 如果发生了改变,就会进行重新赋值等操作
2305                  if (contentInsetsChanged) {
2306                      mAttachInfo.mContentInsets.set(mPendingContentInsets);
2307                      if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
2308                              + mAttachInfo.mContentInsets);
2309                  }
......
2453              } catch (RemoteException e) {
2454              }
2455  
2456              if (DEBUG_ORIENTATION) Log.v(
2457                      TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
2458  
				  // frame指向的是mWinFrame, 此时已经是上面重新请求WMS计算后的值了
				  // 将值保存在mAttachInfo中
2459              mAttachInfo.mWindowLeft = frame.left;
2460              mAttachInfo.mWindowTop = frame.top;
				  // 如果前一次计算的值和这次计算的值有变化就重新赋值
2465              if (mWidth != frame.width() || mHeight != frame.height()) {
2466                  mWidth = frame.width();
2467                  mHeight = frame.height();
2468              }
......
				  // 如果窗口不处于停止状态或者提交了下一次的绘制
2525              if (!mStopped || mReportNextDraw) {
2526                  boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
2527                          (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
					  // 判断是否需要重新测量窗口尺寸
				      // 窗口触摸模式发生改变,焦点发生改变
					  // 或 测量宽高与WMS计算的宽高不相等
					  // 或 insets改变了
					  // 或 配置发生改变,mPendingMergedConfiguration有变化
2528                  if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
2529                          || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
2530                          updatedConfiguration) {
2531                      int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
2532                      int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
2533  
2534                      if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed!  mWidth="
2535                              + mWidth + " measuredWidth=" + host.getMeasuredWidth()
2536                              + " mHeight=" + mHeight
2537                              + " measuredHeight=" + host.getMeasuredHeight()
2538                              + " coveredInsetsChanged=" + contentInsetsChanged);
2539  
2540                       // 执行测量操作
2541                      performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
2542  
2543                      // Implementation of weights from WindowManager.LayoutParams
2544                      // We just grow the dimensions as needed and re-measure if
2545                      // needs be
2546                      int width = host.getMeasuredWidth();
2547                      int height = host.getMeasuredHeight();
2548                      boolean measureAgain = false;
2549  
        				  // 判断是否需要重新测量,如果需要在水平方向上分配额外的像素
2550                      if (lp.horizontalWeight > 0.0f) {
2551                          width += (int) ((mWidth - width) * lp.horizontalWeight);
							  // 重新计算MeasureSpec
2552                          childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
2553                                  MeasureSpec.EXACTLY);
							  // 设置需要重新测量
2554                          measureAgain = true;
2555                      }
2556                      if (lp.verticalWeight > 0.0f) {
2557                          height += (int) ((mHeight - height) * lp.verticalWeight);
2558                          childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
2559                                  MeasureSpec.EXACTLY);
2560                          measureAgain = true;
2561                      }
2562  
						  // 如果需要重新测量了,就载调用一次performMeasure
2563                      if (measureAgain) {
2564                          if (DEBUG_LAYOUT) Log.v(mTag,
2565                                  "And hey let's measure once more: width=" + width
2566                                  + " height=" + height);
2567                          performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
2568                      }
2569  
2570                      layoutRequested = true;
2571                  }
2572              }
2573          } else {
				  // 检查窗口发生移动的情况
2579              maybeHandleWindowMove(frame);
2580          }
......
2586          final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
2587          boolean triggerGlobalLayoutListener = didLayout
2588                  || mAttachInfo.mRecomputeGlobalAttributes;
2589          if (didLayout) {
				  // 开始layout流程
2590              performLayout(lp, mWidth, mHeight);
......
2624          }
......
2631          if (computesInternalInsets) {
2632              // Clear the original insets.
2633              final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
				  // 重置insets树, 清空状态
2634              insets.reset();
2635  
2636              // 遍历计算
2637              mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
2638              mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
2639  
2640              // Tell the window manager.
2641              if (insetsPending || !mLastGivenInsets.equals(insets)) {
2642                  mLastGivenInsets.set(insets);
2643  
2644                  // Translate insets to screen coordinates if needed.
2645                  final Rect contentInsets;
2646                  final Rect visibleInsets;
2647                  final Region touchableRegion;
2648                  if (mTranslator != null) {
2649                      contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
2650                      visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
2651                      touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
2652                  } else {
2653                      contentInsets = insets.contentInsets;
2654                      visibleInsets = insets.visibleInsets;
2655                      touchableRegion = insets.touchableRegion;
2656                  }
2657  
2658                  try {
						  // 远程调用WMS去设置insets
2659                      mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
2660                              contentInsets, visibleInsets, touchableRegion);
2661                  } catch (RemoteException e) {
2662                  }
2663              }
2664          }
......
			  // 设置不是第一次, 之后再次调用traversals
2718          mFirst = false;
2719          mWillDrawSoon = false;
2720          mNewSurfaceNeeded = false;
2721          mActivityRelaunched = false;
2722          mViewVisibility = viewVisibility;
2723          mHadWindowFocus = hasWindowFocus;
......
2741          if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
2742              reportNextDraw();
2743          }
2744  
2745          boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
2746  
2747          if (!cancelDraw) {
				  // 没有取消draw也没有创建新的平面  第一次traversals时newSurface为true
				  // 如果还存在等待执行的动画, 就遍历执行它们
2748              if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
2749                  for (int i = 0; i < mPendingTransitions.size(); ++i) {
2750                      mPendingTransitions.get(i).startChangingAnimations();
2751                  }
2752                  mPendingTransitions.clear();
2753              }
2754  
				  // 开始draw流程
2755              performDraw();
2756          } else {
2757              if (isViewVisible) {
2758                  // 如果是可见的, 就再调用一次traversals
2759                  scheduleTraversals();
2760              } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
					  // 执行等待执行的动画
2761                  for (int i = 0; i < mPendingTransitions.size(); ++i) {
2762                      mPendingTransitions.get(i).endChangingAnimations();
2763                  }
2764                  mPendingTransitions.clear();
2765              }
2766          }
2767  
2768          mIsInTraversal = false;
2769      }

总体而言,performTraversals的逻辑大致可以分为五块:

  1. 确认窗口大小
  2. 预测量
  3. 测量performMeasure()
  4. 布局performLayout()
  5. 绘制performDraw()

首先,为了确认窗口大小,performTraversals()会根据LayoutParams的宽高及其各种标志位,配合WMS给定的窗口大小,最终计算出可供View展示的大小;

然后呢,为了优化顶级View不是DecorView下的展示体验,performTraversals()会进行预测量,经过预测量,会给出一个合理的尺寸,让View进行测量;

经过预测量后,接下来就是View的三大流程:测量布局以及绘制

我们使用网络上的一张图来帮助理解:

4.3.4 performDraw()方法调用Surface,最后会post到SurfaceFlinger。

注意:这里的performDraw()方法会调用Surface的方法渲染,最后会post到SurfaceFlinger进行设备沟通展示。

一张图概括了performTraversals()方法主要做的事情:

由于SurfaceFlinger涉及较底层,这里暂不做过多的分析,后续再出专门的文章对其进行分析。我们可以先简单看一下它的调用流程:

看到这张图mmmmmm,SurfaceFlinger后续再分析吧...

上面performTraversals()方法调用了WMS的更新方法relayoutWindow(),我们继续往下看:

4.3.5 WindowManagerService#relayoutWindow()

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

java 复制代码
1978      public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
1979              int requestedWidth, int requestedHeight, int viewVisibility, int flags,
1980              long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
1981              Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
1982              DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
1983              SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
......
2147              if (shouldRelayout) {
2148                  Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
2149  
2150                  result = win.relayoutVisibleWindow(result, attrChanges);
2151  
2152                  try {
2153                      result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
2154                  } catch (Exception e) {
......
2162                  }
......
2173              } 
......
2307          return result;
2308      }
......
2357      private int createSurfaceControl(SurfaceControl outSurfaceControl, int result, WindowState win,
2358              WindowStateAnimator winAnimator) {
2359          if (!win.mHasSurface) {
2360              result |= RELAYOUT_RES_SURFACE_CHANGED;
2361          }
2362  
2363          WindowSurfaceController surfaceController;
2364          try {
2365              Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
2366              surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
2367          } finally {
2368              Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
2369          }
2370          if (surfaceController != null) {
2371              surfaceController.getSurfaceControl(outSurfaceControl);
2372              if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  OUT SURFACE " + outSurfaceControl + ": copied");
2373          } else {
2374              // For some reason there isn't a surface.  Clear the
2375              // caller's object so they see the same state.
2376              Slog.w(TAG_WM, "Failed to create surface control for " + win);
2377              outSurfaceControl.release();
2378          }
2379  
2380          return result;
2381      }

createSurfaceControl()是创建Surface管理类的方法,实际上调用了surfaceController.getSurfaceControl(outSurfaceControl)方法创建Surface

4.3.6 WindowSurfaceController#copyFrom()

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

java 复制代码
493      void getSurfaceControl(SurfaceControl outSurfaceControl) {
494          outSurfaceControl.copyFrom(mSurfaceControl);
495      }

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

java 复制代码
408      public void copyFrom(SurfaceControl other) {
409          mName = other.mName;
410          mWidth = other.mWidth;
411          mHeight = other.mHeight;
412          assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject));
413      }
414  

SurfaceControl#copyFrom()方法调用的是native层nativeCopyFromSurfaceControl()方法创建Surface

ViewRootImpl中我们可以看到一块画布的创建。但是这里请注意,因为最终的绘制图形数据是由底层SurfaceFilnger完成的,所以这里我们可以认为当前Surface是一个空的数据对象,没有任何的图像数据。

4.3.7 updateViewLayout()总结

updateViewLayout()主要做了这几件事:

  1. 如果是新建View , 调用requestLayout()执行刷新请求
  2. 通过ViewRootImpl的performTraversalsView()方法对View进行重新测量、布局、绘制,最终通过Surface调用了SurfaceFlinger进行绘制。
  3. 通过WindowSession来更新Window视图,这个过程是由WMSrelayoutWindow()来实现,这同样也是一个IPC过程。

我们继续看第三大方法WindowManagerGlobal#removeView()

4.4 View的移除removeView()

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

java 复制代码
420      public void removeView(View view, boolean immediate) {
421          if (view == null) {
422              throw new IllegalArgumentException("view must not be null");
423          }
424  
425          synchronized (mLock) {
426              int index = findViewLocked(view, true);
427              View curView = mRoots.get(index).getView();
428              removeViewLocked(index, immediate);
429              if (curView == view) {
430                  return;
431              }
432  
433              throw new IllegalStateException("Calling with view " + view
434                      + " but the ViewAncestor is attached to " + curView);
435          }
436      }
......
480      private void removeViewLocked(int index, boolean immediate) {
481          ViewRootImpl root = mRoots.get(index);
482          View view = root.getView();
483  
484          if (view != null) {
485              InputMethodManager imm = view.getContext().getSystemService(InputMethodManager.class);
486              if (imm != null) {
487                  imm.windowDismissed(mViews.get(index).getWindowToken());
488              }
489          }
490          boolean deferred = root.die(immediate);
491          if (view != null) {
492              view.assignParent(null);
493              if (deferred) {
494                  mDyingViews.add(view);
495              }
496          }
497      }

removeViewLocked是通过ViewRootImpl来完成删除操作的。在WindowManager中提供了两种删除接口异步删除removeView()同步删除removeViewImmedialte()

一般不会使用removeViewImmedialte来删除Window,以免发生意外错误。

所以这里使用的是异步的删除情况,采用的是die方法。

die方法只是发送了一个请求删除的消息就立刻返回了,这个时候View并没有完成删除操作,所以最后会将其添加到mDyingViews列表中。

4.4.1 ViewRootImpl#die()

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

java 复制代码
7124      boolean die(boolean immediate) {
7125          // Make sure we do execute immediately if we are in the middle of a traversal or the damage
7126          // done by dispatchDetachedFromWindow will cause havoc on return.
7127          if (immediate && !mIsInTraversal) {
				  // 1.同步删除,直接调用
7128              doDie();
7129              return false;
7130          }
7131  
7132          if (!mIsDrawing) {
7133              destroyHardwareRenderer();
7134          } else {
7135              Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
7136                      "  window=" + this + ", title=" + mWindowAttributes.getTitle());
7137          }
			  // 2.异步删除,Handler发消息通知删除
7138          mHandler.sendEmptyMessage(MSG_DIE);
7139          return true;
7140      }
7141  
7142      void doDie() {
7143          checkThread();
7144          if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
7145          synchronized (this) {
7146              if (mRemoved) {
7147                  return;
7148              }
7149              mRemoved = true;
7150              if (mAdded) {
					  // 真正删除的逻辑是在此方法中
7151                  dispatchDetachedFromWindow();
7152              }
......
7177              mAdded = false;
7178          }
			  // WindowManagerGlobal中view和参数等移除
7179          WindowManagerGlobal.getInstance().doRemoveView(this);
7180      }

这个方法里面做了判断,如果是异步删除就会发送一个 MSG_DIE 的消息,ViewRootImpl 中的 handler 会收到这个消息,并调用 doDie 方法,这就是这两种删除方式的区别。

真正删除的方法是ViewRootImpl#dispatchDetachedFromWindow()WindowManagerGlobal#doRemoveView

4.4.2 ViewRootImpl#dispatchDetachedFromWindow()

java 复制代码
4142      void dispatchDetachedFromWindow() {
4143          mFirstInputStage.onDetachedFromWindow();
4144          if (mView != null && mView.mAttachInfo != null) {
4145              mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
4146              mView.dispatchDetachedFromWindow();
4147          }
.....
4160          mView.assignParent(null);
4161          mView = null;
4162          mAttachInfo.mRootView = null;
4163  
4164          destroySurface();
......
4176          try {
				  // 重点:WMS的remove
4177              mWindowSession.remove(mWindow);
4178          } catch (RemoteException e) {
4179          }
......
4183          if (mInputChannel != null) {
4184              mInputChannel.dispose();
4185              mInputChannel = null;
4186          }
4187  
4188          mDisplayManager.unregisterDisplayListener(mDisplayListener);
4189  
4190          unscheduleTraversals();
4191      }

这个方法做了一些View的移除、置空操作:

  1. 回调onDetachedFromeWindow;
  2. 垃圾回收相关操作;
  3. 通过Session的remove()在WMS中删除Window;
  4. 通过Choreographer移除监听器

重点是mWindowSession.remove(mWindow)调用的WMS的removeWindow()方法,这同样也是一个IPC过程,后面再分析。

4.4.3 WindowManagerGlobal#doRemoveView()

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

java 复制代码
499      void doRemoveView(ViewRootImpl root) {
500          synchronized (mLock) {
				 // 从ViewRootImpl获取到索引值
501              final int index = mRoots.indexOf(root);
502              if (index >= 0) {
					 // 删除ViewRootImpl列表中的数据
503                  mRoots.remove(index);
					 // 删除LayoutParams列表中的数据
504                  mParams.remove(index);
					 // 删除DecorView列表中的数据
505                  final View view = mViews.remove(index);
					 // DecorView加入到死亡列表
506                  mDyingViews.remove(view);
507              }
508          }
509          if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
510              doTrimForeground();
511          }
512      }

WindowManagerGlobal#doRemoveView()中view和缓存数据等移除

4.4.4 WindowManagerService#removeWindow()

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

java 复制代码
1759      void removeWindow(Session session, IWindow client) {
1760          synchronized (mGlobalLock) {
1761              WindowState win = windowForClientLocked(session, client, false);
1762              if (win == null) {
1763                  return;
1764              }
				  // 执行删除
1765              win.removeIfPossible();
1766          }
1767      }
......

这个地方有点绕,但其实就是通过WindowState#removeIfPossible()方法其实又调用了WMS等对象window的移除等操作。

4.4.5 WindowState#removeIfPossible()

win.removeIfPossible()方法

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

java 复制代码
1928      @Override
1929      void removeIfPossible() {
1930          super.removeIfPossible();
1931          removeIfPossible(false /*keepVisibleDeadWindow*/);
1932      }
1933  
1934      private void removeIfPossible(boolean keepVisibleDeadWindow) {
.......
2048              removeImmediately();
......
				  // WMS的updateFocusedWindowLocked()方法,
				  // 内部调用了RootWindowContainer的updateFocusedWindowLocked()方法
2057              mWmService.updateFocusedWindowLocked(isFocused()
2058                              ? UPDATE_FOCUS_REMOVING_FOCUS
2059                              : UPDATE_FOCUS_NORMAL,
2060                      true /*updateInputWindows*/);
2061          } finally {
2062              Binder.restoreCallingIdentity(origId);
2063          }
2064      }
......
1879      @Override
1880      void removeImmediately() {
1881          super.removeImmediately();
			  // 是否已经移除
1883          if (mRemoved) {
1884              // Nothing to do.
1885              if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
1886                      "WS.removeImmediately: " + this + " Already removed...");
1887              return;
1888          }
1889  
			  // 标记为已移除
1890          mRemoved = true;
......
			  // policy做移除操作
1911          dc.getDisplayPolicy().removeWindowLw(this);
1912  
			  // 关闭输入事件渠道
1913          disposeInputChannel();
1914  
1915          mWinAnimator.destroyDeferredSurfaceLocked();
1916          mWinAnimator.destroySurfaceLocked();
			  // Session集合冲移除WindowState
1917          mSession.windowRemovedLocked();
1918          try {
1919              mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
1920          } catch (RuntimeException e) {
1921              // Ignore if it has already been removed (usually because
1922              // we are doing this as part of processing a death note.)
1923          }
1924  
			  // 集中处理清除工作
1925          mWmService.postWindowRemoveCleanupLocked(this);
1926      }

这里做了一系列的销毁和置空操作,最后调用了mSession.windowRemovedLocked()方法:

4.4.6 Session#windowRemovedLocked()

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

java 复制代码
......
174      @Override
175      public void remove(IWindow window) {
176          mService.removeWindow(this, window);
177      }
......
489      void windowRemovedLocked() {
490          mNumWindow--;
491          killSessionLocked();
492      }
......
557      private void killSessionLocked() {
558          if (mNumWindow > 0 || !mClientDead) {
559              return;
560          }
561  
562          mService.mSessions.remove(this);
563          if (mSurfaceSession == null) {
564              return;
565          }
566  
567          if (WindowManagerService.localLOGV) Slog.v(TAG_WM, "Last window removed from " + this
568                  + ", destroying " + mSurfaceSession);
569          if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  KILL SURFACE SESSION " + mSurfaceSession);
570          try {
571              mSurfaceSession.kill();
572          } catch (Exception e) {
573              Slog.w(TAG_WM, "Exception thrown when killing surface session " + mSurfaceSession
574                      + " in session " + this + ": " + e.toString());
575          }
576          mSurfaceSession = null;
577          mAlertWindowSurfaces.clear();
578          mAppOverlaySurfaces.clear();
579          setHasOverlayUi(false);
580          cancelAlertWindowNotification();
581      }

Session中将自己在AMS的引用remove()掉,将Surface相关的对象销毁等操作。

4.4.7 removeView()总结

removeView()主要操作:

  1. 检查删除线程的正确性,如果不正确就抛出异常。
  2. 从ViewRootImpl列表、布局参数列表和View列表中删除与V对应的元素。
  3. 判断是否可以直接执行删除操作,如果不能就推迟删除操作。
  4. 执行删除操作,清理和释放与View相关的一切资源。

到这里,第一部分的WindowManager的三大方法:增加addView()、更新updateViewLayout()、删除removeView()分析完成。

上面增加、更新、删除View的操作中,有一个IPC跨进程的类Session。我们来看看Session是怎么获取的

4.5 Session的创建和获取

下面我们先看一下Session的创建和获取:

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

java 复制代码
178      public static IWindowManager getWindowManagerService() {
179          synchronized (WindowManagerGlobal.class) {
180              if (sWindowManagerService == null) {
181                  sWindowManagerService = IWindowManager.Stub.asInterface(
182                          ServiceManager.getService("window"));
183                  try {
184                      if (sWindowManagerService != null) {
185                          ValueAnimator.setDurationScale(
186                                  sWindowManagerService.getCurrentAnimatorScale());
187                      }
188                  } catch (RemoteException e) {
189                      throw e.rethrowFromSystemServer();
190                  }
191              }
192              return sWindowManagerService;
193          }
194      }
......
197      public static IWindowSession getWindowSession() {
198          synchronized (WindowManagerGlobal.class) {
199              if (sWindowSession == null) {
200                  try {
......
204                      InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
205                      IWindowManager windowManager = getWindowManagerService();
206                      sWindowSession = windowManager.openSession(
207                              new IWindowSessionCallback.Stub() {
208                                  @Override
209                                  public void onAnimatorScaleChanged(float scale) {
210                                      ValueAnimator.setDurationScale(scale);
211                                  }
212                              });
213                  } catch (RemoteException e) {
214                      throw e.rethrowFromSystemServer();
215                  }
216              }
217              return sWindowSession;
218          }
219      }

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

java 复制代码
4990      @Override
4991      public IWindowSession openSession(IWindowSessionCallback callback) {
4992          return new Session(this, callback);
4993      }

ViewRootImpl类的mWindowSession是由WindowManagerGlobal中静态方法获取,而我们从上面代码可以看到,其实是调用AMS的openSession()方法创建。

4.6 三大方法的整体流程

  1. WindowManager调用WindowManagerGlobal的方法
  2. WindowManagerGlobal调用ViewRootImpl的方法
  3. ViewRootImpl通过Session使用Binder跨进程调用WMS的方法

5 总结

WMS窗口管理服务,每一个Window都对应着一个View和一个ViewRootImplWindow表示一个窗口的概念,也是一个抽象的概念,它并不是实际存在的,它是以View的方式存在的。
WindowManager是我们访问Window的入口,Window的具体实现位于WindowManagerService中。WindowManagerWindowManagerService交互是一个IPC的过程,最终的IPC是在RootViewImpl中完成的。

我们知道窗口的展示主要有ActivityDialogToast,结合我们前面AMS的章节,以Activity启动为例对WMS流程进行总结:

  1. Launcher发起调用
  2. AMS管理的是配置信息数据
  3. 具体的对象创建过程在ActivityThread中完成
  4. AMSstartActivity触发resume生命周期,在resume生命周期中对于View数据进行推送至WindowManager进行管理,同时生成一个·ViewRootImpl·对象对于所有·View·数据进行绘制管理
  5. ViewRootImpl中依赖于编舞者工具对于绘制进行控制,一般情况为60FPS
  6. 具体绘制有ViewRootImpl中的performTraversals进行具体绘制操作
  7. 绘制完成之后,因为每一个View都是一个Surface,通过SurfaceFilnger提供的Surface每个View绘制完成之后
  8. WMS统一协调各个View的层级尺寸布局
  9. 最终交由SurfaceFilnger进行帧合成,完成整体界面输出
  10. 底层由opengl完成
相关推荐
编程洪同学3 小时前
Spring Boot 中实现自定义注解记录接口日志功能
android·java·spring boot·后端
氤氲息5 小时前
Android 底部tab,使用recycleview实现
android
Clockwiseee6 小时前
PHP之伪协议
android·开发语言·php
小林爱6 小时前
【Compose multiplatform教程08】【组件】Text组件
android·java·前端·ui·前端框架·kotlin·android studio
小何开发7 小时前
Android Studio 安装教程
android·ide·android studio
开发者阿伟7 小时前
Android Jetpack LiveData源码解析
android·android jetpack
weixin_438150998 小时前
广州大彩串口屏安卓/linux触摸屏四路CVBS输入实现同时显示!
android·单片机
CheungChunChiu8 小时前
Android10 rk3399 以太网接入流程分析
android·framework·以太网·eth·net·netd
木头没有瓜9 小时前
ruoyi 请求参数类型不匹配,参数[giftId]要求类型为:‘java.lang.Long‘,但输入值为:‘orderGiftUnionList
android·java·okhttp
键盘侠0079 小时前
springboot 上传图片 转存成webp
android·spring boot·okhttp