Android7.0 PowerManagerService(3) 核心函数updatePowerStateLocked的主要流程
前面的博客中,我們已經分析過,當Android中的進程要使用電量時,需要向PMS申請WakeLock;當進程完成工作后,需要釋放對應的WakeLock。?
PMS收到申請和釋放WakeLock的請求后,均需要調用updatePowerStateLocked來更新電源的狀態,該函數是PMS的核心方法。?
接下來,我們就結合代碼,看一下updatePowerStateLocked的工作流程。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
在PMS中有個很重要的變量mDirty,該變量按位存儲PMS中的各種變化狀態。?
例如,之前介紹PMS的acquire WakeLock流程時,就進行了以下操作:
- 1
- 2
- 3
每當PMS檢測到一些重要事件發生時,就會更新mDirty的相應的位。?
從updatePowerStateLocked的代碼可以看出,它將根據mDirty中的信息,來更新手機中的電源狀態。
根據Android源碼中的注釋,可以看出updatePowerStateLocked的工作主要分為幾個步驟,接下來我們一個一個步驟的來進行分析。
一、更新基本狀態信息?
1、updateIsPoweredLocked?
我們先來看看updateIsPoweredLocked函數:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
從以上代碼可以看出updateIsPoweredLocked主要用于:?
更新PMS中的一些變量,包括記錄終端是否在充電、充電的類型、電池的電量及電池電量是否處于低電狀態;?
當電源的充電狀態,或者充電類型發生變化,判斷出現插拔充電器等操作時,是否需要點亮或熄滅屏幕;?
當電源充電狀態發生變化,或者終端是否處于低電量的標志發生變化的時候,終端調用updateLowPowerModeLocked()更新低電模式相關的操作。
我們跟進一下updateLowPowerModeLocked函數:
private void updateLowPowerModeLocked() {//處于充電狀態,并且設置過低電模式的標志位if (mIsPowered && mLowPowerModeSetting) {........ // Turn setting off if powered//更新數據庫,關閉低電模式Settings.Global.putInt(mContext.getContentResolver(),Settings.Global.LOW_POWER_MODE, 0);mLowPowerModeSetting = false;}//判斷是否可以進入自動省電模式//要求是:未充電 && 進行了自動省電的配置 && 沒有設置低電“打盹” && 電池電量低final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured&& !mAutoLowPowerModeSnoozing && mBatteryLevelLow;//當前是否為低電模式final boolean lowPowerModeEnabled = mLowPowerModeSetting || autoLowPowerModeEnabled;if (mLowPowerModeEnabled != lowPowerModeEnabled) {mLowPowerModeEnabled = lowPowerModeEnabled;//調用底層動態庫的powerHint函數powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);//開機完成后才能執行的Runnable對象postAfterBootCompleted(new Runnable() {//發送低電模式CHANGING的廣播Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING).putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, mLowPowerModeEnabled).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);mContext.sendBroadcast(intent);//PMS提供了registerLowPowerModeObserver的接口//其它進程可以調用該接口,注冊觀察者synchronized (mLock) {listeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(mLowPowerModeListeners);}for (int i=0; i<listeners.size(); i++) {//調用回調接口的onLowPowerModeChanged函數,通知其它進程低電模式發生改變listeners.get(i).onLowPowerModeChanged(lowPowerModeEnabled);}//再次發送CHANGED廣播intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);mContext.sendBroadcast(intent);// Send internal version that requires signature permission.mContext.sendBroadcastAsUser(new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL), UserHandle.ALL,Manifest.permission.DEVICE_POWER);});} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
從上面的代碼可以看出updateLowPowerModeLocked函數,?
首先判斷手機是否在充電,如果手機在充電,退出LowPowerMode模式,同時更新數據庫;?
當手機的低電量模式發生了變化,就發送廣播進行通知,并回調關于監聽該模式變化的觀察者的接口。?
例如:UI對應的APK收到低電量省電模式的廣播,就會彈出低電量省電模式的提醒界面。
可以看出這一部分除了更新PMS中的一些變量外,關注的重點還是集中在:?
充電狀態是否改變;?
充電狀態的改變,將引出對充電器插拔是否需要亮屏的考慮;?
同樣,充電狀態的改變,將引出對終端的低電模式是否發生改變的考慮。?
從這個角度來看,updateIsPoweredLocked函數的命名是實至名歸的。
2、updateStayOnLocked?
現在我們看看基本狀態更新第二部分的updateStayOnLocked函數:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
這一部分的代碼功能比較單一,主要用于更新變量mStayOn的值。?
如果mStayOn如果為true,則屏幕保持長亮的狀態。
3、updateScreenBrightnessBoostLocked?
Android手機定義了一個最大屏幕亮度,用戶可以手動或者讓終端自動確定最大的屏幕亮度。?
updateScreenBrightnessBoostLocked函數主要用于:更新終端可處于最大屏幕亮度的時間。
為了比較好的理解updateScreenBrightnessBoostLocked函數,?
我們可以先分析一下與之相關的,PMS提供的對外的接口boostScreenBrightness。?
該方法的作用是讓屏幕在一段時間內保持最大的亮度,使屏幕在強光下有更好的可讀性。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
從上面的代碼可以看出,該函數:?
首先,使用mLastScreenBrightnessBoostTime變量記錄了終端處于最大屏幕亮度的起始時間;?
然后,將最大屏幕亮度的標志位置為true,并修改mDirty標志位,以表示最大屏幕亮度的狀態發生了變化;?
最后,調用updatePowerStateLocked方法更新電源狀態信息。?
我們已經知道,updatePowerStateLocked將會調用到updateScreenBrightnessBoostLocked。
接下來,我們看看updateScreenBrightnessBoostLocked對應的代碼:
private void updateScreenBrightnessBoostLocked(int dirty) {//根據mDirty的標志位來判斷終端屏幕最大可用亮度的狀態是否發生了變化if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) {//上面的代碼已經提到過,當boostScreenBrightness接口被調用時,mScreenBrightnessBoostInProgress置為trueif (mScreenBrightnessBoostInProgress) {//移除舊的超時事件final long now = SystemClock.uptimeMillis();mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);//終端處于最大屏幕亮度的時間,在sleep的時間之后,說明終端還未息屏之類的if (mLastScreenBrightnessBoostTime > mLastSleepTime) {//此時,重新計算終端可處于最大屏幕亮度的時間final long boostTimeout = mLastScreenBrightnessBoostTime +SCREEN_BRIGHTNESS_BOOST_TIMEOUT;if (boostTimeout > now) {Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);msg.setAsynchronous(true);//發送延遲的超時事件//當屏幕離開最大亮度狀態時,該事件將被發送//當該事件被處理時,會再次進入到updateScreenBrightnessBoostLocked函數mHandler.sendMessageAtTime(msg, boostTimeout);return;}}//進入到這個分支時,說明屏幕處于最大亮度狀態的時間已經超時了//將該標志置為falsemScreenBrightnessBoostInProgress = false;//發送廣播mNotifier.onScreenBrightnessBoostChanged();//觸發一次用戶活動,寫入mDirty標志位,同時做一些其它記錄userActivityNoUpdateLocked(now,PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);}} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
至此,PMS第一階段更新基本狀態信息的流程結束。
二、更新wakelock和用戶活動
for (;;) {int dirtyPhase1 = mDirty;dirtyPhase2 |= dirtyPhase1;mDirty = 0;updateWakeLockSummaryLocked(dirtyPhase1);updateUserActivitySummaryLocked(now, dirtyPhase1);//updateWakefulnessLocked將決定系統是否進入休眠或dreaming狀態//主要是更新DIRTY_WAKEFULNESS位,如果不需要更新,則返回falseif (!updateWakefulnessLocked(dirtyPhase1)) {break;} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
1、updateWakeLockSummaryLocked?
updateWakeLockSummaryLocked函數根據PMS當前持有的所有WakeLock,得到當前終端整體的信息,保存到mWakeLockSummary變量中。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
結合每個WakeLock level的注釋信息,以上代碼還是比較好理解的。
這里唯一需要說明的是,Android定義一個mWakeLockSummary變量的原因是:?
PMS將WakeLock定義為不同進程的請求信息,這些請求信息對CPU、屏幕和鍵盤有不同的需求。?
對于每一種資源而言,只要有一個申請滿足獲取條件,PMS就需要為終端分配該申請對應的資源。?
例如:假設PMS有20個WakeLock,只有1個申請亮屏,另外19個只申請CPU喚醒,PMS仍然需要保持終端亮屏。?
因此,mWakeLockSummary就提供了一種整合多個WakeLock請求的功能,方便PMS進行集中的控制。
2、updateUserActivitySummaryLocked?
updateUserActivitySummaryLocked主要根據用戶最后的活動來決定當前屏幕的狀態。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
從上面的代碼可以看出,在該函數中用mUserActivitySummary變量存儲當前屏幕的狀態。?
一共有3中基本狀態:?
* USER_ACTIVITY_SCREEN_BRIGHT 點亮屏幕?
* USER_ACTIVITY_SCREEN_DIM 屏幕變暗?
* USER_ACTIVITY_SCREEN_DREAM 屏保狀態?
從代碼可以看出,屏幕變化和userActivity活動有關,它根據最后的userActivity活動的時間決定點亮屏幕、調暗屏幕或熄滅屏幕。
之前的很多方法中都會調用userActivityNoUpdateLocked方法。該方法將觸發一次用戶活動,以更新用戶活動的時間,這樣屏幕變暗和熄滅時間就會重新進行計算。?
這也就是為什么用戶一直操作手機,屏幕不會熄滅或者變暗的原因。?
大圖地址?
整體來講,個人感覺這個函數的代碼寫的還是挺繞的,因此還是作一個圖記錄一下。?
大家有興趣可以看一下。
3、updateWakefulnessLocked?
從之前的代碼可以看出,updateWakefulnessLocked將決定第二階段的電源狀態更新是否結束。?
我們看一下updateWakefulnessLocked函數:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
從上面的代碼可以看出,如果終端可以一直保持喚醒狀態,或一開始就是非喚醒態,?
那么mWakefulness不會發生改變,第二階段的for循環將會break;
如果終端要從喚醒態變為非喚醒態,那么for循環將再運行一次,即重新計算一次mWakeLockSummary和mUserActivitySummary。?
這么做的原因是:updateWakeLockSummaryLocked和updateUserActivitySummaryLocked函數的一些計算,與終端是否處于喚醒狀態,即mWakefulness的值有關。?
由于這兩個函數并不會修改mWakefulness,因此在這一次運行時,updateWakefulnessLocked將返回false,即第二階段結束。
因此,我們可以得出結論:更新電源狀態的第二階段,正常情況下最多運行兩次。?
在第二階段的最后,我們看一下isItBedTimeYetLocked函數:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
參考原生代碼的注釋,這一部分代碼還是比較好理解的。
三、更新display power state?
第三階段將負責更新屏幕的顯示狀態。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
我們跟進一下DisplayPowerController的requestPowerState函數:
/** * Requests a new power state. * The controller makes a copy of the provided object and then * begins adjusting the power state to match what was requested. */ public boolean requestPowerState(DisplayPowerRequest request,boolean waitForNegativeProximity) {.........synchronized (mLock) {boolean changed = false;//新需求增加:proximity sensor需要檢測距離if (waitForNegativeProximity//原來沒有這個需求&& !mPendingWaitForNegativeProximityLocked) {mPendingWaitForNegativeProximityLocked = true;changed = true;}//以下表示,參數中的Request對于DisplayPowerController而言,是一個新的需求if (mPendingRequestLocked == null) {mPendingRequestLocked = new DisplayPowerRequest(request);changed = true;} else if (!mPendingRequestLocked.equals(request)) {mPendingRequestLocked.copyFrom(request);changed = true;}if (changed) {//一但有新的需求,mDisplayReadyLocked就是false,表示屏幕有待調整mDisplayReadyLocked = false;}//有新需求,同時有對應的requestif (changed && !mPendingRequestChangedLocked) {mPendingRequestChangedLocked = true;//發送消息,更新屏幕狀態//最終通過DisplayPowerController的updatePowerState函數,進行屏幕狀態更新//這部分代碼也極其復雜,暫時不在這里展開分析//更新屏幕狀態后,將回調PMS的接口sendUpdatePowerStateLocked();}return mDisplayReadyLocked;} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
根據requestPowerState的代碼,我們知道:?
當PMS傳入一個新的mDisplayPowerRequest時,requestPowerState應該返回為false;當DisplayPowerController按照mDisplayPowerRequest修改完屏幕狀態,再次進入回到updateDisplayPowerStateLocked函數,調用requestPowerState時才會返回true。
整體的代碼流程大概可以抽象成下圖:?
這一階段的代碼,我們只是分析了整個過程的冰山一角,并沒有分析更新屏幕狀態的實際操作。?
但從現有的代碼可以看出,PMS的作用僅僅是維護終端電源相關狀態,實際的工作還是通過類似發送Request的方式,讓其它的服務協助完成。?
例如:在整個階段,PMS根據之前得到信息,構造出DisplayPowerRequest,然后發送給DisplayPowerController進行實際的處理。?
當DisplayPowerController完成實際的工作(部分工作還依賴于PhoneWindowManager)后,再通知PMS進行復查。
因此PMS的定位,確實可以用一個”Manager”來形容;?
負責整個終端信息的搜集和維護,然后將相應的工作指派給具體的“員工”執行;?
“員工”執行完畢后,向”Manager”匯報;?
“Manager”檢查工作的完成情況后,然后做出下一步的指示。
四、更新dream state?
updateDreamLocked函數主要用于更新屏保狀態,當設備進入或者退出屏保的時候都會觸發這個方法:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
handleSandman函數比較復雜,主要用于決定設備是否應該停留在dreaming或dozing狀態。?
我們分段介紹該函數的功能。
1、決定是否可以進入屏保狀態
/** * Called when the device enters or exits a dreaming or dozing state. */ private void handleSandman() {final boolean startDreaming;final int wakefulness;synchronized (mLock) {mSandmanScheduled = false;wakefulness = mWakefulness;//前面提到過,當updateWakefulnessLocked判斷進入dozing或sleep狀態時,//會將mSandmanSummoned置為true//mDisplayReady主要確保前面屏幕狀態更新完畢if (mSandmanSummoned && mDisplayReady) {//判斷device是否可以dream或dozingstartDreaming = canDreamLocked() || canDozeLocked();mSandmanSummoned = false;} else {startDreaming = false;}} ..........- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
這段代碼主要用于確定,設備是否可以看是dreaming。?
除去前置條件的限制外,此處的結果主要由canDreamLocked和canDozeLocked決定。
我們分別看看這兩個函數:
/** * Returns true if the device is allowed to dream in its current state. */ private boolean canDreamLocked() {//mWakefulness等于WAKEFULNESS_DREAMINGif (mWakefulness != WAKEFULNESS_DREAMING//設備支持dreaming|| !mDreamsSupportedConfig//設置開關開啟|| !mDreamsEnabledSetting//屏幕熄滅|| !mDisplayPowerRequest.isBrightOrDim()|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT| USER_ACTIVITY_SCREEN_DIM | USER_ACTIVITY_SCREEN_DREAM)) == 0//初始化完成|| !mBootCompleted) {return false;}//以上條件均滿足,才能進入后面的判斷//不處于喚醒態if (!isBeingKeptAwakeLocked()) {//沒充電,電源選項也未配置,不可dreamingif (!mIsPowered && !mDreamsEnabledOnBatteryConfig) {return false;}//沒充電,且電池電量過低,不可dreamingif (!mIsPowered&& mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0&& mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) {return false;}//充電,但電池電量過低,不可dreamingif (mIsPowered&& mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0&& mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) {return false;}//充電和未充電分別有一個最低的dreaming電量門限}return true; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
從上面的代碼可以看出,dreaming除了對終端當前的狀態、配置項有關外,在非喚醒狀態下還與當前的電池電量有關系。
canDozeLocked函數相對簡單:
private boolean canDozeLocked() {return mWakefulness == WAKEFULNESS_DOZING; }- 1
- 2
- 3
2、在必要時,進入屏保狀態
// Start dreaming if needed. final boolean isDreaming; if (mDreamManager != null) {if (startDreaming) {//結束舊夢mDreamManager.stopDream(false /*immediate*/);//開啟新夢mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);}//startDream成功后,一般isDreaming就會返回trueisDreaming = mDreamManager.isDreaming(); } else {isDreaming = false; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
決定了是否可以進入屏保狀態后,這一部分就開始進行實際的工作。
mDreamManager為DreamManagerService的Binder代理。?
我們重點看看DreamManagerService的startDream函數,stopDream的工作內容與startDream相反,不做細致分析:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
從這部分代碼我們知道了,所謂的屏保其實就是拉起一個特殊的服務。
3、更新屏保狀態
// Update dream state. synchronized (mLock) {// Remember the initial battery level when the dream started.if (startDreaming && isDreaming) {mBatteryLevelWhenDreamStarted = mBatteryLevel;................}// If preconditions changed, wait for the next iteration to determine// whether the dream should continue (or be restarted).//例如:mDisplayReady為false時, mSandmanSummoned保持為falseif (mSandmanSummoned || mWakefulness != wakefulness) {return; // wait for next cycle}.............// Determine whether the dream should continue.if (wakefulness == WAKEFULNESS_DREAMING) {if (isDreaming && canDreamLocked()) {if (mDreamsBatteryLevelDrainCutoffConfig >= 0//下面這句我是懵逼的,這不是必然成立的么?//也就是只要配置了mDreamsBatteryLevelDrainCutoffConfig就會成立//按注釋來講,這里好歹重新取一次mBatteryLevel啊!!!懷疑是bug點&& mBatteryLevel < mBatteryLevelWhenDreamStarted- mDreamsBatteryLevelDrainCutoffConfig&& !isBeingKeptAwakeLocked()) {// If the user activity timeout expired and the battery appears// to be draining faster than it is charging then stop dreaming// and go to sleep.} else {return; // continue dreaming}}// Dream has ended or will be stopped. Update the power state.if (isItBedTimeYetLocked()) {//休眠goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);updatePowerStateLocked();} else {//喚醒wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), "android.server.power:DREAM",Process.SYSTEM_UID, mContext.getOpPackageName(), Process.SYSTEM_UID);updatePowerStateLocked();}} else if (wakefulness == WAKEFULNESS_DOZING) {if (isDreaming) {return; // continue dozing}// Doze has ended or will be stopped. Update the power state.reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);updatePowerStateLocked();} }// Stop dream. //執行到這里說明退出了dreaming狀態,如果之前拉起過屏保服務,此時應該停止它 if (isDreaming) {mDreamManager.stopDream(false /*immediate*/); } ...........- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
以上是PMS更新屏保狀態的基本流程,整體來看相當的繁瑣。?
我們還是用一個圖來整體整理一下:?
大圖鏈接?
這部分代碼最后太亂,每次更新狀態后都會重新調用updatePowerStateLocked,然后再次進入到handleSandman函數中。?
這種反復地遞歸調用,比較難以把控。
五、更新suspend blocker?
updateSuspendBlockerLocked函數主要根據之前流程的執行結果,持有或者釋放CPU和屏幕的鎖。?
我們一起來看看對應的函數:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
從上面的代碼可以看出PMS是非常依賴于native層的,真實的持鎖、釋放鎖、設置交互狀態等工作,均是移交到native層進行操作。?
我們以mWakeLockSuspendBlocker的處理流程為例,看看native的調用過程:
- 1
- 2
- 3
之前的博客也提到過,PMS在其構造函數中調用createSuspendBlockerLocked函數,創建出了mWakeLockSuspendBlocker:
private SuspendBlocker createSuspendBlockerLocked(String name) {//實際對象為PMS內部類SuspendBlockerImplSuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);mSuspendBlockers.add(suspendBlocker);return suspendBlocker; }- 1
- 2
- 3
- 4
- 5
- 6
從上面的代碼,我們知道當PMS需要獲取底層鎖時,調用的是SuspendBlockerImpl的acquire函數:
public void acquire() {synchronized (this) {mReferenceCount += 1;if (mReferenceCount == 1) {.......//調用到了native層nativeAcquireSuspendBlocker(mName);}} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
在native層的com_android_server_power_PowerManagerService.cpp中,對應的native函數為:
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {ScopedUtfChars name(env, nameStr);//獲取的是PARTIAL_WAKE_LOCK的類型,即保持CPU喚醒的acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str()); }- 1
- 2
- 3
- 4
- 5
從這里的代碼我們不難發現,盡管PMS定義了不同的WakeLock等級,但當通過PMS的native函數調用HAL層函數acquire_wake_lock時,使用的都是PARTIAL_WAKE_LOCK。?
個人覺得這是可以理解的,當其它進程向PMS申請保持屏幕喚醒的Framework層WakeLock后,PMS在Framework層就進行了對應的處理,例如將請求信息等地交給DisplayPowerController等處理。因此,對于底層的HAL層而言,只需要關注CPU是否需要保持喚醒即可。?
HAL層函數acquire_wake_lock,最后會向/sys/power/wake_lock節點進行write操作。
總結?
至此,updatePowerStateLocked的基本流程介紹完畢,大體上如下圖所示:
通過其中的源碼,我們也能看出僅管理當前的狀態,涉及的細節就非常的瑣碎。?
而屏幕和CPU的實際控制,還牽扯到大量其它對象和HAL層代碼。?
Android電源的管理實際上是基于Linux電源管理策略的,因此若要真正掌握,還需要對Linux的電源管理策略作進一步的了解。?
由于個人水平有限,目前還無法高屋建瓴地整體分析宏觀的電源管理架構,細節也有一些遺漏。?
后續爭取以此博客為基礎,不斷迭代,以求更進一步地了解PMS的知識。
原文地址: http://blog.csdn.net/gaugamela/article/details/52838654
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Android7.0 PowerManagerService(3) 核心函数updatePowerStateLocked的主要流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android7.0 PowerMana
- 下一篇: AndroidL分析之Keyguard