[Android Framework Series] Chapter 7 WMS Principle

1 Introduction

In front of [Android Framework Series] Chapter 5 AMS Startup Process and [Android Framework Series] Chapter 6 AMS Principles Launcher Startup Process, we analyzed the overall process of and, then AMS启动, how did it come out? Let's explore it in this chapter.Launcher启动Launcher(Activity启动)后UI何渲染到屏幕展示

2 Introduction to WMS

2.1 Main Responsibilities of WMS

WindowManagerServiceThe abbreviation WMSis the core service of the system, which is mainly divided into four parts, namely 窗口管理, 窗口动画, 输入系统中转站and Surface管理.

1. Window management: WMS is the manager of the window, responsible for starting, adding and deleting the window. In addition, the size of the window is also managed by the WMS. The core members of the management window are DisplayContent, WindowToken and WindowState. The display order, size, and position of the windows will eventually be fed back to SurfaceFlinger.
2. Window animation: When switching between windows, you can use window animation to look better. The window animation is in charge of the WMS animation subsystem, and the animation management system is WindowAnimator.
3. The transfer station of the input system: InputManagerServer (IMS) will process the touch event generated by touching the window, and it will find the most suitable window to process the touch feedback information. WMS is the manager of the window. Therefore, it is a matter of course that it becomes a transfer station for the input system.
4. Surface management: The window does not have the function of drawing, so each window needs a block Surface for its own drawing, and the allocation of Surface for each window is done by WMS.

Responsibility map of WMS:
insert image description here

2.2 What is Windows

2.2.1 What is Windows?

Representing a 窗口concept is all View的直接管理者, any view is Windowpresented, and the bottom layer Window->DecorView->Viewof Activity setContentView()is completed through Window.
Window is an abstract class, and the specific implementation is PhoneWindow. This can be seen in Activity#attach()the source code of the method.
Creating a Window needs to be WindowManagercreated. WindowManager is the entrance for the outside world to access Window. The specific implementation of Window is located in WindowManagerService, WindowManagerand WindowManagerServicethe interaction with and is completed through IPC.

2.2.2 Relationship between Window and View

Window and View are connected by ViewRootImplestablishing a connection. View is the presentation method of the view, but it cannot exist alone. It must be attached to the abstract concept of Window.
WMSSend all user messages to View/ViewGroup, but in the process of View/ViewGroup processing messages, some operations are common, and Window abstracts these common behaviors, which is Window.

2.2.3 Relationship among Activity, View and Window

It is initialized in the method of Activitythe startup process , but it is the only implementation class. Then the Activity manages the , , and , by setting it to .attach()PhoneWindowPhoneWindowWindow
setContentViewViewPhoneWindowViewWindowManageraddView()removeView()updateViewLayout()View

2.3 Overall framework of WMS

insert image description here

3 WMS startup process

WMSAfter the PMSsystem AMSis started SystemServer, Zygotethe process first forks out of SystemServerthe process and enters SystemServer:main()->run()->startBootstrapServices()the startup boot service, and then completes the startup of core services such as WMS, PMSand . All core services in the Android system will be started , , and are the same. It starts running when the phone is turned on. For how to start it, you can check the article [Android Framework Series] Chapter 3 Zygote Process Related and [Android Car Series] Chapter 10 System Services - SystemServer Source Code Analysis (API28)AMS
SystemServerWMSPMSAMSSystemServerSystemServer

This article is based on the source code analysis of Android10 (Q)

3.1 SystemServer starts WMS

We know WMSthat it is SystemServerstarted in the process, let's see how it is started WMS:
/frameworks/base/services/java/com/android/server/SystemServer.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();

Since there is a relatively strong relationship with WMSand , here we analyze WMS, and briefly analyze IMS by the way. From the above code, there are two core points related to WMS and IMS startup:IMS

  1. SystemServer#WindowManagerService.main(), passed in IMS, as WMSis IMSthe transit point. The observation WindowManagerService.main()method can know that it is running in SystemServerthe run()method, in other words, it is running in system_serverthe thread.
  2. SystemServer#ServiceManager.addService(), WMSand IMSregister in ServerManagerit, so that if the client wants to use it , WMSit needs to first ServiceManagerquery the information, and then WMSestablish communication with the process where it is located, so that the client can use it WMS.

Let's take a look at WMS的main()the creation of the calling method in 1 WMS:

3.2 main() of WMS

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.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      }

The instance DisplayThread.getHandler()obtained through the method . Used to handle the required related operations, the object is created in the expression . method, the creation of is run in . It should be noted that the second parameter timeout of the method is passed in as 0DisplayThreadHandler低延时显示runWithScissorsWMS
runWithScissorsWMSandroid.display线程runWithScissors

HandlerThe runWithScissors()method: A thread sends a message to B thread, so that A thread enters blocking, waits for B thread to process the message before continuing to execute

Let's take a brief look at this runWithScissorsmethod of Handler:
/frameworks/base/core/java/android/os/Handler.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      }

According to the principle that there is only one Looper for each thread system_server线程, it is judged whether the Handler points to the current one android.display线程. If so, Runnable#run()the method is executed directly. If not, BlockingRunnable#postAndWait()the method is called, and the Runnable of the current thread is passed in as a parameter.

The construction method we continue to look WindowManagerServiceat:

3.3 Construction method of WMS

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.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      }

The WMS constructor mainly completes the following core operations:

  1. Gets AMS, ATMS, IMS, DisplayManager, and holds a reference to
  2. Initialization WindowManagerPolicy, which is used to define the specification that a window measurement needs to follow.
  3. created WindowAnimator, which manages all window animations.
  4. create RootWindowContainerobject, root window container
  5. get DisplayManagerservice
  6. Created WMSand LocalServiceadded LocalServicesto

At this point ours WMShas been created, let's continue to look at the method called after the WMS is created in WMS3.1 onInitReady():

3.4 onInitReady() of WMS

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.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      }

Similar to the method WMSof main(), WindowManagerPolicy(简称WMP)it is an interface, init()the specific implementation is in the PhoneWindowManager(PWM)method, init()and the method is run in android.ui线程it. Therefore, its thread priority is higher than that android.display线程, and it must wait until init()the method execution is completed before android.display线程being woken up to continue executing the following code.

3.5 Execution of three threads

A total of three threads are provided, namely system_server, android.display, android.ui, and the relationship between them is shown in the figure below:
insert image description here

  1. system_server线程The method will be called in the method main(), and main()the WMS will be created in the method. The creation process is in the android.display线程middle, and its priority will be higher, and it will wake up after the creation is completed system_server线程.

  2. WMSAfter the creation is complete, the method in the method will be called onInitReady(), initPolicy()and the method called in the method PWMwill wake up after the method call is completed .init()init()android.ui线程system_server线程

  3. Then it will continue to execute system_serverthe code, such as displayReady()etc.

The execution order of threads is as follows:
system_server thread -> android.display thread -> system_server thread -> android.ui thread -> system_server thread

At this point, the WMS has been created and started . Let's continue to look at the running WMS and how to complete the form management:

4 Principles of WMS

The operation of Window has two parts: one part is handled by WindowManager, and the other part is handled by WMS. WMS does not care about the specific content of View, WMS only cares about the display of each application 界面大小, 层级值etc., and these data are included in WindowManager.LayoutParams.

WindowManagerWindowManagerGlobalCreated by ViewRootImpl, that is, Viewthe root of. ViewRootImplComplete operations such as drawing the pair in , Viewand then IPCget it through Session, and finally WMSprocess through it.

WindowManagerThe three major methods finally passed Binder跨进程调用the AMScorresponding 增加, 更新, and 删除methods. Let's analyze it in detail:

4.1 Three methods of adding, updating and deleting View

The functions provided by WindowManager are very simple, and there are only three commonly used methods:
1. Add View: addView()
2. Update View: updateViewLayout()
3. Delete View: removeView()

These three methods are defined in the ViewManager interface, and WindowManagerinherited fromViewManager

/frameworks/base/core/java/android/view/ViewManager.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  }

From this point of view, the process of ** WindowManageroperation Windowis more like ** in operation Window. ViewOur usual simple Window effect that can be dragged is actually very easy to achieve. You only need to modify the x and y values ​​​​in LayoutParams. Change the position of the Window. First set the onTouchListener for the View, and then continuously update the position of the View in the onTouch method.

addViewThe addition of Window needs to be realized through , updateViewLayout, of WindowManager removeView. WindowManager is an interface, and its real implementation is WindowManageImpl. as follows:

/frameworks/base/core/java/android/view/WindowManagerImpl.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      }

It can be seen that WindowManagerImpl does not directly implement the three major operations of Window, but all of them are handed over WindowManagerGlobalto handle.
Let's take a look firstWindowManagerGlobal#addView()

4.2 Add View addView()

4.2.1 WindowManagerGlobal#addView()

/frameworks/base/core/java/android/view/WindowManagerGlobal.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      }

We see that the final call in addView is ViewRootImpl#setView(), let's take a look at this method first:

4.2.2 ViewRootImpl#setView()

/frameworks/base/core/java/android/view/ViewRootImpl.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      }

This method will be called first requestLayout()to make a refresh request. After scheduleTraversals()the entry of View drawing
requestLayout()is called, the method is called mWindowSession.addToDisplay()to complete the final Window addition process.
In the above code, the type of mWindowSession is IWindowSession, which is an Binderobject. The real implementation is Sessionthat the addition process of Window is an IPC call. The addition of Window will be implemented internally
, as follows:SessionWindowManagerService#addWindow()

4.2.3 Session#addToDisplay()

/frameworks/base/services/core/java/com/android/server/wm/Session.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()

From the above, we can know that the last method to add View is called AMS的addWindow(). Let's take a look at what this method does:

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.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      }

WMSThe addWindowmethods return 各种状态, for example 添加成功, 失败, 无效的displayetc. These states are defined in WindowManagerGloabl. Mainly did the following things:

  1. Check parameters and other settings
  2. check token
  3. Save Token and Window to WMS
  4. Save WindowState to Session

insert image description here

4.2.5 Summary of addView()

In this way, the process of adding Window is handed over WMSto deal with. WMSIt will be assigned Surfaceto determine the order in which the windows are displayed, and finally by drawing SurfaceFlingerthese Surfaceto the screen, WindowManagerService#addWindow()we will analyze this part later.

Let's sort out the process first WindowManager#addView():

  1. The first call is WindowManagerImpl.addView():
    in addView, the implementation is delegated to WindowManagerGlobal.addView()

  2. WindowManagerGlobal.addView():
    ViewRootImpl is created in addView and assigned to root. Then the view, params, and root are all stored in their respective lists. Finally, ViewRootImpl.setView() is called

  3. ViewRootImpl.setView(): The refresh request is completed by calling, and then the final Window addition process will be completed through IWindowSession
    . setView()IWindowSession is an object, and the real implementation class is , that is to say, the Window addition process tries an IPC call.requestLayout()addToDisplay()BinderSession

  4. Session.addToDisplay():
    Through WindowManagerService#addWindow()to realize the addition of Window.
    insert image description here

Let's continue to look at the second method WindowManagerGlobal#updateViewLayout():

4.3 View update updateViewLayout()

/frameworks/base/core/java/android/view/WindowManagerGlobal.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#updateViewLayoutActually call ViewRootImpl.setLayoutPrams()to update the parameters

4.3.1 ViewRootImpl#setLayoutParams()

/frameworks/base/core/java/android/view/ViewRootImpl.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();
......

The above ViewRootImpl#setLayoutParamsmethod mainly does two things:

  1. The method is called scheduleTraversalsto re-strategy, layout, and redraw the View.
  2. By WindowSessionupdating the Window view, this process is implemented by , which is also an IPC process WMS.relayoutWindow()

mTraversalRunnableNote: The callback of the object here mChoreographeris actually the callback of returning the VSYNC signal after requesting the VSYNC signal.

4.3.2 Choreographer Choreographer

Choreographer#postCallback()Above we see that the drawing request is called and sent in the message queue. In Choreographerthe creation phase, we can see that its drawing rhythm is fixed 16.63ms每帧, and the frame rate is stored in the system property file at the framework level.

		 // 回调(回调函数控制)
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()

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      }

If it is on the main thread, it will request a synchronization signal from the bottom layer, and
if it is a drawing message on the sub-thread, it will be executed through message sending, and
both will eventually go toscheduleVsyncLocked()

4.3.2.2 Choreographer#doScheduleVsync()

805      void doScheduleVsync() {
    
    
806          synchronized (mLock) {
    
    
807              if (mFrameScheduled) {
    
    
808                  scheduleVsyncLocked();
809              }
810          }
811      }

There is only one situation that is triggered here is the drawing called in the child thread

4.3.2.3 Choreographer#scheduleVsyncLocked()

824      @UnsupportedAppUsage
825      private void scheduleVsyncLocked() {
    
    
826          mDisplayEventReceiver.scheduleVsync();
827      }

4.3.2.3 DisplayEventReceiver#scheduleVsync()

/frameworks/base/core/java/android/view/DisplayEventReceiver.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

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

Finally, the native method is called to request the vertical synchronization signal nativeScheduleVsync()from the bottom layer , and the bottom layer signal will be called back after it is sent synchronously.Surfacefilnger
SurfacefilngeronVsync()

/frameworks/base/core/java/android/view/Choreographer.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      }

Here it is finally triggered to doFrame()perform specific drawing

4.3.2.3 Choreographer#doFrame()

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      }

callbackWhat is finally called in is CallbackRecordthe object run, that is, the object postCallbackpassed in in the previous article runnble, and calling the object is callingdoTraversal

Let's take a look at the key methods first ViewRootImpl#performTraversals():

4.3.3 ViewRootImpl#performTraversals()

/frameworks/base/core/java/android/view/ViewRootImpl.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      }

Overall, the logic of performTraversals can be roughly divided into five parts:

  1. Confirm window size
  2. Pre-measurement
  3. MeasurementperformMeasure()
  4. layoutperformLayout()
  5. drawperformDraw()

First, in order to confirm the size of the window, performTraversals()according to the width and height of LayoutParams and its various flags, and the window size given by WMS, the size that can be displayed by View is finally calculated;

Then, in order to optimize the display experience of the top Viewnot the bottom, a pre-measurement will be carried out. After the pre-measurement, a reasonable size will be given for measurement;DecorViewperformTraversals()View

After pre-measurement, the next three processes of View are: 测量, 布局and 绘制.

We use a picture on the Internet to help understand:
insert image description here

4.3.4 The performDraw() method calls Surface, and finally posts to SurfaceFlinger.

Note: The method here performDraw()will call Surfacethe method to render, and finally post it SurfaceFlingerto communicate with the device.

A picture summarizes performTraversals()the main things that the method does:
insert image description here
because SurfaceFlingerit involves the lower layer, we will not do too much analysis here, and we will publish a special article to analyze it later. We can take a brief look at its calling process first:
insert image description here
see this picture mmmmmm, SurfaceFlingerlet's analyze it later...

The update method performTraversals()called by the above method , we continue to look down:WMSrelayoutWindow()

4.3.5 WindowManagerService#relayoutWindow()

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.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()It is a method to create Surfacea management class, and actually calls surfaceController.getSurfaceControl(outSurfaceControl)the method to create a Surface

4.3.6 WindowSurfaceController#copyFrom()

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

493      void getSurfaceControl(SurfaceControl outSurfaceControl) {
    
    
494          outSurfaceControl.copyFrom(mSurfaceControl);
495      }

/frameworks/base/core/java/android/view/SurfaceControl.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()The method call is native层the nativeCopyFromSurfaceControl()method created Surface.
In ViewRootImplwe can see the creation of a canvas. But please note here, because the final drawing graphics data is SurfaceFilngerdone by the bottom layer, so here we can think that Surfaceit is currently an empty data object without any image data.

4.3.7 updateViewLayout() summary

updateViewLayout()Mainly did the following things:

  1. If it is a new View, call to requestLayout()execute the refresh request
  2. Through performTraversalsView()the method of ViewRootImpl, the View is re-measured, laid out, drawn, and finally drawn by Surfacecalling .SurfaceFlinger
  3. By WindowSessionupdating the Window view, this process is implemented by , which is also an IPC process WMS.relayoutWindow()
    insert image description here

insert image description here

Let's continue to look at the third method WindowManagerGlobal#removeView():

4.4 View removal removeView()

/frameworks/base/core/java/android/view/WindowManagerGlobal.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      }

removeViewLockedIs to ViewRootImplcomplete the delete operation. In WindowManager provides two delete interface 异步删除removeView()and 同步删除removeViewImmedialte().

Generally, removeViewImmedialte is not used to delete Window to avoid unexpected errors.
So the asynchronous deletion situation is used here, and diethe method is used.
The die method just sends a request to delete and returns immediately. At this time, View has not completed the deletion operation, so it will be added to the mDyingViewslist at the end.

4.4.1 ViewRootImpl#die()

/frameworks/base/core/java/android/view/ViewRootImpl.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      }

This method makes a judgment. If it is asynchronous deletion, it will send a MSG_DIE message. The handler in ViewRootImpl will receive this message and call the doDie method. This is the difference between the two deletion methods.
The way to actually delete is ViewRootImpl#dispatchDetachedFromWindow()withWindowManagerGlobal#doRemoveView

4.4.2 ViewRootImpl#dispatchDetachedFromWindow()

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      }

This method does some View removal and blanking operations:

  1. callback onDetachedFromWindow;
  2. Garbage collection related operations;
  3. Delete Window in WMS through Session's remove();
  4. Remove listeners via Choreographer

The focus is mWindowSession.remove(mWindow)on calling the WMS removeWindow()method, which is also an IPC process, which will be analyzed later.

4.4.3 WindowManagerGlobal#doRemoveView()

/frameworks/base/core/java/android/view/WindowManagerGlobal.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()Remove middle view and cached data

4.4.4 WindowManagerService#removeWindow()

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.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      }
......

This place is a bit convoluted, but in fact, through WindowState#removeIfPossible()the method, it actually calls operations such as the removal of the window of WMS and other objects.

4.4.5 WindowState#removeIfPossible()

win.removeIfPossible()method
/frameworks/base/services/core/ java/com/android/server/wm/WindowState.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      }

A series of destruction and emptying operations are done here, and finally mSession.windowRemovedLocked()the method is called:

4.4.6 Session#windowRemovedLocked()

/frameworks/base/services/core/java/com/android/server/wm/Session.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      }

SessionAMSIn the process, you will refer to yourself remove(), destroy the Surface-related objects, and other operations.

4.4.7 removeView() summary

removeView()Main operations:

  1. Checks the correctness of deleting the thread, and throws an exception if it is not correct.
  2. Removes the element corresponding to V from the ViewRootImpl list, layout parameter list, and View list.
  3. Determine whether the delete operation can be performed directly, and if not, the delete operation will be postponed.
  4. Perform delete operations to clean up and release all resources related to View.
    insert image description here

At this point, the first part of the three major methods of WindowManager: add addView(), update updateViewLayout(), delete removeView()analysis is complete.

In the operations of adding, updating, and deleting View above, there is an IPC cross-process class Session. Let's see Sessionhow to get

4.5 Session creation and acquisition

Let's take a look at the creation and acquisition of Session first:

/frameworks/base/core/java/android/view/WindowManagerGlobal.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

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

The ViewRootImpl class mWindowSessionis obtained WindowManagerGlobalby the static method, and we can see from the above code that it is actually openSession()created by calling the AMS method.

4.6 The overall process of the three methods

  1. WindowManagerWindowManagerGlobalmethod called
  2. WindowManagerGlobalViewRootImplmethod called
  3. ViewRootImplBy Sessionusing the method of Bindercross-process callWMS

5 summary

WMSWindow management services, each Windowcorresponding to one Viewand one ViewRootImpl. WindowThe concept of representing a window is also an abstract concept, it does not actually exist, it Viewexists in the form of .
WindowManagerIs Windowthe entrance we visit, Windowthe specific implementation is located WindowManagerServicein. WindowManagerAnd WindowManagerServiceinteraction is a IPCprocess, the final IPC is RootViewImpldone in.

We know that the display of the window mainly includes Activityand Dialog, Toast, combined with our previous AMS chapters, take Activity startup as an example to summarize the WMS process:

  1. Launcherinvoked by
  2. AMSManagement is configuration information data
  3. The specific object creation process ActivityThreadis done in
  4. AMSSome startActivitytrigger resumethe life cycle, push the data to manage in resumethe life cycle , and generate a ViewRootImpl object to draw and manage all the View dataViewWindowManager
  5. ViewRootImplRelying on the choreographer tool to control the drawing, the general situation is60FPS
  6. ViewRootImplConcrete drawing has performTraversalsa specific drawing operation
  7. After drawing is complete, since each Viewis one Surface, after each drawing is completed by SurfaceFilngerprovidingSurfaceView
  8. Coordinate the , , etc. WMSof each View in a unified manner层级尺寸布局
  9. Finally, it is handed SurfaceFilngerover to frame synthesis to complete the overall interface output
  10. bottom layer is opengldone by

Guess you like

Origin blog.csdn.net/u010687761/article/details/131716999