WakeLock是Android中为应用层及框架层提供的用来保证CPU处于唤醒状态的一种锁机制。PMS中为应用及框架层其他组件提供了接口,进行WakeLock的申请和释放。应用在申请WakeLock时,需要在清单文件中配置android.Manifest.permission.WAKE_LOCK
权限。下面详细看下WakeLock机制的实现。
1.WakeLock分类
根据作用时间,WakeLock可以分为永久锁和超时锁:
- 永久锁:只要获取了WakeLock锁,必须显式进行释放,否则系统会一直持有该锁;
- 超时锁:在到达给定时间后,自动释放WakeLock锁,其实现原理为方法内部维护了一个Handler进行。 根据释放原则,WakeLock可以分为计数锁和非计数锁:
- 计数锁:一次申请必须对应一次释放;
- 非计数锁:不管申请多少次,只需要一次就可以释放该WakeLock。 默认为计数锁。WakeLock机制从上到下架构如下:
WakeLock有三种表现形式:
- PowerManger.WakeLock:PMS暴露给应用层和其他组件用来申请WakeLock的接口;
- PowerManagerService.WakeLock: PowerManager.WakeLock在PMS中的表现形式;
- SuspendBlocker: PowerManagerService.WakeLock在向底层节点操作时的表现形式。
下面是一个申请WakeLock锁的示例:
// 获取PowerManager对象
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
// 创建WakeLock锁实例
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
// 申请WakeLock
wl.acquire();
// 释放WakeLock
wl.release();
在PowerManager中,共定义了以下七种WakeLock:
// 保证CPU处于唤醒状态
public static final int PARTIAL_WAKE_LOCK; // 0x00000001
//Deprecated,保证屏幕一直保持Dim状态,按Power键灭屏后,会忽略该锁
public static final int SCREEN_DIM_WAKE_LOCK; // 0x00000006
//Deprecated,保证屏幕一直保持常亮状态,按Power键灭屏后,会忽略该锁
public static final int SCREEN_BRIGHT_WAKE_LOCK // 0x0000000a
//Deprecated,保证屏幕、键盘灯都保持常亮状态,按Power键灭屏后,会忽略该锁
public static final int FULL_WAKE_LOCK // 0x0000001a
// 通过PSensor进行亮灭屏工作,PSensor检测到有物体靠近时关闭屏幕,远离时又亮屏
public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK // 0x00000020
// 仅用于PMS唤醒状态为Doze时,进入Doze状态后,DreamMangerService会申请该锁,允许CPU挂起
public static final int DOZE_WAKE_LOCK // 0x00000040
// 仅用于PMS唤醒状态为Doze时,保证CPU处于运行状态,以进行Doze状态下屏幕的绘制,如AOD、防烧屏显示
public static final int DRAW_WAKE_LOCK // 0x00000080
此外还定义了三个Flag,可以在创建、申请及释放WakeLock时和以上几类搭配使用:
// 在申请WakeLock的同时,会点亮屏幕,如来通知亮屏的实现,不能和PARTIAL_WAKE_LOCK一起使用
public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
// 在释放有该Flag的WakeLock时,会稍微延长自动休眠时间一小会儿,不能和PARTIAL_WAKE_LOCK一起使用
public static final int ON_AFTER_RELEASE = 0x20000000;
// 在释放PROXIMITY_SCREEN_OFF_WAKE_LOCK锁时,不会立即解除PSensor监听,而是在PSensor上报远离后,才会亮屏并解除Psensor监听,仅用于释放PROXIMITY_SCREEN_OFF_WAKE_LOCK锁
public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1 << 0;
2.获取WakeLock对象
PowerManager中提供了接口newWakeLock()
来创建WakeLock对象:
// frameworks/base/core/java/android/os/PowerManager.java
public WakeLock newWakeLock(int levelAndFlags, String tag) {
validateWakeLockParameters(levelAndFlags, tag); // 校验Flag
// 创建WakeLock对象
return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
}
首先进行了参数的校验,然后调用WakeLock构造方法创建WakeLock对象:
// frameworks/base/core/java/android/os/PowerManager.java
WakeLock(int flags, String tag, String packageName) {
mFlags = flags; //表示wakelock类型
mTag = tag; //一个tag,一般为当前类名
mPackageName = packageName; //申请wakelock的应用包名
mToken = new Binder(); //一个Binder标记
mTraceName = "WakeLock (" + mTag + ")";
}
除以上几个属性之外,WakeLock中还有如下几个属性:
// frameworks/base/core/java/android/os/PowerManager.java
//表示内部计数
private int mInternalCount;
//表示外部计数
private int mExternalCount;
//表示是否是计数锁,默认true
private boolean mRefCounted = true;
//表示是否已经持有该锁
private boolean mHeld;
//表示和该wakelock相关联的工作源,这在一些服务获取wakelock时很有用,以便计算工作成本
private WorkSource mWorkSource;
//表示一个历史标签
private String mHistoryTag;
3.WakeLock申请流程
当创建好WakeLock对象以后,就可以申请WakeLock锁了。不管是永久锁还是超时锁,都是通过acquire()
方法来申请:
mWakeLock.acquire(); //申请一个永久锁
mWakeLock.acquire(int timeout); //申请一个超时锁,指定作用时间
PowerManager#acquire()方法如下:
// 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发送一个延时消息,到达时间后去自动释放锁。继续看acquireLocked()
方法:
// frameworks/base/core/java/android/os/PowerManager.java
private void acquireLocked() {
// 计数器+1
mInternalCount++;
mExternalCount++;
//如果是非计数锁或者内部计数值为1,即第一次申请该锁,才会真正去申请
if (!mRefCounted || mInternalCount == 1) {
// 移除释放超时锁的Msg
mHandler.removeCallbacks(mReleaser);
try {
// 通过Binder进入PMS中
mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
mHistoryTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
mHeld = true; // 表示已持有该锁,申请成功
}
}
对同一个WakeLock每申请一次,属性值mInternalCount和mExternalCount都会+1,这两个值都用来表示引用计数,前者相对于PowerManager内部,后者则相对于用户操作,之所以有两个引用计数器,主要是为了针对超时锁的释放,如果一个超时锁在已自动释放的情况下,用户手动再释放一次,相当于释放两次。这种情况下由于mExternalCount的存在,就不会导致crash。
mRefCounted用来表示计数锁或非计数锁,默认为true(计数锁),可以通过setReferenceCount()来设置:
public void setReferenceCounted(boolean value) {
synchronized (mToken) {
mRefCounted = value;
}
}
mHeld
表示是否已经持有锁,可以通过调用isHeld()
来判断是已申请WakeLock。
以上逻辑都是在APP进程执行的,接下来通过mService进入到system_server,开始执行了PMS中的流程。直接来看PMS#acquireWakeLockInternal()方法:
// 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;
// 通过IBinder标记确认是否已申请该WakeLock
int index = findWakeLockIndexLocked(lock);
boolean notifyAcquire;
// 说明已申请过该WakeLock,则更新下该WakeLock即可
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 { // 说明没有申请过该WakeLock
......
// 创建一个WakeLock
wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid,
state);
// .......
// 添加到保存系统所有WakeLock的list中
mWakeLocks.add(wakeLock);
// 对于PowerManager.PARTIAL_WAKE_LOCK类型锁,省电机制Doze模式会对其进行disable处理
setWakeLockDisabledStateLocked(wakeLock);
notifyAcquire = true;
}
// 处理PowerManager.ACQUIRE_CAUSES_WAKEUP标记,带有此标记,进行亮屏处理
applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
mDirty |= DIRTY_WAKE_LOCKS; // 设置DIRTY_WAKE_LOCKS标记位
updatePowerStateLocked(); // 更新状态
if (notifyAcquire) {
// 将申请WakeLock动作通知其他组件
notifyWakeLockAcquiredLocked(wakeLock);
}
}
}
首先,通过传入的第一个参数IBinder进行查找WakeLock是否已经存在,若存在,则在原有的WakeLock上更新其属性值;若不存在,则创建一个WakeLock对象,同时将该WakeLock保存到List中,并将相关数据保存到UidState中。
3.1.setWakeLockDisabledStateLocked()
创建WakeLock实例后,接下来调用setWakeLockDisabledStateLocked()
方法,这个方法会对PARTIAL_WAKE_LOCK类型的WakeLock进行disable。系统如果持有该类型锁,会导致CPU一直保持唤醒状态而无法休眠,因此在省电策略DeviceIdle模块中,会在某些特定状态下将该类型的锁进行diable:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
== PowerManager.PARTIAL_WAKE_LOCK) {
boolean disabled = false;
final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
// 非系统进程
if (appid >= Process.FIRST_APPLICATION_UID) {
// Cached inactive processes are never allowed to hold wake locks.
if (mConstants.NO_CACHED_WAKE_LOCKS) {
// 强制进入suspend、对应uid进程没有处于active且进程adj大于PROCESS_STATE_RECEIVER
disabled = mForceSuspendActive // 强制进入suspend
|| (!wakeLock.mUidState.mActive && wakeLock.mUidState.mProcState
!= ActivityManager.PROCESS_STATE_NONEXISTENT &&
wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER);
}
if (mDeviceIdleMode) { //处于idle状态时,将非白名单应用wakeLock 禁用
final UidState state = wakeLock.mUidState;
if (Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 &&
Arrays.binarySearch(mDeviceIdleTempWhitelist, appid) < 0 &&
state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT &&
state.mProcState >
ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
disabled = true;
}
}
}
// 更新mDisabled属性
if (wakeLock.mDisabled != disabled) {
wakeLock.mDisabled = disabled;
return true;
}
}
return false;
}
主要有三种情况下会禁用Partical WakeLock:
- 强制进入suspend;
- WakeLock所属进程不处于active状态,且进程adj大于PROCESS_STATE_RECEIVER;
- DeviceIdle处于IDLE状态,且所属进程不在doze白名单中;
3.2.applyWakeLockFlagsOnAcquireLocked()处理亮屏标记
接下来调用applyWakeLockFlagsOnAcquireLocked()
方法,对ACQUIRE_CAUSES_WAKEUP
标记进行处理。如果WakeLock带有标志,并且WakeLock类型为FULL_WAKE_LOCK、SCREEN_BRIGHT_WAKE_LOCK、SCREEN_DIM_WAKE_LOCK这三种其中之一,则会点亮屏幕:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
// 如果持有ACQUIRE_CAUSES_WAKEUP标记,且为亮屏相关三类锁之一
if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
&& isScreenLock(wakeLock)) {
......
// 亮屏流程
wakeUpNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag,
opUid, opPackageName, opUid);
}
}
wakeUpNoUpdateLocked()
方法是点亮屏幕的主要方法,会在后面部分分析。
3.3.updatePowerStateLocked()更新全局状态
这个方法在PowerManagerService模块(一) 启动流程和核心方法中进行了分析,其中涉及到WakeLock流程的有两个方法:updateWakeLockSummaryLocked()和updateSuspendBlockerLocked()方法,前者已经分析过了,用来将所有的WakeLock统计到mWakeLockSummary全局变量中,这里对后一个方法进行分析。
3.4.updateSuspendBlockerLocked()更新SuspendBlocker
在这个方法中,将会根据系统所有WakeLock的状态,获得一个SuspendBlocker锁:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void updateSuspendBlockerLocked() {
// 是否因持有WakeLock锁而需要CPU保持唤醒
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
// 是否因Display状态而需要CPU保持唤醒
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
// 是否开启auto_suspend模式
final boolean autoSuspend = !needDisplaySuspendBlocker;
// 是否处于交互状态
final boolean interactive = mDisplayPowerRequest.isBrightOrDim();
// 如果持有Display SuspendBlocker,则关闭auto-suspend模式
if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(false);
}
// 申请mWakeLockSuspendBlocker锁
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.acquire();
mHoldingWakeLockSuspendBlocker = true;
}
// 申请mDisplaySuspendBlocker锁
if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.acquire();
mHoldingDisplaySuspendBlocker = true;
}
// 设置交互状态
if (mDecoupleHalInteractiveModeFromDisplayConfig) {
if (interactive || mDisplayReady) {
setHalInteractiveModeLocked(interactive);
}
}
// 释放mWakeLockSuspendBlocker
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release();
mHoldingWakeLockSuspendBlocker = false;
}
// 释放mDisplaySuspendBlocker
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
// 开启auto_suspend模式
if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(true);
}
}
在创建PMS实例时,创建了两个SuspendBlocker对象:mWakeLockSuspendBlocker和mDisplaySuspendBlocker,在这个方法中则体现出了他们的作用。当系统当前持有WakeLock锁,通过mWakeLockSuspendBlocker使CPU保持唤醒,当屏幕亮屏时,则通过mDisplaySuspendBlocker使CPU保持唤醒。
再看看needDisplaySuspendBlockerLocked()方法,如果该方法返回true,表示需要mDisplaySuspendBlocker锁:
private boolean needDisplaySuspendBlockerLocked() {
if (!mDisplayReady) {
return true;
}
// 当请求policy为bright或dim时,需要对psensor灭屏场景进行区分
if (mDisplayPowerRequest.isBrightOrDim()) {
// 如果在使用psensor且psensor上报靠近事件且psensor灭屏后允许CPU休眠,则表示不需要mDisplaySuspendBlocker
if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive
|| !mSuspendWhenScreenOffDueToProximityConfig) {
return true;
}
}
if (mScreenBrightnessBoostInProgress) {
return true;
}
return false;
}
3.5.SuspendBlocker#acquire()申请SuspendBlocker
接下来将目光聚焦到SuspendBlocker上,它是一个接口,并且只有acquire()
和release()
两个方法,用来申请和释放SuspendBlocker。PMS.SuspendBlockerImpl实现了该接口,acquire()方法如下:
public void acquire() {
synchronized (this) {
// 引用计数+1
mReferenceCount += 1;
if (mReferenceCount == 1) {
// 进入native层
mNativeWrapper.nativeAcquireSuspendBlocker(mName);
}
}
}
SuspendBlocker对象的申请操作也使用了引用计数方式,每申请一次,其引用计数+1,如果mReferenceCount > 1,不会进行锁的申请,只有当mReferenceCount为0时,才会真正执行申请锁操作,然后通过JNI进入了native层:
// frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}
最终,在SystemSuspend中,将会在/sys/power/wake_lock节点中,写入SuspendBlocker的name,完成申请过程:
// system/hardware/interfaces/suspend/1.0/default/SystemSuspend.cpp
void SystemSuspend::incSuspendCounter(const string& name) {
auto l = std::lock_guard(mCounterLock);
if (mUseSuspendCounter) {
mSuspendCounter++;
} else {
if (!WriteStringToFd(name, mWakeLockFd)) {
}
}
}
这个name就是在创建SuspendBlocker对象时传入的String类型参数,可以通过adb shell看看这个节点内容:
$ adb shell cat /sys/power/wake_lock
PowerManager.SuspendLockout PowerManagerService.Display
整个申请流程可以看出,WakeLock的申请和释放锁,对应着SuspendBlocker的申请和释放锁。也可以说SuspendBlocker类是WakeLock锁功能的具体实现者。只要持有SuspendBlocker锁,都会使得CPU处于唤醒状态。
WakeLock申请时序图如下:
4.WakeLock的释放
当申请了WakeLock锁(更准确地说是PARTIAL_WAKELOCK类型的WakeLock锁)执行完相应的任务后,要及时对其进行释放,否则会导致CPU无法进入休眠状态,导致电量消耗过快。
在释放WakeLock时,也有两种释放形式:
- release():正常释放WakeLock;
- release(int flag):传入一个标志值,以达到修改释放行为的目的。目前只支持一个Flag——
RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY
,这个值前面已经说过,主要和PSensor灭屏后的动作有关。release()方法如下:
// frameworks/base/core/java/android/os/PowerManager.java
public void release(int flags) {
synchronized (mToken) {
if (mInternalCount > 0) {
// 计数-1
mInternalCount--;
}
// 如果非超时锁,外部计数-1
if ((flags & RELEASE_FLAG_TIMEOUT) == 0) {
mExternalCount--;
}
if (!mRefCounted || mInternalCount == 0) {
mHandler.removeCallbacks(mReleaser);
if (mHeld) {
try {
// 进入PMS中
mService.releaseWakeLock(mToken, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
mHeld = false;
}
}
// 在没有申请锁时进行释放操作,直接抛出异常
if (mRefCounted && mExternalCount < 0) {
throw new RuntimeException("WakeLock under-locked " + mTag);
}
}
}
对于计数锁的释放,每次都会对内部计数值mInternalCount减一,且当它减为0时,才会去执行PMS中的释放流程;对于非计数锁的释放,每次都会调用到PMS释放流程中。
进入PMS流程后,PMS#releaseWakeLock()在进行权限验证后,执行PMS#releaseWakeLockInternal()方法:
// 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,它会在距离传感器上报远离事件后才会取消PSensor监听
if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {
//表示在点亮屏幕前需要等待PSensor返回远离值
mRequestWaitForNegativeProximity = true;
}
//释放锁
removeWakeLockLocked(wakeLock, index);
}
}
这里对RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY标记进行了处理。这个标记和PSensor的行为有关。
当应用申请了PROXIMITY_SCREEN_OFF_WAKE_LOCK类型WakeLock锁,PMS模块会请求DMS模块注册一个PSensor监听,根据PSensor的事件状态来进行亮灭屏,通话时贴耳灭屏就是这样实现的。如果在PSensor灭屏的场景下,带这个flag去释放WakeLock,那么即使该WakeLock已经释放,依然会保持PSensor的监听状态,直到PSensor上报远离事件后,才会解除PSensor监听。
然后将执行removeWakeLockLocked()方法进行进一步操作:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void removeWakeLockLocked(WakeLock wakeLock, int index) {
mWakeLocks.remove(index); // 从保存系统WakeLock列表中移除该WakeLock
// 更新WakeLock所属的UidState中的相关wakeLock数据
......
// 对带有ON_AFTER_RELEASE标志的wakelock进行处理
applyWakeLockFlagsOnReleaseLocked(wakeLock);
mDirty |= DIRTY_WAKE_LOCKS; // 设置标记位
// 更新PMS全局状态
updatePowerStateLocked();
}
首先,将该WakeLock从mWakeLocks列表中移除;
接下来,执行applyWakeLockFlagsOnReleaseLocked()方法,对带有ON_AFTER_RELEASE标志的WakeLock进行处理。在释放带有该标记的WakeLock时,会更新用户活动状态,从而当没有用户操作情况下,会延迟自动灭屏时间:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
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);
}
}
userActivityNoUpdateLocked()
方法会更新用户活动时间,该方法的详细分析见Android R PowerManagerService模块(4) 灭屏流程。
最后,执行updatePowerStateLocked()方法,该方法中和WakeLock相关的方法已经在申请流程中说过,这里只看看释放相关代码:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void updateSuspendBlockerLocked() {
......
// 释放mWakeLockSuspendBlocker
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release();
mHoldingWakeLockSuspendBlocker = false;
}
// 释放mDisplaySuspendBlocker
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
}
和申请流程一样,还是对mWakeLockSuspendBlocker和mDisplaySuspendBlocker进行释放:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public void release() {
synchronized (this) {
mReferenceCount -= 1; // 引用计数-1
if (mReferenceCount == 0) {
// 进入native层
mNativeWrapper.nativeReleaseSuspendBlocker(mName);
} else if (mReferenceCount < 0) {
// ......
}
}
}
在释放时对引用计数-1,当mReferenceCount为0时,会进入native层进行最后的释放:
// hardware/libhardware_legacy/power.cpp
static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
release_wake_lock(name.c_str());
}
最终,也会在SystemSuspend中,在/sys/power/wake_unlock节点中写入SuspendBlocker的name,完成释放:
// system/hardware/interfaces/suspend/1.0/default/SystemSuspend.cpp
void SystemSuspend::decSuspendCounter(const string& name) {
auto l = std::lock_guard(mCounterLock);
if (mUseSuspendCounter) {
if (--mSuspendCounter == 0) {
mCounterCondVar.notify_one();
}
} else {
if (!WriteStringToFd(name, mWakeUnlockFd)) {
PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeUnlock;
}
}
}
至此,WakeLock释放流程执行完毕。
5.总结
WakeLock锁的申请和释放流程,实际上就是通过SuspendBlocker操作/sys/power/wake_lock和/sys/power/wake_unlock节点,来控制设备的唤醒和休眠。 SuspendBlocker官方的解释是:SuspendBlocker相当于持有部分唤醒锁,该接口在内部使用,以避免在高级别唤醒锁机制上引入内部依赖关系。
在PMS中,共创建了三个SuspendBlocker锁,其中两个已经见过了:
-
- mWakeLockSuspendBlocker锁:表示由WakeLock而使CPU保持唤醒状态,该锁的申请条件是
mWakeLockSummary & WAKE_LOCK_CPU) != 0
; mWakeLockSummary汇总了所有WakeLock锁,当申请了PARTIAL_WAKE_LOCK、DRAW_WAKE_LOCK锁,或者屏幕处于唤醒、屏保时,会给该属性设置WAKE_LOCK_CPU标记位,从而申请mWakeLockSuspendBlocker锁,向/sys/power/wake_lock节点中写入”PowerManager.WakeLocks”,使CPU保持唤醒状态。
- mWakeLockSuspendBlocker锁:表示由WakeLock而使CPU保持唤醒状态,该锁的申请条件是
-
- mDisplaySuspendBlocker锁:表示由于屏幕亮屏而使CPU保持唤醒状态。只要屏幕处于亮屏状态时,就会申请mDisplaySuspendBlocker锁,向/sys/power/wake_lock中写入“PowerManagerService.Display”;
-
- PowerManagerService.Broadcasts锁:表示由于需要确保Notifier中广播的成功发送,而使CPU保持唤醒状态;
该锁在分析流程中还暂时没有碰到,它以构造方法的形式传给了Notifier类,PMS中和其他服务的部分交互通过Notifier进行,还有亮灭屏广播都是由PMS交给Notifier来发送。如果CPU在广播发送过程中进入休眠,则广播无法发送完成,因此,需要一个锁来保证Notifier中广播的成功发送,这就是PowerManagerService.Broadcasts锁的作用。当广播发送完毕后,该锁就立即释放。
今天的文章Android R PowerManagerService模块(2) WakeLock机制分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/23534.html