Android7.0 PowerManagerService 之亮滅屏(一)

Android7.0 PowerManagerService 之亮滅屏(一)

本篇從按下power按鍵後,按鍵事件從InputManagerService 傳到PhoneWindowManager.java開始分析power 按鍵做屏幕亮滅過程的分析,關於power 按鍵的其他行爲參考另一篇博文(Android 7.0 Power 按鍵處理流程

    (注:博客園顯示的圖片很模糊,上傳的爲大圖,可以圖片另存爲查看)

    言歸正傳,本篇涉及的幾個模塊(文件)如下,先做個簡單的介紹有個直觀大概的瞭解,方便後面流程細節的理解。

Ø  PowerManagerService.Java(/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java)

   PMS,是Android系統中的電源處理服務,主要負責電源相關的計算和決策,如是否應該滅屏 或者讓屏幕變暗,是否應該讓系統休眠等等。

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

  DPC,管理顯示設備(這裏指的顯示設備是屏幕)狀態,主要處理距離傳感器(如打電話時候靠近則滅屏,離開時候屏幕亮起)以及亮滅屏動畫(包括根據光感傳感器計算屏幕目標亮度值)。在DisplayManagerService.java(DMS)中實例化一個對象,以DMS爲橋樑與PMS進行交互通過異步回調機制來通知PMS那些發生了改變。同時也與WMS進行交互。

Ø  DisplayPowerState.java(/frameworks/base/services/core/java/com/android/server/display/DisplayPowerState.java)

  DPS,管理顯示設備的狀態僅在DPC中實例化一個對象,是DPC的一部分。

Ø  Notifier.java:( /frameworks/base/services/core/java/com/android/server/power/Notifier.java

  將電源狀態的重要變化,通過廣播通知出去。

Ø  ColorFade.java:(/frameworks/base/services/core/java/com/android/server/display/ColorFade.java

  是負責屏幕由關到開,由開到關的一些GL動畫,由DPC進行控制。

Ø  AutomaticBrightnessController.java:(/frameworks/base/services/core/java/com/android/server/display/AutomaticBrightnessController.java)

  主要處理光傳感器,將底層上傳的參數進行處理計算,將計算的新的亮度值傳給DPC來設定屏幕的亮度值(即根據環境的光線強度來計算屏幕的亮暗程度)。

Ø  RampAnimator.java:(/frameworks/base/services/core/java/com/android/server/display/RampAnimator.java)

  僅僅是屏幕亮度漸變動畫。

一、Power按鍵的上報與處理

詳細見【Android 7.0 Power 按鍵處理流程】此處僅略微的複習一下,方便了後面的理解。

1)Power按鍵的上報

在InputManagerService收到power按鍵事件經過一系列的處理和轉換最終將會傳遞到PhoneWindowManager(PWM)的interceptKeyBeforeQueueing()函數來做具體的業務邏輯.下圖爲上報的流程圖。

 

2)power 按鍵關於量滅屏處理

關於量滅屏的處理主要在interceptKeyBeforeQueueing()函數中。判斷是否是isWakeKey,如果是則在此函數的最後通過調用wakeUp()函數來具體處理,這就拉開了本文的序幕。

注:此函數很長本文刪除無關的部分,僅僅保留部分和量滅屏相關的說明具體處理流程即可。詳細參考【Android 7.0 Power 按鍵處理流程

A: 按鍵處理判斷是否要量滅屏

複製代碼

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

        boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
                || event.isWakeKey();
        if (interactive || (isInjected && !isWakeKey)) {
            // When the device is interactive or the key is injected pass the
            // key to the application.
            result = ACTION_PASS_TO_USER;
            isWakeKey = false;

            if (interactive) {
                // If the screen is awake, but the button pressed was the one that woke the device
                // then don't pass it to the application
                if (keyCode == mPendingWakeKey && !down) {
                    result = 0;
                }
                // Reset the pending key
                mPendingWakeKey = PENDING_KEY_NULL;
            }
        } else if (!interactive && shouldDispatchInputWhenNonInteractive(event)) {
            // If we're currently dozing with the screen on and the keyguard showing, pass the key
            // to the application but preserve its wake key status to make sure we still move
            // from dozing to fully interactive if we would normally go from off to fully
            // interactive.
            result = ACTION_PASS_TO_USER;
            // Since we're dispatching the input, reset the pending key
            mPendingWakeKey = PENDING_KEY_NULL;
        } else {
            // When the screen is off and the key is not injected, determine whether
            // to wake the device but don't pass the key to the application.
            result = 0;
            if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
                isWakeKey = false;
            }
            // Cache the wake key on down event so we can also avoid sending the up event to the app
            if (isWakeKey && down) {
                mPendingWakeKey = keyCode;
            }
        }

        // If the key would be handled globally, just return the result, don't worry about special
        // key processing.
        if (isValidGlobalKey(keyCode)
                && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
            if (isWakeKey) {
                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
            }
            return result;
        }

     ....................

            case KeyEvent.KEYCODE_ENDCALL: {
                result &= ~ACTION_PASS_TO_USER;
                if (down) {
                    TelecomManager telecomManager = getTelecommService();
                    boolean hungUp = false;
                    if (telecomManager != null) {
                        hungUp = telecomManager.endCall();
                    }
                    if (interactive && !hungUp) {
                        mEndCallKeyHandled = false;
                        mHandler.postDelayed(mEndCallLongPress,
                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                    } else {
                        mEndCallKeyHandled = true;
                    }
                } else {
                    if (!mEndCallKeyHandled) {
                        mHandler.removeCallbacks(mEndCallLongPress);
                        if (!canceled) {
                            if ((mEndcallBehavior
                                    & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
                                if (goHome()) {
                                    break;
                                }
                            }
                            if ((mEndcallBehavior
                                    & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
                                mPowerManager.goToSleep(event.getEventTime(),
                                        PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                                isWakeKey = false;
                            }
                        }
                    }
                }
                break;
            }

  

....................

        if (useHapticFeedback) {
            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
        }

        if (isWakeKey) {
            wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
        }

        return result;
    }

複製代碼

 

B:wakeUp處理量滅屏

 

複製代碼

private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason) {  
    final boolean theaterModeEnabled = isTheaterModeEnabled();  
    if (!wakeInTheaterMode && theaterModeEnabled) {  
        return false;  
    }  
  
    if (theaterModeEnabled) {  
        Settings.Global.putInt(mContext.getContentResolver(),  
                    Settings.Global.THEATER_MODE_ON, 0);  
        }  
      
        mPowerManager.wakeUp(wakeTime, reason);      //調用PowerManagerService亮屏操作
        return true;  
    } 
}

複製代碼

 

二、PowerManagerService處理量滅屏過程

從上面的分析可知,在PWM中處理按鍵事件如果需要喚醒屏幕則會調用PWM的wakeUp()函數,此函數會調用PMS 的wakeUp()函數來具體處理。

從上面的分析可知,在PWM中處理按鍵事件如果需要喚醒屏幕則會調用PWM的wakeUp()函數,此函數會調用PMS 的wakeUp()函數來具體處理。

  注:限於篇幅本文僅列出重要的函數和調用過程

首先來個概覽,瞭解一下主要完成了如下三件事

1)  由Notifier根據系統的具體狀態來發出廣播

2)  PMS 通過updatePowerStateLocked()計算和更新電源的全局狀態

3)  PMS將最新的電源狀態等傳入DPC中,根據距離傳感器和光感傳感器,計算具體的屏幕亮度和量滅屏動畫等

4)  DPC通知PWM繪製keyguard與windows(此時會block等待繪製完成,滅屏時候無需繪製),繪製完成後通知DPC繼續

5)  DPC具體調用顯示設備開啓或關閉屏幕(執行量滅屏的動畫效果)

1)PowerManagerService--wakeUpNoUpdateLocked()

PMS首先講wakefullness狀態. 之後發送亮滅屏廣播通知其他應用手機處於亮屏還是滅屏狀態。

複製代碼

private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,  
        String opPackageName, int opUid) {  
    if (DEBUG_SPEW) {  
        Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);  
    }  
  
    if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE  
            || !mBootCompleted || !mSystemReady) {  
        return false;        //判斷是否要去亮屏  
     }  
   
     Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");  
     try {  
         switch (mWakefulness) {  
             case WAKEFULNESS_ASLEEP:  
                 Slog.i(TAG, "Waking up from sleep due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");  
                 break;  
             case WAKEFULNESS_DREAMING:  
                 Slog.i(TAG, "Waking up from dream due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");  
                 break;  
             case WAKEFULNESS_DOZING:  
                 Slog.i(TAG, "Waking up from dozing due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");  
                 break;  
         }  
   
         mLastWakeTime = eventTime;   //設置最後一次喚醒的時間  
         setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);   //Notifier調用onWakefulnessChangeStarted發送亮屏廣播  
   
         mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);  //調用Notifier通知battery處理  
         userActivityNoUpdateLocked(     //更新最後一次用戶事件時間  
                 eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);  
     } finally {  
         Trace.traceEnd(Trace.TRACE_TAG_POWER);  
     }  
     return true;  
 }  

複製代碼

1)Notifier 發送量滅屏廣播

 

Notifier發送廣播前會與與AMS,WMS,IMS進行交互,通知各模塊電源狀態的改變,各模塊會自行處理電源狀態改變通知。

A:onWakefulnessChangeStarted()

 

 

複製代碼

public void onWakefulnessChangeStarted(final int wakefulness, int reason) {  
   final boolean interactive = PowerManagerInternal.isInteractive(wakefulness); //亮屏true, 滅屏false  
   if (DEBUG) {  
       Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness  
               + ", reason=" + reason + ", interactive=" + interactive);  
   }  
 
   // Tell the activity manager about changes in wakefulness, not just interactivity.  
   // It needs more granularity than other components.  
    mHandler.post(new Runnable() {  
        @Override  
        public void run() {  
            mActivityManagerInternal.onWakefulnessChanged(wakefulness);   //與AMS交互處理  
        }  
    });  
  
    // Handle any early interactive state changes.  
    // Finish pending incomplete ones from a previous cycle.  
    if (mInteractive != interactive) {  
        // Finish up late behaviors if needed.  
        if (mInteractiveChanging) {  
            handleLateInteractiveChange();  
        }  
  
        // Start input as soon as we start waking up or going to sleep.  
        mInputManagerInternal.setInteractive(interactive);    //在IMS中記錄現在的屏幕狀態  
        mInputMethodManagerInternal.setInteractive(interactive);  
  
        // Notify battery stats.  
        try {  
            mBatteryStats.noteInteractive(interactive);   //喚醒battery狀態  
        } catch (RemoteException ex) { }  
  
        // Handle early behaviors.  
        mInteractive = interactive;  
        mInteractiveChangeReason = reason;  
        mInteractiveChanging = true;  
        handleEarlyInteractiveChange();   //初期處理交互模式改變  
    }  
}  

複製代碼

 

 

B: handleEarlyInteractiveChange()

當屏幕在wakingup時需要通知window進行更新手勢監聽,更新方向監聽,更新鎖屏超時時間 

複製代碼

private void handleEarlyInteractiveChange() {  
    synchronized (mLock) {  
        if (mInteractive) {  
            // Waking up...    //亮屏  
            mHandler.post(new Runnable() {  
                @Override  
                public void run() {  
                    EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);  
                    mPolicy.startedWakingUp();   
                 }  
             });  
   
             // Send interactive broadcast.  
             mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;  
             mPendingWakeUpBroadcast = true;  
             updatePendingBroadcastLocked();   //更新亮屏廣播  
         } else {  
             // Going to sleep...   //滅屏  
             // Tell the policy that we started going to sleep.  
             final int why = translateOffReason(mInteractiveChangeReason);  
             mHandler.post(new Runnable() {  
                 @Override  
                 public void run() {  
                     mPolicy.startedGoingToSleep(why);  
                 }  
             });  
         }  
     } 

複製代碼

(1):updatePendingBroadcastLocked()

複製代碼

    private void updatePendingBroadcastLocked() {
        if (!mBroadcastInProgress
                && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
                && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mPendingInteractiveState != mBroadcastedInteractiveState)) {
            mBroadcastInProgress = true;
            mSuspendBlocker.acquire();
            Message msg = mHandler.obtainMessage(MSG_BROADCAST);
            msg.setAsynchronous(true);
            mHandler.sendMessage(msg);
        }
    }

複製代碼

(2)sendNextBroadcast()

複製代碼

 private void sendNextBroadcast() {
        final int powerState;
        synchronized (mLock) {
            if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
                // Broadcasted power state is unknown.  Send wake up.
                mPendingWakeUpBroadcast = false;
                mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
            } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
                // Broadcasted power state is awake.  Send asleep if needed.
                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
                    mPendingGoToSleepBroadcast = false;
                    mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
                } else {
                    finishPendingBroadcastLocked();
                    return;
                }
            } else {
                // Broadcasted power state is asleep.  Send awake if needed.
                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
                    mPendingWakeUpBroadcast = false;
                    mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
                } else {
                    finishPendingBroadcastLocked();
                    return;
                }
            }

            mBroadcastStartTime = SystemClock.uptimeMillis();
            powerState = mBroadcastedInteractiveState;
        }

        EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);

        if (powerState == INTERACTIVE_STATE_AWAKE) {
            sendWakeUpBroadcast();//這裏發送亮屏廣播
        } else {
            sendGoToSleepBroadcast();
        }
    }

複製代碼

 (3)sendWakeUpBroadcast()

 注意:Notifier 自身也會接收亮屏廣播,其受到後會調用finishPendingBroadcastLocked()函數來釋放wakeLock

複製代碼

    private void sendWakeUpBroadcast() {
        if (DEBUG) {
            Slog.d(TAG, "Sending wake up broadcast.");
        }

        if (ActivityManagerNative.isSystemReady()) {
            mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
                    mWakeUpBroadcastDone, mHandler, 0, null, null);
        } else {
            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
            sendNextBroadcast();
        }
    }

複製代碼

 

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