Android Wakelock管理【app至kernel】

目录:
一、 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管理流程
在这里插入图片描述

申请与释放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申请与释放代码流程
在这里插入图片描述

四、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;
}

// wakelock加入到lru list,系统进入suspend流程会进行check
static inline void wakelocks_lru_add(struct wakelock *wl)
{
        list_add(&wl->lru, &wakelocks_lru_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; 

        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_add(ws);
        }
        return ws;
}
EXPORT_SYMBOL_GPL(wakeup_source_register);

五、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时长,低等级的场景可以禁止申请

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>