在Android系統(tǒng)中我們常用wake lock鎖來(lái)保持設(shè)備喚醒,使設(shè)備不進(jìn)入休眠狀態(tài),本文從源碼角度分析一下wake_lock的基本流程原理
1.WakeLock使用
WakeLock有三種表現(xiàn)形式:
PowerManger.WakeLock:PMS暴露給應(yīng)用層和其他組件用來(lái)申請(qǐng)WakeLock的接口;
PowerManagerService.WakeLock: PowerManager.WakeLock在PMS中的表現(xiàn)形式;
SuspendBlocker: PowerManagerService.WakeLock在向底層節(jié)點(diǎn)操作時(shí)的表現(xiàn)形式。
下面是一個(gè)申請(qǐng)WakeLock鎖的示例:
// 獲取PowerManager對(duì)象
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
// 創(chuàng)建WakeLock鎖實(shí)例
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
// 申請(qǐng)WakeLock
wl.acquire();
// 釋放WakeLock
wl.release();
2.結(jié)構(gòu)圖
3.acquire
/**
* Acquires the wake lock.
* <p>
* Ensures that the device is on at the level requested when
* the wake lock was created.
* </p>
*/
public void acquire() {
synchronized (mToken) {
acquireLocked();
}
}
/**
* Acquires the wake lock with a timeout.
* <p>
* Ensures that the device is on at the level requested when
* the wake lock was created. The lock will be released after the given timeout
* expires.
* </p>
*
* @param timeout The timeout after which to release the wake lock, in milliseconds.
*/
public void acquire(long timeout) {
synchronized (mToken) {
acquireLocked();
//如果是超時(shí)鎖,延時(shí)釋放
mHandler.postDelayed(mReleaser, timeout);
}
}
private void acquireLocked() {
mInternalCount++;
mExternalCount++;
if (!mRefCounted || mInternalCount == 1) {
// Do this even if the wake lock is already thought to be held (mHeld == true)
// because non-reference counted wake locks are not always properly released.
// For example, the keyguard's wake lock might be forcibly released by the
// power manager without the keyguard knowing. A subsequent call to acquire
// should immediately acquire the wake lock once again despite never having
// been explicitly released by the keyguard.
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;
}
}
newWakeLoc WakeLock 對(duì)象的創(chuàng)建
// frameworks/base/core/java/android/os/PowerManager.java
public WakeLock newWakeLock(int levelAndFlags, String tag) {
validateWakeLockParameters(levelAndFlags, tag); // 校驗(yàn)Flag
// 創(chuàng)建WakeLock對(duì)象
return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
}
4.PowerManagerService
//// 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) {
if (lock == null) {
throw new IllegalArgumentException("lock must not be null");
}
if (packageName == null) {
throw new IllegalArgumentException("packageName must not be null");
}
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);
}
if (ws != null && !ws.isEmpty()) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.UPDATE_DEVICE_STATS, null);
} else {
ws = null;
}
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final long ident = Binder.clearCallingIdentity();
try {
acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag, uid, pid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
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) {
if (DEBUG_SPEW) {
Slog.d(TAG, "acquireWakeLockInternal: lock=" + Objects.hashCode(lock)
+ ", flags=0x" + Integer.toHexString(flags)
+ ", tag=\"" + tag + "\", ws=" + ws + ", uid=" + uid + ", pid=" + pid);
}
WakeLock wakeLock;
//如果之前申請(qǐng)過(guò),從列表里拿出來(lái)直接用
int index = findWakeLockIndexLocked(lock);
boolean notifyAcquire;
if (index >= 0) {
wakeLock = mWakeLocks.get(index);
if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
// Update existing wake lock. This shouldn't happen but is harmless.
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);
}
state.mNumWakeLocks++;
//新創(chuàng)建一個(gè)lock放到列表
wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid,
state);
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) {
// This needs to be done last so we are sure we have acquired the
// kernel wake lock. Otherwise we have a race where the system may
// go to sleep between the time we start the accounting in battery
// stats and when we actually get around to telling the kernel to
// stay awake.
notifyWakeLockAcquiredLocked(wakeLock);
}
}
}
setWakeLockDisabledStateLocked
這里特別注意下,在某些情況下wake-lock鎖可能被disable掉。
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) {
// 強(qiáng)制進(jìn)入suspend、對(duì)應(yīng)uid進(jìn)程沒(méi)有處于active且進(jìn)程adj大于PROCESS_STATE_RECEIVER
disabled = mForceSuspendActive
|| (!wakeLock.mUidState.mActive && wakeLock.mUidState.mProcState
!= ActivityManager.PROCESS_STATE_NONEXISTENT &&
wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER);
}
if (mDeviceIdleMode) {
// If we are in idle mode, we will also ignore all partial wake locks that are
// for application uids that are not whitelisted.
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) {
//處于idle狀態(tài)時(shí),將非白名單應(yīng)用wakeLock 禁用
disabled = true;
}
}
}
if (wakeLock.mDisabled != disabled) {
wakeLock.mDisabled = disabled;
return true;
}
}
return false;
}
updatePowerStateLocked
/**
* Updates the global power state based on dirty bits recorded in mDirty.
*
* This is the main function that performs power state transitions.
* We centralize them here so that we can recompute the power state completely
* each time something important changes, and ensure that we do it the same
* way each time. The point is to gather all of the transition logic here.
*/
private void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0) {
return;
}
if (!Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
try {
// Phase 0: Basic state updates.
updateIsPoweredLocked(mDirty);
updateStayOnLocked(mDirty);
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: Lock profiles that became inactive/not kept awake.
updateProfilesLocked(now);
// Phase 3: Update display power state.
final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
// Phase 4: Update dream state (depends on display ready signal).
updateDreamLocked(dirtyPhase2, displayBecameReady);
// Phase 5: Send notifications, if needed.
finishWakefulnessChangeIfNeededLocked();
// Phase 6: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
主要有三種情況下會(huì)禁用Partical WakeLock:
強(qiáng)制進(jìn)入suspend;
WakeLock所屬進(jìn)程不處于active狀態(tài),且進(jìn)程adj大于PROCESS_STATE_RECEIVER;
DeviceIdle處于IDLE狀態(tài),且所屬進(jìn)程不在doze白名單中;
updateSuspendBlockerLocked
// 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狀態(tài)而需要CPU保持喚醒
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
// 是否開啟auto_suspend模式
final boolean autoSuspend = !needDisplaySuspendBlocker;
// 是否處于交互狀態(tài)
final boolean interactive = mDisplayPowerRequest.isBrightOrDim();
// 如果持有Display SuspendBlocker,則關(guān)閉auto-suspend模式
if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(false);
}
// 申請(qǐng)mWakeLockSuspendBlocker鎖
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.acquire();
mHoldingWakeLockSuspendBlocker = true;
}
// 申請(qǐng)mDisplaySuspendBlocker鎖
if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.acquire();
mHoldingDisplaySuspendBlocker = true;
}
// 設(shè)置交互狀態(tài)
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);
}
}
mWakeLockSuspendBlocker 會(huì)調(diào)用JNI的方法nativeAcquireSuspendBlocker
nativeAcquireSuspendBlocker
// frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}
5.power.c
acquire_wake_lock的實(shí)現(xiàn)在power.c
acquire_wake_lock
///hardware/libhardware_legacy/power.c
int acquire_wake_lock(int lock, const char* id)
{
initialize_fds();
// ALOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id);
if (g_error) return g_error;
int fd;
ssize_t ret;
if (lock != PARTIAL_WAKE_LOCK) {
return -EINVAL;
}
fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];
ret = write(fd, id, strlen(id));
if (ret < 0) {
return -errno;
}
return ret;
}
const char * const OLD_PATHS[] = {
"/sys/android_power/acquire_partial_wake_lock",
"/sys/android_power/release_wake_lock",
};
const char * const NEW_PATHS[] = {
"/sys/power/wake_lock",
"/sys/power/wake_unlock",
};
最終是往指定的path的文件節(jié)點(diǎn)下寫入一份string數(shù)據(jù),新版本是“/sys/power/wake_lock”舊版本“/sys/android_power/acquire_partial_wake_lock”。
至此wake_lock鎖的大概流程講述完,release過(guò)程與acquire類似。最后是一個(gè)時(shí)序圖。
參考文章:https://juejin.cn/post/6947092185930350622
本文由mdnice多平臺(tái)發(fā)布