美文网首页
Android亮屏流程之窗口绘制

Android亮屏流程之窗口绘制

作者: 米豆同学 | 来源:发表于2019-10-08 15:17 被阅读0次

    一、亮屏流程

    点亮屏幕会调用PowerManagerService关键方法updatePowerStateLocked
    frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java

         protected void updatePowerStateLocked() {
             if (!mSystemReady || mDirty == 0) {
                 return;
             }
             if (!Thread.holdsLock(mLock)) {
                 Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
             }
     
             Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
             try {
                 // Phase 0: Basic state updates.
                 updateIsPoweredLocked(mDirty);
                 updateStayOnLocked(mDirty);
                 updateScreenBrightnessBoostLocked(mDirty);
     
                 // Phase 1: Update wakefulness.
                 // Loop because the wake lock and user activity computations are influenced
                 // by changes in wakefulness.
                 final long now = SystemClock.uptimeMillis();
                 int dirtyPhase2 = 0;
                 for (;;) {
                     int dirtyPhase1 = mDirty;
                     dirtyPhase2 |= dirtyPhase1;
                     mDirty = 0;
     
                     updateWakeLockSummaryLocked(dirtyPhase1);
                     updateUserActivitySummaryLocked(now, dirtyPhase1);
                     if (!updateWakefulnessLocked(dirtyPhase1)) {
                         break;
                     }
                 }
     
                 // Phase 2: Update display power state.
                 boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
     
                 // Phase 3: Update dream state (depends on display ready signal).
                 updateDreamLocked(dirtyPhase2, displayBecameReady);
     
                 // Phase 4: Send notifications, if needed.
                 finishWakefulnessChangeIfNeededLocked();
     
                 // Phase 5: Update suspend blocker.
                 // Because we might release the last suspend blocker here, we need to make sure
                 // we finished everything else first!
                 updateSuspendBlockerLocked();
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_POWER);
             }
         }
    

    其中调用updateDisplayPowerStateLocked->DisplayPowerController.requestPowerState->sendUpdatePowerStateLocked->updatePowerState->animateScreenStateChange->setScreenState->blockScreenOn()

    frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

       private boolean setScreenState(int state, boolean reportOnly) {
           ... ...
           if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
               setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_ON);
               if (mPowerState.getColorFadeLevel() == 0.0f) {
                   blockScreenOn();
               } else {
                   unblockScreenOn();
               }
               mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);
           }
    
           // Return true if the screen isn't blocked.
           return mPendingScreenOnUnblocker == null;
       }
    
    

    blockScreenOn中对mPendingScreenOnUnblocker赋值,并记录时间用于打印log,

        private void blockScreenOn() {
            if (mPendingScreenOnUnblocker == null) {
                //asyncTrace可以不在一个方法里
                Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
                //创建ScreenOnUnblocker对象等待窗口绘制玩回调
                mPendingScreenOnUnblocker = new ScreenOnUnblocker();
                mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
                Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
            }
        }
    

    接下来看mWindowManagerPolicy.screenTurningOn,这里开始绘制锁屏和其他窗口,分别调用PhoneWindowManager 的finishKeyguardDrawn->mWindowManagerInternal.waitForAllWindowsDrawn->mWindowManagerDrawCallback.run->finishWindowsDrawn->finishScreenTurningOn,在这里回调blockScreenOn中创建的mPendingScreenOnUnblocker.onScreenOn方法

    frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

        @Override
        public void screenTurningOn(final ScreenOnListener screenOnListener) {
            if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
    
            updateScreenOffSleepToken(false);
            synchronized (mLock) {
                mScreenOnEarly = true;
                mScreenOnFully = false;
                mKeyguardDrawComplete = false;
                mWindowManagerDrawComplete = false;
                mScreenOnListener = screenOnListener;
    
                if (mKeyguardDelegate != null) {
                    mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
                    mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
                            getKeyguardDrawnTimeout());
                    mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
                } else {
                    if (DEBUG_WAKEUP) Slog.d(TAG,
                            "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
                    finishKeyguardDrawn();
                }
            }
        }
    

    frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

       private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
           @Override
           public void onScreenOn() {
               Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this);
               msg.setAsynchronous(true);
               mHandler.sendMessage(msg);
           }
       }
    
       private final class DisplayControllerHandler extends Handler {
           public DisplayControllerHandler(Looper looper) {
               super(looper, null, true /*async*/);
           }
    
           @Override
           public void handleMessage(Message msg) {
                   ... ...
    
                   case MSG_SCREEN_ON_UNBLOCKED:
                       if (mPendingScreenOnUnblocker == msg.obj) {
                           unblockScreenOn();
                           updatePowerState();
                       }
                       break;
               }
           }
       }
    

    收到窗口绘制完成回调后将mPendingScreenOnUnblocker赋空

        private void unblockScreenOn() {
            if (mPendingScreenOnUnblocker != null) {
                mPendingScreenOnUnblocker = null;
                long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
                Slog.i(TAG, "Unblocked screen on after " + delay + " ms");
                Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
            }
        }
    

    然后再次调用updatePowerState ,此时mPendingScreenOnUnblocker == null,因此调用mWindowManagerPolicy.screenTurnedOn通知PhoneWindowManager 屏幕已点亮

    private void updatePowerState() {
        ... ...
            // Determine whether the display is ready for use in the newly requested state.
            // Note that we do not wait for the brightness ramp animation to complete before
            // reporting the display is ready because we only need to ensure the screen is in the
            // right power state even as it continues to converge on the desired brightness.
            final boolean ready = mPendingScreenOnUnblocker == null &&
                    (!mColorFadeEnabled ||
                            (!mColorFadeOnAnimator.isStarted() && !mColorFadeOffAnimator.isStarted()))
                    && mPowerState.waitUntilClean(mCleanListener);
            final boolean finished = ready
                    && !mScreenBrightnessRampAnimator.isAnimating();
                // Notify policy about screen turned on.
            if (ready && state != Display.STATE_OFF
                    && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_ON) {
                setReportedScreenState(REPORTED_TO_POLICY_SCREEN_ON);
                mWindowManagerPolicy.screenTurnedOn();
            }
    }
    
        private void setReportedScreenState(int state) {
            Trace.traceCounter(Trace.TRACE_TAG_POWER, "ReportedScreenStateToPolicy", state);
            mReportedScreenStateToPolicy = state;
        }
    

    updatePowerState后面有调用setScreenState

       private boolean setScreenState(int state, boolean reportOnly) {
           final boolean isOff = (state == Display.STATE_OFF);
           if (mPowerState.getScreenState() != state) {
    
               ... ...
    
               if (!reportOnly) {
                   mPowerState.setScreenState(state);
                   // Tell battery stats about the transition.
                   try {
                       mBatteryStats.noteScreenState(state);
                   } catch (RemoteException ex) {
                       // same process
                   }
               }
           }
       }
    

    DisplayPowerState.setScreenState->scheduleScreenUpdate 最终通知底层(LocalDisplayAdapter,SurfaceControl,HWComposer)真正的点亮屏幕

    二、绘制锁屏和窗口

    上面DisplayPowerController.setScreenState方法中首先blockScreenOn,然后开始绘制窗口,等待回调

    frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

       private boolean setScreenState(int state, boolean reportOnly) {
           ... ...
           if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
               setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_ON);
               if (mPowerState.getColorFadeLevel() == 0.0f) {
                   blockScreenOn();
               } else {
                   unblockScreenOn();
               }
               mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);
           }
    
           // Return true if the screen isn't blocked.
           return mPendingScreenOnUnblocker == null;
       }
    
    

    /MP02/AMSS/LINUX/android/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

          // Called on the DisplayManager's DisplayPowerController thread.
          @Override
          public void screenTurningOn(final ScreenOnListener screenOnListener) {
              if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
      
              updateScreenOffSleepToken(false);
              synchronized (mLock) {
                  mScreenOnEarly = true;
                  mScreenOnFully = false;
                  mKeyguardDrawComplete = false;
                  mWindowManagerDrawComplete = false;
                  mScreenOnListener = screenOnListener;
      
                  if (mKeyguardDelegate != null) {
                      mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
                      mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
                              getKeyguardDrawnTimeout());
                      mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
                  } else {
                      if (DEBUG_WAKEUP) Slog.d(TAG,
                              "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
                      finishKeyguardDrawn();
                  }
              }
          }
          //绘制结束后回调
        final DrawnListener mKeyguardDrawnCallback = new DrawnListener() {
              @Override
              public void onDrawn() {
                  if (DEBUG_WAKEUP) Slog.d(TAG, "mKeyguardDelegate.ShowListener.onDrawn.");
                  mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
              }
          };
    

    开始绘制锁屏

    MP02/AMSS/LINUX/android/frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java

          public void onScreenTurnedOn() {
              Trace.beginSection("KeyguardViewMediator#onScreenTurnedOn");
              notifyScreenTurnedOn();
              mUpdateMonitor.dispatchScreenTurnedOn();
              Trace.endSection();
          }
          
          private void handleNotifyScreenTurnedOn() {
              Trace.beginSection("KeyguardViewMediator#handleNotifyScreenTurnedOn");
              if (LatencyTracker.isEnabled(mContext)) {
                  LatencyTracker.getInstance(mContext).onActionEnd(LatencyTracker.ACTION_TURN_ON_SCREEN);
              }
              synchronized (this) {
                  if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOn");
                  mStatusBarKeyguardViewManager.onScreenTurnedOn();
              }
              Trace.endSection();
          }
    

    绘制结束后调用finishKeyguardDrawn

    /MP02/AMSS/LINUX/android/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

          private void finishKeyguardDrawn() {
              synchronized (mLock) {
                  if (!mScreenOnEarly || mKeyguardDrawComplete) {
                      return; // We are not awake yet or we have already informed of this event.
                  }
      
                  mKeyguardDrawComplete = true;
                  if (mKeyguardDelegate != null) {
                      mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
                  }
                  mWindowManagerDrawComplete = false;
              }
      
              // ... eventually calls finishWindowsDrawn which will finalize our screen turn on
              // as well as enabling the orientation change logic/sensor.
              mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
                      WAITING_FOR_DRAWN_TIMEOUT);
          }
    

    开始绘制其他可见窗口
    frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

              @Override
              public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
                  boolean allWindowsDrawn = false;
                  synchronized (mWindowMap) {
                      mWaitingForDrawnCallback = callback;
                      getDefaultDisplayContentLocked().waitForAllWindowsDrawn();
                      mWindowPlacerLocked.requestTraversal();
                      mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
                      if (mWaitingForDrawn.isEmpty()) {
                          allWindowsDrawn = true;
                      } else {
                          mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
                          checkDrawnWindowsLocked();
                      }
                  }
                  if (allWindowsDrawn) {
                      callback.run();
                  }
              }
    

    所以绘制锁屏和其他可见窗口的时间会影响亮屏速度,继续往下看

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

          void waitForAllWindowsDrawn() {
              final WindowManagerPolicy policy = mService.mPolicy;
              forAllWindows(w -> {
                  final boolean keyguard = policy.isKeyguardHostWindow(w.mAttrs);
                  if (w.isVisibleLw() && (w.mAppToken != null || keyguard)) {
                      w.mWinAnimator.mDrawState = DRAW_PENDING;
                      // Force add to mResizingWindows.
                      w.mLastContentInsets.set(-1, -1, -1, -1);
                      mService.mWaitingForDrawn.add(w);
                  }
              }, true /* traverseTopToBottom */);
          }
    
    1. waitForAllWindowsDrawn 设置窗口绘制状态,将需要绘制的窗口放入mWaitingForDrawn,
    2. mWindowPlacerLocked.requestTraversal 绘制窗口
      WindowSurfacePlacer的requestTraversal方法只是向AnimationThread 线程post了一个mPerformSurfacePlacement Runnable,mAnimationHandler收到这个消息后,performSurfacePlacement()方法就会执行,接着调用 performSurfacePlacementLoop->RootWindowContainer.performSurfacePlacement,
      AnimationThread 继承 HandlerThread 一个带Looper 的Thread

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

         void requestTraversal() {
             if (!mTraversalScheduled) {
                 mTraversalScheduled = true;
                 mService.mAnimationHandler.post(mPerformSurfacePlacement);
             }
         }
    
         public WindowSurfacePlacer(WindowManagerService service) {
             mService = service;
             mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
             mPerformSurfacePlacement = () -> {
                 synchronized (mService.mWindowMap) {
                     performSurfacePlacement();
                 }
             };
         }
    

    所以performSurfacePlacement 也是在AnimationThread中执行,因此如果有耗时动画,会影响performSurfacePlacement方法执行,进而影响commitFinishDrawingLocked调用,commitFinishDrawingLocked调用后才会点亮屏幕,因此如果出现亮屏慢的问题,也可以监控AnimationThread中的Looper,看看改线程正在执行什么消息

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

       //"Something has changed!  Let's make it correct now."
       // TODO: Super crazy long method that should be broken down...
       void performSurfacePlacement(boolean recoveringMemory) {
           if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
                   + Debug.getCallers(3));
           ... ...
           //建立和SurfaceFlinger通信 ,openTransaction和closeTransaction之间是对surface进行操作,如setSize,setLayer,setPosition等都不是及时生效的,而是要等到业务关闭之后才统一通知SurfaceFlinger,可以避免属性过快带来的画面不稳定
                   ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
           mService.openSurfaceTransaction();
           try {
               applySurfaceChangesTransaction(recoveringMemory, defaultDw, defaultDh);
           } catch (RuntimeException e) {
               Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
           } finally {
               mService.closeSurfaceTransaction();
               if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                       "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
           }
    
           ... ...
    
           //开始动画发送choreography.postCallback
           mService.scheduleAnimationLocked();
           mService.mWindowPlacerLocked.destroyPendingSurfaces();
    
           if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
                   "performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
       }
    
    

    applySurfaceChangesTransaction中计算窗口大小及完成窗口动画

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

       boolean applySurfaceChangesTransaction(boolean recoveringMemory) {
    
           final int dw = mDisplayInfo.logicalWidth;
           final int dh = mDisplayInfo.logicalHeight;
           final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
    
           mTmpUpdateAllDrawn.clear();
    
           int repeats = 0;
           //最多循环6次,计算窗口大小
           do {
               repeats++;
               if (repeats > 6) {
                   Slog.w(TAG, "Animation repeat aborted after too many iterations");
                   clearLayoutNeeded();
                   break;
               }
               ... ...
    
               if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
                   setLayoutNeeded();
               }
    
               // FIRST LOOP: Perform a layout, if needed.
               //计算窗口重点在这里
               if (repeats < LAYOUT_REPEAT_THRESHOLD) {
                   performLayout(repeats == 1, false /* updateInputWindows */);
               } else {
                   Slog.w(TAG, "Layout repeat skipped after too many iterations");
               }
    
               // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think it is animating.
               pendingLayoutChanges = 0;
               //pendingLayoutChanges赋值,判断是否需要下一次计算
               if (isDefaultDisplay) {
                   mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);
                   forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
                   pendingLayoutChanges |= mService.mPolicy.finishPostLayoutPolicyLw();
                   if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
                           "after finishPostLayoutPolicyLw", pendingLayoutChanges);
               }
           } while (pendingLayoutChanges != 0);
    
           mTmpApplySurfaceChangesTransactionState.reset();
           resetDimming();
    
           mTmpRecoveringMemory = recoveringMemory;
           //调用 winAnimator.computeShownFrameLocked(); 计算动画变换矩阵 包括转屏,平移等动画
           forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
           ... ...
    
           return mTmpApplySurfaceChangesTransactionState.focusDisplayed;
       }
    
    
    1. 窗口大小计算
      void performLayout(boolean initial, boolean updateInputWindows) {
         ... ...
    
         // First perform layout of any root windows (not attached to another window).
         //mPerformLayout中调用mPolicy.layoutWindowLw()得到窗口布局的8个区域,而后WindowState.computeFrameLw()得到四个区域,根据这四个区域再加上
         //LayoutParames和ViewRootImpl中的requestHeight,requestWidth得到最终的窗口大小保存到mFrame中
         forAllWindows(mPerformLayout, true /* traverseTopToBottom */);
    
         ... ...
     }
    
    1. 窗口绘制状态更新
      private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
          ... ...
    
          final WindowStateAnimator winAnimator = w.mWinAnimator;
    
          //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
          w.mContentChanged = false;
    
          // Moved from updateWindowsAndWallpaperLocked().
          if (w.mHasSurface) {
              // Take care of the window being ready to display.
              // 窗口绘制完成,更新状态
              final boolean committed = winAnimator.commitFinishDrawingLocked();
              ... ...       
              final TaskStack stack = w.getStack();
              if ((!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening())
                      || (stack != null && stack.isAnimatingBounds())) {
                  //计算AppWindowAnimator,ScreenRotationAnimation,WindowStateAnimatior加一起的变换矩阵
                  winAnimator.computeShownFrameLocked();
              }
              winAnimator.setSurfaceBoundariesLocked(mTmpRecoveringMemory /* recoveringMemory */);
          }
          ... ...
      };
    

    commitFinishDrawingLocked方法中调用WindowState.performShowLocked更新窗口绘制状态 为HAS_DRAWN

    绘制之后检查窗口状态checkDrawnWindowsLocked,已经画完的窗口,从mWaitingForDrawn中移除,如果mWaitingForDrawn为空,则移除WAITING_FOR_DRAWN_TIMEOUT消息。

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

          void checkDrawnWindowsLocked() {
              if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
                  return;
              }
              for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) {
                  WindowState win = mWaitingForDrawn.get(j);
                  if (DEBUG_SCREEN_ON) Slog.i(TAG_WM, "Waiting for drawn " + win +
                          ": removed=" + win.mRemoved + " visible=" + win.isVisibleLw() +
                          " mHasSurface=" + win.mHasSurface +
                          " drawState=" + win.mWinAnimator.mDrawState);
                  if (win.mRemoved || !win.mHasSurface || !win.mPolicyVisibility) {
                      // Window has been removed or hidden; no draw will now happen, so stop waiting.
                      if (DEBUG_SCREEN_ON) Slog.w(TAG_WM, "Aborted waiting for drawn: " + win);
                      mWaitingForDrawn.remove(win);
                  } else if (win.hasDrawnLw()) {
                      // Window is now drawn (and shown).
                      if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "Window drawn win=" + win);
                      mWaitingForDrawn.remove(win);
                  }
              }
              if (mWaitingForDrawn.isEmpty()) {
                  if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "All windows drawn!");
                  mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
                  mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN);
              }
          }
    

    如果1s内还没有移除WAITING_FOR_DRAWN_TIMEOUT消息,则打印timeout log,不再等待窗口绘制,直接亮屏
    android/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

              case WAITING_FOR_DRAWN_TIMEOUT: {
                  Runnable callback = null;
                  synchronized (mWindowMap) {
                      Slog.w(TAG_WM, "Timeout waiting for drawn: undrawn=" + mWaitingForDrawn);
                      mWaitingForDrawn.clear();
                      callback = mWaitingForDrawnCallback;
                      mWaitingForDrawnCallback = null;
                  }
                  if (callback != null) {
                      callback.run();
                  }
                  break;
              }
    
    1. 触发绘制动画
      frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
       void scheduleAnimationLocked() {
           mAnimator.scheduleAnimation();
       }
    

    向Choreographer 发起绘制动画请求
    frameworks/base/services/core/java/com/android/server/wm/

       void scheduleAnimation() {
           if (!mAnimationFrameCallbackScheduled) {
               mAnimationFrameCallbackScheduled = true;
               mChoreographer.postFrameCallback(mAnimationFrameCallback);
           }
       }
    

    Callback mAnimationFrameCallback在AnimationThread线程执行,AnimationThread是一个HandlerThread,所有窗口动画在该线程中执行
    android/frameworks/base/services/core/java/com/android/server/wm/WindowAnimator.java

       WindowAnimator(final WindowManagerService service) {
           mService = service;
           mContext = service.mContext;
           mPolicy = service.mPolicy;
           mWindowPlacerLocked = service.mWindowPlacerLocked;
           //在AnimationThread中创建Choreographer对象,所以实在AnimationThread所在的线程执行动画
           AnimationThread.getHandler().runWithScissors(
                   () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
    
            mAnimationFrameCallback = frameTimeNs -> {
                synchronized (mService.mWindowMap) {
                    mAnimationFrameCallbackScheduled = false;
                }
                animate(frameTimeNs);
            };
        }
    

    窗口动画分为:

    • AppWindowAnimator
      Activity进入退出动画

    • ScreenRotationAnimation
      窗口旋转动画

    • WindowStateAnimator
      普通窗口动画

      1. 负责合成 AppWindowAnimator,ScreenRotationAnimation,WindowStateAnimatior的变换矩阵
      2. 保存了窗口Surface属性
    • DimAnimation

    WindowAnimator单例,用于管理所有窗口动画

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

      private void animate(long frameTimeNs) {
        ... ... 
    
            synchronized (mService.mWindowMap) {
                mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
                mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
                mAnimating = false;
                mAppWindowAnimating = false;
                if (DEBUG_WINDOW_TRACE) {
                    Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
                }
    
                if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate");
                mService.openSurfaceTransaction();
                try {
                    final AccessibilityController accessibilityController =
                            mService.mAccessibilityController;
                    final int numDisplays = mDisplayContentsAnimators.size();
                    for (int i = 0; i < numDisplays; i++) {
                        final int displayId = mDisplayContentsAnimators.keyAt(i);
                        final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
                        //1. Activity切换动画,AppWindowAnimator中专门执行Activity动画
                        dc.stepAppWindowsAnimation(mCurrentTime);
                        DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
                        //2. 屏幕旋转动画
                        final ScreenRotationAnimation screenRotationAnimation =
                                displayAnimator.mScreenRotationAnimation;
                        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
                            if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
                                setAnimating(true);
                            } else {
                                mBulkUpdateParams |= SET_UPDATE_ROTATION;
                                screenRotationAnimation.kill();
                                displayAnimator.mScreenRotationAnimation = null;
    
                                //TODO (multidisplay): Accessibility supported only for the default
                                // display.
                                if (accessibilityController != null && dc.isDefaultDisplay) {
                                    // We just finished rotation animation which means we did not
                                    // announce the rotation and waited for it to end, announce now.
                                    accessibilityController.onRotationChangedLocked(
                                            mService.getDefaultDisplayContentLocked());
                                }
                            }
                        }
    
                        // Update animations of all applications, including those
                        // associated with exiting/removed apps
                        ++mAnimTransactionSequence;
                        //3.  WindowStateAnimator.stepAnimationLocked更新普通窗口动画
                        dc.updateWindowsForAnimator(this);
                        //4. 壁纸动画
                        dc.updateWallpaperForAnimator(this);
                        //5. 将变换矩阵设置在Surface上
                        dc.prepareWindowSurfaces();
                    }
                    ... ...
                    //是否申请绘制下一桢动画
                    if (mService.mDragState != null) {
                        mAnimating |= mService.mDragState.stepAnimationLocked(mCurrentTime);
                    }
                    ... ...
                } catch (RuntimeException e) {
                    Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
                } finally {
                    mService.closeSurfaceTransaction();
                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
                }
                //继续绘制
                if (!mAnimating && mLastAnimating) {
                    mWindowPlacerLocked.requestTraversal();
                    mService.mTaskSnapshotController.setPersisterPaused(false);
                    Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
                }
    
                 ... ...
            }
        }
    

    animate方法主要调用了AppWindowAnimator,ScreenRotationAnimation,WindowStateAnimator的stepAnimationLocked方法,stepAnimationLocked将状态迁移到由时间戳currentTime所指定的一桢上。
    下面以WindowStateAnimator的stepAnimationLocked方法为例

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

      //计算mTransformation
      private boolean stepAnimation(long currentTime) {
           if ((mAnimation == null) || !mLocalAnimating) {
               return false;
           }
           currentTime = getAnimationFrameTime(mAnimation, currentTime);
           mTransformation.clear();
           final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
           if (mAnimationStartDelayed && mAnimationIsEntrance) {
               mTransformation.setAlpha(0f);
           }
           if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
                   + ", xform=" + mTransformation);
           return more;
       }
    
       // This must be called while inside a transaction.  Returns true if
       // there is more animation to run.
       boolean stepAnimationLocked(long currentTime) {
           // Save the animation state as it was before this step so WindowManagerService can tell if
           // we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
           mWasAnimating = mAnimating;
           final DisplayContent displayContent = mWin.getDisplayContent();
           if (mWin.mToken.okToAnimate()) {
               // We will run animations as long as the display isn't frozen.
    
               if (mWin.isDrawnLw() && mAnimation != null) {
                   mHasTransformation = true;
                   mHasLocalTransformation = true;
                   if (!mLocalAnimating) {
                       if (DEBUG_ANIM) Slog.v(
                           TAG, "Starting animation in " + this +
                           " @ " + currentTime + ": ww=" + mWin.mFrame.width() +
                           " wh=" + mWin.mFrame.height() +
                           " dx=" + mAnimDx + " dy=" + mAnimDy +
                           " scale=" + mService.getWindowAnimationScaleLocked());
                       final DisplayInfo displayInfo = displayContent.getDisplayInfo();
                       if (mAnimateMove) {
                           mAnimateMove = false;
                           mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
                                   mAnimDx, mAnimDy);
                       } else {
                           mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
                                   displayInfo.appWidth, displayInfo.appHeight);
                       }
                       mAnimDx = displayInfo.appWidth;
                       mAnimDy = displayInfo.appHeight;
                       mAnimation.setStartTime(mAnimationStartTime != -1
                               ? mAnimationStartTime
                               : currentTime);
                       mLocalAnimating = true;
                       mAnimating = true;
                   }
                   if ((mAnimation != null) && mLocalAnimating) {
                       mLastAnimationTime = currentTime;
                       if (stepAnimation(currentTime)) {
                           return true;
                       }
                   }
    
               }
               ... ...
    
           return false;
       }
    

    来到animate方法的第五步开始在Surface上绘制

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

     void prepareSurfaceLocked(final boolean recoveringMemory) {
           ... ...
           //计算AppWindowAnimatior,ScreenRotaionAnimator,WindowStateAnimatior 的变换矩阵 Transformation
           computeShownFrameLocked();
    
           setSurfaceBoundariesLocked(recoveringMemory);
    
           if (mIsWallpaper && !mWin.mWallpaperVisible) {
               // Wallpaper is no longer visible and there is no wp target => hide it.
               hide("prepareSurfaceLocked");
           } else if (w.isParentWindowHidden() || !w.isOnScreen()) {
               hide("prepareSurfaceLocked");
               mWallpaperControllerLocked.hideWallpapers(w);
    
               // If we are waiting for this window to handle an orientation change. If this window is
               // really hidden (gone for layout), there is no point in still waiting for it.
               // Note that this does introduce a potential glitch if the window becomes unhidden
               // before it has drawn for the new orientation.
               if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
                   w.setOrientationChanging(false);
                   if (DEBUG_ORIENTATION) Slog.v(TAG,
                           "Orientation change skips hidden " + w);
               }
           } else if (mLastLayer != mAnimLayer
                   || mLastAlpha != mShownAlpha
                   || mLastDsDx != mDsDx
                   || mLastDtDx != mDtDx
                   || mLastDsDy != mDsDy
                   || mLastDtDy != mDtDy
                   || w.mLastHScale != w.mHScale
                   || w.mLastVScale != w.mVScale
                   || mLastHidden) {
               displayed = true;
               mLastAlpha = mShownAlpha;
               mLastLayer = mAnimLayer;
               mLastDsDx = mDsDx;
               mLastDtDx = mDtDx;
               mLastDsDy = mDsDy;
               mLastDtDy = mDtDy;
               w.mLastHScale = w.mHScale;
               w.mLastVScale = w.mVScale;
               if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
                       "controller=" + mSurfaceController +
                       "alpha=" + mShownAlpha + " layer=" + mAnimLayer
                       + " matrix=[" + mDsDx + "*" + w.mHScale
                       + "," + mDtDx + "*" + w.mVScale
                       + "][" + mDtDy + "*" + w.mHScale
                       + "," + mDsDy + "*" + w.mVScale + "]", false);
                //修改Surface的layer、matrix、alpha等属性,从而实现窗口动画的渲染
               boolean prepared =
                   mSurfaceController.prepareToShowInTransaction(mShownAlpha,
                           mDsDx * w.mHScale * mExtraHScale,
                           mDtDx * w.mVScale * mExtraVScale,
                           mDtDy * w.mHScale * mExtraHScale,
                           mDsDy * w.mVScale * mExtraVScale,
                           recoveringMemory);
               mSurfaceController.setLayer(mAnimLayer);
    
               ... ...
       }
    

    至此完成了一帧窗口动画的绘制

    总结

    1. 屏幕点亮首先调用PowerManagerService.updatePowerStateLocked方法,DisplayPowerController通过调用blockScreenOn和unblockScreenOn方法等待锁屏和其他窗口绘制
    2. 首先绘制锁屏,锁屏绘制完后调用WMS.waitForAllWindowsDrawn绘制其他可见窗口,一般是statusBar和Wallpaper窗口,同时发送1s timeout消息WAITING_FOR_DRAWN_TIMEOUT,如果1s内绘制完成则remove这个消息,如果没有绘制完则执行WAITING_FOR_DRAWN_TIMEOUT消息,不再等待直接唤醒屏幕。
    3. 窗口绘制的最主要方法是RootWindowContainer.performSurfacePlacement,该方法在AnimationThread中执行,窗口动画也是在这个线程执行。在这个方法中首先计算窗口大小,准备窗口动画,然后更新窗口绘制状态,调用commitFinishDrawingLocked更新窗口绘制状态为HAS_DRAWN
    4. 窗口绘制准备就绪,回调ScreenOnUnblocker.onScreenOn方法,通知PowerManagerService点亮屏幕。在performSurfacePlacement最后向Chrographer发起执行窗口动画请求。

    相关文章

      网友评论

          本文标题:Android亮屏流程之窗口绘制

          本文链接:https://www.haomeiwen.com/subject/ukgsyctx.html