1 前言
前面【Android Framework系列】第5章 AMS启动流程和【Android Framework系列】第6章 AMS原理之Launcher启动流程我们分析了AMS启动
以及Launcher启动
的整体流程,那Launcher(Activity启动)后
,UI
是如何渲染到屏幕
并且展示
出来的呢?我们这章节来探讨一下。
2 WMS简介
2.1 WMS的主要职责
WindowManagerService
简称WMS
,是系统的核心服务,主要分为四大部分,分别是窗口管理
,窗口动画
,输入系统中转站
和Surface管理
。
1.窗口管理:WMS是窗口的管理者,负责窗口的启动,添加和删除,另外窗口的大小也是由WMS管理的,管理窗口的核心成员有DisplayContent,WindowToken和WindowState。窗口的显示顺序、尺寸、位置, 最终都会反馈SurfaceFlinger。
2.窗口动画:窗口间进行切换时,使用窗口动画可以更好看一些,窗口动画由WMS动画子系统来负责,动画的管理系统为WindowAnimator。
3.输入系统的中转站:通过对窗口触摸而产生的触摸事件,InputManagerServer(IMS)会对触摸事件进行处理,他会寻找一个最合适的窗口来处理触摸反馈信息,WMS是窗口的管理者,因此理所当然的就成为了输入系统的中转站。
4.Surface管理:窗口并不具备绘制的功能,因此每个窗口都需要有一个块Surface来供自己绘制,为每个窗口分配Surface是由WMS来完成。
WMS的职责图:
2.2 什么是Window
2.2.1 Window是什么?
表示一个窗口
的概念,是所有View的直接管理者
,任何视图都通过Window
呈现,由Window->DecorView->View
,Activity的setContentView()
底层通过Window完成。
Window是一个抽象类,具体实现是PhoneWindow
。这个可以看Activity#attach()
方法源码
创建Window需要通过WindowManager
创建,WindowManager是外界访问Window的入口,Window具体实现位于WindowManagerService中,WindowManager
和WindowManagerService
的交互是通过IPC完成。
2.2.2 Window和View关系
Window和View通过ViewRootImpl
建立联系,View是视图的呈现方式,但是不能单独存在,必须依附在Window这个抽象的概念上。WMS
把所有的用户消息发给View/ViewGroup
,但是在View/ViewGroup处理消息的过程中,有一些操作是公共的, Window把这些公共行为抽象出来, 这就是Window。
2.2.3 Activity、View、Window三者之间的关系
在Activity
启动过程其中的attach()
方法中初始化了PhoneWindow
,而PhoneWindow
是Window
的唯一实现类。
然后Activity通过setContentView
将View
设置到了PhoneWindow
上,而View
通过WindowManager
的addView()
、removeView()
、updateViewLayout()
对View
进行管理。
2.3 WMS整体框架
3 WMS启动流程
WMS
跟PMS
、AMS
的启动都是在SystemServer
进程,系统启动后Zygote
进程第一个fork出SystemServer
进程,进入到SystemServer:main()->run()->startBootstrapServices()
启动引导服务,进而完成WMS
、PMS
和AMS
等核心服务的启动。
在Android系统所有的核心服务都会经过SystemServer
启动,WMS
、PMS
和AMS
都是一样。SystemServer
会在手机开机时启动运行。关于SystemServer
是如何启动的可以查看文章【Android Framework系列】第3章 Zygote进程相关和【Android车载系列】第10章 系统服务-SystemServer源码分析(API28)
本文基于Android10(Q)的源码做分析
3.1 SystemServer启动WMS
我们知道WMS
是在SystemServer
进程中被启动,下面我们来看看具体是怎么启动的WMS
:
/frameworks/base/services/java/com/android/server/SystemServer.java
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();
由于WMS
和IMS
有着比较强的关联,所以这里我们分析WMS,会顺带简单分析一下IMS。
从上面代码,关于WMS、IMS启动相关的核心两个点:
-
SystemServer#WindowManagerService.main()
,传入了IMS
,因为WMS
是IMS
的中转站。观察WindowManagerService.main()
方法可以知道他是运行在SystemServer
的run()
方法中,换句话说就是运行在system_server
线程中。 -
SystemServer#ServiceManager.addService()
,将WMS
和IMS
注册到ServerManager
里面,这样客户端想要使用WMS
就需要先去ServiceManager
中查询信息,然后与WMS
所在的进程建立通信,这样客户端就可以使用WMS
。
下面我们先来看看1中调用WMS的main()
方法创建WMS
:
3.2 WMS的main()
/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 }
通过DisplayThread.getHandler()
方法获取到了DisplayThread
的Handler
实例。用来处理需要低延时显示
的相关操作,runWithScissors
表达式中创建了WMS
对象。runWithScissors
方法中,WMS
的创建是运行在android.display线程
中的。需要注意的是,runWithScissors
方法的第二个参数timeout传入的是0
Handler
的runWithScissors()
方法:A线程向B线程发送一个消息,使A线程进入阻塞,等待B线程处理完消息后再继续执行
我们来简单看一下Handler的这个runWithScissors
方法:
/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 }
根据每个线程只有一个Looper 的原理来判断当前system_server线程
,是否Handler所指向的android.display线程
,如果是则直接执行Runnable#run()
方法,如果不是则调用BlockingRunnable#postAndWait()
方法,并将当前线程的Runnable作为参数传进去。
我们继续看WindowManagerService
的构造方法:
3.3 WMS的构造方法
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
1000 private WindowManagerService(Context context, InputManagerService inputManager,
1001 boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
1002 ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
......
// 保存IMS, 持有了IMS引用。
1027 mInputManager = inputManager; // Must be before createDisplayContentLocked.
......
// 初始化WindowManagerPolicy,它用来定义一个窗口测量所需要遵循的规范。
1033 mPolicy = policy;
// 创建了WindowAnimator,它用于管理所有的窗口动画。
1034 mAnimator = new WindowAnimator(this);
// 创建RootWindowContainer对象,根窗口容器
1035 mRoot = new RootWindowContainer(this);
1036
1037 mWindowPlacerLocked = new WindowSurfacePlacer(this);
1038 mTaskSnapshotController = new TaskSnapshotController(this);
1039
1040 mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,
1041 Choreographer.getInstance());
1042
1043 LocalServices.addService(WindowManagerPolicy.class, mPolicy);
// 获取DisplayManager服务
1045 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
// 获取AMS、ATMS,并持有其引用
1078 mActivityManager = ActivityManager.getService();
1079 mActivityTaskManager = ActivityTaskManager.getService();
1080 mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
1081 mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
......
// 将LocalService添加到LocalServices中
1168 LocalServices.addService(WindowManagerInternal.class, new LocalService());
1169 }
WMS构造函数主要完成以下几点核心操作:
- 获取
AMS
、ATMS
、IMS
、DisplayManager
,并持有其引用 - 初始化
WindowManagerPolicy
,它用来定义一个窗口测量所需要遵循的规范。 - 创建了
WindowAnimator
,它用于管理所有的窗口动画。 - 创建
RootWindowContainer
对象,根窗口容器 - 获取
DisplayManager
服务 - 创建
WMS
的LocalService
添加到LocalServices
中
到这里我们的WMS
已经被创建完成,我们继续看3.1中WMS创建完成后调用WMS
的onInitReady()
方法:
3.4 WMS的onInitReady()
/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 }
和WMS
的main()
方法类似,WindowManagerPolicy(简称WMP)
是一个接口,init()
的具体实现在PhoneWindowManager(PWM)
中,init()
方法运行在android.ui线程
中。因此他的线程优先级要高于android.display线程
,必须等init()
方法执行完成后,android.display线程
才会被唤醒从而继续执行下面的代码。
3.5 三个线程的执行
一共提供了三个线程,分别是system_server
,android.display
,android.ui
,他们之间的关系如下图所示:
-
system_server线程
中会调用main()
方法,main()
方法中会创建WMS,创建的过程是在android.display线程
中,他的优先级会高一些,创建完成后才会唤醒system_server线程
。 -
WMS
创建完成后会调用onInitReady()
中的initPolicy()
方法,该方法中调用PWM
的init()
方法,init()
在android.ui线程
,方法调用完成之后就会唤醒system_server线程
。 -
之后就会接着执行
system_server
中的代码,例如displayReady()
等。
线程的执行顺序如下:
system_server线程->android.display线程->system_server线程->android.ui线程->system_server线程
到这里,WMS已被创建并启动完成,下面我们继续看运行中的WMS,到底是怎么完成窗体管理:
4 WMS原理
Window的操作有两大部分:一部分是WindowManager来处理,一部分是WMS来处理。WMS并不关心View的具体内容,WMS只关心各个应用显示的界面大小
,层级值
等,这些数据都包含在WindowManager.LayoutParams
中。
WindowManager
通过WindowManagerGlobal
创建ViewRootImpl
,也就是View
的根。在ViewRootImpl
中完成对View
的绘制等操作,然后通过IPC
获取到Session
,最终通过WMS
来进行处理。
WindowManager
三大方法,最后都是通过Binder跨进程调用
了AMS
对应的增加
、更新
、删除
方法。下面我们来详细分析:
4.1 添加、更新、删除View的三大方法
WindowManager 所提供的功能很简单,常用的只有三个方法:
1. 添加 View: addView()
2. 更新 View: updateViewLayout()
3. 删除 View: removeView()
这三个方法定义在 ViewManager 接口中,而 WindowManager
继承了ViewManager
/frameworks/base/core/java/android/view/ViewManager.java
22 public interface ViewManager
23 {
......
34 public void addView(View view, ViewGroup.LayoutParams params);
35 public void updateViewLayout(View view, ViewGroup.LayoutParams params);
36 public void removeView(View view);
37 }
由此看来**WindowManager
操作Window
的过程更像是在操作Window
中的View
**,我们平常简单的那种可以拖动的Window效果其实是很好实现的,只需要修改LayoutParams中的x,y值就可以改变Window的位置。首先给View设置onTouchListener,然后在onTouch方法中不断的更新View的位置即可。
Window的添加需要通过WindowManager的addView
、updateViewLayout
、removeView
来实现,WindowManager是一个接口,他的真正实现是WindowManageImpl
。如下:
/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 }
可以看到WindowManagerImpl并没有直接实现Window三大操作,而是全部交给了WindowManagerGlobal
来处理。
下面我们先来看看WindowManagerGlobal#addView()
4.2 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 }
我们看到addView中最终调用的是ViewRootImpl#setView()
,先来看一下这个方法:
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 }
这个方法首先会调用requestLayout()
来进行一次刷新请求,其中scheduleTraversals()
是View绘制的入口requestLayout()
调用之后,调用了mWindowSession.addToDisplay()
方法,来完成最终的Window的添加过程。
在上面代码中,mWindowSession的类型是IWindowSession,他是一个Binder
对象,真正的实现是Session
,也就是Window的添加过程是一次IPC调用。
在Session
内部会通过WindowManagerService#addWindow()
来实现Window的添加,如下所示:
4.2.3 Session#addToDisplay()
/frameworks/base/services/core/java/com/android/server/wm/Session.java
153 @Override
154 public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
155 int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
156 Rect outStableInsets, Rect outOutsets,
157 DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
158 InsetsState outInsetsState) {
// 这里的mService是WMS
159 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
160 outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
161 outInsetsState);
162 }
4.2.4 WindowManagerService#addWindow()
从上面可以知道,添加View最后调用的是AMS的addWindow()
方法,我们来看看这个方法到底做了什么:
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
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
的addWindow
方法返回各种状态
,例如添加成功
,失败
,无效的display
等,这些状态定义在WindowManagerGloabl
中。主要做了这几件事:
- 检查参数等设置
- 检查Token
- 将Token、Window保存到WMS中
- 将WindowState保存到Session中
4.2.5 addView()总结
如此一来,Window的添加过程就交给了WMS
去处理。WMS
会为其分配Surface
,确定窗口显示的次序,最终通过SurfaceFlinger
将这些Surface
绘制到屏幕上,WindowManagerService#addWindow()
这部分我们后面再做分析。
我们先来梳理一下WindowManager#addView()
流程:
-
首先调用的是
WindowManagerImpl.addView()
:
在addView中将实现委托给了WindowManagerGlobal.addView() -
WindowManagerGlobal.addView()
:
在addView中创建了ViewRootImpl赋值给了root。然后将view,params,root全部存入了各自的列表中。最后调用了ViewRootImpl.setView() -
ViewRootImpl.setView()
:
在setView()
中通过调用requestLayout()
完成刷新的请求,接着会通过IWindowSession的addToDisplay()
来完成最终的Window添加的过程,IWindowSession是一个Binder
对象,真正的实现类是Session
,也就是说Window的添加过程试一次IPC的调用。 -
Session.addToDisplay()
:
通过WindowManagerService#addWindow()
来实现Window的添加。
我们继续看第二大方法WindowManagerGlobal#updateViewLayout()
:
4.3 View的更新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
实际上调用ViewRootImpl.setLayoutPrams()
对参数进行更新
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();
......
上面的ViewRootImpl#setLayoutParams
方法中主要做了两件事:
- 调用了
scheduleTraversals
方法来对View重新策略,布局,重绘。 - 通过
WindowSession
来更新Window视图,这个过程是由WMS
的relayoutWindow()
来实现,这同样也是一个IPC过程。
注意:这里的mTraversalRunnable
为mChoreographer
对象的回调,实际上是请求VSYNC信号后,返回VSYNC信号的回调。
4.3.2 Choreographer 编舞者
上面我们看到调用了Choreographer#postCallback()
绘制请求,进入消息队列发送,在Choreographer
创建阶段我们可以看到他的绘制节奏固定是16.63ms每帧
,帧率存储在框架层面的系统属性文件当中。
// 回调(回调函数控制)
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 }
如果是在主线程上,则向底层请求同步信号,
如果是在子线程的绘制消息,则通过消息发送执行,
两者最终都是走到scheduleVsyncLocked()
4.3.2.2 Choreographer#doScheduleVsync()
805 void doScheduleVsync() {
806 synchronized (mLock) {
807 if (mFrameScheduled) {
808 scheduleVsyncLocked();
809 }
810 }
811 }
这里被触发只有一种状况就是在子线程中调用的绘制
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 }
最后调用native方法nativeScheduleVsync()
向底层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 }
这里最终触发到doFrame()
进行具体绘制
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
中最终调用的是CallbackRecord
对象的run
,也就是前文在postCallback
中传入的runnble
对象,调用该对象就是调用doTraversal
下面我们先来看看重点方法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 }
总体而言,performTraversals的逻辑大致可以分为五块:
- 确认窗口大小
- 预测量
- 测量
performMeasure()
- 布局
performLayout()
- 绘制
performDraw()
首先,为了确认窗口大小,performTraversals()
会根据LayoutParams的宽高及其各种标志位,配合WMS给定的窗口大小,最终计算出可供View展示的大小;
然后呢,为了优化顶级View
不是DecorView
下的展示体验,performTraversals()
会进行预测量,经过预测量,会给出一个合理的尺寸,让View
进行测量;
经过预测量后,接下来就是View的三大流程:测量
、布局
以及绘制
。
我们使用网络上的一张图来帮助理解:
4.3.4 performDraw()方法调用Surface,最后会post到SurfaceFlinger。
注意:这里的performDraw()
方法会调用Surface
的方法渲染,最后会post到SurfaceFlinger
进行设备沟通展示。
一张图概括了performTraversals()
方法主要做的事情:
由于SurfaceFlinger
涉及较底层,这里暂不做过多的分析,后续再出专门的文章对其进行分析。我们可以先简单看一下它的调用流程:
看到这张图mmmmmm,SurfaceFlinger
后续再分析吧…
上面performTraversals()
方法调用了WMS
的更新方法relayoutWindow()
,我们继续往下看:
4.3.5 WindowManagerService#relayoutWindow()
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
1978 public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
1979 int requestedWidth, int requestedHeight, int viewVisibility, int flags,
1980 long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
1981 Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
1982 DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
1983 SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
......
2147 if (shouldRelayout) {
2148 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
2149
2150 result = win.relayoutVisibleWindow(result, attrChanges);
2151
2152 try {
2153 result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
2154 } catch (Exception e) {
......
2162 }
......
2173 }
......
2307 return result;
2308 }
......
2357 private int createSurfaceControl(SurfaceControl outSurfaceControl, int result, WindowState win,
2358 WindowStateAnimator winAnimator) {
2359 if (!win.mHasSurface) {
2360 result |= RELAYOUT_RES_SURFACE_CHANGED;
2361 }
2362
2363 WindowSurfaceController surfaceController;
2364 try {
2365 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
2366 surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
2367 } finally {
2368 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
2369 }
2370 if (surfaceController != null) {
2371 surfaceController.getSurfaceControl(outSurfaceControl);
2372 if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurfaceControl + ": copied");
2373 } else {
2374 // For some reason there isn't a surface. Clear the
2375 // caller's object so they see the same state.
2376 Slog.w(TAG_WM, "Failed to create surface control for " + win);
2377 outSurfaceControl.release();
2378 }
2379
2380 return result;
2381 }
createSurfaceControl()
是创建Surface
管理类的方法,实际上调用了surfaceController.getSurfaceControl(outSurfaceControl)
方法创建Surface
4.3.6 WindowSurfaceController#copyFrom()
/frameworks/base/services/core/java/com/android/server/wm/WindowSurfaceController.java
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()
方法调用的是native层
的nativeCopyFromSurfaceControl()
方法创建Surface
。
在ViewRootImpl
中我们可以看到一块画布的创建。但是这里请注意,因为最终的绘制图形数据是由底层SurfaceFilnger
完成的,所以这里我们可以认为当前Surface
是一个空的数据对象,没有任何的图像数据。
4.3.7 updateViewLayout()总结
updateViewLayout()
主要做了这几件事:
- 如果是新建View , 调用
requestLayout()
执行刷新请求 - 通过ViewRootImpl的
performTraversalsView()
方法对View进行重新测量、布局、绘制,最终通过Surface
调用了SurfaceFlinger
进行绘制。 - 通过
WindowSession
来更新Window视图,这个过程是由WMS
的relayoutWindow()
来实现,这同样也是一个IPC过程。
我们继续看第三大方法WindowManagerGlobal#removeView()
:
4.4 View的移除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
是通过ViewRootImpl
来完成删除操作的。在WindowManager中提供了两种删除接口异步删除removeView()
和同步删除removeViewImmedialte()
。
一般不会使用removeViewImmedialte来删除Window,以免发生意外错误。
所以这里使用的是异步的删除情况,采用的是die
方法。
die方法只是发送了一个请求删除的消息就立刻返回了,这个时候View并没有完成删除操作,所以最后会将其添加到mDyingViews
列表中。
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 }
这个方法里面做了判断,如果是异步删除就会发送一个 MSG_DIE 的消息,ViewRootImpl 中的 handler 会收到这个消息,并调用 doDie 方法,这就是这两种删除方式的区别。
真正删除的方法是ViewRootImpl#dispatchDetachedFromWindow()
和WindowManagerGlobal#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 }
这个方法做了一些View的移除、置空操作:
- 回调onDetachedFromeWindow;
- 垃圾回收相关操作;
- 通过Session的remove()在WMS中删除Window;
- 通过Choreographer移除监听器
重点是mWindowSession.remove(mWindow)
调用的WMS的removeWindow()
方法,这同样也是一个IPC过程,后面再分析。
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()
中view和缓存数据等移除
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 }
......
这个地方有点绕,但其实就是通过WindowState#removeIfPossible()
方法其实又调用了WMS等对象window的移除等操作。
4.4.5 WindowState#removeIfPossible()
win.removeIfPossible()
方法
/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 }
这里做了一系列的销毁和置空操作,最后调用了mSession.windowRemovedLocked()
方法:
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
的引用remove()
掉,将Surface相关的对象销毁等操作。
4.4.7 removeView()总结
removeView()
主要操作:
- 检查删除线程的正确性,如果不正确就抛出异常。
- 从ViewRootImpl列表、布局参数列表和View列表中删除与V对应的元素。
- 判断是否可以直接执行删除操作,如果不能就推迟删除操作。
- 执行删除操作,清理和释放与View相关的一切资源。
到这里,第一部分的WindowManager的三大方法:增加addView()
、更新updateViewLayout()
、删除removeView()
分析完成。
上面增加、更新、删除View的操作中,有一个IPC跨进程的类Session
。我们来看看Session
是怎么获取的
4.5 Session的创建和获取
下面我们先看一下Session的创建和获取:
/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 }
ViewRootImpl类的mWindowSession
是由WindowManagerGlobal
中静态方法获取,而我们从上面代码可以看到,其实是调用AMS的openSession()
方法创建。
4.6 三大方法的整体流程
-
WindowManager
调用WindowManagerGlobal
的方法 -
WindowManagerGlobal
调用ViewRootImpl
的方法 -
ViewRootImpl
通过Session
使用Binder
跨进程调用WMS
的方法
5 总结
WMS
窗口管理服务,每一个Window
都对应着一个View
和一个ViewRootImpl
。Window
表示一个窗口的概念,也是一个抽象的概念,它并不是实际存在的,它是以View
的方式存在的。WindowManager
是我们访问Window
的入口,Window
的具体实现位于WindowManagerService
中。WindowManager
和WindowManagerService
交互是一个IPC
的过程,最终的IPC是在RootViewImpl
中完成的。文章来源:https://www.toymoban.com/news/detail-579948.html
我们知道窗口的展示主要有Activity
和Dialog
、Toast
,结合我们前面AMS的章节,以Activity启动为例对WMS流程进行总结:文章来源地址https://www.toymoban.com/news/detail-579948.html
- 由
Launcher
发起调用 -
AMS
管理的是配置信息数据 - 具体的对象创建过程在
ActivityThread
中完成 - 有
AMS
的startActivity
触发resume
生命周期,在resume
生命周期中对于View
数据进行推送至WindowManager
进行管理,同时生成一个·ViewRootImpl·对象对于所有·View·数据进行绘制管理 -
ViewRootImpl
中依赖于编舞者工具对于绘制进行控制,一般情况为60FPS
- 具体绘制有
ViewRootImpl
中的performTraversals
进行具体绘制操作 - 绘制完成之后,因为每一个
View
都是一个Surface
,通过SurfaceFilnger
提供的Surface
每个View
绘制完成之后 - 由
WMS
统一协调各个View的层级
、尺寸
、布局
等 - 最终交由
SurfaceFilnger
进行帧合成,完成整体界面输出 - 底层由
opengl
完成
到了这里,关于【Android Framework系列】第7章 WMS原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!