Android7.0 PowerManagerService(2) WakeLock的使用及流程
作為移動終端,電量是一種稀缺資源,需要盡可能的節省。于是,Android系統在空閑時,會主動進入到休眠狀態。?
我們知道整個Android系統中運行著很多個進程,因此必須有一種機制能夠知道每個進程是否正在進行重要的工作,只有這樣Android系統才能對整個終端當前的狀態做出判斷。
顯然我們不能啟動一個進程,去主動監管其它所有進程的工作狀態,這樣CPU開銷太大,反而加劇了電量的消耗。為此Android引入了基于WakeLock的電量管理機制,而PMS就是專門負責管理WakeLock的進程。
個人覺得WakeLock機制的思想,有點類似于早期通信領域局域網中的令牌環機制。當局域網中有設備需要發送數據時,需要申請令牌(Token),申請到令牌才能發送數據;設備發送完數據后,再釋放掉令牌。
與此相似,Android設備中運行的進程需要使用電量資源時,也需要向PMS申請一個WakeLock;當工作完成后,就釋放掉申請的WakeLock。PMS通過判斷當前是否還有進程持有WakeLock,就能得出系統是否空閑的結論。
從這里也可以看出,當我們寫一個永不停止工作的線程,但不申請WakeLock時,系統仍然可以休眠。在休眠時,CPU不會再耗費資源去調度該線程,于是“永不停止工作”被打上了引號。
接下來,我們就來看看PMS中的WakeLock。
一、創建WakeLock?
我們以RIL.java為例,看看一般情況下,PMS以外的其它進程如何使用WakeLock。?
在RIL.java的構造函數中:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
從上面的代碼,可以看出調用PowerManager的newWakeLock函數,可以創建出WakeLock。
我們看看newWakeLock函數定義:
public WakeLock newWakeLock(int levelAndFlags, String tag) {//檢查參數有效性,即levelAndFlags必須對應于PowerManager中定義的WakeLock級別和flag,tag不能為空validateWakeLockParameters(levelAndFlags, tag);//此WakeLock為PowerManager定義的內部類return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName()); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
1、WakeLock Level?
newWakeLock中的第一個參數對應于WakeLock的級別和標志位構成的位圖。?
目前,在PowerManger中一共為WakeLock定義了7種level。
- 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
從上面的代碼注釋可以看出,WakeLock主要用于控制CPU、屏幕和鍵盤三大部分(當然,現在的Anroid中基本沒有鍵盤了)。?
對于PARTIAL_WAKE_LOCK、SCREEN_DIM_WAKE_LOCK、SCREEN_BRIGHT_WAKE_LOCK和FULL_WAKE_LOCK而言,不考慮Power鍵的話,隨著等級的提高,權限也相應增大,即持有高等級的鎖,能夠激活的部分越多;如果考慮Power鍵的話,PARTIAL_WAKE_LOCK可以保證CPU不休眠,反而是權限最大的。
PROXIMITY_SCREEN_OFF_WAKE_LOCK、DOZE_WAKE_LOCK和DRAW_WAKE_LOCK都是和具體場景相關的鎖。
2、WakeLock Flag?
PowerManager定義的WakeLock Flag很多,無法一一列舉,就看一下比較常用的:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
總結一下上面的內容,如下所示:?
?
WakeLock Flag一般與WakeLock Level組合使用,使用的時候參照一下注釋即可。
3、WakeLock的構造函數?
最后,我們來看看WakeLock的構造函數:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
WakeLock的構造函數中需要注意的地方是,創建了一個Binder對象。?
回憶一下RIL.java中創建WakeLock的過程,我們就知道這個Binder對象應該是創建在RIL.java所在的Phone進程中。
二、Acquire WakeLock?
從上面的分析,我們知道一個進程創建的WakeLock,實際上表明了該進程執行某個工作時對電量的需求,例如聲明該工作需要保持屏幕處于點亮狀態,或該工作需要CPU處于喚醒態等。?
因此,進程創建了WakeLock后,需要將WakeLock發送到PMS中,讓PMS明白該進程的需求。?
這種將WakeLock通知到PMS的過程,就被稱為acquire WakeLock。
同樣,我們還是以RIL.java中的使用過程舉例:
private void send(RILRequest rr) {Message msg;if (mSocket == null) {rr.onError(RADIO_NOT_AVAILABLE, null);rr.release();return;}msg = mSender.obtainMessage(EVENT_SEND, rr);//重點在這里acquireWakeLock(rr, FOR_WAKELOCK);msg.sendToTarget(); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
當AP側向modem發送請求時,將要調用RIL.java的send函數。send函數將會發送消息給RILSender,后者利用socket將消息發送給rild進程。?
從上面的代碼可以看出,在發送消息給RILSender之前,調用了acquireWakeLock函數:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
我們跟進一下PowerManager中WakeLock的acquire函數:
public void acquire() {synchronized (mToken) {acquireLocked();} }private void acquireLocked() {//前面已經提過,RIL.java中已經將mRefCounted置為false//如果不將mRefCounted置為false,意味著acquire和release必須一一對應//那么每個WakeLock只能acquire一次if (!mRefCounted || mCount++ == 0) {........try {mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,mHistoryTag);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}mHeld = true;} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
容易看出實際的工作流程將通過Binder通信進入到PMS中:
public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,WorkSource ws, String historyTag) {//參數和權限檢查............final int uid = Binder.getCallingUid();final int pid = Binder.getCallingPid();final long ident = Binder.clearCallingIdentity();try {acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag, uid, pid);} finally {Binder.restoreCallingIdentity(ident);} }private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,WorkSource ws, String historyTag, int uid, int pid) {synchronized (mLock) {...........//PMS中也定義了WakeLock內部類WakeLock wakeLock;//PMS中維持了一個ArrayList,記錄當前已申請的WakeLock//findWakeLockIndexLocked查找ArrayList,判斷參數對應的WakeLock,是否在之前被申請過int index = findWakeLockIndexLocked(lock);boolean notifyAcquire;if (index >= 0) {//如果index大于0,說明此時Acquire的是一個舊的WakeLock//例如RIL會多次調用send函數,于是除第一次外,都會進入這個分支wakeLock = mWakeLocks.get(index);//這是判斷WakeLock對應的成員變量是否發生改變if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {// Update existing wake lock. This shouldn't happen but is harmless.notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName,uid, pid, ws, historyTag);//若wakelock屬性發生了變化,更新該屬性wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid);}notifyAcquire = false;} else {//創建一個新的WakeLock,例如RIL第一次調用send就會進入該分支wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid);try {//1、監控申請WakeLock的進程是否死亡lock.linkToDeath(wakeLock, 0);} catch (RemoteException ex) {throw new IllegalArgumentException("Wake lock is already dead.");}//添加到wakelock列表mWakeLocks.add(wakeLock);//2、特殊處理PARTIAL_WAKE_LOCK//實際上,根據Doze模式的白名單更新wakelock的disabled變量setWakeLockDisabledStateLocked(wakeLock);notifyAcquire = true;}//3、處理WakeLock對應的Flag//實際上判斷WakeLock是否有ACQUIRE_CAUSES_WAKEUP,在必要時喚醒屏幕applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);mDirty |= DIRTY_WAKE_LOCKS;//更新電源狀態,以后單獨分析updatePowerStateLocked();if (notifyAcquire) {// This needs to be done last so we are sure we have acquired the// kernel wake lock. Otherwise we have a race where the system may// go to sleep between the time we start the accounting in battery// stats and when we actually get around to telling the kernel to// stay awake.//通知wakeLock發生變化 //電量統計服務做相關統計notifyWakeLockAcquiredLocked(wakeLock);}} }- 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
如上代碼中標注的注釋,acquireWakeLockInternal中有幾處比較重要的地方,我們一起來分析一下。
1、監聽客戶端進程死亡?
上面的代碼中,第一次創建WakeLock后,調用了:
- 1
- 2
- 3
我們將acquire WakeLock的進程定義為PMS的客戶端進程,那么上面代碼的lock,就是客戶端進程中創建的Binder對象的代理。對于RIL而言,就是存在于Phone進程中的Binder的代理。?
PMS調用Binder代理的linkToDeath,實際上使得PMS成為了對應進程Binder的客戶端。于是,當對應進程死亡后,將通知PMS。?
linkToDeath傳入的必須是繼承IBinder.DeathRecipient的對象,作為進程死亡的”訃告”接收者。
我們看看PMS中WakeLock與此相關的定義:
private final class WakeLock implements IBinder.DeathRecipient {...........@Overridepublic void binderDied() {//發現客戶端進程死亡后,調用PMS的handleWakeLockDeath進行處理,傳入的參數為WakeLock自己PowerManagerService.this.handleWakeLockDeath(this);}....... }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
我們看看PMS的handleWakeLockDeath函數:
private void handleWakeLockDeath(WakeLock wakeLock) {synchronized (mLock) {..........int index = mWakeLocks.indexOf(wakeLock);if (index < 0) {return;}removeWakeLockLocked(wakeLock, index);} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
跟進removeWakeLockLocked函數:
private void removeWakeLockLocked(WakeLock wakeLock, int index) {mWakeLocks.remove(index);//通知到BatteryStatsServicenotifyWakeLockReleasedLocked(wakeLock);//處理WakeLock對應的flag,與后文applyWakeLockFlagsOnAcquireLocked一起分析//實際上是判斷是否需要立即息屏applyWakeLockFlagsOnReleaseLocked(wakeLock);mDirty |= DIRTY_WAKE_LOCKS;//鎖移除后,還是利用updatePowerStateLocked更新電源狀態updatePowerStateLocked(); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
2、特殊處理PARTIAL_WAKE_LOCK?
PMS處理第一次創建的WakeLock時,還會調用setWakeLockDisabledStateLocked函數進行處理:
- 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
上面代碼大致的含義就是:?
在Android Doze模式下,當終端處于device Idle Mode時,?
對于一個非系統應用而言,如果該應用不在系統定義的白名單中,?
并且該應用所在進程的類型表明,該進程對事件處理的時效性要求不高,?
那么即使該應用申請了PARTIAL_WAKE_LOCK,也不能阻止系統進入休眠狀態。
有些設備商,為了優化系統的功耗,就修改了這個地方。?
例如,有些系統應用其實也很耗電,因此可以去掉該函數中對非系統應用的限制,對系統應用也進行管控。
3、處理WakeLock對應的Flag?
前面的代碼已經提到,當acquire WakeLock時,將調用applyWakeLockFlagsOnAcquireLocked處理WakeLock對應的flag;?
當由于進程死亡,釋放WakeLock時,會調用applyWakeLockFlagsOnReleaseLocked處理WakeLock對應的flag。?
從函數命名來看,這兩個函數應該有相似的地方。
3.1 applyWakeLockFlagsOnAcquireLocked?
我們先看看applyWakeLockFlagsOnAcquireLocked:
- 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
3.1.1 setWakefulnessLocked?
我們看看喚醒屏幕相關的操作:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 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
從上面的代碼來看,應該是PhoneWindowManager完成亮屏前的初始化工作,然后回調到PowerManager的wakeUp函數。?
整個過程還是比較復雜的,需要單獨進行分析,此處不做進一步說明。
3.2 applyWakeLockFlagsOnReleaseLocked?
現在我們再看看applyWakeLockFlagsOnReleaseLocked函數:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
可以看出applyWakeLockFlagsOnAcquireLocked和applyWakeLockFlagsOnReleaseLocked最后均會調用userActivityNoUpdateLocked函數,只是參數不同。
3.3 userActivityNoUpdateLocked?
我們一起來看一下userActivityNoUpdateLocked:
- 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
從以上代碼來看,acquire WakeLock將申請信息遞交給PMS統一進行處理。?
PMS根據WakeLock的level和flag,完成修改一些變量、通知BatteryStatsService等工作后,?
最終還是依賴于updatePowerStateLocked函數來進行實際的電源狀態更新操作。
PMS類中有很多***NoUpdateLocked()方法,這些方法都有一些共性,就是僅更新狀態,不負責具體的執行。因為PMS中具體的執行邏輯都是在updatePowerStateLocked方法中。
上述acquire WakeLock主要的工作大致可以總結為下圖:?
三、釋放WakeLock?
當進程完成工作后,需要釋放之前申請的WakeLock。我們同樣以RIL.java中的操作為例:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
我們跟進decrementWakeLock函數:
private void decrementWakeLock(RILRequest rr) {synchronized(rr) {switch(rr.mWakeLockType) {case FOR_WAKELOCK:synchronized (mWakeLock) {//前面已經提到過,RIL.java多個請求復用同一個WakeLock//并且利用mWakeLockCount記錄復用的次數//這么設計的目的是:RIL發送請求的數量非常多,復用WakeLock可以避免多次構造釋放//同時減少與PMS之間Binder通信的次數if (mWakeLockCount > 1) {mWakeLockCount--;} else {mWakeLockCount = 0;//所有請求均得到了處理,調用PowerManager中WakeLock的release函數mWakeLock.release();}}break;........}}........ }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
現在我們跟進PowerManager中WakeLock定義的release函數:
/** * Releases the wake lock with flags to modify the release behavior. * * This method releases your claim to the CPU or screen being on. * The screen may turn off shortly after you release the wake lock, or it may * not if there are other wake locks still held. * */ public void release(int flags) {synchronized (mToken) {if (!mRefCounted || --mCount == 0) {mHandler.removeCallbacks(mReleaser);if (mHeld) {.......try {//還是會調用到PMS中的函數mService.releaseWakeLock(mToken, flags);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}mHeld = false;}}....} }- 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
最后一起來看看PMS中釋放WakeLock的函數:
public void releaseWakeLock(IBinder lock, int flags) {//參數和權限檢查.............final long ident = Binder.clearCallingIdentity();try {releaseWakeLockInternal(lock, flags);} finally {Binder.restoreCallingIdentity(ident);} }private void releaseWakeLockInternal(IBinder lock, int flags) {synchronized (mLock) {//根據Binder代理,從存儲的ArrayList中找到對應WakeLock的序號int index = findWakeLockIndexLocked(lock);...........WakeLock wakeLock = mWakeLocks.get(index);...........//RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY,表示當sensor判斷終端離物體較遠時,//才真正釋放PROXIMITY_SCREEN_OFF_WAKE_LOCK等級的WakeLockif ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {mRequestWaitForNegativeProximity = true;}//PMS不再關注客戶端進程是否死亡wakeLock.mLock.unlinkToDeath(wakeLock, 0);removeWakeLockLocked(wakeLock, index);} }private void removeWakeLockLocked(WakeLock wakeLock, int index) {mWakeLocks.remove(index);//通知BatteryStatsServicenotifyWakeLockReleasedLocked(wakeLock);//之前分析過,會做一些記錄信息等applyWakeLockFlagsOnReleaseLocked(wakeLock);mDirty |= DIRTY_WAKE_LOCKS;//依然靠updatePowerStateLocked函數更新終端的電源狀態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
整個release的過程大致可以總結為下圖:?
四、總結?
通過前面的分析,我們知道了向PMS申請電量的基本用法類似于:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
當申請發送到PMS后,PMS將針對WakeLock的level和flag信息進行一些處理。?
無論是acquire還是release WakeLock,PMS最終將利用updatePowerStateLocked函數對終端的電源狀態進行調整。?
我們將單獨分析一下PMS核心的updatePowerStateLocked函數。
原文地址:http://blog.csdn.net/gaugamela/article/details/52813400
總結
以上是生活随笔為你收集整理的Android7.0 PowerManagerService(2) WakeLock的使用及流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android7.0 PowerMana
- 下一篇: Android7.0 PowerMana