Android電源管理之三:PowerManager.WakeLock原始碼詳讀
PowerManager.WakeLock 有加鎖和解鎖兩種狀態,加鎖的方式有兩種,一種是永久的鎖,這樣的鎖除非顯式的放開,是不會解鎖的,所以這種鎖用起來要非常的小心。第二種鎖是超時鎖,這種鎖會在鎖住後一段時間自動解鎖。
在建立了PowerManager.WakeLock 後,有兩種機制,第一種是不計數鎖機制,另一種是計數鎖機制。這可以通過setReferenceCounted( boolean value) 來指定,預設為計數機制。這兩種機制的區別在於,前者無論acquire() 了多少次,只要通過一次release() 即可解鎖。而後者正真解鎖是在(--count == 0 )的時候,同樣當(count == 0) 的時候才會去申請加鎖,其他情況下isHeld 狀態是不會改變的。所以PowerManager.WakeLock 的計數機制並不是正真意義上的對每次請求進行申請/釋放每一把鎖,它只是對同一把鎖被申請/釋放的次數進行了統計。
(1)我們來分析一下 PowerManager.WakeLock 超時鎖的機制。我們可以通過 acquire( long timeout) 來使用,在原始碼中我們可以看到
-
public void acquire(long timeout) {
-
synchronized (mToken) {
-
acquireLocked();
-
mHandler.postDelayed(mReleaser, timeout);
-
}
-
}
在申請一把鎖的同時傳送了 release() 鎖的延時訊息。在時間到達後自動釋放。在來看看原始碼中 acquire 和 release 程式碼:
-
public void acquire()
-
{
-
synchronized (mToken) {
-
acquireLocked();
-
}
-
}
-
private void acquireLocked() {
-
if (!mRefCounted || mCount++ == 0) {
-
mHandler.removeCallbacks(mReleaser);
-
try {
-
mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
-
} catch (RemoteException e) {
-
}
-
mHeld = true;
-
}
-
}
-
public void release() {
-
release(0);
-
}
-
public void release(int flags) {
-
synchronized (mToken) {
-
if (!mRefCounted || --mCount == 0) {
-
mHandler.removeCallbacks(mReleaser);
-
try {
-
mService.releaseWakeLock(mToken, flags);
-
} catch (RemoteException e) {
-
}
-
mHeld = false;
-
}
-
if (mCount < 0) {
-
throw new RuntimeException("WakeLock under-locked " + mTag);
-
}
-
}
-
}
(2)在通常的wakelock使用時,有時會報錯:java.lang.RuntimeException: WakeLock under-locked。這是因為出現了上述release函式末尾if(mCount<0)的情況,出現的原因請見參考原文的分析。我這裡只說明:用setReferenceCounted(false);就可以解決這個問題。
-
public void setReferenceCounted(boolean value)
-
{
-
mRefCounted = value;
-
}
這個函式的作用是是不是需要計算鎖的數量,設定為false時,在release的時候,不管你acquire()了多少回,可以一次releaseWakeLock掉。