1. 程式人生 > >Android電源管理之三:PowerManager.WakeLock原始碼詳讀

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) 來使用,在原始碼中我們可以看到

  1. public void acquire(long timeout) {

  2. synchronized (mToken) {

  3. acquireLocked();

  4. mHandler.postDelayed(mReleaser, timeout);

  5. }

  6. }

       在申請一把鎖的同時傳送了 release() 鎖的延時訊息。在時間到達後自動釋放。在來看看原始碼中 acquire 和 release 程式碼:

  1. public void acquire()

  2. {

  3. synchronized (mToken) {

  4. acquireLocked();

  5. }

  6. }

  7. private void acquireLocked() {

  8. if (!mRefCounted || mCount++ == 0) {

  9. mHandler.removeCallbacks(mReleaser);

  10. try {

  11. mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);

  12. } catch (RemoteException e) {

  13. }

  14. mHeld = true;

  15. }

  16. }

  17. public void release() {

  18. release(0);

  19. }

  20. public void release(int flags) {

  21. synchronized (mToken) {

  22. if (!mRefCounted || --mCount == 0) {

  23. mHandler.removeCallbacks(mReleaser);

  24. try {

  25. mService.releaseWakeLock(mToken, flags);

  26. } catch (RemoteException e) {

  27. }

  28. mHeld = false;

  29. }

  30. if (mCount < 0) {

  31. throw new RuntimeException("WakeLock under-locked " + mTag);

  32. }

  33. }

  34. }

  (2)在通常的wakelock使用時,有時會報錯:java.lang.RuntimeException: WakeLock under-locked。這是因為出現了上述release函式末尾if(mCount<0)的情況,出現的原因請見參考原文的分析。我這裡只說明:用setReferenceCounted(false);就可以解決這個問題。

  1. public void setReferenceCounted(boolean value)

  2. {

  3. mRefCounted = value;

  4. }

    這個函式的作用是是不是需要計算鎖的數量,設定為false時,在release的時候,不管你acquire()了多少回,可以一次releaseWakeLock掉。