WMS - Window显示流程

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 做合成操作。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,548评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,069评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,985评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,305评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,324评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,030评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,639评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,552评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,081评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,194评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,327评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,004评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,688评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,188评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,307评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,667评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,337评论 2 358

推荐阅读更多精彩内容