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的申请与释放,参考4.1
2)fwk系统组件可以通过PowerManagerService实现wakelock的申请与释放,调用acquireWakeLock接口
3)native和hal层的系统组件可以通过libpower、system supend hal或直接写/sys/power/wake_lock(wake_unlock)节点方式实现wakelock的申请与释放
4)kernel层申请与释放锁
a.设置唤醒源
b.申请与释放wakelock


static struct wakeup_source *my_wake_source;

static int __init my_module_init(void)
{
    // a.设置"my_module_wake_source"的wakeup_source
    my_wake_source = wakeup_source_register("my_module_wake_source");
    if (!my_wake_source) {
        pr_err("Failed to register wake source\n");
        return -ENOMEM;
    }
    return 0;
}
module_init(my_module_init);

static void __exit my_module_cleanup(void)
{
   // a.注销这个wakeup_source
    wakeup_source_unregister(my_wake_source);
}
module_exit(my_module_cleanup);


// b. 申请与释放wakeup_source
void my_function(void)
{
    // 获取wwakeup_source
    __pm_stay_awake(my_wake_source);
	......
    // 释放wakeup_source
    __pm_relax(my_wake_source);
}

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

// 当wakelock数量为0,将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模块核心代码

app、native、kernel模块申请的wakelock最终会转换成wakeup_source.

struct wakeup_source {
        const char                 *name;
        struct list_head        entry;
        spinlock_t                lock;
        struct wake_irq                *wakeirq;
        struct timer_list        timer;
        unsigned long                timer_expires;
        ktime_t total_time;
        ktime_t max_time;
        ktime_t last_time;
        ktime_t start_prevent_time;
        ktime_t prevent_sleep_time;
        unsigned long                event_count;
        unsigned long                active_count;
        unsigned long                relax_count;
        unsigned long                expire_count;
        unsigned long                wakeup_count;
        bool                        active:1;
        bool                        autosleep_enabled:1;
};

结构体 wakeup_source 中包含以下成员变量:

  • name:唤醒源的名称,通常用来标识唤醒源的具体信息。
  • entry:链表节点,用于将不同的唤醒源链接在一起。
  • lock:自旋锁,用于保护对唤醒源中部分字段的并发访问。
  • wakeirq:指向一个 wake_irq 结构体的指针,可能与唤醒源相关联的唤醒中断。
  • timer:定时器结构体,用于处理唤醒源的定时事件。
  • timer_expires:定时器过期时间。
  • total_time:总运行时间。
  • max_time:最长运行时间。
  • last_time:最后更新时间。
  • start_prevent_time:开始阻止睡眠的时间。
  • prevent_sleep_time:阻止睡眠的时间。
  • event_count:事件计数。
  • active_count:激活计数。
  • relax_count:休眠计数。
  • expire_count:过期计数。
  • wakeup_count:唤醒计数。
  • active:活跃状态标志,1 表示活跃,0 表示非活跃。
  • autosleep_enabled:自动休眠启用状态。

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);
                // 创建wakeup_source,并添加到lru list
                __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);
        // lru list中移除非active的wakeup_source
        wakelocks_gc();

 out:
        mutex_unlock(&wakelocks_lock);
        return ret;
}

static void __wakelocks_gc(struct work_struct *work)
{
        struct wakelock *wl, *aux;
        ktime_t now;

        mutex_lock(&wakelocks_lock);

        now = ktime_get();
        list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
                u64 idle_time_ns;
                bool active;

                spin_lock_irq(&wl->ws.lock);
                idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));
                active = wl->ws.active;
                spin_unlock_irq(&wl->ws.lock);

                if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))
                        break;
                 f (!active) {
                        // 移除wakeup_source
                        wakeup_source_remove(&wl->ws);
                        rb_erase(&wl->node, &wakelocks_tree);
                        list_del(&wl->lru);
                        kfree(wl->name);
                        kfree(wl);
                        decrement_wakelocks_number();
                }
        }
        wakelocks_gc_count = 0;

        mutex_unlock(&wakelocks_lock);
}

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

七、系统持唤醒锁查询

7.1 查询用户空间持有唤醒锁

cat sys/power/wake_lock
在这里插入图片描述
当前用户空间只有一个wakelock,该wakelock通过PMS服务申请。

7.2 查询用户空间和kernel空间持有唤醒锁

cat sys/kernel/debug/wakeup_source,查看active_since是否为0,如果不为0,说明正在持锁
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值