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
WindowManagerService
The abbreviation WMS
is 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:
2.2 What is Windows
2.2.1 What is Windows?
Representing a 窗口
concept is all View的直接管理者
, any view is Window
presented, and the bottom layer Window->DecorView->View
of 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 WindowManager
created. WindowManager is the entrance for the outside world to access Window. The specific implementation of Window is located in WindowManagerService, WindowManager
and WindowManagerService
the interaction with and is completed through IPC.
2.2.2 Relationship between Window and View
Window and View are connected by ViewRootImpl
establishing 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.
WMS
Send 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 Activity
the startup process , but it is the only implementation class. Then the Activity manages the , , and , by setting it to .attach()
PhoneWindow
PhoneWindow
Window
setContentView
View
PhoneWindow
View
WindowManager
addView()
removeView()
updateViewLayout()
View
2.3 Overall framework of WMS
3 WMS startup process
WMS
After the PMS
system AMS
is started SystemServer
, Zygote
the process first forks out of SystemServer
the process and enters SystemServer:main()->run()->startBootstrapServices()
the startup boot service, and then completes the startup of core services such as WMS
, PMS
and . 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
SystemServer
WMS
PMS
AMS
SystemServer
SystemServer
This article is based on the source code analysis of Android10 (Q)
3.1 SystemServer starts WMS
We know WMS
that it is SystemServer
started 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 WMS
and , 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
SystemServer#WindowManagerService.main()
, passed inIMS
, asWMS
isIMS
the transit point. The observationWindowManagerService.main()
method can know that it is running inSystemServer
therun()
method, in other words, it is running insystem_server
the thread.SystemServer#ServiceManager.addService()
,WMS
andIMS
register inServerManager
it, so that if the client wants to use it ,WMS
it needs to firstServiceManager
query the information, and thenWMS
establish communication with the process where it is located, so that the client can use itWMS
.
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 0DisplayThread
Handler
低延时显示
runWithScissors
WMS
runWithScissors
WMS
android.display线程
runWithScissors
Handler
The 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 runWithScissors
method 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 WindowManagerService
at:
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:
- Gets
AMS
,ATMS
,IMS
,DisplayManager
, and holds a reference to - Initialization
WindowManagerPolicy
, which is used to define the specification that a window measurement needs to follow. - created
WindowAnimator
, which manages all window animations. - create
RootWindowContainer
object, root window container - get
DisplayManager
service - Created
WMS
andLocalService
addedLocalServices
to
At this point ours WMS
has been created, let's continue to look at the method called after the WMS is created in WMS
3.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 WMS
of 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:
-
system_server线程
The method will be called in the methodmain()
, andmain()
the WMS will be created in the method. The creation process is in theandroid.display线程
middle, and its priority will be higher, and it will wake up after the creation is completedsystem_server线程
. -
WMS
After the creation is complete, the method in the method will be calledonInitReady()
,initPolicy()
and the method called in the methodPWM
will wake up after the method call is completed .init()
init()
android.ui线程
system_server线程
-
Then it will continue to execute
system_server
the code, such asdisplayReady()
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
.
WindowManager
WindowManagerGlobal
Created by ViewRootImpl
, that is, View
the root of. ViewRootImpl
Complete operations such as drawing the pair in , View
and then IPC
get it through Session
, and finally WMS
process through it.
WindowManager
The three major methods finally passed Binder跨进程调用
the AMS
corresponding 增加
, 更新
, 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 WindowManager
inherited 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 ** WindowManager
operation Window
is more like ** in operation Window
. View
Our 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.
addView
The 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 WindowManagerGlobal
to 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 Binder
object. The real implementation is Session
that the addition process of Window is an IPC call. The addition of Window will be implemented internally
, as follows:Session
WindowManagerService#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 }
WMS
The addWindow
methods return 各种状态
, for example 添加成功
, 失败
, 无效的display
etc. These states are defined in WindowManagerGloabl
. Mainly did the following things:
- Check parameters and other settings
- check token
- Save Token and Window to WMS
- Save WindowState to Session
4.2.5 Summary of addView()
In this way, the process of adding Window is handed over WMS
to deal with. WMS
It will be assigned Surface
to determine the order in which the windows are displayed, and finally by drawing SurfaceFlinger
these Surface
to the screen, WindowManagerService#addWindow()
we will analyze this part later.
Let's sort out the process first WindowManager#addView()
:
-
The first call is
WindowManagerImpl.addView()
:
in addView, the implementation is delegated to WindowManagerGlobal.addView() -
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 -
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()
Binder
Session
-
Session.addToDisplay()
:
ThroughWindowManagerService#addWindow()
to realize the addition of Window.
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#updateViewLayout
Actually 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#setLayoutParams
method mainly does two things:
- The method is called
scheduleTraversals
to re-strategy, layout, and redraw the View. - By
WindowSession
updating the Window view, this process is implemented by , which is also an IPC processWMS
.relayoutWindow()
mTraversalRunnable
Note: The callback of the object here mChoreographer
is 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 Choreographer
the 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
Surfacefilnger
onVsync()
/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 }
callback
What is finally called in is CallbackRecord
the object run
, that is, the object postCallback
passed 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:
- Confirm window size
- Pre-measurement
- Measurement
performMeasure()
- layout
performLayout()
- draw
performDraw()
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 View
not the bottom, a pre-measurement will be carried out. After the pre-measurement, a reasonable size will be given for measurement;DecorView
performTraversals()
View
After pre-measurement, the next three processes of View are: 测量
, 布局
and 绘制
.
We use a picture on the Internet to help understand:
4.3.4 The performDraw() method calls Surface, and finally posts to SurfaceFlinger.
Note: The method here performDraw()
will call Surface
the method to render, and finally post it SurfaceFlinger
to communicate with the device.
A picture summarizes performTraversals()
the main things that the method does:
because SurfaceFlinger
it 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:
see this picture mmmmmm, SurfaceFlinger
let's analyze it later...
The update method performTraversals()
called by the above method , we continue to look down:WMS
relayoutWindow()
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 Surface
a 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 ViewRootImpl
we can see the creation of a canvas. But please note here, because the final drawing graphics data is SurfaceFilnger
done by the bottom layer, so here we can think that Surface
it is currently an empty data object without any image data.
4.3.7 updateViewLayout() summary
updateViewLayout()
Mainly did the following things:
- If it is a new View, call to
requestLayout()
execute the refresh request - Through
performTraversalsView()
the method of ViewRootImpl, the View is re-measured, laid out, drawn, and finally drawn bySurface
calling .SurfaceFlinger
- By
WindowSession
updating the Window view, this process is implemented by , which is also an IPC processWMS
.relayoutWindow()
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 }
removeViewLocked
Is to ViewRootImpl
complete 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 die
the 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 mDyingViews
list 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:
- callback onDetachedFromWindow;
- Garbage collection related operations;
- Delete Window in WMS through Session's remove();
- 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 }
Session
AMS
In the process, you will refer to yourself remove()
, destroy the Surface-related objects, and other operations.
4.4.7 removeView() summary
removeView()
Main operations:
- Checks the correctness of deleting the thread, and throws an exception if it is not correct.
- Removes the element corresponding to V from the ViewRootImpl list, layout parameter list, and View list.
- Determine whether the delete operation can be performed directly, and if not, the delete operation will be postponed.
- Perform delete operations to clean up and release all resources related to View.
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 Session
how 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 mWindowSession
is obtained WindowManagerGlobal
by 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
WindowManager
WindowManagerGlobal
method calledWindowManagerGlobal
ViewRootImpl
method calledViewRootImpl
BySession
using the method ofBinder
cross-process callWMS
5 summary
WMS
Window management services, each Window
corresponding to one View
and one ViewRootImpl
. Window
The concept of representing a window is also an abstract concept, it does not actually exist, it View
exists in the form of .
WindowManager
Is Window
the entrance we visit, Window
the specific implementation is located WindowManagerService
in. WindowManager
And WindowManagerService
interaction is a IPC
process, the final IPC is RootViewImpl
done in.
We know that the display of the window mainly includes Activity
and Dialog
, Toast
, combined with our previous AMS chapters, take Activity startup as an example to summarize the WMS process:
Launcher
invoked byAMS
Management is configuration information data- The specific object creation process
ActivityThread
is done in AMS
SomestartActivity
triggerresume
the life cycle, push the data to manage inresume
the life cycle , and generate a ViewRootImpl object to draw and manage all the View dataView
WindowManager
ViewRootImpl
Relying on the choreographer tool to control the drawing, the general situation is60FPS
ViewRootImpl
Concrete drawing hasperformTraversals
a specific drawing operation- After drawing is complete, since each
View
is oneSurface
, after each drawing is completed bySurfaceFilnger
providingSurface
View
- Coordinate the , , etc.
WMS
of each View in a unified manner层级
尺寸
布局
- Finally, it is handed
SurfaceFilnger
over to frame synthesis to complete the overall interface output - bottom layer is
opengl
done by