1. 程式人生 > >Android6.0亮屏流程之Keyguard Window繪製

Android6.0亮屏流程之Keyguard Window繪製

亮滅屏問題一直是Android模組最常見的問題之一。


       由於問題出現問題的地方涉及到公司程式碼,我這裡僅僅只作原生程式碼模組的分析

       其實在看過另外一篇關於android亮屏流程的文章就會發現,影響亮屏快慢的因素大致有三種:1.設定背光流程出問題了,導致螢幕黑屏,2.window繪製時間過長,導致螢幕block時間過長;3.底層surfacecontroller準備時間過長。

而根據遇到的亮屏慢的問題,基本上都是由於window繪製時間過長,導致螢幕亮屏慢

最近處理的幾個亮屏慢的問題,其中關鍵log資訊基本都是:

10-28 09:02:59.002  1393  1462 I DisplayPowerController: Blocking screen on until initial contents have been drawn.

10-28 09:03:05.020  1393  1462 I DisplayPowerController: Unblocked screen on after 6018 ms

由於在android亮屏流程中大致描述的亮屏所走的流程點,但是僅僅只能作為一個粗略的點做參考,但是看到上面的兩條資訊,我們可以去追溯一下程式碼流程:

在每一次螢幕電源狀態發生改變的都會呼叫的到DisplayPowerController中的updatePowerState方法,在該方法中如果螢幕狀態發生改變的話,會去呼叫到

animateScreenStateChange,在setScreenState方法裡面去設定螢幕狀態。那麼就到了該問題的主要流程了。


在DisplayPowerController.java中的setScreenState()方法中,有程式碼:

[java]  view plain  copy
  1.     if (mPowerState.getColorFadeLevel() == 
    0.0f) {  
  2.         blockScreenOn();  
  3.     } else {  
  4.         unblockScreenOn();  
  5.     }  
  6.     mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);  
  7. }  
  8.   
  9. // Return true if the screen isn't blocked.  
  10. return mPendingScreenOnUnblocker == null;  

首先會呼叫到 blockScreenOn方法,先看看該方法以及後面要呼叫到的unblockScreenOn的方法

[java]  view plain  copy
  1. private void blockScreenOn() {  
  2.     if (mPendingScreenOnUnblocker == null) {  
  3.         Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);  
  4.         mPendingScreenOnUnblocker = new ScreenOnUnblocker();  
  5.         mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();  
  6.         Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");  
  7.     }  
  8. }  
  9.    
  10. private void unblockScreenOn() {  
  11.     if (mPendingScreenOnUnblocke != null) {  
  12.         mPendingScreenOnUnblocker = null;  
  13.         long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;  
  14.         Slog.i(TAG, "Unblocked screen on after " + delay + " ms");  
  15.         Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);  
  16.     }  
  17. }  

在blockScreenOn函式中其實就是建立了一個mPendingScreenOnUnblocker 物件,當該物件為空時,mPendingScreenOnUnblocker == null;返回值才為true。animateScreenStateChange才能繼續往下執行下去。

 

亮屏過程中繪製window過程是通過mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker); 呼叫到PhoneWindowManager中的screenTurningOn(),

[java]  view plain  copy
  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. }  
可以看到mPendingScreenOnUnblocker是繼承了WindowManagerPolicy.ScreenOnListener這個介面,而該介面同樣是作為一個callback到PhoneWindowManager那邊去繪製window,當all window for drawn 完成之後,會回撥到 mPendingScreenOnUnblocker的onScreenOn,會去unblock螢幕


這裡用一個圖來詳細描述






可以看到 整個過程呼叫的點較為混亂,這裡只能簡單描述一下其呼叫過程當PowerManagerService發出的wakeup請求到DisplayPowerController這邊,在DisplayPowerConrtoller中setScreenState方法中會呼叫到PhoneWindowManager模組的screenTurningOn方法去通過window繪製螢幕。

由於在滅屏之後亮屏首先現實的介面應該是鎖屏介面,所以亮屏首先應該去繪製keyguard,並且keyguard經常會出現超時,當出現keyguard超時時會列印:

WindowManager:Keyguard drawn timeout. Setting mKeyguardDrawComplete

當出現上述列印,便可以確定時keyguard模組繪製鎖屏超時,需要鎖屏的人去確認超時原因。鎖屏超時時間最長也只有2秒時間。因為

[java]  view plain  copy
  1. if (mKeyguardDelegate != null) {  
  2.     mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);  
  3.     mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);  
  4.     mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);  
  5. else {  

當mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);正常執行完成的情況下會呼叫到finishKeyguardDrawn,當未能正常執行,超過1秒還未完成便會發送訊息MSG_KEYGUARD_DRAWN_TIMEOUT強制執行finishKeyguardDrawn,    

 在finishKeyguardDrawn完成後會檢查所有的亮屏後所依賴的window是否都繪製完成,在mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,WAITING_FOR_DRAWN_TIMEOUT);//WAITING_FOR_DRAWN_TIMEOUT = 1000 中會去檢查window繪製,如上,當超過1秒後,會自動release等待的window,然後正常亮屏。