WakeLock 是 Android 系统中一种锁的机制,只要有进程持有这个锁,系统就无法进入休眠状态。应用程序要申请 WakeLock 时,需要在清单文件中配置 android.Manifest.permission.WAKE_LOCK
权限。
根据作用时间,WakeLock 可以分为永久锁和超时锁,永久锁表示只要获取了 WakeLock 锁,必须显式的进行释放,否则系统会一直持有该锁;后者表示在到达给定时间后,自动释放 WakeLock 锁,其实现原理为方法内部维护了一个 Handler。
根据释放原则,WakeLock 可以分为计数锁和非计数锁,默认为计数锁,如果一个 WakeLock 对象为计数锁,则一次申请必须对应一次释放;如果为非计数锁,则不管申请多少次,一次就可以释放该 WakeLock。以下代码为 WakeLock 申请释放示例,要申请 WakeLock,必须有 PowerManager 实例,如下:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
//获取 WakeLock 对象
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
wl.acquire();//申请锁
Wl.acquire(int timeout);//申请超时锁
wl.release();//释放锁
在整个 WakeLock 机制中,对应不同的范围,有三种表现形式:
- PowerManger.WakeLock:PowerManagerService 和其他应用、服务交互的接口;
- PowerManagerService.WakeLock:PowerManager.WakeLock 在 PMS 中的表现形式;
- SuspendBlocker:PowerManagerService.WakeLock 在向底层节点操作时的表现形式。
下面开始对 WakeLock 的详细分析。
WakeLock 共有以下几种等级:
//如果持有该类型的 wakelock 锁,则按 Power 键灭屏后,
//即使允许屏幕、按键灯灭,也不会释放该锁,CPU 不会进入休眠状态
public static final int PARTIAL_WAKE_LOCK;
//Deprecated,如果持有该类型的 wakelock 锁,
//则使屏幕保持亮/ Dim 的状态,键盘灯允许灭,按 Power 键灭屏后,会立即释放
public static final int SCREEN_DIM_WAKE_LOCK;
//Deprecated,如果持有该类型的 wakelock 锁,
//则使屏幕保持亮的状态,键盘灯允许灭,按 Power 键灭屏后,会立即释放
public static final int SCREEN_BRIGHT_WAKE_LOCK;
//Deprecated,如果持有该类型的 wakelock 锁,
//则使屏幕、键盘灯都保持亮,按 Power 键灭屏后,会立即释放
public static final int FULL_WAKE_LOCK;
//如果持有该锁,则当 PSensor 检测到有物体靠近时关闭屏幕,
//远离时又亮屏,该类型锁不会阻止系统进入睡眠状态,比如
//当到达休眠时间后会进入睡眠状态,但是如果当前屏幕由该 wakelock 关闭,则不会进入睡眠状态。
public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK;
//如果持有该锁,则会使屏幕处于 DOZE 状态,同时允许 CPU 挂起,
//该锁用于 DreamManager 实现 Doze 模式,如 SystemUI 的 DozeService
public static final int DOZE_WAKE_LOCK;
//如果持有该锁,则会时设备保持唤醒状态,以进行绘制屏幕,
//该锁常用于 WindowManager 中,允许应用在系统处于 Doze 状态下时进行绘制
public static final int DRAW_WAKE_LOCK;
除了等级之外,还有几个标记:
//该值为 0x0000FFFF,用于根据 flag 判断 Wakelock 的级别,如:
//if((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) == PowerManager.PARTIAL_WAKE_LOCK){}
public static final int WAKE_LOCK_LEVEL_MASK;
//用于在申请锁时唤醒设备,一般情况下,申请 wakelock 锁时不会唤醒设备,
//它只会导致屏幕保持打开状态,如果带有这个 flag,则会在申请 wakelock 时就点亮屏幕,
//如:常见通知来时屏幕亮,该 flag 不能和 PowerManager.PARTIAL_WAKE_LOCE 一起使用。
public static final int ACQUIRE_CAUSES_WAKEUP;
//在释放锁时,如果 wakelock 带有该标志,则会小亮一会再灭屏,
//该 flag 不能和 PowerManager.PARTIAL_WAKE_LOCE 一起使用。
public static final int ON_AFTER_RELEASE;
//和其他标记不同,该标记是作为 release() 方法的参数,
//且仅仅用于释放 PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK 类型的锁,
//如果带有该参数,则会延迟释放锁,直到传感器不再感到对象接近
public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY;
当获取到 WakeLock 实例后,就可以申请 WakeLock 了。前面说过了,根据作用时间,WakeLock 锁可以分为永久锁和超时锁,根据释放原则,WakeLock 可以分为计数锁和非计数锁。申请方式如下:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
//详见
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();//申请一个永久锁
Wl.acquire(int timeout);//申请一个超时锁
应用中获取 WakeLock 对象,获取的是位于 PowerManager 中的内部类 —— WakeLock 的实例,在 PowerManager 中看看相关方法:
//frameworks/base/core/java/android/os/PowerManager.java
public WakeLock newWakeLock(int levelAndFlags, String tag) {
validateWakeLockParameters(levelAndFlags, tag);
return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
}
在 PowerManager 的 newWakeLock() 方法中,首先进行了参数的校验,然后调用 WakeLock 构造方法获取实例,构造方法如下:
//frameworks/base/core/java/android/os/PowerManager.java
WakeLock(int flags, String tag, String packageName) {
//表示 wakelock 类型或等级
mFlags = flags;
//一个 tag,一般为当前类名
mTag = tag;
//获取 wakelock 的包名
mPackageName = packageName;
//一个 Binder 标记
mToken = new Binder();
mTraceName = "WakeLock (" + mTag + ")";
}
//frameworks/base/core/java/android/os/PowerManager.java
public void acquire() {
synchronized (mToken) {
acquireLocked();
}
}
public void acquire(long timeout) {
synchronized (mToken) {
acquireLocked();
//申请锁之后,内部会维护一个 Handler 去完成自动释放锁
mHandler.postDelayed(mReleaser, timeout);
}
}
可以看到这两种方式申请方式完全一样,只不过如果是申请一个超时锁,则会通过 Handler 延时发送一个消息,到达时间后去自动释放锁。
到这一步,对于申请 wakelock 的应用或系统服务来说就完成了,具体的申请在 PowerManager 中进行,继续看看:
//frameworks/base/core/java/android/os/PowerManager.java
private void acquireLocked() {
//应用每次申请 wakelock,内部计数和外部计数加 1
mInternalCount++;
mExternalCount++;
//如果是非计数锁或者内部计数值为 1,即第一次申请该锁,才会真正去申请
if (!mRefCounted || mInternalCount == 1) {
mHandler.removeCallbacks(mReleaser);
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
try {
//向 PowerManagerService 申请锁,详见【3.4】
mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
mHistoryTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
//表示此时持有该锁
mHeld = true;
}
}
是否是计数锁可以通过 setReferenceCount() 来设置,默认为计数锁:
//frameworks/base/core/java/android/os/PowerManager.java
public void setReferenceCounted(boolean value) {
synchronized (mToken) {
mRefCounted = value;
}
}
从 acquire() 方法可以看出,对于计数锁来说,只会在第一次申请时向 PowerManagerService 去申请锁,当该 wakelock 实例第二次、第三次去申请时,如果没有进行过释放,则只会对计数引用加 1,不会向 PowerManagerService 去申请。如果是非计数锁,则每次申请,都会调到 PowerManagerService 中去。
PowerManagerService 中的 acquireWakeLock() 方法如下:
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
@Override // Binder call
public void acquireWakeLock(IBinder lock, int flags, String tag,
String packageName,WorkSource ws, String historyTag) {
//...
//检查 wakelock 级别
PowerManager.validateWakeLockParameters(flags, tag);
//检查 WAKE_LOCK 权限
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LO
CK, null);
//如果是 DOZE_WAKE_LOCK 级别 wakelock,还要检查 DEVICE_POWER 权限
if ((flags & PowerManager.DOZE_WAKE_LOCK) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
} else {
ws = null
}
//...
//重置当前线程上传入的IPC标志
final long ident = Binder.clearCallingIdentity();
try {
//详见【3.5】
acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag,
uid, pid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
WorkSource ws, String historyTag, int uid, int pid) {
synchronized (mLock) {
//PMS 中的 WakeLock 类
WakeLock wakeLock;
//查找是否已存在该 PM.WakeLock 实例
int index = findWakeLockIndexLocked(lock);
boolean notifyAcquire;
//是否存在 wakelock
if (index >= 0) {
wakeLock = mWakeLocks.get(index);
if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
//更新 wakelock
notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName,
uid, pid, ws, historyTag);
wakeLock.updateProperties(flags, tag, packageName,
ws, historyTag, uid, pid);
}
notifyAcquire = false;
} else {
//从 SpareArray<UidState> 中查找是否存在该 uid
UidState state = mUidState.get(uid);
if (state == null) {
state = new UidState(uid);
//设置该 Uid 的进程状态
state.mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
mUidState.put(uid, state);
}
//将该 uid 申请的 WakeLock 计数加 1
//创建新的 PMS.WakeLock 实例
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.");
}
//添加到 wakelock 集合中
mWakeLocks.add(wakeLock);
//用于设置 PowerManger.PARTIAL_WAKE_LOCK 能否可用
//1.缓存的不活动进程不能持有 wakelock 锁
//2.如果处于 idle 模式,则会忽略掉所有未处于白名单中的应用申请的锁
setWakeLockDisabledStateLocked(wakeLock);
//表示有新的wakelock申请了
notifyAcquire = true;
}
//判断是否直接点亮屏幕,如果带有点亮屏幕标志值,并且 wakelock 类型为
//FULL_WAKE_LOCK,SCREEN_BRIGHT_WAKE_LOCK,SCREEN_DIM_WAKE_LOCK,则进行下
//步处理
applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);//更新电源状态,详见【3.6】
//更新标志位
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();//更新电源状态,详见【3.7】
if (notifyAcquire) {
//当申请了锁后,在该方法中进行长时锁的判断,通知 BatteryStatsService
// 进行统计持锁时间等,详见【3.8】
notifyWakeLockAcquiredLocked(wakeLock);
}
}
}
首先通过传入的第一个参数 IBinder 进行查找 WakeLock 是否已经存在,若存在,则不再进行实例化,在原有的 WakeLock 上更新其属性值;若不存在,则创建一个 WakeLock 对象,同时将该 WakeLock 保存到 List 中。此时已经获取到了 WakeLock 对象,这里需要注意的是,此处的 WakeLock 对象和 PowerManager 中获取的不是同一个 WakeLock 哦!
获取到 WakeLock 实例后,还通过 setWakeLockDisabledStateLocked(wakeLock) 进行了判断该 WakeLock 是否可用,主要有两种情况:
- 缓存的不活动进程不能持有 WakeLock 锁;
- 如果处于 idle 模式,则会忽略掉所有未处于白名单中的应用申请的锁。
根据情况会设置 WakeLock 实例的 disable 属性值表示该 WakeLock 是否不可用。下一步进行判断是否直接点亮屏幕。
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
&& isScreenLock(wakeLock)) {
//...
//详见上一章【PackageManagerService 启动 - 2.4.1.1.1】
wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), wakeLock.mTag, opUid,
opPackageName, opUid);
}
}
wakeUpNoUpdateLocked() 方法是唤醒设备的主要方法。在这个方法中,首先更新了 mLastWakeTime 这个值,表示上次唤醒设备的时间,在系统超时休眠时用到这个值进行判断。现在,只需要知道每次亮屏,都走的是这个方法,详细分析请看上一章中的内容。
该流程分析详见上一章【PackageManagerService 启动 - updatePowerStateLocked() 分析】
如果有新的 WakeLock 实例创建,则 notifyAcquire 值为 true,通过以下这个方法通知 Notifier,Notifier 中则会根据该锁申请的时间开始计时,并以此来判断是否是一个长时间持有的锁。
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void notifyWakeLockAcquiredLocked(WakeLock wakeLock) {
if (mSystemReady && !wakeLock.mDisabled) {
wakeLock.mNotifiedAcquired = true;
wakeLock.mStartTimeStamp = SystemClock.elapsedRealtime();
//Called when a wake lock is acquired.
mNotifier.onWakeLockAcquired(wakeLock.mFlags,
wakeLock.mTag, wakeLock.mPackageName,
wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource,
wakeLock.mHistoryTag);
//...
//重新开始检查持锁时间
restartNofifyLongTimerLocked(wakeLock);
}
}
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
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);
}
}
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void enqueueNotifyLongMsgLocked(long time) {
mNotifyLongScheduled = time;
Message msg = mHandler.obtainMessage(MSG_CHECK_FOR_LONG_WAKELOCKS);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, time);
}
到这里 WakeLock 的申请已经分析完了,我们来看下整体流程。
如果是通过 acquire(long timeout)
方法申请的超时锁,则会在到达时间后自动去释放,如果是通过 acquire() 方法申请的永久锁,则必须进行显式的释放,否则由于系统一直持有 wakelock 锁,将导致无法进入休眠状态,从而导致耗电过快等功耗问题。
在前面分析申请锁时已经说了,如果是超时锁,通过 Handler.post(Runnable) 的方式进行释放,该 Runnable 定义如下:
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private final Runnable mReleaser = new Runnable() {
public void run() {
release();
}
};
RELEASE_FLAG_TIMEOUT 是一个用于 release() 方法的 flag,表示释放的为超时锁。如果是永久锁,则必须通过调用 release() 方法进行释放了,该方法如下:
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public void release() {
release(0);
}
因此,不管是哪种锁的释放,其实都是在 release(int) 中进行的,只不过参数不同,该方法如下:
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public void release(int flags) {
synchronized (mToken) {
//内部计数 -1
mInternalCount--;
//如果释放超时锁,外部计数 -1
if ((flags & RELEASE_FLAG_TIMEOUT) == 0) {
mExternalCount--;
}
//如果释放非计数锁或内部计数为 0,并且该锁还在持有,则通过 PowerManagerService 去释放
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;
}
}
//如果时计数锁,并且外部计数小于 0,则抛出异常
if (mRefCounted && mExternalCount < 0) {
throw new RuntimeException("WakeLock under-locked " + mTag);
}
}
}
对于计数锁的释放,每次都会对内部计数值减一,只有当你内部计数值减为 0 时,才会去调用 PowerManagerService 去真正的释放锁;如果释放非计数锁,则每次都会调用 PowerManagerService 进行释放。
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
@Override // Binder call
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);
//重置当前线程的 IPC 标志
final long ident = Binder.clearCallingIdentity();
try {
//去释放锁
releaseWakeLockInternal(lock, flags);
} finally {
//设置新的 IPC 标志
Binder.restoreCallingIdentity(ident);
}
}
在这个方法中,进行了权限检查后,就交给下一个方法去处理了,具体代码如下:
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void releaseWakeLockInternal(IBinder lock, int flags) {
synchronized (mLock) {
//查找 WakeLock 是否存在
int index = findWakeLockIndexLocked(lock);
if (index < 0) {
return;
}
WakeLock wakeLock = mWakeLocks.get(index);
//该 flag 用来推迟释放 PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK 类型的锁,
//它会在传感器感觉不在靠近的时候才释放该锁
if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {
//表示在点亮屏幕前需要等待 PSensor 返回负值
mRequestWaitForNegativeProximity = true;
}
if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {
mRequestWaitForNegativeProximity = true;
}
//取消 Binder 的死亡代理
wakeLock.mLock.unlinkToDeath(wakeLock, 0);
//释放锁,详见下面分析
removeWakeLockLocked(wakeLock, index);
}
}
在 releaseWakeLockInternal() 中处理时,首先查找 WakeLock 是否存在,若不存在,直接返回;然后检查是否带有影响释放行为的标志值,上面已经提到过,目前只有一个值,之后取消了 Binder 的死亡代理,最后调用了 removeWakeLockLocked() 方法。
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void removeWakeLockLocked(WakeLock wakeLock, int index) {
//从 List中 移除
mWakeLocks.remove(index);
//得到该 wakelock 中的 UidState 属性
UidState state = wakeLock.mUidState;
state.mNumWakeLocks--;
if (state.mNumWakeLocks <= 0 &&
state.mProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
//从 SpareArray<UidState> 中移除该 wakelock 的 UidState
//注意,下面的 mUidState 是 SpareArray<UidState>,而上面的 mUidState 是 wakeLock.mUidState
mUidState.remove(state.mUid);
}
//使用 Notifier 通知其他应用
notifyWakeLockReleasedLocked(wakeLock);
//对带有 ON_AFTER_RELEASE 标志的 wakelock 进行处理
applyWakeLockFlagsOnReleaseLocked(wakeLock);
mDirty |= DIRTY_WAKE_LOCKS;
//更新电源状态信息,详见
updatePowerStateLocked();
}
在 removeWakeLockLocked() 中,对带有 ON_AFTER_RELEASE 标志的 wakelock 进行处理,前面分析过了,该标志和用户体验相关,当有该标志时,释放锁后会亮一段时间后灭屏,这里来看看 applyWakeLockFlagsOnReleaseLocked(wakeLock) 方法:
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
/**
*如果当前释放的 wakelock 带有 PowerManager.ON_AFTER_RELEASE 标志,则会屏幕在灭屏时小亮一会儿才会熄灭
*/
private void applyWakeLockFlagsOnReleaseLocked(WakeLock wakeLock) {
if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0
&& isScreenLock(wakeLock)) {
//更新用户活动时间,并带有 PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS 标志,用于延缓灭屏时间
userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.USER_ACTIVITY_EVENT_OTHER,
PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS,
wakeLock.mOwnerUid);
}
}
最后,又将调用 updatePowerStateLocked()。
该流程分析详见上一章【PackageManagerService 启动 - updatePowerStateLocked() 分析】,updatePowerStateLocked() 中的第5阶段会调用 updateSuspendBlockerLocked(),其中和 WakeLock 申请和释放相关的都 updateSuspendBlockerLocked() 中。
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void updateSuspendBlockerLocked() {
//...
//如果不再持有 PARTIAL_WAKELOCK 类型的 WakeLock 锁,释放 mWakeLockSuspendBlocker 锁
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release();
mHoldingWakeLockSuspendBlocker = false;
}
//如果不再需要屏幕保持亮屏,释放 mDisplaySuspendBlocker 锁
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
//...
}
如果满足条件,则释放 SuspendBlocker 锁。申请 SuspendBlocker 流程已经分析过了,接下来我们分析释放 SuspendBlocker 流程。在 SuspendBlocker 中释放锁如下:
//frameworks\base\services\core\jni\com_android_server_power_PowerManagerService.cpp
@Override
public void release() {
synchronized (this) {
//计数-1
mReferenceCount -= 1;
if (mReferenceCount == 0) {
//调用 JNI 层进行释放
nativeReleaseSuspendBlocker(mName);
} else if (mReferenceCount < 0) {
mReferenceCount = 0;
}
}
}
在释放锁时,如果有多个锁,实际上是对锁计数的属性减1,直到剩余一个时才会调用 JNI 层执行释放操作。
//hardware/libhardware_legacy/power/power.c
static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
release_wake_lock(name.c_str());
}
在 JNI 层方法中,调用了 HAL 层的方法,通过文件描述符向 /sys/power/wake_unlock
中写值完成释放:
//hardware/libhardware_legacy/power/power.c
int release_wake_lock(const char* id) {
initialize_fds();
// ALOGI("release_wake_lock id='%s'\n", id);
if (g_error) return g_error;
ssize_t len = write(g_fds[RELEASE_WAKE_LOCK], id, strlen(id));
if (len < 0) {
return -errno;
}
return len;
}
到这里为止,WakeLock 的释放流程也就分析完毕了,我们来看下整体流程。
这个类型的 SuspendBlocker 并没有在 PowerManagerService 中进行实例化,它以构造方法的形式传入了 Notifier 中,Notifier 类相当于是 PowerManagerService 的”中介“,PowerManagerService 中和其他服务的部分交互通过 Notifier 进行,还有比如亮屏广播、灭屏广播等,都是由 PowerManagerService 交给 Notifier 来发送,这点在下篇文章中进行分析。因此,如果 CPU 在广播发送过程中进入休眠,则广播无法发送完成,因此,需要一个锁来保证 Notifier 中广播的成功发送,这就是 PowerManagerService.Broadcasts 锁的作用,当广播发送完毕后,该锁立即就释放了。
欢迎你「扫一扫」下面的二维码,关注我的公众号,可以接受最新的文章推送,有丰厚的抽奖活动和福利等着你哦!😍
如果你有什么疑问或者问题,可以 点击这里 提交 issue,也可以发邮件给我 [email protected]。