Android6.0 亮屏滅屏流程(DisplayPowerController、WMS)(一)WMS繪製

亮屏、滅屏流程整個流程涉及的模塊比較多,包括PowerManagerService、DisplayPowerControl、WMS、AMS。因此在分析完WMS之後,我們把這塊也分析下。


DisplayPowerControl

我們知道滅屏流程的發起是在PowerManagerService中,會通過updatePowerState函數調用updateDisplayPowerStateLocked函數,再調用DisplayPowerControl的requestPowerState函數,到DisplayPowerControl中。DisplayPowerControl中後面會調用updatePowerState函數,我們也主要從這個函數開始分析:

updatePowerState會根據PowerManagerService傳過來的顯示狀態,然後調用animateScreenStateChange函數。

        animateScreenStateChange(state, performScreenOffTransition);

下面我們先來看animateScreenStateChange函數:

  1. private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
  2. // If there is already an animation in progress, don't interfere with it.
  3. if (mColorFadeOnAnimator.isStarted()
  4. || mColorFadeOffAnimator.isStarted()) {
  5. return;
  6. }
  7. // If we were in the process of turning off the screen but didn't quite
  8. // finish. Then finish up now to prevent a jarring transition back
  9. // to screen on if we skipped blocking screen on as usual.
  10. if (mPendingScreenOff && target != Display.STATE_OFF) {
  11. setScreenState(Display.STATE_OFF);
  12. mPendingScreenOff = false;
  13. mPowerState.dismissColorFadeResources();
  14. }
  15. if (target == Display.STATE_ON) {//亮屏處理
  16. // Want screen on. The contents of the screen may not yet
  17. // be visible if the color fade has not been dismissed because
  18. // its last frame of animation is solid black.
  19. if (!setScreenState(Display.STATE_ON)) {
  20. return; // screen on blocked
  21. }
  22. if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {//亮屏動畫
  23. // Perform screen on animation.
  24. if (mPowerState.getColorFadeLevel() == 1.0f) {
  25. mPowerState.dismissColorFade();
  26. } else if (mPowerState.prepareColorFade(mContext,
  27. mColorFadeFadesConfig ?
  28. ColorFade.MODE_FADE :
  29. ColorFade.MODE_WARM_UP)) {
  30. mColorFadeOnAnimator.start();
  31. } else {
  32. mColorFadeOnAnimator.end();
  33. }
  34. } else {//跳過亮屏動畫
  35. // Skip screen on animation.
  36. mPowerState.setColorFadeLevel(1.0f);
  37. mPowerState.dismissColorFade();
  38. }
  39. } else if (target == Display.STATE_DOZE) {
  40. // Want screen dozing.
  41. // Wait for brightness animation to complete beforehand when entering doze
  42. // from screen on to prevent a perceptible jump because brightness may operate
  43. // differently when the display is configured for dozing.
  44. ......
  45. } else if (target == Display.STATE_DOZE_SUSPEND) {
  46. // Want screen dozing and suspended.
  47. // Wait for brightness animation to complete beforehand unless already
  48. // suspended because we may not be able to change it after suspension.
  49. ......
  50. } else {//滅屏處理
  51. // Want screen off.
  52. mPendingScreenOff = true;
  53. if (mPowerState.getColorFadeLevel() == 0.0f) {//滅屏動畫結束
  54. // Turn the screen off.
  55. // A black surface is already hiding the contents of the screen.
  56. setScreenState(Display.STATE_OFF);
  57. mPendingScreenOff = false;
  58. mPowerState.dismissColorFadeResources();
  59. } else if (performScreenOffTransition
  60. && mPowerState.prepareColorFade(mContext,
  61. mColorFadeFadesConfig ?
  62. ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN)
  63. && mPowerState.getScreenState() != Display.STATE_OFF) {
  64. // Perform the screen off animation.
  65. mColorFadeOffAnimator.start();//開啓滅屏動畫
  66. } else {
  67. // Skip the screen off animation and add a black surface to hide the
  68. // contents of the screen.
  69. mColorFadeOffAnimator.end();//關閉滅屏動畫
  70. }
  71. }
  72. }

animateScreenStateChange在亮屏的處理的時候,先會調用setScreenState(Display.STATE_ON),然後根據USE_COLOR_FADE_ON_ANIMATION 判斷是否要開啓亮屏動畫,這裏我們是沒有設置的。因此直接跳過亮屏動畫。滅屏的處理的話,會有一個滅屏動畫(也是註冊一個VSync信號回調函數處理的,這裏我們不分析了),當動畫結束後,直接就調用setScreenState(Display.STATE_OFF)結束。

我們再來看看setScreenState函數

  1. private boolean setScreenState(int state) {
  2. if (mPowerState.getScreenState() != state) {
  3. final boolean wasOn = (mPowerState.getScreenState() != Display.STATE_OFF);
  4. mPowerState.setScreenState(state);
  5. ......
  6. }
  7. // Tell the window manager policy when the screen is turned off or on unless it's due
  8. // to the proximity sensor. We temporarily block turning the screen on until the
  9. // window manager is ready by leaving a black surface covering the screen.
  10. // This surface is essentially the final state of the color fade animation and
  11. // it is only removed once the window manager tells us that the activity has
  12. // finished drawing underneath.
  13. final boolean isOff = (state == Display.STATE_OFF);
  14. if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF
  15. && !mScreenOffBecauseOfProximity) {
  16. mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_OFF;
  17. unblockScreenOn();
  18. mWindowManagerPolicy.screenTurnedOff();//調用PhoneWindowManager的screenTurnedOff
  19. } else if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
  20. mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_TURNING_ON;
  21. if (mPowerState.getColorFadeLevel() == 0.0f) {
  22. blockScreenOn();
  23. } else {
  24. unblockScreenOn();
  25. }
  26. mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);//調用PhoneWindowManager的screenTurningOn函數
  27. }
  28. // Return true if the screen isn't blocked.
  29. return mPendingScreenOnUnblocker == null;
  30. }

setScreenState函數,先是調用了DisplayPowerState的setScreenState函數,然後根據屏幕是滅屏還是亮屏調用PhoneWindowManager的相關函數。


PhoneWindowManager的screenTurnedOff和screenTurningOn函數

PhoneWindowManager的screenTurnedOff函數主要是通知kerguard,屏幕滅屏了。

  1. @Override
  2. public void screenTurnedOff() {
  3. if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
  4. updateScreenOffSleepToken(true);
  5. synchronized (mLock) {
  6. mScreenOnEarly = false;
  7. mScreenOnFully = false;
  8. mKeyguardDrawComplete = false;
  9. mWindowManagerDrawComplete = false;
  10. mScreenOnListener = null;
  11. updateOrientationListenerLp();
  12. if (mKeyguardDelegate != null) {
  13. mKeyguardDelegate.onScreenTurnedOff();
  14. }
  15. }
  16. }

我們再來看PhoneWindowManager的screenTurningOn函數。當有keyguard時,我們會先發一個延時的MSG_KEYGUARD_DRAWN_TIMEOUT信號,並且會調用keyguard的onScreenTurningOn函數,當完成會調用mKeyguardDrawnCallback回調函數。我們這裏還要注意下有一個屏幕點亮後的回調。

  1. @Override
  2. public void screenTurningOn(final ScreenOnListener screenOnListener) {
  3. if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
  4. updateScreenOffSleepToken(false);
  5. synchronized (mLock) {
  6. mScreenOnEarly = true;
  7. mScreenOnFully = false;
  8. mKeyguardDrawComplete = false;
  9. mWindowManagerDrawComplete = false;
  10. mScreenOnListener = screenOnListener;//屏幕點亮後的回調
  11. if (mKeyguardDelegate != null) {
  12. if (DEBUG_WAKEUP) Slog.d(TAG,
  13. "send delay message MSG_KEYGUARD_DRAWN_TIMEOUT");
  14. mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
  15. mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);
  16. mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
  17. } else {
  18. if (DEBUG_WAKEUP) Slog.d(TAG,
  19. "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
  20. finishKeyguardDrawn();
  21. }
  22. }
  23. }

我們先看下mKeyguardDrawnCallback 回調,就是發送MSG_KEYGUARD_DRAWN_COMPLETE(keyguard繪製完的消息)

  1. final DrawnListener mKeyguardDrawnCallback = new DrawnListener() {
  2. @Override
  3. public void onDrawn() {
  4. if (DEBUG_WAKEUP) Slog.d(TAG, "mKeyguardDelegate.ShowListener.onDrawn.");
  5. mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
  6. }
  7. };

我們再來看看MSG_KEYGUARD_DRAWN_COMPLETE以及MSG_KEYGUARD_DRAWN_TIMEOUT信號的處理,都會調用finishKeyguardDrawn函數。

  1. case MSG_KEYGUARD_DRAWN_COMPLETE:
  2. if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mKeyguardDrawComplete");
  3. finishKeyguardDrawn();
  4. break;
  5. case MSG_KEYGUARD_DRAWN_TIMEOUT:
  6. Slog.w(TAG, "Keyguard drawn timeout. Setting mKeyguardDrawComplete");
  7. finishKeyguardDrawn();
  8. break;
我們再來看看finishKeyguardDrawn函數,會先去除隊列中的MSG_KEYGUARD_DRAWN_TIMEOUT消息(因爲之前發的MSG_KEYGUARD_DRAWN_TIMEOUT消息,可能keyguard結束髮送MSG_KEYGUARD_DRAWN_COMPLETE消息調用的finishKeyguardDrawn就要把MSG_KEYGUARD_DRAWN_TIMEOUT去除了)。然後會調用

  1. private void finishKeyguardDrawn() {
  2. synchronized (mLock) {
  3. if (!mScreenOnEarly || mKeyguardDrawComplete) {
  4. return; // We are not awake yet or we have already informed of this event.
  5. }
  6. mKeyguardDrawComplete = true;
  7. if (mKeyguardDelegate != null) {
  8. mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
  9. }
  10. mWindowManagerDrawComplete = false;
  11. }
  12. // ... eventually calls finishWindowsDrawn which will finalize our screen turn on
  13. // as well as enabling the orientation change logic/sensor.
  14. mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
  15. WAITING_FOR_DRAWN_TIMEOUT);
  16. }

最後我們再看看WMS的waitForAllWindowsDrawn函數,以及兩個參數mWindowManagerDrawCallback和一個WAITING_FOR_DRAWN_TIMEOUT(1秒)。


WMS的waitForAllWindowsDrawn函數

我們先來看看WMS的waitForAllWindowsDrawn函數,會把傳進來的回調保存在mWaitingForDrawnCallback 。然後遍歷所有的windows,把需要顯示或者已經顯示的窗口全部加入到mWaitingForDrawn,然後調用requestTraversalLocked這個函數我們之前分析過,就是發送一個消息,重新刷新UI佈局。然後我們繼續分析這個函數,如果mWaitingForDrawn爲空,代表沒啥顯示的直接調用回調函數,如果mWaitingForDrawn有要顯示的窗口,就要會先發送一個WAITING_FOR_DRAWN_TIMEOUT,這個timeout之前傳進來的是1秒。然後調用checkDrawnWindowsLocked函數。

  1. @Override
  2. public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
  3. synchronized (mWindowMap) {
  4. mWaitingForDrawnCallback = callback;//回調保存在mWaitingForDrawnCallback
  5. final WindowList windows = getDefaultWindowListLocked();
  6. for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
  7. final WindowState win = windows.get(winNdx);
  8. final boolean isForceHiding = mPolicy.isForceHiding(win.mAttrs);
  9. Slog.i(TAG,"In the function waitForAllWindowsDrawn");
  10. if (win.isVisibleLw()
  11. && (win.mAppToken != null || isForceHiding)) {
  12. Slog.i(TAG,"In the function win.isVisibleLw()");
  13. win.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
  14. // Force add to mResizingWindows.
  15. win.mLastContentInsets.set(-1, -1, -1, -1);
  16. mWaitingForDrawn.add(win);
  17. // No need to wait for the windows below Keyguard.
  18. if (isForceHiding) {
  19. break;
  20. }
  21. }
  22. }
  23. requestTraversalLocked();
  24. }
  25. mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
  26. if (mWaitingForDrawn.isEmpty()) {
  27. callback.run();
  28. Slog.i(TAG,"In the function mWaitingForDrawn.isEmpty()");
  29. } else {
  30. mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
  31. checkDrawnWindowsLocked();
  32. Slog.i(TAG,"In the function checkDrawnWindowsLocked()");
  33. }
  34. }

我們先來看下checkDrawnWindowsLocked函數,這個函數。遍歷之前加入的mWaitingForDrawn(要顯示的窗口),這個時候我們把已經去除的,不需要顯示的,沒有surface的窗口從mWaitingForDrawn去除,還有已經繪製好的也去除。然後再當mWaitingForDrawn爲空時,就發送ALL_WINDOWS_DRAWN消息。

  1. void checkDrawnWindowsLocked() {
  2. if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
  3. return;
  4. }
  5. for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) {
  6. WindowState win = mWaitingForDrawn.get(j);
  7. if (win.mRemoved || !win.mHasSurface || !win.mPolicyVisibility) {
  8. // Window has been removed or hidden; no draw will now happen, so stop waiting.
  9. if (DEBUG_SCREEN_ON) Slog.w(TAG, "Aborted waiting for drawn: " + win);
  10. mWaitingForDrawn.remove(win);
  11. } else if (win.hasDrawnLw()) {
  12. // Window is now drawn (and shown).
  13. if (DEBUG_SCREEN_ON) Slog.d(TAG, "Window drawn win=" + win);
  14. mWaitingForDrawn.remove(win);
  15. }
  16. }
  17. if (mWaitingForDrawn.isEmpty()) {
  18. if (DEBUG_SCREEN_ON) Slog.d(TAG, "All windows drawn!");
  19. mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
  20. mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN);
  21. }
  22. }

ALL_WINDOWS_DRAWN消息的處理就是清除mWaitingForDrawnCallback ,然後調用回調。

  1. case ALL_WINDOWS_DRAWN: {
  2. Runnable callback;
  3. synchronized (mWindowMap) {
  4. callback = mWaitingForDrawnCallback;
  5. mWaitingForDrawnCallback = null;
  6. }
  7. if (callback != null) {
  8. callback.run();
  9. }
  10. }

還有當我們調用waitForAllWindowsDrawn一般都是有需要顯示的窗口,但是我們直接調用checkDrawnWindowsLocked函數,發現有的窗口還沒繪製完成。那麼我們就要等,會在刷新的核心函數中performLayoutAndPlaceSurfacesLockedInner有如下代碼,這個時候如果之前還沒繪製完成的窗口,繪製好了。會再調用checkDrawnWindowsLocked函數,如果mWaitingForDrawn中的窗口繪製好了,會在mWaitingForDrawn中去除這個窗口。然後mWaitingForDrawn爲空了,之後會發送ALL_WINDOWS_DRAWN消息,還調用mWaitingForDrawnCallback回調函數。

  1. if (mWaitingForDrawnCallback != null ||
  2. (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded &&
  3. !mInnerFields.mUpdateRotation)) {
  4. checkDrawnWindowsLocked();
  5. }

當然如果我們之前沒有把mWaitingForDrawn中的窗口清空,最後在WAITING_FOR_DRAWN_TIMEOUT(這裏是1秒)時間到了也會調用回調的。

  1. case WAITING_FOR_DRAWN_TIMEOUT: {
  2. Runnable callback = null;
  3. synchronized (mWindowMap) {
  4. Slog.w(TAG, "Timeout waiting for drawn: undrawn=" + mWaitingForDrawn);
  5. mWaitingForDrawn.clear();
  6. callback = mWaitingForDrawnCallback;
  7. mWaitingForDrawnCallback = null;
  8. }
  9. if (callback != null) {
  10. callback.run();
  11. }
  12. break;
  13. }



PhoneWindowManager窗口繪製完成的回調函數

那下面我們就要繼續看PhoneWindowManager中窗口繪製完成之後的回調函數。代碼如下就是發送了一個消息。

  1. final Runnable mWindowManagerDrawCallback = new Runnable() {
  2. @Override
  3. public void run() {
  4. if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for display!");
  5. mHandler.sendEmptyMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE);
  6. }
  7. };

我們來看這個消息的處理

  1. case MSG_WINDOW_MANAGER_DRAWN_COMPLETE:
  2. if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mWindowManagerDrawComplete");
  3. finishWindowsDrawn();
  4. break;

finishWindowsDrawn就是把mWindowManagerDrawComplete 置爲true,然後調用finishScreenTurningOn函數。

  1. private void finishWindowsDrawn() {
  2. synchronized (mLock) {
  3. if (!mScreenOnEarly || mWindowManagerDrawComplete) {
  4. return; // Screen is not turned on or we did already handle this case earlier.
  5. }
  6. mWindowManagerDrawComplete = true;
  7. }
  8. finishScreenTurningOn();
  9. }

finishScreenTurningOn函數調用了之前在DisplayPowerControl中調用screenTurningOn傳入的回調,然後再調用WMS的enableScreenIfNeeded函數。

  1. private void finishScreenTurningOn() {
  2. synchronized (mLock) {
  3. updateOrientationListenerLp();
  4. }
  5. final ScreenOnListener listener;
  6. final boolean enableScreen;
  7. synchronized (mLock) {
  8. if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
  9. || (mAwake && !mKeyguardDrawComplete)) {
  10. return; // spurious or not ready yet
  11. }
  12. listener = mScreenOnListener;
  13. mScreenOnListener = null;
  14. mScreenOnFully = true;
  15. ......
  16. }
  17. if (listener != null) {
  18. listener.onScreenOn();
  19. }
  20. if (enableScreen) {
  21. try {
  22. mWindowManager.enableScreenIfNeeded();
  23. } catch (RemoteException unhandled) {
  24. }
  25. }
  26. }

我們先分析下WMS的enableScreenIfNeeded函數,然後再看DisplayPowerControl的回調onScreenOn函數。



WMS的enableScreenIfNeeded函數

WMS的enableScreenIfNeeded函數就是調用了enableScreenIfNeededLocked函數

  1. @Override
  2. public void enableScreenIfNeeded() {
  3. synchronized (mWindowMap) {
  4. enableScreenIfNeededLocked();
  5. }
  6. }

enableScreenIfNeededLocked這個函數僅僅是保證mDisplayEnabled爲true,如果爲true直接結束。

  1. void enableScreenIfNeededLocked() {
  2. if (mDisplayEnabled) {
  3. return;
  4. }
  5. if (!mSystemBooted && !mShowingBootMessages) {
  6. return;
  7. }
  8. mH.sendEmptyMessage(H.ENABLE_SCREEN);
  9. }

mDisplayEnabled不爲true,發送ENABLE_SCREEN消息

  1. case ENABLE_SCREEN: {
  2. performEnableScreen();
  3. break;

performEnableScreen函數會讓SurfaceFlinger去停止開機動畫等,也會把mDisplayEnabled置爲true。當然performEnableScreen在開機的時候會AMS中調用WMS的enableScreenAfterBoot函數來調用performEnableScreen函數。這個我們在博客http://blog.csdn.net/kc58236582/article/details/52921978分析過了。

  1. public void performEnableScreen() {
  2. synchronized(mWindowMap) {
  3. if (mDisplayEnabled) {
  4. return;
  5. }
  6. if (!mSystemBooted && !mShowingBootMessages) {
  7. return;
  8. }
  9. // Don't enable the screen until all existing windows have been drawn.
  10. if (!mForceDisplayEnabled && checkWaitingForWindowsLocked()) {
  11. return;
  12. }
  13. if (!mBootAnimationStopped) {
  14. // Do this one time.
  15. try {//停止開機動畫
  16. IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
  17. if (surfaceFlinger != null) {
  18. //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
  19. Parcel data = Parcel.obtain();
  20. data.writeInterfaceToken("android.ui.ISurfaceComposer");
  21. surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
  22. data, null, 0);
  23. data.recycle();
  24. }
  25. } catch (RemoteException ex) {
  26. Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
  27. }
  28. mBootAnimationStopped = true;
  29. }
  30. if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
  31. if (DEBUG_BOOT) Slog.i(TAG, "performEnableScreen: Waiting for anim complete");
  32. return;
  33. }
  34. mDisplayEnabled = true;//置爲true
  35. if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
  36. // Enable input dispatch.
  37. mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
  38. }
  39. try {
  40. mActivityManager.bootAnimationComplete();
  41. } catch (RemoteException e) {
  42. }
  43. mPolicy.enableScreenAfterBoot();
  44. // Make sure the last requested orientation has been applied.
  45. updateRotationUnchecked(false, false);
  46. }


窗口繪製完成後調用DisplayPowerControl中的回調

當WMS窗口繪製完成後,會在PhoneWindowManager中的finishScreenTurningOn函數調用DisplayPowerControl的回調函數。最後我們再來看看DisplayPowerControl中的回調的onScreenOn函數。只是發送了一個MSG_SCREEN_ON_UNBLOCKED消息。

  1. private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
  2. @Override
  3. public void onScreenOn() {
  4. Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this);
  5. msg.setAsynchronous(true);
  6. mHandler.sendMessage(msg);
  7. }
  8. }

MSG_SCREEN_ON_UNBLOCKED的處理先是調用了unblockScreenOn函數,然後再調用updatePowerState更新狀態。

  1. case MSG_SCREEN_ON_UNBLOCKED:
  2. if (mPendingScreenOnUnblocker == msg.obj) {
  3. unblockScreenOn();
  4. updatePowerState();
  5. }
  6. break;

unblockScreenOn函數,只是打印下從調用screenTurningOn開始,到窗口繪製完成在PhoneWindowManager中回調這個函數的時間差打印。

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章