源码 位置:frameworks/base/core/java/android/os/PowerManager.java
Wake Lock是一种锁的机制, 只要有人拿着这个锁,系统就无法进入休眠, 可以被用户态程序和内核获得. 这个锁可以是有超时的 或者 是没有超时的, 超时的锁会在时间过去以后自动解锁。如果没有锁了或者超时了, 内核就会启动休眠的那套机制来进入休眠.
PowerManager.WakeLock 有加锁和解锁两种状态,加锁的方式有两种:
第一种是永久的锁住,这样的锁除非显式的放开,否则是不会解锁的,所以这种锁用起来要非常的小心。
第二种锁是超时锁,这种锁会在锁住后一段时间解锁。
在创建了 PowerManager.WakeLock 后,有两种机制,第一种是不计数锁机制,另一种是计数锁机制。可以通过 setReferenceCounted(boolean value) 来指定,一般默认为计数机制。这两种机制的区别在于,前者无论 acquire() 了多少次,只要通过一次 release()即可解锁。而后者正真解锁是在( --count == 0 )的时候,同样当 (count == 0) 的时候才会去申请加锁。所以 PowerManager.WakeLock 的计数机制并不是正真意义上的对每次请求进行申请/释放每一把锁,它只是对同一把锁被申请/释放的次数进行了统计,然后再去操作。
1).应用程序申请锁
实例:
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, “MyTag”);
wl.acquire();//申请锁,这里会调用PowerManagerService里面acquireWakeLock()
wl.release(); //释放锁,显示的释放锁,如果申请的锁不在此释放,系统就不会进入休眠。
2). frameworks层
acquire() --> PWS-->acquireWakeLock()-->acquireWakeLockInternal()-->updatePowerStateLocked()
-->updateSuspendBlockerLocked()-->mWakeLockSuspendBlocker.acquire()
@Override
public void acquire() {
synchronized (this) {
mReferenceCount += 1;
if (mReferenceCount == 1) {
if (DEBUG_SPEW || DEBUG_WAKELOCK) {
Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
}
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
nativeAcquireSuspendBlocker(mName);
}
}
}
nativeAcquireSuspendBlocker就将进程传入到了底层
3).JNI层
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}
4).Kernel层
int acquire_wake_lock(int lock, const char* id){
...
return write(fd, id, strlen(id));
}
WakeLock级别:
PARTIAL_WAKE_LOCK 保持CPU运转,屏幕和键盘背光可能关闭
SCREEN_DIM_WAKE_LOCK 保持CPU运转,保持屏幕常亮(亮度低),键盘背光可能关闭
SCREEN_BRIGHT_WAKE_LOCK 保持CPU运转,保持屏幕和键盘背光高亮
FULL_WAKE_LOCK 保持CPU运转,保持屏幕和键盘背光高亮(亮度最高)
ACQUIRE_CAUSES_WAKEUP 强制亮屏,针对一些必须通知用户的操作
ON_AFTER_RELEASE 当锁被释放时,保持亮屏一段时间(如果释放时屏幕没亮,则不会亮屏)
PROXIMITY_SCREEN_OFF_WAKE_LOCK 和接近传感器配合,当用户接近屏幕时黑屏,离开时亮屏(例如打电话),该API在API21后开放,以前被hide