WindowManagerService是Framework层的核心系统服务之一,主要是用来管理window,具体包括以下几个功能:窗口添加\删除\显示、窗口动画、中转input事件、管理surface与SurfaceFlinger交互等。
以冷启动为例,activity从启动到显示,要经过创建进程、创建activity、走activity生命周期流程、创建window、绘制window、请求焦点、更新window显示状态、获得焦点等几个大的流程。对于WMS而言,主要负责的是activity生命周期走完之后的流程,以下是简要介绍。
1. Activity onResume
Activity 走生命周期流程,最终调用到 handleResumeActivity 方法,该方法中会调用 performResumeActivity 来执行 Activity的onResume方法,onResume结束后,接下来就开始调用wm.addView方法走创建window流程。
创建window结束后,若activity未退到后台,则调用makeVisible方法来使activity可见。
/frameworks/base/core/java/android/app/ActivityThread.java
5097 @Override
5098 public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
5099 boolean isForward, boolean shouldSendCompatFakeFocus, String reason) {
// 调用 performResumeActivity 来执行 Activity的onResume方法
5107 if (!performResumeActivity(r, finalStateRequest, reason)) {
5108 return;
5109 }
5136 if (r.window == null && !a.mFinished && willBeVisible) {
5137 r.window = r.activity.getWindow();
5138 View decor = r.window.getDecorView();
5139 decor.setVisibility(View.INVISIBLE);
5140 ViewManager wm = a.getWindowManager();
5141 WindowManager.LayoutParams l = r.window.getAttributes();
5142 a.mDecor = decor;
5143 l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
5157 if (a.mVisibleFromClient) {
5158 if (!a.mWindowAdded) {
5159 a.mWindowAdded = true;
// 调用 wm.addView 方法走创建 Window 流程
5160 wm.addView(decor, l);
5168 }
5183 if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
5201 r.activity.mVisibleFromServer = true;
5202 mNumVisibleActivities++;
5203 if (r.activity.mVisibleFromClient) {
// 调用 makeVisible 方法来使 Activity 可见
5204 r.activity.makeVisible();
5205 }
2. 创建 Window
2.1 创建 ViewRootImpl
ActivityThread.java handleResumeActivity 方法中 wm.addView 经过调用,最终来到 WindowManagerGlobal 中的 addView 方法:
/frameworks/base/core/java/android/view/WindowManagerImpl.java
147 @Override
148 public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
149 applyTokens(params);
// 调用 WindowManagerGlobal 中的 addView 方法
150 mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
151 mContext.getUserId());
152 }
addView 方法中,会为 Activity 创建 ViewRootImpl 对象。ViewRootImpl 是 Activity 中根 View,即 DecorView 的 parent,它的作用是连接 View 和 WindowManager,负责处理输入事件的分发、View 的绘制以及 View 的 UI 更新等。
创建viewRootImpl后,会调用setView方法来继续创建window。
/frameworks/base/core/java/android/view/WindowManagerGlobal.java
328 public void addView(View view, ViewGroup.LayoutParams params,
329 Display display, Window parentWindow, int userId) {
364 ViewRootImpl root = null;
368 synchronized (mLock) {
434 if (windowlessSession == null) {
// 为Activity 创建 ViewRootImpl 对象
435 root = UniFrameworkComponentFactory.getInstance()
436 .makeViewRootImpl(view.getContext(), display);
437 } else {
438 root = UniFrameworkComponentFactory.getInstance()
439 .makeViewRootImpl(view.getContext(), display,
440 windowlessSession, new WindowlessWindowLayout());
441 }
443 view.setLayoutParams(wparams);
445 mViews.add(view);
446 mRoots.add(root);
447 mParams.add(wparams);
450 try {
// 调用 setView 方法来继续创建 Window
451 root.setView(view, wparams, panelParentView, userId);
452 }
2.2 发起遍历绘制请求
viewRootImpl的setView方法:
- 调用 第1376行 requestLayout() 发起一次遍历绘制请求;
- 第1380行会先向应用主线程发送一个消息屏障,暂停对同步消息的处理,来使遍历绘制的请求能最快的被响应;
- 第1406行则是向choreographer注册了回调,当下一个vsync信号到来时则会执行mTraversalRunnable对象,该对象封装了遍历绘制的操作。
/frameworks/base/core/java/android/view/ViewRootImpl.java
1270 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
1271 int userId) {
1272 synchronized (this) {
1273 if (mView == null) {
1274 mView = view;
1370 mAdded = true;
1371 int res; /* = WindowManagerImpl.ADD_OKAY; */
// 发起遍历绘制请求
1376 requestLayout();
1377 InputChannel inputChannel = null;
1378 if ((mWindowAttributes.inputFeatures
1379 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
// 向应用主线程发送一个消息屏障,暂停对同步消息的处理,来使遍历绘制的请求能最快的被响应
1380 inputChannel = new InputChannel();
1381 }
1397 try {
// 向choreographer注册了回调,当下一个vsync信号到来时则会执行mTraversalRunnable对象,该对象封装了遍历绘制的操作
1406 res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
1407 getHostVisibility(), mDisplay.getDisplayId(), userId,
1408 mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
1409 mTempControls, attachedFrame, compatScale);
1434 }
1538 view.assignParent(this);
requestLayout() 发起遍历绘制请求的具体流程:
- 第2194行发完请求后,则会继续向下执行。
- 第2579行是创建了inputChanel对象(此时该对象只是一个空对象),用来后续处理input事件。
- 第2588行则是通过binder通信的方式,调用到WMS中继续走创建window的流程。mWindowSession是一个Session实例,用来进行APP --> WMS的binder通信。
/frameworks/base/core/java/android/view/ViewRootImpl.java
2178 @Override
2179 public void requestLayout() {
2192 checkThread();
2193 mLayoutRequested = true;
// 发完请求,向下执行:
2194 scheduleTraversals();
2195 }
2196 }
2558 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2559 void scheduleTraversals() {
2570 if (!mTraversalScheduled) {
2571 mTraversalScheduled = true;
// 创建了inputChanel对象(此时该对象只是一个空对象),用来后续处理input事件
2579 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过binder通信的方式,调用到WMS中继续走创建window的流程
2588 mChoreographer.postCallback(
2589 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
2607 }
2.3 创建 WindowState
windowState具有一个窗口所有的属性,是WMS中事实上的窗口。
ViewRootImpl.java setView 方法 走到 Session.java addToDisplayAsUser 方法,调用 addWindow:
/frameworks/base/services/core/java/com/android/server/wm/Session.java
208 @Override
209 public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
210 int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes,
211 InputChannel outInputChannel, InsetsState outInsetsState,
212 InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
213 float[] outSizeCompatScale) {
214 return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
215 requestedVisibleTypes, outInputChannel, outInsetsState, outActiveControls,
216 outAttachedFrame, outSizeCompatScale);
217 }
- 第1567行到第1674行在 WindowManagerService.java addWindow 方法中,首先要查找或创建 WindowToken,它是APP向WMS发起对window操作时的令牌,用来验证该APP是否有权限来改变该window。对于Activity而言,启动时会创建一个 ActivityRecord,其内部具有一个binder类型的变量token,token是对此 ActivityRecord 的弱引用,该token会被添加到 DisplayContent 中进行管理;同时 ActivityRecord 继承了 windowToken 类,因此可以作为一个 windowToken 对象。一个 DisplayContent 对应着一块屏幕,因此一个 DisplayContent 对应着多个 ActivityRecord。
- 第1747行是创建windowState,它代表着一个屏幕上的显示窗口,包含窗口的一切特性,切换activity对应着windowState的切换。
- 第1775行是真正的创建inputChanel,使input事件可以传递到viewRootImpl。
- 第1939行是因为有了对window的操作,因此当前的焦点窗口状态有可能会受影响,要走更新input窗口的流程。
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
1541 public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
1542 int displayId, int requestUserId, @InsetsType int requestedVisibleTypes,
1543 InputChannel outInputChannel, InsetsState outInsetsState,
1544 InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
1545 float[] outSizeCompatScale) {
// 查找或创建 WindowToken
1567 final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
1630 ActivityRecord activity = null;
1634 WindowToken token = displayContent.getWindowToken(
1635 hasParent ? parentWindow.mAttrs.token : attrs.token);
1644 if (token == null) {
1672 } else if (rootType >= FIRST_APPLICATION_WINDOW
1673 && rootType <= LAST_APPLICATION_WINDOW) {
1674 activity = token.asActivityRecord();
1746
// 创建 WindowState
1747 final WindowState win = new WindowState(this, session, client, token, parentWindow,
1748 appOp[0], attrs, viewVisibility, session.mUid, userId,
1749 session.mCanAddInternalSystemWindow);
// 真正的创建inputChanel,使input事件可以传递到viewRootImpl
1775 final boolean openInputChannels = (outInputChannel != null
1776 && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
1777 if (openInputChannels) {
1778 win.openInputChannel(outInputChannel);
1779 }
// 为 WindowState 创建 SurfaceSession,用来和SF进行通信
1853 win.attach();
// mWindowMap 是HashMap,中记录着所有的WindowState
1854 mWindowMap.put(client.asBinder(), win);
// 将 windowState 添加到WindowToken中
1866 win.mToken.addWindow(win);
// 有WIndow相关的操作,将更新input窗口的变量置为true
1912 displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
// 此时分配的layer是一个空layer,真正分配是在遍历绘制的时候
1933 win.getParent().assignChildLayers();
// 有了对window的操作,因此当前的焦点窗口状态有可能会受影响,要走更新input窗口的流程
1939 displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
1953 if (Build.IS_USERDEBUG) {
1954 Slog.v(TAG, "addWindow: focusChanged="+ focusChanged+" ,canReceiveKeys="
1955 + win.canReceiveKeys() + ", client=" + client.asBinder() + ", win=" + win);
1956 }
1989 return res;
1990 }
2.3 更新 Input 窗口
上述 WindowManagerService.java addWindow 方法中调到了 InputMonitor.java updateInputWindowsLw 方法:
/frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
343 void updateInputWindowsLw(boolean force) {
344 if (!force && !mUpdateInputWindowsNeeded) {
345 return;
346 }
347 scheduleUpdateInputWindows();
348 }
- 第357行,更新input窗口的流程是通过向线程post runnable对象的方式来进行的,该handler对应的线程为android.anim。
- 第717行和第718行,先遍历displayContent下属各windowState状态,更新当前的focus窗口状态。然后根据focus状态是否有变化,来确定是否发起request去通知inputDispatcher更新状态。displayContent和windowState的对应关系为:displayContent 一对多 windowToken(ActivityRecord),windowToken 一对多 windowState。
至此,window创建流程结束。
/frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
343 void updateInputWindowsLw(boolean force) {
344 if (!force && !mUpdateInputWindowsNeeded) {
345 return;
346 }
347 scheduleUpdateInputWindows();
348 }
350 private void scheduleUpdateInputWindows() {
355 if (!mUpdateInputWindowsPending) {
356 mUpdateInputWindowsPending = true;
// 更新input窗口的流程是通过向线程post runnable对象的方式来进行的
357 mHandler.post(mUpdateInputWindows);
358 }
122 private class UpdateInputWindows implements Runnable {
123 @Override
124 public void run() {
125 synchronized (mService.mGlobalLock) {
143 mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
146 }
663 private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> {
675 private void updateInputWindows(boolean inDrag) {
// 遍历displayContent下属各windowState状态,更新当前的focus窗口状态
717 mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
// 根据focus状态是否有变化,来确定是否发起request去通知inputDispatcher更新状态
718 updateInputFocusRequest(mRecentsAnimationInputConsumer);
726 }
449 private void updateInputFocusRequest(InputConsumerImpl recentsAnimationInputConsumer) {
450 final WindowState focus = mDisplayContent.mCurrentFocus;
517 final IBinder focusToken = focus != null ? focus.mInputChannelToken : null;
569 mInputFocus = null;
570 return;
571 }
2.4 执行遍历绘制
应用主线程执行完创建window后,将会去消息队列取出消息进行处理。由于之前在发起遍历绘制请求时,对消息队列设置了同步消息屏障,因此现在将首先取出异步防止的封装了遍历绘制操作的runnable对象来执行。具体流程如下:
/frameworks/base/core/java/android/view/ViewRootImpl.java
9737 final class TraversalRunnable implements Runnable {
9738 @Override
9739 public void run() {
9740 doTraversal();
9741 }
9742 }
2618 void doTraversal() {
2630 if (mTraversalScheduled) {
2631 mTraversalScheduled = false;
// 在正式开始遍历绘制之前,先移除同步消息屏障,恢复消息队列的正常状态
2632 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
2638 performTraversals();
3090 private void performTraversals() {
3094 final View host = mView;
3287 // Ask host how big it wants to be
// 对view树执行一次预测量
3288 windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(),
3289 desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure);
3388 if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
3389 || mForceNextWindowRelayout) {
3416 try {
// binder通信到WMS,由WMS根据预测量结果,对view树的参数进行调整,同时WMS也会真正为窗口创建surface
3425 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
3614 }
3695 if (!mStopped || mReportNextDraw) {
3709 // Ask host how big it wants to be
// 根据WMS调整过的参数,对view树做最终的测量
3710 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3741 }
3789 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
3792 if (didLayout) {
// layout
3793 performLayout(lp, mWidth, mHeight);
3842 }
3995 if (!cancelAndRedraw) {
// 创建Sync,sync ready后,会去执行reportDrawFinished方法继续走window绘制状态流程
4002 createSyncIfNeeded();
4020 }
4022 if (!isViewVisible) {
4040 } else {
// draw,绘制完成后调用markSyncReady,sync ready
4052 if (!performDraw(mActiveSurfaceSyncGroup) && mActiveSurfaceSyncGroup != null) {
4053 mActiveSurfaceSyncGroup.markSyncReady();
4054 }
- 1,在正式开始遍历绘制之前,先移除同步消息屏障,恢复消息队列的正常状态。
- 2,先对view树执行一次预测量。
- 3,binder通信到WMS,由WMS根据预测量结果,对view树的参数进行调整,同时WMS也会真正为窗口创建surface。
relayoutResult = mWindowSession.relayout - 4,根据WMS调整过的参数,对view树做最终的测量;
- 5,layout
- 6,创建Sync,sync ready后,会去执行reportDrawFinished方法继续走window绘制状态流程:
/frameworks/base/core/java/android/view/ViewRootImpl.java
4084 private void createSyncIfNeeded() {
4095 mWmsRequestSyncGroup = new SurfaceSyncGroup("wmsSync-" + mTag, t -> {
4096 mWmsRequestSyncGroupState = WMS_SYNC_MERGED;
4101 if (Process.myUid() == Process.SYSTEM_UID) {
4102 mHandler.postAtFrontOfQueue(() -> reportDrawFinished(t, seqId));
4103 } else {
4104 reportDrawFinished(t, seqId);
4105 }
4106 });
- 7,draw,绘制完成后调用markSyncReady,sync ready。
3. Window 显示状态更新
Window 显示状态更新流程如下:
3.1 NO_SURFACE=0
当一个窗口刚刚被WMS执行addWindow()方法创建的时候,WindowStateAnimator在WindowState的构造函数中一起被创建,在relayoutWindow之前,窗口是没有Surface的,所以不可能被显示出来,此时状态就是NO_SURFACE。
3.2 DRAWING_PENDING=1
执行遍历绘制调用relayoutWindow(),WMS会真正为窗口创建Surface,此时Surface处于空白状态,等待被绘制,即为DRAWING_PENDING。
3.3 COMMIT_DRAW_PENDING=2
window绘制完成后,等待下次刷帧被提交时的状态即为COMMIT_DRAW_PENDING;应用完成遍历绘制后,会通过以下调用更新window的显示状态:
/frameworks/base/core/java/android/view/ViewRootImpl.java
4767 private void reportDrawFinished(@Nullable Transaction t, int seqId) {
4775 try {
4776 mWindowSession.finishDrawing(mWindow, t, seqId);
/frameworks/base/services/core/java/com/android/server/wm/Session.java
286 @Override
287 public void finishDrawing(IWindow window,
288 @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
293 mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
295 }
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
2864 void finishDrawingWindow(Session session, IWindow client,
2865 @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
2871 try {
2872 synchronized (mGlobalLock) {
2873 WindowState win = windowForClientLocked(session, client, false);
2876 if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
/frameworks/base/services/core/java/com/android/server/wm/WindowState.java
5936 boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
6020 layoutNeeded |= mWinAnimator.finishDrawingLocked(postDrawTransaction);
6021 // We always want to force a traversal after a finish draw for blast sync.
6022 return !skipLayout && (hasSyncHandlers || layoutNeeded);
6023 }
/frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
214 boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction) {
224 if (mDrawState == DRAW_PENDING) {
231 mDrawState = COMMIT_DRAW_PENDING;
232 layoutNeeded = true;
248 }
250 if (postDrawTransaction != null) {
261 SurfaceControl.Transaction syncTransaction = mWin.getSyncTransaction();
268 syncTransaction.merge(postDrawTransaction);
269 /* @} */
270 layoutNeeded = true;
271 }
272
273 return layoutNeeded;
274 }
3.4 READY_TO_SHOW
window绘制完成的状态已经被提交,等待被显示时的状态即为READY_TO_SHOW,一般要等待同一个windowToken下的所有窗口均绘制完成才能向下一个状态切换,会通过以下调用更新显示状态:
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
2864 void finishDrawingWindow(Session session, IWindow client,
2865 @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
2871 try {
2872 synchronized (mGlobalLock) {
2882 mWindowPlacerLocked.requestTraversal();
/frameworks/base/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
232 void requestTraversal() {
239 mTraversalScheduled = true;
245 mService.mAnimationHandler.post(mPerformSurfacePlacement);
55 private class Traverser implements Runnable {
56 @Override
57 public void run() {
58 synchronized (mService.mGlobalLock) {
59 performSurfacePlacement();
60 }
61 }
62 }
116 final void performSurfacePlacement() {
117 performSurfacePlacement(false /* force */);
118 }
120 final void performSurfacePlacement(boolean force) {
126 do {
127 mTraversalScheduled = false;
128 performSurfacePlacementLoop();
129 mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
130 loopCount--;
131 } while (mTraversalScheduled && loopCount > 0);
132 mService.mRoot.mWallpaperActionPending = false;
133 }
135 private void performSurfacePlacementLoop() {
186 try {
187 mService.mRoot.performSurfacePlacement();
/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
786 void performSurfacePlacement() {
788 try {
789 performSurfacePlacementNoTrace();
797 void performSurfacePlacementNoTrace() {
826 mWmService.openSurfaceTransaction();
827 try {
828 applySurfaceChangesTransaction();
831 } finally {
832 mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
838 }
846 checkAppTransitionReady(surfacePlacer);
962 // Check to see if we are now in a state where the screen should
963 // be enabled, because the window obscured flags have changed.
964 mWmService.enableScreenIfNeededLocked();
966 mWmService.scheduleAnimationLocked();
1003 private void applySurfaceChangesTransaction() {
1021 final int count = mChildren.size();
1022 for (int j = 0; j < count; ++j) {
1023 final DisplayContent dc = mChildren.get(j);
1024 dc.applySurfaceChangesTransaction();
1025 }
/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
5279 // TODO: Super unexpected long method that should be broken down...
5280 void applySurfaceChangesTransaction() {
5323 try {
5324 forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
1086 private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
1184 if (w.mHasSurface) {
1185 // Take care of the window being ready to display.
1186 final boolean committed = winAnimator.commitFinishDrawingLocked();
/frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
276 // This must be called while inside a transaction.
277 boolean commitFinishDrawingLocked() {
288 mDrawState = READY_TO_SHOW;
289 boolean result = false;
290 final ActivityRecord activity = mWin.mActivityRecord;
291 if (activity == null || activity.canShowWindows()
292 || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
293 result = mWin.performShowLocked();
294 }
295 return result;
296 }
3.5 HAS_DRAWN
上述的 WindowStateAnimator.java commitFinishDrawingLocked 中调用 performShowLocked 方法,window在WMS端已经被显示的状态即为HAS_DRAWN;会通过以下调用更新显示状态:
/frameworks/base/services/core/java/com/android/server/wm/WindowState.java
4479 // This must be called while inside a transaction.
4480 boolean performShowLocked() {
4497 logPerformShow("performShow on ", true);
4523 logPerformShow("Showing ", false);
4526 mWmService.enableScreenIfNeededLocked();
4527 mWinAnimator.applyEnterAnimationLocked();
4529 // Force the show in the next prepareSurfaceLocked() call.
4530 mWinAnimator.mLastAlpha = -1;
4546 mWinAnimator.mDrawState = HAS_DRAWN;
4547 mWmService.scheduleAnimationLocked();
Window的状态为HAS_DRAWN,这个时候的绘制就已经完成了,等着下一步去显示。
4. 送显流程
当mDrawState的值为HAS_DRAWN的时候会进入下面的逻辑,这个时候就是开始show的过程,调用 showRobustly() 方法:
/frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
510 void prepareSurfaceLocked(SurfaceControl.Transaction t) {
545 boolean prepared =
546 mSurfaceController.prepareToShowInTransaction(t, mShownAlpha);
547
548 if (prepared && mDrawState == HAS_DRAWN) {
549 if (mLastHidden) {
550 mSurfaceController.showRobustly(t);
551 mLastHidden = false;
552 final DisplayContent displayContent = w.getDisplayContent();
553 if (!displayContent.getLastHasContent()) {
554 // This draw means the difference between unique content and mirroring.
555 // Run another pass through performLayout to set mHasContent in the
556 // LogicalDisplay.
557 displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
563 }
564 }
565 }
566 }
在showRobuly()中通过t.show的方式告知底层做了show的动作:
/frameworks/base/services/core/java/com/android/server/wm/WindowSurfaceController.java
270 void showRobustly(SurfaceControl.Transaction t) {
296 setShown(true);
297 t.show(mSurfaceControl);
304 }
最终调到 SurfaceControl.java 中的 show 方法,通过nativeSetFlags调到Jni层。(JNI 是Java Native Interface的缩写,表示"Java本地调用"。通过JNI技术可以实现Java调用C程序、C程序调用Java代码。JNi的使用步骤:java声明native函数 -> jni实现对应的c函数 -> 编译生成so库 -> java 加载so库,并调用native函数)
/frameworks/base/core/java/android/view/SurfaceControl.java
2991 public Transaction show(SurfaceControl sc) {
3002 checkPreconditions(sc);
3003 nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
3004 return this;
3005 }
110 public final class SurfaceControl implements Parcelable {
155 private static native void nativeSetFlags(long transactionObj, long nativeObject,
156 int flags, int mask);
Transaction->setFlags(ctrl, flags, mask)是传到SurfaceComposerClient中的接口。
/frameworks/base/core/jni/android_view_SurfaceControl.cpp
716 static void nativeSetFlags(JNIEnv* env, jclass clazz, jlong transactionObj,
717 jlong nativeObject, jint flags, jint mask) {
718 auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
719
720 SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
721 transaction->setFlags(ctrl, flags, mask);
722 }
READY_TO_SHOW 和 HAS_DRAW 状态与底层的合成和送显流程没有必要的对应关系。HAS_DRAW 的状态只能说明此时 window 的状态完成了,但是是否显示需要看是否走到show流程,show流程会通过 nativeSetFlag 将相关 flag 传递到底层,底层根据 flag 做合成操作。