WakeLock 锁机制
1、WakeLock锁简介
WakeLock是Android系统中一种锁的机制,当进程持有这个锁,系统则不会进入休眠状态。在申请WakeLock锁时,需要在AndroidManifest.xml文件中配置android.Manifest.permission.WAKE_LOCK
权限。
WakeLock锁分类:
-
根据作用时间,WakeLock可以分为永久锁和超时锁。
永久锁:在获取了WakeLock锁后必须显式的释放,否则系统会一直持有该锁。
超时锁:在到达给定时间后会自动释放WakeLock锁。
-
根据释放原则,WakeLock可以分为计数锁和非计数锁,默认为计数锁。
计数锁:一次申请必须对应一次释放。
非计数锁:不管申请多少次,一次就可以释放该WakeLock。
2、WakeLock的等级
WakeLock具有以下七种等级:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public static final int PARTIAL_WAKE_LOCK;
public static final int SCREEN_DIM_WAKE_LOCK;
public static final int SCREEN_BRIGHT_WAKE_LOCK;
public static final int FULL_WAKE_LOCK;
public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK;
public static final int DOZE_WAKE_LOCK;
public static final int DRAW_WAKE_LOCK;
|
除等级外,还有以下标记:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
public static final int WAKE_LOCK_LEVEL_MASK;
public static final int ACQUIRE_CAUSES_WAKEUP;
public static final int ON_AFTER_RELEASE;
public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY;
|
3、WakeLock锁申请
WakeLock锁申请:
1 2 3 4 5 6
| PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag"); wl.acquire(); Wl.acquire(int timeout); wl.release();
|
newWakeLock()
方法:
应用中获取WakeLock对象,获取的是位于PowerManager中的内部类(WakeLock的实例)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public WakeLock newWakeLock(int levelAndFlags, String tag) { validateWakeLockParameters(levelAndFlags, tag); return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName()); }
WakeLock(int flags, String tag, String packageName) { mFlags = flags; mTag = tag; mPackageName = packageName; mToken = new Binder(); mTraceName = "WakeLock (" + mTag + ")"; }
|
acquire()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
public void acquire() { synchronized (mToken) { acquireLocked(); } }
public void acquire(long timeout) { synchronized (mToken) { acquireLocked(); mHandler.postDelayed(mReleaser, timeout); } }
|
acquireLocked()
方法:
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
|
private void acquireLocked() { mInternalCount++; mExternalCount++; if (!mRefCounted || mInternalCount == 1) { mHandler.removeCallbacks(mReleaser); Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0); try { mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource, mHistoryTag); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } mHeld = true; } }
public void setReferenceCounted(boolean value) { synchronized (mToken) { mRefCounted = value; } }
|
从acquireLocked()
方法中可以发现,对于计数锁,只会在第一次申请时向PowerManagerService去申请锁,当该wakelock实例后续再去申请时,如果锁未释放,则只会对计数引用加1。而如果是非计数锁,则每次申请都会调到PowerManagerService中去。
acquireWakeLock()
方法:
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
|
@Override public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,WorkSource ws, String historyTag) { PowerManager.validateWakeLockParameters(flags, tag); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); if ((flags & PowerManager.DOZE_WAKE_LOCK) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); } else { ws = null } final long ident = Binder.clearCallingIdentity(); try { acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag, uid, pid); } finally { Binder.restoreCallingIdentity(ident); } }
|
acquireWakeLockInternal()
方法:
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
|
private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName, WorkSource ws, String historyTag, int uid, int pid) { synchronized (mLock) { WakeLock wakeLock; int index = findWakeLockIndexLocked(lock); boolean notifyAcquire; if (index >= 0) { wakeLock = mWakeLocks.get(index); if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) { notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName, uid, pid, ws, historyTag); wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid); } notifyAcquire = false; } else { UidState state = mUidState.get(uid); if (state == null) { state = new UidState(uid); state.mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT; mUidState.put(uid, state); } wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid); try { lock.linkToDeath(wakeLock, 0); } catch (RemoteException ex) { throw new IllegalArgumentException("Wake lock is already dead."); } mWakeLocks.add(wakeLock); setWakeLockDisabledStateLocked(wakeLock); notifyAcquire = true; } applyWakeLockFlagsOnAcquireLocked(wakeLock, uid); mDirty |= DIRTY_WAKE_LOCKS; updatePowerStateLocked(); if (notifyAcquire) { notifyWakeLockAcquiredLocked(wakeLock); } } }
|
分析acquireWakeLockInternal()
方法可知,首先通过传入的第一个参数IBinder查找WakeLock是否已经存在,若存在,则不再进行实例化,只在原有的WakeLock上更新其属性值,若不存在,则创建一个WakeLock对象,同时将该WakeLock保存到List中。需要注意的是,此处的WakeLock对象和PowerManager中获取的不是同一个WakeLock。
获取到 WakeLock 实例后,通过 setWakeLockDisabledStateLocked(wakeLock) 进行了判断该 WakeLock 是否可用,主要有两种情况:
- 缓存的不活动进程不能持有 WakeLock 锁;
- 如果处于 idle 模式,则会忽略掉所有未处于白名单中的应用申请的锁。
根据情况会设置 WakeLock 实例的 disable 属性值表示该 WakeLock 是否不可用。下一步进行判断是否直接点亮屏幕。
applyWakeLockFlagsOnAcquireLocked()
1 2 3 4 5 6 7 8 9 10 11
|
private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) { if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0 && isScreenLock(wakeLock)) { wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), wakeLock.mTag, opUid, opPackageName, opUid); } }
|
notifyWakeLockAcquiredLocked()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
private void notifyWakeLockAcquiredLocked(WakeLock wakeLock) { if (mSystemReady && !wakeLock.mDisabled) { wakeLock.mNotifiedAcquired = true; wakeLock.mStartTimeStamp = SystemClock.elapsedRealtime(); mNotifier.onWakeLockAcquired(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource, wakeLock.mHistoryTag); restartNofifyLongTimerLocked(wakeLock); } }
|
restartNofifyLongTimerLocked()
方法:
1 2 3 4 5 6 7 8 9
|
private void restartNofifyLongTimerLocked(WakeLock wakeLock) { wakeLock.mAcquireTime = SystemClock.uptimeMillis(); if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) == PowerManager.PARTIAL_WAKE_LOCK && mNotifyLongScheduled == 0) { enqueueNotifyLongMsgLocked(wakeLock.mAcquireTime + MIN_LONG_WAKE_CHECK_INTERVAL); } }
|
enqueueNotifyLongMsgLocked()
方法:
1 2 3 4 5 6 7 8
|
private void enqueueNotifyLongMsgLocked(long time) { mNotifyLongScheduled = time; Message msg = mHandler.obtainMessage(MSG_CHECK_FOR_LONG_WAKELOCKS); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, time); }
|
至此,WakeLock锁的申请便已结束,完整流程如下:
.png)
4、WakeLock锁释放
对于使用acquire()
方法申请的永久锁,必须显式的释放。否则如果系统一直持有wakelock锁,将无法进入休眠状态,从而导致耗电过快等功耗问题。
而通过acquire(long timeout)
方法申请的超时锁则会在时间到达后自动释放(通过Handler.post(Runnable)的方式释放)。
release(int flags)
方法:
不管是哪种锁的释放,其实都是在 release(int) 中进行的,只不过参数不同。如果flags为RELEASE_FLAG_TIMEOUT,表示释放的为超时锁。
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
|
public void release(int flags) { synchronized (mToken) { mInternalCount--; if ((flags & RELEASE_FLAG_TIMEOUT) == 0) { mExternalCount--; } if (!mRefCounted || mInternalCount == 0) { mHandler.removeCallbacks(mReleaser); if (mHeld) { Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0); try { mService.releaseWakeLock(mToken, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } mHeld = false; } } if (mRefCounted && mExternalCount < 0) { throw new RuntimeException("WakeLock under-locked " + mTag); } } }
|
对于计数锁(一次申请一次释放)的释放,每次都会对内部计数值减一,只有当你内部计数值减为 0 时,才会去调用 PowerManagerService 去真正的释放锁;如果释放非计数锁(无论申请多少次,一次可释放),则每次都会调用 PowerManagerService 进行释放。
releaseWakeLock()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
@Override public void releaseWakeLock(IBinder lock, int flags) { if (lock == null) { throw new IllegalArgumentException("lock must not be null"); } mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); final long ident = Binder.clearCallingIdentity(); try { releaseWakeLockInternal(lock, flags); } finally { Binder.restoreCallingIdentity(ident); } }
|
releaseWakeLockInternal()
方法:
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
|
private void releaseWakeLockInternal(IBinder lock, int flags) { synchronized (mLock) { int index = findWakeLockIndexLocked(lock); if (index < 0) { return; } WakeLock wakeLock = mWakeLocks.get(index); if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) { mRequestWaitForNegativeProximity = true; } if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) { mRequestWaitForNegativeProximity = true; } wakeLock.mLock.unlinkToDeath(wakeLock, 0); removeWakeLockLocked(wakeLock, index); } }
|
在 releaseWakeLockInternal()
中处理时,首先查找 WakeLock 是否存在,若不存在,直接返回;然后检查是否带有影响释放行为的标志值,上面已经提到过,目前只有一个值,之后取消了 Binder 的死亡代理,最后调用了 removeWakeLockLocked()
方法。
removeWakeLockLocked()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
private void removeWakeLockLocked(WakeLock wakeLock, int index) { mWakeLocks.remove(index); UidState state = wakeLock.mUidState; state.mNumWakeLocks--; if (state.mNumWakeLocks <= 0 && state.mProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) { mUidState.remove(state.mUid); } notifyWakeLockReleasedLocked(wakeLock); applyWakeLockFlagsOnReleaseLocked(wakeLock); mDirty |= DIRTY_WAKE_LOCKS; updatePowerStateLocked(); }
|
在 removeWakeLockLocked() 中,对带有 ON_AFTER_RELEASE 标志的 wakelock 进行处理时,释放锁后会亮一段时间后灭屏,这里来看看 applyWakeLockFlagsOnReleaseLocked(wakeLock) 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
private void applyWakeLockFlagsOnReleaseLocked(WakeLock wakeLock) { 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); } }
|
最后,又将调用updatePowerStateLocked()
方法,然后调用updateSuspendBlockerLocked()
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
private void updateSuspendBlockerLocked() { if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) { mWakeLockSuspendBlocker.release(); mHoldingWakeLockSuspendBlocker = false; } if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) { mDisplaySuspendBlocker.release(); mHoldingDisplaySuspendBlocker = false; } }
|
在释放锁流程中,调用release()
方法,在该方法中继续调用JNI层方法nativeReleaseSuspendBlocker()
,在JNI层方法中调用HAL层方法,通过向/sys/power/wake_unlock中写值完成释放。
完整流程图如下:
.png)