目录:
一、 wakelock流程
二、wakelock分类
三、wakelock申请与释放代码流程
四、wakelock申请与释放核心代码
4.1 app层申请与释放wakelock
4.2 PowerManager模块核心代码逻辑
4.3 PowerManagerService核心代码逻辑
4.4 PMS JNI接口逻辑
4.5 libpower库核心代码逻辑
4.6 system suspend hal service模块核心代码
4.7 kernel power wakelock模块核心代码
五、wakeLock数据类型封装与传递
六、 user space wakelock优化
申请与释放wakelock的几种方式:
1)三方app可以通过PowerManager实现wakelock的申请与释放
2)fwk系统组件可以通过PowerManagerService实现wakelock的申请与释放
3)native和hal层的系统组件可以通过libpower、system supend hal或直接写/sys/power/wake_lock(wake_unlock)方式实现wakelock的申请与释放
APP的代码参考4.1
PowerManager的代码参考4.2
PowerManagerService的代码参考4.3
PowerManager JNI的代码参考4.4
libpower的代码参考4.5
System syspend hal的代码参考4.6
Kernel wakelock的代码参考4.7
二、wakelock分类
1)按类型分类
| 1 | PARTIAL_WAKE_LOCK | 保持CPU唤醒状态的锁 |
| 2 | SCREEN_DIM_WAKE_LOCK | 保持屏幕昏暗亮度状态的锁 |
| 3 | SCREEN_BRIGHT_WAKE_LOCK | 保持屏幕高亮状态的锁 |
| 4 | FULL_WAKE_LOCK | 唤醒屏幕的锁,CPU保持运行状态 |
| 5 | PROXIMITY_SCREEN_OFF_WAKE_LOCK | 设备靠近人体时,它可以使用该类型的WakeLock来关闭屏幕而不会导致设备进入休眠状态 |
| 6 | DOZE_WAKE_LOCK | 将屏幕置于低功耗状态,并允许CPU Suspend |
| 7 | DRAW_WAKE_LOCK | 图形绘制时保持系统唤醒状态 |
2)其它维度分类
按其它维度分类,可分类计数锁非计数锁、超时锁非超时锁。
计数锁非计数锁:app在使用WakeLock时,可以选择使用计数器(Counter)来跟踪引用计数或者使用标志位(Flag)来表示是否已经获得了锁。计数器允许在同一个锁对象上多次调用acquire()方法,并且在每次release()调用后递减计数,只有当计数器变为零时才会完全释放锁。这种方式下的WakeLock被称为“计数锁”。反之,为“非计数锁”。
超时锁非超时锁:app在使用WakeLock时,可以设置timeout,时间到了自动释放,这种方式下的WakeLock被称为“超时锁”。反之,不设置timeout,需app调用释放锁的接口,为“非超时锁”。
// PowerManager.java
// 设置计数锁非计数锁,false为计数锁,true为非计数锁(默认为true)
public void setReferenceCounted(boolean value) {
synchronized (mToken) {
mRefCounted = value;
}
}
// 申请超时锁,timeout后自动释放
public void acquire(long timeout) {
synchronized (mToken) {
acquireLocked();
mHandler.postDelayed(mReleaser, timeout);
}
}
// 申请非超时锁,需app调用释放接口
public void acquire() {
synchronized (mToken) {
acquireLocked();
}
}
四、wakelock申请与释放核心代码
4.1 app层申请与释放wakelock
应用可以通过PowerManager和PowerManager的WakeLock内部类,实现不同类型的wakelock申请与释放。
// 获取PowerManager实例
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
// 创建WakeLock实例
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLockTag");
// 判断WakeLock是否已经被获取
if (!wakeLock.isHeld()) {
// 获取WakeLock
wakeLock.acquire();
}
// 判断WakeLock是否已经被获取并且还没有被释放
if (wakeLock != null && wakeLock.isHeld()) {
// 释放WakeLock
wakeLock.release();
}
4.2 PowerManager模块核心代码逻辑
PowerManager提供Wakelock内部类给三方app申请与释放wakelock的接口、管理超时锁与计数锁、调用PMS服务申请与释放wakelock接口。
public final class PowerManager {
......
// app通过该接口创建获取一个wakelock对象
public WakeLock newWakeLock(int levelAndFlags, String tag) {
validateWakeLockParameters(levelAndFlags, tag);
return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName(),
Display.INVALID_DISPLAY);
}
// PowerManager的内部类
public final class WakeLock {
@UnsupportedAppUsageprivate int mFlags;
@UnsupportedAppUsageprivate String mTag;
private int mTagHash;
private final String mPackageName;
private final IBinder mToken;
private int mInternalCount;
private int mExternalCount;
private boolean mRefCounted = true;
private boolean mHeld;
private WorkSource mWorkSource;
private String mHistoryTag;
private final int mDisplayId;
private WakeLockStateListener mListener;
private IWakeLockCallback mCallback;
private final Runnable mReleaser = () -> release(RELEASE_FLAG_TIMEOUT);
WakeLock(int flags, String tag, String packageName, int displayId) { mFlags = flags;
mTag = tag;
mTagHash = mTag.hashCode();
mPackageName = packageName;
mToken = new Binder();
mDisplayId = displayId;
}
// 申请wakelock
private void acquireLocked() {
mInternalCount++; // count计算递增
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.asyncTraceForTrackBegin(Trace.TRACE_TAG_POWER,
"WakeLocks", mTag, mTagHash);
try {
// 调用PMS中申请wakelock接口
mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
mHistoryTag, mDisplayId, mCallback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
mHeld = true;
}
}
// 申请wakelock,timeout后自动释放
public void acquire(long timeout) {
synchronized (mToken) {
acquireLocked();
mHandler.postDelayed(mReleaser, timeout);
}
}
// 释放wakelock
public void release(int flags) {
synchronized (mToken) {
if (mInternalCount > 0) {
// internal count must only be decreased if it is > 0 or state of// the WakeLock object is broken.mInternalCount--;
}
if ((flags & RELEASE_FLAG_TIMEOUT) == 0) {
mExternalCount--; // count计算递减
}
if (!mRefCounted || mInternalCount == 0) {
mHandler.removeCallbacks(mReleaser);
if (mHeld) {
Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_POWER,
"WakeLocks", mTagHash);
try {
// 调用PMS中释放wakelock接口
mService.releaseWakeLock(mToken, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
mHeld = false;
}
}
if (mRefCounted && mExternalCount < 0) {
throw new RuntimeException("WakeLock under-locked " + mTag);
}
}
}
}
......
}
4.3 PowerManagerService核心代码逻辑
PMS创建wakelock对象,存到wakelock list进行管理、通过JNI机制调用native层申请与释放wakelock接口,传入”PowerManagerService.wakelocks” String类型的wakelock名称。
public final class PowerManagerService extends SystemServiceimplements Watchdog.Monitor {
......
private static native void nativeAcquireSuspendBlocker(String name); // 申请suspend锁的JNI接口
private static native void nativeReleaseSuspendBlocker(String name); // 释放suspend锁的JNI接口
// 申请wakelock的PMS内部逻辑API
private void acquireWakeLockInternal(IBinder lock, int displayId, int flags, String tag,
String packageName, WorkSource ws, String historyTag, int uid, int pid,
@Nullable IWakeLockCallback callback) {
synchronized (mLock) {
......
WakeLock wakeLock;
int index = findWakeLockIndexLocked(lock);
boolean notifyAcquire;
// 已经申请了wakelock
if (index >= 0) {
wakeLock = mWakeLocks.get(index);
if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid, callback)) {
// Update existing wake lock. This shouldn't happen but is harmless.notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName,
uid, pid, ws, historyTag, callback);
wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid,
callback);
}
notifyAcquire = false;
} else {
// 未申请wakelock,创建一个wakelock,并存放到wakelock list
UidState state = mUidState.get(uid);
if (state == null) {
state = new UidState(uid);
state.mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
mUidState.put(uid, state);
}
state.mNumWakeLocks++;
wakeLock = new WakeLock(lock, displayId, flags, tag, packageName, ws, historyTag,
uid, pid, state, callback);
mWakeLocks.add(wakeLock); //存入wakelock list
setWakeLockDisabledStateLocked(wakeLock);
notifyAcquire = true;
}
applyWakeLockFlagsOnAcquireLocked(wakeLock);
mDirty |= DIRTY_WAKE_LOCKS;
// 更新电源状态,包括wakelock状态
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);
}
}
}
// 更新电源状态
private void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0 || mUpdatePowerStateInProgress) {
return;
}
if (!Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
mUpdatePowerStateInProgress = true;
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 = mClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
updateAttentiveStateLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
.......
// Phase 6: Update suspend blocker.
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
mUpdatePowerStateInProgress = false;
}
}
// Update suspend blocker
private void updateSuspendBlockerLocked() {
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
final boolean needDisplaySuspendBlocker = needSuspendBlockerLocked();
final boolean autoSuspend = !needDisplaySuspendBlocker;
boolean interactive = false;
for (int idx = 0; idx < mPowerGroups.size() && !interactive; idx++) {
interactive = mPowerGroups.valueAt(idx).isBrightOrDimLocked();
}
// Disable auto-suspend if needed.// FIXME We should consider just leaving auto-suspend enabled forever since// we already hold the necessary wakelocks.if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(false);
}
// First acquire suspend blockers if needed.if (!mBootCompleted && !mHoldingBootingSuspendBlocker) {
mBootingSuspendBlocker.acquire();
mHoldingBootingSuspendBlocker = true;
}
// 申请suspend wakelock
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.acquire();
mHoldingWakeLockSuspendBlocker = true;
}
if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.acquire(HOLDING_DISPLAY_SUSPEND_BLOCKER);
mHoldingDisplaySuspendBlocker = true;
}
// Inform the power HAL about interactive mode.// Although we could set interactive strictly based on the wakefulness// as reported by isInteractive(), it is actually more desirable to track// the display policy state instead so that the interactive state observed// by the HAL more accurately tracks transitions between AWAKE and DOZING.// Refer to getDesiredScreenPolicyLocked() for details.if (mDecoupleHalInteractiveModeFromDisplayConfig) {
// When becoming non-interactive, we want to defer sending this signal// until the display is actually ready so that all transitions have// completed. This is probably a good sign that things have gotten// too tangled over here...if (interactive || areAllPowerGroupsReadyLocked()) {
setHalInteractiveModeLocked(interactive);
}
}
// Then release suspend blockers if needed.if (mBootCompleted && mHoldingBootingSuspendBlocker) {
mBootingSuspendBlocker.release();
mHoldingBootingSuspendBlocker = false;
}
// 释放suspend wakelock
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release();
mHoldingWakeLockSuspendBlocker = false;
}
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release(HOLDING_DISPLAY_SUSPEND_BLOCKER);
mHoldingDisplaySuspendBlocker = false;
}
// Enable auto-suspend if needed.if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(true);
}
}
// PMS内部类,用于管理申请与释放wakelock native接口
private final class SuspendBlockerImpl implements SuspendBlocker {
private static final String UNKNOWN_ID = "unknown";
private final String mName;
private final int mNameHash;
private int mReferenceCount;
public SuspendBlockerImpl(String name) {
mName = name;
mNameHash = mName.hashCode();
}
......
@Override
public void acquire(String id) {
synchronized (this) {
recordReferenceLocked(id);
mReferenceCount += 1;
if (mReferenceCount == 1) {
if (DEBUG_SPEW) {
Slog.d(TAG, "Acquiring suspend blocker "" + mName + "".");
}
Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_POWER,
"SuspendBlockers", mName, mNameHash);
mNativeWrapper.nativeAcquireSuspendBlocker(mName);
}
}
}
@Override
public void release(String id) {
synchronized (this) {
removeReferenceLocked(id);
mReferenceCount -= 1;
if (mReferenceCount == 0) {
if (DEBUG_SPEW) {
Slog.d(TAG, "Releasing suspend blocker "" + mName + "".");
}
mNativeWrapper.nativeReleaseSuspendBlocker(mName);
if (Trace.isTagEnabled(Trace.TRACE_TAG_POWER)) {
Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_POWER,
"SuspendBlockers", mNameHash);
}
} else if (mReferenceCount < 0) {
Slog.wtf(TAG, "Suspend blocker "" + mName
+ "" was released without being acquired!", new Throwable());
mReferenceCount = 0;
}
}
}
......
}
}
4.4 PMS JNI接口逻辑
将java层传入的java String类型数据转化为c++ string(char*)类型
// frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
#include <hardware_legacy/power.h>
// 调用libpower库中的acquire_wake_lock接口,传递的wakelock类型为PARTIAL_WAKE_LOCK
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) { ScopedUtfChars name(env, nameStr);
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}
static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) { ScopedUtfChars name(env, nameStr);
release_wake_lock(name.c_str());
}
4.5 libpower库核心代码逻辑
获取system suspend hal服务,调用申请与释放锁的接口。
// hardware/libhardware_legacy/power.cpp
#include <aidl/android/system/suspend/ISystemSuspend.h>
#include <aidl/android/system/suspend/IWakeLock.h>
using aidl::android::system::suspend::ISystemSuspend;
using aidl::android::system::suspend::IWakeLock;
using aidl::android::system::suspend::WakeLockType;
static std::unordered_map<std::string, std::shared_ptr<IWakeLock>> gWakeLockMap;
int acquire_wake_lock(int, const char* id) {
ATRACE_CALL();
// 获取system suspend hal service
const auto suspendService = getSystemSuspendServiceOnce();
if (!suspendService) {
LOG(ERROR) << "Failed to get SystemSuspend service";
return -1;
}
std::lock_guard<std::mutex> l{gLock};
if (!gWakeLockMap[id]) {
// 创建IWakeLock对象,进行数据封装(IWakeLock数据类型由system suspend hal service提供)
std::shared_ptr<IWakeLock> wl = nullptr;
auto status = suspendService->acquireWakeLock(WakeLockType::PARTIAL, id, &wl);
// It's possible that during device shutdown SystemSuspend service has already exited.
// Check that the wakelock object is not null.
if (!wl) {
LOG(ERROR) << "ISuspendService::acquireWakeLock() call failed: "
<< status.getDescription();
return -1;
} else {
gWakeLockMap[id] = wl; // 存到wakelock map<char* wakelock_name, IWakeLock>
}
}
return 0;
}
int release_wake_lock(const char* id) {
ATRACE_CALL();
std::lock_guard<std::mutex> l{gLock};
if (gWakeLockMap[id]) {
// Ignore errors on release() call since hwbinder driver will clean up the underlying object
// once we clear the corresponding
shared_ptr.auto status = gWakeLockMap[id]->release();
if (!status.isOk()) {
LOG(ERROR) << "IWakeLock::release() call failed: " << status.getDescription();
}
gWakeLockMap[id] = nullptr;
return 0;
}
return -1;
}
4.6 system suspend hal service模块核心代码
写/sys/power/wake_lock(wake_unlock)节点,进行系统调用kernel power模块中的wake_lock_store函数。
// SystemSuspendAidl.cpp@[TOC](
// 对象创建时,申请wakelock
WakeLock::WakeLock(SystemSuspend* systemSuspend, const std::string& name, int pid)
: mReleased(), mSystemSuspend(systemSuspend), mName(name), mPid(pid) {
mSystemSuspend->incSuspendCounter(mName); // 申请wakelock
}
// 对象销毁时,释放wakelock
WakeLock::~WakeLock() {
releaseOnce();
}
ndk::ScopedAStatus WakeLock::release() { )
releaseOnce();
return ndk::ScopedAStatus::ok();
}
void WakeLock::releaseOnce() {
std::call_once(mReleased, [this]() {
mSystemSuspend->decSuspendCounter(mName); // 释放wakelock
mSystemSuspend->updateWakeLockStatOnRelease(mName, mPid);
});
}
ndk::ScopedAStatus SystemSuspendAidl::acquireWakeLock(WakeLockType /* type */, const std::string& name,
std::shared_ptr<IWakeLock>* _aidl_return) {
auto pid = getCallingPid();
if (_aidl_return == nullptr) {
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
// 创建wakelock时,会通过写/sys/power/wake_lock节点方式进行系统调用
*_aidl_return = ndk::SharedRefBase::make<WakeLock>(mSystemSuspend, name, pid);
mSystemSuspend->updateWakeLockStatOnAcquire(name, pid);
return ndk::ScopedAStatus::ok();
}
// SystemSuspend.cpp
static constexpr char kSysPowerWakeLock[] = "/sys/power/wake_lock";
static constexpr char kSysPowerWakeUnlock[] = "/sys/power/wake_unlock";
// 将PowerManagerService.WakeLocks字符串写入/sys/power/wake_lock节点,syscall调用kernel API(wake_lock_store())
void SystemSuspend::incSuspendCounter(const string& name) { auto l = std::lock_guard(mAutosuspendLock);
if (mUseSuspendCounter) {
mSuspendCounter++;
} else {
if (!WriteStringToFd(name, mWakeLockFd)) {
PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeLock;
}
}
}
// 将PowerManagerService.WakeLocks字符串写入/sys/power/wake_unlock节点,syscall调用kernel API(wake_unlock_store())
void SystemSuspend::decSuspendCounter(const string& name) { auto l = std::lock_guard(mAutosuspendLock);
if (mUseSuspendCounter) {
if (--mSuspendCounter == 0) {
mAutosuspendCondVar.notify_one();
}
} else {
if (!WriteStringToFd(name, mWakeUnlockFd)) {
PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeUnlock;
}
}
}
4.7 kernel power wakelock模块核心代码
user space写/sys/power/wake_lock(unwake_lock)节点,触发wake_lock_store(wake_unlock_store)函数。
// kernel/kernel/power/main.c
// wake_lock_store为syscall函数,提供给user space调用
static ssize_t wake_lock_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t n)
{
int error = pm_wake_lock(buf);
return error ? error : n;
}
// wake_unlock_store为syscall函数,提供给user space调用
static ssize_t wake_unlock_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t n)
{
int error = pm_wake_unlock(buf);
return error ? error : n;
}
// kernel/kernel/power/wakelock.c
// 接收user space传递的字符串,封装到struct wakelock
int pm_wake_lock(const char *buf)
{
const char *str = buf;
struct wakelock *wl;
u64 timeout_ns = 0;
size_t len;
int ret = 0;
if (!capable(CAP_BLOCK_SUSPEND))
return -EPERM;
while (*str && !isspace(*str))
str++;
len = str - buf;
if (!len)
return -EINVAL;
if (*str && *str != 'n') {
/* Find out if there's a valid timeout string appended. */
ret = kstrtou64(skip_spaces(str), 10, &timeout_ns);
if (ret)
return -EINVAL;
}
mutex_lock(&wakelocks_lock);
// 加入到wakelock lru list
wl = wakelock_lookup_add(buf, len, true);
if (IS_ERR(wl)) {
ret = PTR_ERR(wl);
goto out;
}
if (timeout_ns) {
u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1;
do_div(timeout_ms, NSEC_PER_MSEC);
__pm_wakeup_event(wl->ws, timeout_ms);
} else {
__pm_stay_awake(wl->ws);
}
wakelocks_lru_most_recent(wl);
out:
mutex_unlock(&wakelocks_lock);
return ret;
}
int pm_wake_unlock(const char *buf)
{
struct wakelock *wl;
size_t len;
int ret = 0;
if (!capable(CAP_BLOCK_SUSPEND))
return -EPERM;
len = strlen(buf);
if (!len)
return -EINVAL;
if (buf[len-1] == 'n')
len--;
if (!len)
return -EINVAL;
mutex_lock(&wakelocks_lock);
wl = wakelock_lookup_add(buf, len, false);
if (IS_ERR(wl)) {
ret = PTR_ERR(wl);
goto out;
}
__pm_relax(wl->ws);
wakelocks_lru_most_recent(wl);
wakelocks_gc();
out:
mutex_unlock(&wakelocks_lock);
return ret;
}
// 将char* wakelock_name封装到struct wakelock,并加入到wakelock lru list,方便查询
static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
bool add_if_not_found)
{
struct rb_node **node = &wakelocks_tree.rb_node;
struct rb_node *parent = *node;
struct wakelock *wl;
while (*node) {
int diff;
parent = *node;
wl = rb_entry(*node, struct wakelock, node);
// 查看是否已存在char* wakelock_name
diff = strncmp(name, wl->name, len);
// 申请的wakelock已存在
if (diff == 0) {
if (wl->name[len])
diff = -1;
else
return wl;
}
if (diff < 0)
node = &(*node)->rb_left;
else
node = &(*node)->rb_right;
} // while end
if (!add_if_not_found)
return ERR_PTR(-EINVAL);
if (wakelocks_limit_exceeded())
return ERR_PTR(-ENOSPC);
/* Not found, we have to add a new one. */
wl = kzalloc(sizeof(*wl), GFP_KERNEL);
if (!wl)
return ERR_PTR(-ENOMEM);
// wakelock name拷贝封装到struct wakelock
wl->name = kstrndup(name, len, GFP_KERNEL);
if (!wl->name) {
kfree(wl);
return ERR_PTR(-ENOMEM);
}
// Create wakeup source and add it to the list
wl->ws =
(NULL, wl->name);
if (!wl->ws) {
kfree(wl->name);
kfree(wl);
return ERR_PTR(-ENOMEM);
}
wl->ws->last_time = ktime_get();
// 将新的struct wakelock->node节点插入到红黑树中(红黑树特点是查找速度很快)
rb_link_node(&wl->node, parent, node);
rb_insert_color(&wl->node, &wakelocks_tree);
// struct wakelock接入wakelock lru list
wakelocks_lru_add(wl);
// wakelock cout++
increment_wakelocks_number();
return wl;
}
static inline void wakelocks_lru_add(struct wakelock *wl)
{
list_add(&wl->lru, &wakelocks_lru_list);
}
创建wakeup source,并加入到wakeup_source list,
// kernel/drivers/base/power/wakeup.c
// Create wakeup source and add it to the list
struct wakeup_source *wakeup_source_register(struct device *dev,
const char *name)
{
struct wakeup_source *ws;
int ret;
// 创建wakeup_source
ws = wakeup_source_create(name);
if (ws) {
if (!dev || device_is_registered(dev)) {
ret = wakeup_source_sysfs_add(dev, ws);
if (ret) {
wakeup_source_free(ws);
return NULL;
}
}
// 加入到wakeup_source list
wakeup_source_add(ws);
}
return ws;
}
EXPORT_SYMBOL_GPL(wakeup_source_register);
系统进入休眠或睡眠流程,kernel suspend模块会查询wakeup_source lru list。如果,list为空,则可以进入休眠或睡眠模式。否则,进入无法进入休眠或睡眠。可参考https://blog.csdn.net/youthcowboy/article/details/134593442?spm=1001.2014.3001.5502 中的pm_wakeup_pending(void)函数。
五、wakeLock数据类型封装与传递
数据封装与传递流程:
1) app获取PowerManager类中的WakeLock内部类,并调用其方法
2)PowerManager类中构建一个IBinder对象,传给PMS
3)PowerManagerService服务中构建一个WakeLock内部类对象,将IBinder对象封装到WakeLock,存入wakelock list;调用native方法传递String类型的wakelock_name给PMS JNI
4)PMS JNI调用libpower中的API,传入char类型的wakelock_name
5)libpower模块中构建IWakeLock类型的对象,存放在wakelock map<wakelock_name, wl>;调用suspend hal service接口,传入char wakelock_name和IWakeLock类型的对象
6) suspend hal service通过syscall给kernel power传递char* wakelock_name
7)kernel power模块接收user space传递的char* wakelock_name,封装到struct WakeLock结构体,存放到wakelock lru list
六、 user space wakelock优化
影响设备功耗的主要可分为三类:1)系统长时间无法进入休眠或睡眠 2)系统休眠后,很快又被唤醒 3)应用或系统模块的异常或不恰当的行为导致耗电
wakelock属于第一类(PARTIAL_WAKE_LOCK才会影响系统休眠)。由于kernel space的wakelock都是由user space设置的,因此user space的wakelock可以基于一些用户异常申请wakelock的行为或不影响用户体验等方面做一些wakelock的优化,从而达到优化设备功耗高或设备发热的效果。
相关优化源码由于其它原因无法公开,下面看下优化思路。
1)PARTIAL_WAKE_LOCK优化
PARTIAL_WAKE_LOCK是一种保持CPU唤醒状态的锁。
某些应用长时间持有PARTIAL_WAKE_LOCK没有释放,但没有做任务,导致CPU长时间没法进入休眠状态,白白浪费了功耗及导致设备温度变高。
针对这类现象可以在PMS中对这种类型的wakelock做一些合理的管控,如开发一套监控系统异常wakelock监测机制,如audio、video的应用,长时间持有这类的wakelock但不持有音频焦点、应用或其它模块在该时间段内持有锁但kernel space中没有对应的待执行task等行为可以认为是异常持锁行为,将其做disable或release操作。
2)FULL_WAKE_LOCK优化
FULL_WAKE_LOCK是一种保持CPU唤醒状态的锁。
当应用来消息时会申请一个FULL_WAKE_LOCK,导致点亮屏幕,长时间亮屏会导致设备耗电快。
针对这类现象可以在PMS中对这种类型的wakelock做一些合理的管控,如应用来消息时,结合用户当前的设备环境、根据不同等级的应用做出合理的管控,如非top类应用禁止申请、top类应用设置一个timeout时长等。
3)SCREEN_BRIGHT_WAKE_LOCK优化
SCREEN_BRIGHT_WAKE_LOCK是一种使屏幕全亮(100%亮度)的锁。
在某些场景下,应用或系统模块会申请全亮锁,屏幕亮度提到最高,导致设备耗电快。
将这些场景做等级划分,如中等级的场景可以设置一个timeout时长,低等级的场景可以禁止申请
原文地址:https://blog.csdn.net/youthcowboy/article/details/134312903
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_26672.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!