Android-WakeLock(唤醒锁与CPU休眠/屏幕常亮)

本文介绍了Android中WakeLock的使用方法,包括创建、释放锁,不同WakeLock级别及屏幕相关FLAG等,还提及屏幕锁屏和解锁操作。同时阐述了其原理,如通过adb命令查看锁的个数,介绍了不计数和计数两种锁机制,以及Wakelock框架在应用层、frameworks层、JNI层和kernel层的大致流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考: 
https://blog.youkuaiyun.com/wh_19910525/article/details/8287202 
http://landerlyoung.github.io/blog/2014/10/31/androidzhong-de-wakelockshi-yong/

一.使用
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyTAG");
wakeLock.acquire();

在Manifest中添加如下权限
<uses-permission android:name="android.permission.WAKE_LOCK" />

WakeLock级别:
    PARTIAL_WAKE_LOCK       保持CPU运转,屏幕和键盘背光可能关闭
    SCREEN_DIM_WAKE_LOCK    保持CPU运转,保持屏幕常亮(亮度低),键盘背光可能关闭
    SCREEN_BRIGHT_WAKE_LOCK 保持CPU运转,保持屏幕和键盘背光高亮
    FULL_WAKE_LOCK          保持CPU运转,保持屏幕和键盘背光高亮(亮度最高)

    ACQUIRE_CAUSES_WAKEUP            强制亮屏,针对一些必须通知用户的操作
    ON_AFTER_RELEASE                 当锁被释放时,保持亮屏一段时间(如果释放时屏幕没亮,则不会亮屏)
    PROXIMITY_SCREEN_OFF_WAKE_LOCK   和接近传感器配合,当用户接近屏幕时黑屏,离开时亮屏(例如打电话),该API在API21后开放,以前被hide

    保持屏幕长亮的WakeLock被建议弃用,系统推荐如下方法(当Activity或view可见时,屏幕才保持常亮):
        在Activity.onCreate()中:  getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        或在xml布局中: android:keepScreenOn="true"
        或对View设置:  view.setKeepScreenOn(true);

        FLAG_KEEP_SCREEN_ON实际就是一个SCREEN_BRIGHT_WAKE_LOCK级别的WakeLock
        创建和释放锁都由系统自动管理,更加方便和安全,在后面通过adb命令验证         

        屏幕相关的其它FLAG:
        WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD    解锁屏幕
        WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON      点亮屏幕
        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED    屏幕锁定时也能显示
        WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON   屏幕打开时允许锁屏

        屏幕锁屏和解锁(需要权限"android.permission.DISABLE_KEYGUARD")
        KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(KEYGUARD_SERVICE);
        KeyguardManager.KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("unLock");          
        keyguardLock.reenableKeyguard(); // 锁屏
        //keyguardLock.disableKeyguard();// 解锁          

!注意:
    如果申请partial wakelock,那么即使用户按Power键,系统也不会Sleep
    如果申请其它wakelocks,用户按Power键,系统还是会Sleep

PowerManager方法
    boolean isScreenOn()       判断屏幕是否亮着,在API20被弃用,推荐isInteractive()
    void goToSleep(long time)  强制休眠(系统APP权限"android.permission.DEVICE_POWER",按下电源键锁屏时调用该方法)
    void wakeUp(long time)     强制唤醒(权限同上,按下电源键时调用该方法)
    void reboot(String reason) 重启手机(系统APP权限"android.permission.REBOOT"),参数:"recovery","fastboot"

WakeLock方法:
    void acquire()              获得WakeLock,除非显式释放,否则不会解锁(经测试,APP进程被杀死后,锁会失效)
    void acquire(long timeOut)  当超过timeOut之后系统自动释放WakeLock
    void release()              释放WakeLock
    boolean isHeld()            是否已经获取WakeLock  
    void setReferenceCounted(boolean value) 是否使用引用计数(默认ture): 一个WakeLock调用acquire()多次,也必须release()多次才能释放,
    如果释放次数比acquire()多,则抛出异常: java.lang.RuntimeException: WakeLock under-locked MyTAG

二.原理
通过adb命令查看WakeLock锁的个数:
adb shell dumpsys power

Wake Locks: size=4
    mLock:346803 PARTIAL_WAKE_LOCK         'MyTAG' ACQ=-1s175ms (uid=10201 pid=3862)
    mLock:141928 SCREEN_DIM_WAKE_LOCK      'MyTAG' ACQ=-1s174ms (uid=10201 pid=3862)
    mLock:402427 SCREEN_BRIGHT_WAKE_LOCK   'MyTAG' ACQ=-1s173ms (uid=10201 pid=3862)
    mLock:124789 SCREEN_BRIGHT_WAKE_LOCK   'WindowManager' ON_AFTER_RELEASE ACQ=-1s70ms (uid=1000 pid=1196 ws=WorkSource{10201})
注:最后一个Lock是由FLAG_KEEP_SCREEN_ON创建的,由系统用户进程管理(uid=1000是系统用户)  

在创建了 PowerManager.WakeLock 后,有两种机制,第一种是不计数锁机制,另一种是计数锁机制。
可以通过 setReferenceCounted(boolean value) 来指定,一般默认为计数机制。
这两种机制的区别在于,前者无论 acquire() 了多少次,只要通过一次 release()即可解锁。
而后者正真解锁是在( --count == 0 )的时候,同样当 (count == 0) 的时候才会去申请加锁。
所以 PowerManager.WakeLock 的计数机制并不是正真意义上的对每次请求进行申请/释放每一把锁,
它只是对同一把锁被申请/释放的次数进行了统计,然后再去操作。

Wakelock框架的大致流程:
    1).应用层  /frameworks/base/core/java/android/os/PowerManager.java
    WakeLock.acquire() -> PowerManagerService.acquireWakeLock()

    2).frameworks层  /frameworks/base/services/java/com/android/server/PowerManagerService.java
    管理所有APP申请的wakelock,比如音视、频播放器、camera等        
    static final String PARTIAL_NAME ="PowerManagerService";
    public static native void nativeAcquireWakeLock(int lock, String id);       
    nativeAcquireWakeLock(PARTIAL_WAKE_LOCK_ID, PARTIAL_NAME);

    3).JNI层 /frameworks/base/core/jni/android_os_Power.cpp
    static void acquireWakeLock(JNIEnv *env, jobject clazz,  jint lock, jstring idObj){
        ...
        const char *id = env->GetStringUTFChars(idObj, NULL);
        acquire_wake_lock(lock, id);
        env->ReleaseStringUTFChars(idObj, id);
    }

    4).kernel层 /hardware/libhardware_legacy/power/power.c       
    int acquire_wake_lock(int lock, const char* id){
        ...
        return write(fd, id, strlen(id));
    }
    fd是文件描述符: "/sys/power/wake_lock"
    id是从frameworks层传来的参数: "PowerManagerService"  

简书: https://www.jianshu.com/p/2cfd179ef8dc 
优快云: https://blog.youkuaiyun.com/qq_32115439/article/details/80169222 
GitHub博客: http://lioil.win/2018/05/02/Android-WakeLock.html 
Coding博客: http://c.lioil.win/2018/05/02/Android-WakeLock.html
 

<think>好的,我现在需要帮助用户了解Android中的WakeLock,包括它的详细用法、原理、使用场景和实现机制。首先,我应该回顾一下用户提供的引用内容,看看里面有哪些关键点需要涵盖。 根据引用1,WakeLock用于在灭屏时保持设备唤醒,比如接收微信消息。引用2提到WakeLock阻止AP进入休眠,确保关键代码运行,并给出了代码示例。引用3解释了功耗的来源和WakeLock的作用,以及滥用可能的问题。引用4详细介绍了WakeLock的分类和级别,比如永久锁、超时锁等。 接下来,我需要将这些信息组织成一个结构清晰的回答。按照用户的要求,分点说明原理、使用场景、使用方法和注意事项。同时,确保使用正确的中文和LaTeX格式,比如行内公式用$...$,独立公式用$$...$$。不过,可能WakeLock的内容里数学公式较少,但如果有相关算法或时间计算可能需要应用。 然后,生成相关问题,这需要根据内容提出用户可能感兴趣的问题,比如原理机制、常见问题、优化方法等。确保问题回答内容相关,并且有助于用户进一步学习。 需要注意的是,用户可能希望了解WakeLock的不同类型和级别,以及如何正确使用避免功耗问题。因此,在回答中要详细说明分类和使用时的注意事项,比如及时释放锁,选择合适的级别。 另外,代码示例是必须的,用户提供的引用中有代码片段,需要正确展示,并解释每个参数的作用,比如PowerManager的不同标志位。 最后,检查引用标识是否正确添加,每个引用段落末尾自然地加上对应的标识符,确保引用来源准确。同时,避免使用Markdown格式,保持回答的纯文本但结构清晰。</think>### Android WakeLock 详解 #### 一、核心原理 WakeLockAndroid 系统提供的电源管理机制,通过控制硬件(如 CPU屏幕)的唤醒状态,确保关键任务在灭屏后仍能执行。其核心原理如下: 1. **硬件控制**:通过操作系统内核接口,直接干预硬件电源状态(如保持 CPU 运行或屏幕常亮)[^3]。 2. **锁分级**:根据需求选择不同级别的锁,例如: - $PowerManager.PARTIAL\_WAKE\_LOCK$:仅保持 CPU 运行 - $PowerManager.FULL\_WAKE\_LOCK$:同时保持屏幕和键盘亮起[^4] 3. **引用计数机制**:非计数锁(默认)需一次释放,计数锁需多次匹配的 `acquire()` 和 `release()`[^4]。 #### 二、使用场景 | 场景类型 | 具体示例 | 推荐锁类型 | |-------------------|----------------------------|--------------------------| | 后台服务 | 音乐播放、文件下载 | `PARTIAL_WAKE_LOCK` | | 即时通信 | 消息通知点亮屏幕 | `ACQUIRE_CAUSES_WAKEUP` | | 传感器持续监控 | 健康监测、GPS 定位 | `SCREEN_DIM_WAKE_LOCK` | #### 三、代码实现 ```java // 1. 获取 PowerManager 实例 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); // 2. 创建 WakeLock 对象(带超时自动释放) WakeLock wakeLock = pm.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "MyApp::MyWakeLockTag"); // 3. 获取锁(设置 10 分钟超时) wakeLock.acquire(10 * 60 * 1000); // 4. 关键任务执行完成后释放 if (wakeLock.isHeld()) { wakeLock.release(); } ``` **关键参数说明**: - `ON_AFTER_RELEASE`:释放后短暂保持屏幕亮起[^2] - 超时时间单位:毫秒(建议不超过 30 分钟) #### 四、实现机制 Android 通过以下层级实现 WakeLock: $$ \text{应用层} \xrightarrow{Binder} \text{PowerManagerService} \xrightarrow{JNI} \text{内核层(/sys/power/wake_lock)} $$ 当锁被持有时,系统会向 `/sys/power/wake_lock` 写入标记,阻止进入低功耗状态[^3]。 #### 五、注意事项 1. **功耗控制**:滥用 WakeLock 可能导致待机功耗增加 20%-40%[^3] 2. **生命周期绑定**:建议在 `onResume()` 中申请,`onPause()` 中释放 3. **Android 6.0+ 限制**:Doze 模式会强制中断非白名单应用的 WakeLock[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值