日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android7.0 PowerManagerService(2) WakeLock的使用及流程

發(fā)布時(shí)間:2025/3/15 Android 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android7.0 PowerManagerService(2) WakeLock的使用及流程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

作為移動(dòng)終端,電量是一種稀缺資源,需要盡可能的節(jié)省。于是,Android系統(tǒng)在空閑時(shí),會(huì)主動(dòng)進(jìn)入到休眠狀態(tài)。?
我們知道整個(gè)Android系統(tǒng)中運(yùn)行著很多個(gè)進(jìn)程,因此必須有一種機(jī)制能夠知道每個(gè)進(jìn)程是否正在進(jìn)行重要的工作,只有這樣Android系統(tǒng)才能對(duì)整個(gè)終端當(dāng)前的狀態(tài)做出判斷。

顯然我們不能啟動(dòng)一個(gè)進(jìn)程,去主動(dòng)監(jiān)管其它所有進(jìn)程的工作狀態(tài),這樣CPU開銷太大,反而加劇了電量的消耗。為此Android引入了基于WakeLock的電量管理機(jī)制,而PMS就是專門負(fù)責(zé)管理WakeLock的進(jìn)程。

個(gè)人覺得WakeLock機(jī)制的思想,有點(diǎn)類似于早期通信領(lǐng)域局域網(wǎng)中的令牌環(huán)機(jī)制。當(dāng)局域網(wǎng)中有設(shè)備需要發(fā)送數(shù)據(jù)時(shí),需要申請(qǐng)令牌(Token),申請(qǐng)到令牌才能發(fā)送數(shù)據(jù);設(shè)備發(fā)送完數(shù)據(jù)后,再釋放掉令牌。

與此相似,Android設(shè)備中運(yùn)行的進(jìn)程需要使用電量資源時(shí),也需要向PMS申請(qǐng)一個(gè)WakeLock;當(dāng)工作完成后,就釋放掉申請(qǐng)的WakeLock。PMS通過判斷當(dāng)前是否還有進(jìn)程持有WakeLock,就能得出系統(tǒng)是否空閑的結(jié)論。

從這里也可以看出,當(dāng)我們寫一個(gè)永不停止工作的線程,但不申請(qǐng)WakeLock時(shí),系統(tǒng)仍然可以休眠。在休眠時(shí),CPU不會(huì)再耗費(fèi)資源去調(diào)度該線程,于是“永不停止工作”被打上了引號(hào)。

接下來,我們就來看看PMS中的WakeLock。

一、創(chuàng)建WakeLock?
我們以RIL.java為例,看看一般情況下,PMS以外的其它進(jìn)程如何使用WakeLock。?
在RIL.java的構(gòu)造函數(shù)中:

public RIL(Context context, int preferredNetworkType,int cdmaSubscription, Integer instanceId) {.............PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);//獲取WakeLock,第一個(gè)參數(shù)決定了WakeLock的等級(jí)和flagmWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_LOG_TAG);//默認(rèn)WakeLocked會(huì)ReferenceCounted,即一次申請(qǐng)對(duì)應(yīng)一次釋放//設(shè)為false后,一次釋放就可以對(duì)應(yīng)所有的申請(qǐng)mWakeLock.setReferenceCounted(false);...........//RIL.java中自己維護(hù)了WakeLockCountmWakeLockCount = 0;........... }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

從上面的代碼,可以看出調(diào)用PowerManager的newWakeLock函數(shù),可以創(chuàng)建出WakeLock。

我們看看newWakeLock函數(shù)定義:

public WakeLock newWakeLock(int levelAndFlags, String tag) {//檢查參數(shù)有效性,即levelAndFlags必須對(duì)應(yīng)于PowerManager中定義的WakeLock級(jí)別和flag,tag不能為空validateWakeLockParameters(levelAndFlags, tag);//此WakeLock為PowerManager定義的內(nèi)部類return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName()); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

1、WakeLock Level?
newWakeLock中的第一個(gè)參數(shù)對(duì)應(yīng)于WakeLock的級(jí)別和標(biāo)志位構(gòu)成的位圖。?
目前,在PowerManger中一共為WakeLock定義了7種level。

/** * Wake lock level: Ensures that the CPU is running; the screen and keyboard * backlight will be allowed to go off. * * If the user presses the power button, then the screen will be turned off * but the CPU will be kept on until all partial wake locks have been released. * / public static final int PARTIAL_WAKE_LOCK = 0x00000001;/** * Wake lock level: Ensures that the screen is on (but may be dimmed); * the keyboard backlight will be allowed to go off. * * If the user presses the power button, then the SCREEN_DIM_WAKE_LOCK will be * implicitly released by the system, causing both the screen and the CPU to be turned off. */ @Deprecated public static final int SCREEN_DIM_WAKE_LOCK = 0x00000006;/** * Wake lock level: Ensures that the screen is on at full brightness; * the keyboard backlight will be allowed to go off. * *If the user presses the power button, then the SCREEN_BRIGHT_WAKE_LOCK will be * implicitly released by the system, causing both the screen and the CPU to be turned off. */ @Deprecated public static final int SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a;/** * Wake lock level: Ensures that the screen and keyboard backlight are on at * full brightness. * *If the user presses the power button, then the FULL_WAKE_LOCK will be * implicitly released by the system, causing both the screen and the CPU to be turned off. */ @Deprecated public static final int FULL_WAKE_LOCK = 0x0000001a;/** * Wake lock level: Turns the screen off when the proximity sensor activates. * If the proximity sensor detects that an object is nearby, the screen turns off * immediately. Shortly after the object moves away, the screen turns on again. * * A proximity wake lock does not prevent the device from falling asleep * unlike link FULL_WAKE_LOCK, SCREEN_BRIGHT_WAKE_LOCK and SCREEN_DIM_WAKE_LOCK. * If there is no user activity and no other wake locks are held, then the device will fall asleep (and lock) as usual. * However, the device will not fall asleep while the screen has been turned off * by the proximity sensor because it effectively counts as ongoing user activity. * * Cannot be used with ACQUIRE_CAUSES_WAKEUP (WakeLock的flag). */ //例如撥號(hào),打通后接聽電話,屏幕變黑 public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;/** * Wake lock level: Put the screen in a low power state and allow the CPU to suspend * if no other wake locks are held. * * This is used by the dream manager to implement doze mode. It currently * has no effect unless the power manager is in the dozing state. * / public static final int DOZE_WAKE_LOCK = 0x00000040;/** * Wake lock level: Keep the device awake enough to allow drawing to occur. * * This is used by the window manager to allow applications to draw while the * system is dozing. It currently has no effect unless the power manager is in * the dozing state. * / public static final int DRAW_WAKE_LOCK = 0x00000080;
  • 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、屏幕和鍵盤三大部分(當(dāng)然,現(xiàn)在的Anroid中基本沒有鍵盤了)。?
對(duì)于PARTIAL_WAKE_LOCK、SCREEN_DIM_WAKE_LOCK、SCREEN_BRIGHT_WAKE_LOCK和FULL_WAKE_LOCK而言,不考慮Power鍵的話,隨著等級(jí)的提高,權(quán)限也相應(yīng)增大,即持有高等級(jí)的鎖,能夠激活的部分越多;如果考慮Power鍵的話,PARTIAL_WAKE_LOCK可以保證CPU不休眠,反而是權(quán)限最大的。

PROXIMITY_SCREEN_OFF_WAKE_LOCK、DOZE_WAKE_LOCK和DRAW_WAKE_LOCK都是和具體場(chǎng)景相關(guān)的鎖。

2、WakeLock Flag?
PowerManager定義的WakeLock Flag很多,無法一一列舉,就看一下比較常用的:

/** * Wake lock flag: Turn the screen on when the wake lock is acquired. * * Normally wake locks don't actually wake the device, they just cause * the screen to remain on once it's already on. Think of the video player * application as the normal behavior. Notifications that pop up and want * the device to be on are the exception; use this flag to be like them. * * Cannot be used with PARTIAL_WAKE_LOCK. * / public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;/** * Wake lock flag: When this wake lock is released, poke the user activity timer * so the screen stays on for a little longer. * * Will not turn the screen on if it is not already on. * * Cannot be used with PARTIAL_WAKE_LOCK. * / public static final int ON_AFTER_RELEASE = 0x20000000;..................
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

總結(jié)一下上面的內(nèi)容,如下所示:?
?
WakeLock Flag一般與WakeLock Level組合使用,使用的時(shí)候參照一下注釋即可。

3、WakeLock的構(gòu)造函數(shù)?
最后,我們來看看WakeLock的構(gòu)造函數(shù):

WakeLock(int flags, String tag, String packageName) {//level and flagmFlags = flags;//創(chuàng)建類對(duì)應(yīng)的打印TagmTag = tag;//創(chuàng)建類的類名 mPackageName = packageName;//創(chuàng)建一個(gè)Binder對(duì)象//PMS將作為該Binder的客戶端監(jiān)聽對(duì)應(yīng)進(jìn)程是否死亡mToken = new Binder();mTraceName = "WakeLock (" + mTag + ")"; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

WakeLock的構(gòu)造函數(shù)中需要注意的地方是,創(chuàng)建了一個(gè)Binder對(duì)象。?
回憶一下RIL.java中創(chuàng)建WakeLock的過程,我們就知道這個(gè)Binder對(duì)象應(yīng)該是創(chuàng)建在RIL.java所在的Phone進(jìn)程中。

二、Acquire WakeLock?
從上面的分析,我們知道一個(gè)進(jìn)程創(chuàng)建的WakeLock,實(shí)際上表明了該進(jìn)程執(zhí)行某個(gè)工作時(shí)對(duì)電量的需求,例如聲明該工作需要保持屏幕處于點(diǎn)亮狀態(tài),或該工作需要CPU處于喚醒態(tài)等。?
因此,進(jìn)程創(chuàng)建了WakeLock后,需要將WakeLock發(fā)送到PMS中,讓PMS明白該進(jìn)程的需求。?
這種將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);//重點(diǎn)在這里acquireWakeLock(rr, FOR_WAKELOCK);msg.sendToTarget(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

當(dāng)AP側(cè)向modem發(fā)送請(qǐng)求時(shí),將要調(diào)用RIL.java的send函數(shù)。send函數(shù)將會(huì)發(fā)送消息給RILSender,后者利用socket將消息發(fā)送給rild進(jìn)程。?
從上面的代碼可以看出,在發(fā)送消息給RILSender之前,調(diào)用了acquireWakeLock函數(shù):

private void acquireWakeLock(RILRequest rr, int wakeLockType) {synchronized(rr) {.............switch(wakeLockType) {case FOR_WAKELOCK:synchronized (mWakeLock) {//調(diào)用acquire函數(shù)mWakeLock.acquire();mWakeLockCount++;mWlSequenceNum++;............}break;.........}rr.mWakeLockType = wakeLockType;} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

我們跟進(jìn)一下PowerManager中WakeLock的acquire函數(shù):

public void acquire() {synchronized (mToken) {acquireLocked();} }private void acquireLocked() {//前面已經(jīng)提過,RIL.java中已經(jīng)將mRefCounted置為false//如果不將mRefCounted置為false,意味著acquire和release必須一一對(duì)應(yīng)//那么每個(gè)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

容易看出實(shí)際的工作流程將通過Binder通信進(jìn)入到PMS中:

public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,WorkSource ws, String historyTag) {//參數(shù)和權(quán)限檢查............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內(nèi)部類WakeLock wakeLock;//PMS中維持了一個(gè)ArrayList,記錄當(dāng)前已申請(qǐng)的WakeLock//findWakeLockIndexLocked查找ArrayList,判斷參數(shù)對(duì)應(yīng)的WakeLock,是否在之前被申請(qǐng)過int index = findWakeLockIndexLocked(lock);boolean notifyAcquire;if (index >= 0) {//如果index大于0,說明此時(shí)Acquire的是一個(gè)舊的WakeLock//例如RIL會(huì)多次調(diào)用send函數(shù),于是除第一次外,都會(huì)進(jìn)入這個(gè)分支wakeLock = mWakeLocks.get(index);//這是判斷WakeLock對(duì)應(yīng)的成員變量是否發(fā)生改變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屬性發(fā)生了變化,更新該屬性wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid);}notifyAcquire = false;} else {//創(chuàng)建一個(gè)新的WakeLock,例如RIL第一次調(diào)用send就會(huì)進(jìn)入該分支wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid);try {//1、監(jiān)控申請(qǐng)WakeLock的進(jìn)程是否死亡lock.linkToDeath(wakeLock, 0);} catch (RemoteException ex) {throw new IllegalArgumentException("Wake lock is already dead.");}//添加到wakelock列表mWakeLocks.add(wakeLock);//2、特殊處理PARTIAL_WAKE_LOCK//實(shí)際上,根據(jù)Doze模式的白名單更新wakelock的disabled變量setWakeLockDisabledStateLocked(wakeLock);notifyAcquire = true;}//3、處理WakeLock對(duì)應(yīng)的Flag//實(shí)際上判斷WakeLock是否有ACQUIRE_CAUSES_WAKEUP,在必要時(shí)喚醒屏幕applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);mDirty |= DIRTY_WAKE_LOCKS;//更新電源狀態(tài),以后單獨(dú)分析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發(fā)生變化 //電量統(tǒng)計(jì)服務(wù)做相關(guān)統(tǒng)計(jì)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

如上代碼中標(biāo)注的注釋,acquireWakeLockInternal中有幾處比較重要的地方,我們一起來分析一下。

1、監(jiān)聽客戶端進(jìn)程死亡?
上面的代碼中,第一次創(chuàng)建WakeLock后,調(diào)用了:

......... lock.linkToDeath(wakeLock, 0); .........
  • 1
  • 2
  • 3

我們將acquire WakeLock的進(jìn)程定義為PMS的客戶端進(jìn)程,那么上面代碼的lock,就是客戶端進(jìn)程中創(chuàng)建的Binder對(duì)象的代理。對(duì)于RIL而言,就是存在于Phone進(jìn)程中的Binder的代理。?
PMS調(diào)用Binder代理的linkToDeath,實(shí)際上使得PMS成為了對(duì)應(yīng)進(jìn)程Binder的客戶端。于是,當(dāng)對(duì)應(yīng)進(jìn)程死亡后,將通知PMS。?
linkToDeath傳入的必須是繼承IBinder.DeathRecipient的對(duì)象,作為進(jìn)程死亡的”訃告”接收者。

我們看看PMS中WakeLock與此相關(guān)的定義:

private final class WakeLock implements IBinder.DeathRecipient {...........@Overridepublic void binderDied() {//發(fā)現(xiàn)客戶端進(jìn)程死亡后,調(diào)用PMS的handleWakeLockDeath進(jìn)行處理,傳入的參數(shù)為WakeLock自己PowerManagerService.this.handleWakeLockDeath(this);}....... }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我們看看PMS的handleWakeLockDeath函數(shù):

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

跟進(jìn)removeWakeLockLocked函數(shù):

private void removeWakeLockLocked(WakeLock wakeLock, int index) {mWakeLocks.remove(index);//通知到BatteryStatsServicenotifyWakeLockReleasedLocked(wakeLock);//處理WakeLock對(duì)應(yīng)的flag,與后文applyWakeLockFlagsOnAcquireLocked一起分析//實(shí)際上是判斷是否需要立即息屏applyWakeLockFlagsOnReleaseLocked(wakeLock);mDirty |= DIRTY_WAKE_LOCKS;//鎖移除后,還是利用updatePowerStateLocked更新電源狀態(tài)updatePowerStateLocked(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2、特殊處理PARTIAL_WAKE_LOCK?
PMS處理第一次創(chuàng)建的WakeLock時(shí),還會(huì)調(diào)用setWakeLockDisabledStateLocked函數(shù)進(jìn)行處理:

private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {//僅會(huì)特殊處理PARTIAL_WAKE_LOCK,畢竟PARTIAL_WAKE_LOCK要求按Power鍵后CPU依然可以工作if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)== PowerManager.PARTIAL_WAKE_LOCK) {boolean disabled = false;//設(shè)備處于Doze定義的device idle模式時(shí)if (mDeviceIdleMode) {final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);// If we are in idle mode, we will ignore all partial wake locks that are// for application uids that are not whitelisted.//判斷是否為非系統(tǒng)應(yīng)用 if (appid >= Process.FIRST_APPLICATION_UID &&//白名單searchArrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 &&Arrays.binarySearch(mDeviceIdleTempWhitelist, appid) < 0 &&//判斷進(jìn)程的類型//ActivityManager中定義的數(shù)字最小的為:常駐的操作UI的系統(tǒng)進(jìn)程//因此大概可理解為:數(shù)字越大,對(duì)處理事件的時(shí)效性要求越低mUidState.get(wakeLock.mOwnerUid,ActivityManager.PROCESS_STATE_CACHED_EMPTY)> ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {disabled = true;}}if (wakeLock.mDisabled != disabled) {wakeLock.mDisabled = disabled;return true;}}return 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
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

上面代碼大致的含義就是:?
在Android Doze模式下,當(dāng)終端處于device Idle Mode時(shí),?
對(duì)于一個(gè)非系統(tǒng)應(yīng)用而言,如果該應(yīng)用不在系統(tǒng)定義的白名單中,?
并且該應(yīng)用所在進(jìn)程的類型表明,該進(jìn)程對(duì)事件處理的時(shí)效性要求不高,?
那么即使該應(yīng)用申請(qǐng)了PARTIAL_WAKE_LOCK,也不能阻止系統(tǒng)進(jìn)入休眠狀態(tài)。

有些設(shè)備商,為了優(yōu)化系統(tǒng)的功耗,就修改了這個(gè)地方。?
例如,有些系統(tǒng)應(yīng)用其實(shí)也很耗電,因此可以去掉該函數(shù)中對(duì)非系統(tǒng)應(yīng)用的限制,對(duì)系統(tǒng)應(yīng)用也進(jìn)行管控。

3、處理WakeLock對(duì)應(yīng)的Flag?
前面的代碼已經(jīng)提到,當(dāng)acquire WakeLock時(shí),將調(diào)用applyWakeLockFlagsOnAcquireLocked處理WakeLock對(duì)應(yīng)的flag;?
當(dāng)由于進(jìn)程死亡,釋放WakeLock時(shí),會(huì)調(diào)用applyWakeLockFlagsOnReleaseLocked處理WakeLock對(duì)應(yīng)的flag。?
從函數(shù)命名來看,這兩個(gè)函數(shù)應(yīng)該有相似的地方。

3.1 applyWakeLockFlagsOnAcquireLocked?
我們先看看applyWakeLockFlagsOnAcquireLocked:

private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {//僅處理ACQUIRE_CAUSES_WAKEUP flag,同時(shí)要求WakeLock的level是與screen有關(guān)的,//即FULL_WAKE_LOCK、SCREEN_BRIGHT_WAKE_LOCK和SCREEN_DIM_WAKE_LOCKif ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0&& isScreenLock(wakeLock)) {..............wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), wakeLock.mTag, opUid,opPackageName, opUid);} }private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,String opPackageName, int opUid) {............//不滿足以下條件,沒有喚醒屏幕的必要if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE|| !mBootCompleted || !mSystemReady) {return false;}try {mLastWakeTime = eventTime;//修改PMS的一些成員變量,并進(jìn)行通知//其中主要的是將mDirty變量的DIRTY_WAKEFULNESS位置為了1//PMS根據(jù)mDirty的位信息管理電源狀態(tài),同時(shí)喚醒屏幕setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);//通知給電源統(tǒng)計(jì)服務(wù)mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);//調(diào)用userActivityNoUpdateLocked函數(shù)userActivityNoUpdateLocked(eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);} .....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

3.1.1 setWakefulnessLocked?
我們看看喚醒屏幕相關(guān)的操作:

private void setWakefulnessLocked(int wakefulness, int reason) {if (mWakefulness != wakefulness) {mWakefulness = wakefulness;mWakefulnessChanging = true;mDirty |= DIRTY_WAKEFULNESS;//定義于frameworks/base/services/core/java/com/android/server/power/Notifier.java中mNotifier.onWakefulnessChangeStarted(wakefulness, reason);} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
public void onWakefulnessChangeStarted(final int wakefulness, int reason) {final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);.......// Tell the activity manager about changes in wakefulness, not just interactivity.mHandler.post(new Runnable() {@Overridepublic void run() {mActivityManagerInternal.onWakefulnessChanged(wakefulness);}});// 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);mInputMethodManagerInternal.setInteractive(interactive);// Notify battery stats.try {mBatteryStats.noteInteractive(interactive);} catch (RemoteException ex) { }// Handle early behaviors.mInteractive = interactive;mInteractiveChangeReason = reason;mInteractiveChanging = true;//重點(diǎn)在這個(gè)位置handleEarlyInteractiveChange();} }/** * Handle early interactive state changes such as getting applications or the lock * screen running and ready for the user to see (such as when turning on the screen). */ private void handleEarlyInteractiveChange() {synchronized (mLock) {if (mInteractive) {// Waking up...mHandler.post(new Runnable() {@Overridepublic void run() {EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);//mPolicy對(duì)應(yīng)于PhoneWindowManagermPolicy.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() {@Overridepublic void run() {mPolicy.startedGoingToSleep(why);}});}} }
  • 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

從上面的代碼來看,應(yīng)該是PhoneWindowManager完成亮屏前的初始化工作,然后回調(diào)到PowerManager的wakeUp函數(shù)。?
整個(gè)過程還是比較復(fù)雜的,需要單獨(dú)進(jìn)行分析,此處不做進(jìn)一步說明。

3.2 applyWakeLockFlagsOnReleaseLocked?
現(xiàn)在我們?cè)倏纯碼pplyWakeLockFlagsOnReleaseLocked函數(shù):

private void applyWakeLockFlagsOnReleaseLocked(WakeLock wakeLock) {//僅處理ON_AFTER_RELEASE,同樣要求WakeLock的level是與screen有關(guān)的//ON_AFTER_RELEASE并不會(huì)立即息屏if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0&& isScreenLock(wakeLock)) {userActivityNoUpdateLocked(SystemClock.uptimeMillis(),PowerManager.USER_ACTIVITY_EVENT_OTHER,PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS,wakeLock.mOwnerUid);} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

可以看出applyWakeLockFlagsOnAcquireLocked和applyWakeLockFlagsOnReleaseLocked最后均會(huì)調(diào)用userActivityNoUpdateLocked函數(shù),只是參數(shù)不同。

3.3 userActivityNoUpdateLocked?
我們一起來看一下userActivityNoUpdateLocked:

private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {.............//過時(shí)的事件不需要處理if (eventTime < mLastSleepTime || eventTime < mLastWakeTime|| !mBootCompleted || !mSystemReady) {return false;}...........try {if (eventTime > mLastInteractivePowerHintTime) {//調(diào)用native加載的動(dòng)態(tài)庫的powerHint函數(shù),具體意義不是很清楚powerHintInternal(POWER_HINT_INTERACTION, 0);mLastInteractivePowerHintTime = eventTime;}//調(diào)用BatteryStatsService的noteUserActivity函數(shù),看代碼好像是做一些記錄mNotifier.onUserActivity(event, uid);//根據(jù)參數(shù)信息修改mDirty的一些變量.............} finally {........} }
  • 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將申請(qǐng)信息遞交給PMS統(tǒng)一進(jìn)行處理。?
PMS根據(jù)WakeLock的level和flag,完成修改一些變量、通知BatteryStatsService等工作后,?
最終還是依賴于updatePowerStateLocked函數(shù)來進(jìn)行實(shí)際的電源狀態(tài)更新操作。

PMS類中有很多***NoUpdateLocked()方法,這些方法都有一些共性,就是僅更新狀態(tài),不負(fù)責(zé)具體的執(zhí)行。因?yàn)镻MS中具體的執(zhí)行邏輯都是在updatePowerStateLocked方法中。

上述acquire WakeLock主要的工作大致可以總結(jié)為下圖:?

三、釋放WakeLock?
當(dāng)進(jìn)程完成工作后,需要釋放之前申請(qǐng)的WakeLock。我們同樣以RIL.java中的操作為例:

private void processResponse (Parcel p) {int type;type = p.readInt();if (type == RESPONSE_UNSOLICITED || type == RESPONSE_UNSOLICITED_ACK_EXP) {...........} else if (type == RESPONSE_SOLICITED || type == RESPONSE_SOLICITED_ACK_EXP) {//處理請(qǐng)求對(duì)應(yīng)的回復(fù)信息RILRequest rr = processSolicited (p, type);if (rr != null) {if (type == RESPONSE_SOLICITED) {//重點(diǎn)在這里decrementWakeLock(rr);}rr.release();return;}} else if (type == RESPONSE_SOLICITED_ACK) {...........} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

我們跟進(jìn)decrementWakeLock函數(shù):

private void decrementWakeLock(RILRequest rr) {synchronized(rr) {switch(rr.mWakeLockType) {case FOR_WAKELOCK:synchronized (mWakeLock) {//前面已經(jīng)提到過,RIL.java多個(gè)請(qǐng)求復(fù)用同一個(gè)WakeLock//并且利用mWakeLockCount記錄復(fù)用的次數(shù)//這么設(shè)計(jì)的目的是:RIL發(fā)送請(qǐng)求的數(shù)量非常多,復(fù)用WakeLock可以避免多次構(gòu)造釋放//同時(shí)減少與PMS之間Binder通信的次數(shù)if (mWakeLockCount > 1) {mWakeLockCount--;} else {mWakeLockCount = 0;//所有請(qǐng)求均得到了處理,調(diào)用PowerManager中WakeLock的release函數(shù)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

現(xiàn)在我們跟進(jìn)PowerManager中WakeLock定義的release函數(shù):

/** * 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 {//還是會(huì)調(diào)用到PMS中的函數(shù)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的函數(shù):

public void releaseWakeLock(IBinder lock, int flags) {//參數(shù)和權(quán)限檢查.............final long ident = Binder.clearCallingIdentity();try {releaseWakeLockInternal(lock, flags);} finally {Binder.restoreCallingIdentity(ident);} }private void releaseWakeLockInternal(IBinder lock, int flags) {synchronized (mLock) {//根據(jù)Binder代理,從存儲(chǔ)的ArrayList中找到對(duì)應(yīng)WakeLock的序號(hào)int index = findWakeLockIndexLocked(lock);...........WakeLock wakeLock = mWakeLocks.get(index);...........//RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY,表示當(dāng)sensor判斷終端離物體較遠(yuǎn)時(shí),//才真正釋放PROXIMITY_SCREEN_OFF_WAKE_LOCK等級(jí)的WakeLockif ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {mRequestWaitForNegativeProximity = true;}//PMS不再關(guān)注客戶端進(jìn)程是否死亡wakeLock.mLock.unlinkToDeath(wakeLock, 0);removeWakeLockLocked(wakeLock, index);} }private void removeWakeLockLocked(WakeLock wakeLock, int index) {mWakeLocks.remove(index);//通知BatteryStatsServicenotifyWakeLockReleasedLocked(wakeLock);//之前分析過,會(huì)做一些記錄信息等applyWakeLockFlagsOnReleaseLocked(wakeLock);mDirty |= DIRTY_WAKE_LOCKS;//依然靠updatePowerStateLocked函數(shù)更新終端的電源狀態(tài)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

整個(gè)release的過程大致可以總結(jié)為下圖:?

四、總結(jié)?
通過前面的分析,我們知道了向PMS申請(qǐng)電量的基本用法類似于:

........ //1、創(chuàng)建 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_LOG_TAG); ...... //2、acquire mWakeLock.acquire(); ......... //3、release mWakeLock.release(); ...........
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

當(dāng)申請(qǐng)發(fā)送到PMS后,PMS將針對(duì)WakeLock的level和flag信息進(jìn)行一些處理。?
無論是acquire還是release WakeLock,PMS最終將利用updatePowerStateLocked函數(shù)對(duì)終端的電源狀態(tài)進(jìn)行調(diào)整。?

我們將單獨(dú)分析一下PMS核心的updatePowerStateLocked函數(shù)。


原文地址:http://blog.csdn.net/gaugamela/article/details/52813400

總結(jié)

以上是生活随笔為你收集整理的Android7.0 PowerManagerService(2) WakeLock的使用及流程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。