精华内容
下载资源
问答
  • wakeLock
    2022-05-01 15:34:41

    Wake lock - wakelock在android的电源管理系统中扮演一个核心的角色,wakelock是一种锁的机制, 只要有task拿着这个锁, 系统就无法进入休眠, 可以被用户态进程和内核线程获得。这个锁可以是有超时的或者是没有超时的, 超时的锁会在时间过去以后自动解锁。如果没有锁了或者超时了, 内核就会启动标准linux的那套休眠机制机制来进入休眠。
    wakelock在android的休眠唤醒机制中扮演着及其重要的角色,主要源码位于文件:
    kernel/kernel/power/wakelock.c
    kernel/include/linux/wakelock.h

       wakelock有两种形式的锁:超时锁和非超时锁,这两种形式的锁都是使用函数wake_lock_init()来初始化,只是在上锁的时候会有一点点差别,超时锁使用函数wake_lock_timeout(),而非超时锁使用函数wake_lock(), 这个两个函数会最终调用到同一个函数wake_lock_internal(),该函数依靠传入的不同参数来选择不同的路径来工作。值得注意的是,非超时锁必须手工解锁,否则系统永远不能进入睡眠
    

    Wakelock的机制被文件userwakelock.c中的code封装成了sys的接口sys/power/wake_lock和sys/power/wake_unlock文件,那么上层如果需要新建wakelock或者注销wakelock,或者是解锁wakelock,都是操作这两个sys接口文件。

    申请与释放(如何使用)

    wakelock可以被内核空间 申请和释放。如果申请的是非超时锁wake_lock,需要相应的调用wake_unlock来释放,而超时锁则不需要手工释放(当然你也可以手工释放),超时后kernel系统会自动释放锁,在内核空间可以直接调用wake_lock, wake_lock_timeout 申请锁 Android kernel为用户空间提供了申请和释放wakelock的接口,实现在kernel/power/userwakelock.c中。
    实例:
    1:首先申明一个wake_lock
    static struct wake_lock alarm_rtc_wake_lock;

    2:在init函数中对wake_lock初始化        
    

    wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, “alarm_rtc”);//WAKE_LOCK_SUSPEND 为suspend lock还有一种idle lock
    WAKE_LOCK_SUSPEND, /* Prevent suspend /
    WAKE_LOCK_IDLE, /
    Prevent low power idle*/

    3:使用wake_lock()或者wake_lock_timeout()     
    

    wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
    wake_lock(&alarm_rtc_wake_lock);

    4:使用wake_unlock()
    

    wake_unlock(&alarm_rtc_wake_lock);

    4:在exit中调用wake_lock_destroy()
    

    wake_lock_destroy(&alarm_rtc_wake_lock);

    wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, “alarm_rtc”);
    if (is_wakeup && !suspended && head_removed)
    wake_unlock(&alarm_rtc_wake_lock);
    if (is_wakeup && suspended) {
    pr_alarm(FLOW, “changed alarm while suspened\n”);
    wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
    return;
    }
    wake_lock(&alarm_rtc_wake_lock);
    wake_unlock(&alarm_rtc_wake_lock);
    wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
    suspended = false;
    wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ);
    wake_lock_destroy(&alarm_rtc_wake_lock)

    更多相关内容
  • 本篇文章主要介绍了使用WakeLock使Android应用程序保持后台唤醒的相关知识。具有很好的参考价值。下面跟着小编一起来看下吧
  • Wakelock是Flutter插件,可让您保持设备屏幕清醒,即防止屏幕进入Hibernate状态。 支持平台 平台 wakelock支持 安卓 :check_mark_button: 的iOS :check_mark_button: 网页 :check_mark_button: 苹果系统 :...
  • WakeLock使用方法代码实例,需要的朋友可以参考一下
  • Android设备中运行的进程需要使用电量资源时,也需要向PMS申请一个WakeLock;当工作完成后,就释放掉申请的WakeLock。PMS通过判断当前是否还有进程持有WakeLock,就能得出系统是否空闲。 经过调研PMS机制和HW的逆向...

    1. 前言

    作为移动终端,电量是一种稀缺资源,需要尽可能的节省。于是,Android系统在空闲时,会主动进入到休眠状态。

    Android设备中运行的进程需要使用电量资源时,也需要向PMS申请一个WakeLock;当工作完成后,就释放掉申请的WakeLock。PMS通过判断当前是否还有进程持有WakeLock,就能得出系统是否空闲。

    经过调研PMS机制和HW的逆向源码,我们得到如下埋点函数。
    在这里插入图片描述

    即HW也是根据电量服务的notifyWakeLockAcquiredLocked/notifyWakeLockReleasedLocked/notifyWakeLockChangingLocked 进行wakeLock的埋点,从而建立wakeLock状态的最小模型,方便获取各种定制化接口。

    埋点函数作用
    PowerManagerService.notifyWakeLockAcquiredLocked应用持锁埋点
    PowerManagerService.notifyWakeLockReleasedLocked应用释放锁埋点
    PowerManagerService.notifyWakeLockChangingLocked锁配置更新埋点

    通过上述函数我们需要得到的函数

    API接口作用
    getWkTimeByUidPid根据UID\PID获取持锁时间
    getWkTimeByUid根据UID获取持锁时间
    getWkHoldingTime获取阻止休眠时长
    getWkTimeByUidPidTAG根据UID\PID\TAG获取持锁TAG
    getWkTagByUidPid根据UID\PID获取持锁TAG
    getWkTimeByTag根据TAG获取持锁时长
    getWkUidsByTag根据TAG获取持锁UID
    getWkPidsByTag根据TAG获取持锁PID
    getHoldingWkPidsByUid根据UID获取阻止休眠PID
    isHoldWkByTag根据TAG获取持锁TAG
    getLastReleaseAudioMixUid获取最近音频输出的释放锁
    getLastReleaseAudioInUid获取最近音频输入的释放锁
    getHoldingJobWkTime获取持锁Job时长
    在这里插入图片描述

    2. PowerManagerService SDK

    2.1 DEMO

    使用 PowerManager.newWakeLock API 进行持锁管理,WakeLock Flag一般与WakeLock Level组合使用

    /*
     Flag Value                 CPU        Screen      Keyboard
     PARTIAL_WAKE_LOCK            On           Off         Off 0x00000001 1
     SCREEN_DIM_WAKE_LOCK         On           Dim         Off 0x00000006 6
     SCREEN_BRIGHT_WAKE_LOCK      On           Bright      Off 0x0000000a 10
     FULL_WAKE_LOCK               On           Bright      Bright 0x0000001a 26
     */
    object AlertWakeLock {
        private val TAG = "AlertWakeLock"
        private var sCpuWakeLock: PowerManager.WakeLock? = null
    
        @SuppressLint("InvalidWakeLockTag")
        internal fun createPartialWakeLock(context: Context): PowerManager.WakeLock? {
            // 第一步:获取PowerManager的实例
            val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager ?: return null
            // 第二步:调用PowerManager中的newWakeLock方法创建一个WakeLock对象
            return pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, TAG)
            //return pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, TAG);
        }
    
        fun acquireCpuWakeLock(context: Context) {
            if (sCpuWakeLock != null) {
                return
            }
    
            sCpuWakeLock = createPartialWakeLock(context)
            // 第三步:acquire()获取相应的锁
            sCpuWakeLock!!.acquire()
        }
    
        fun releaseCpuLock() {
            if (sCpuWakeLock != null) {
                // 最后:release释放
                sCpuWakeLock!!.release()
                sCpuWakeLock = null
            }
        }
    }
    
    

    2.2 levelAndFlags

    WakeLock主要用于控制CPU、屏幕、键盘三部分

    • PARTIAL_WAKE_LOCK = 0x00000001
    • SCREEN_DIM_WAKE_LOCK = 0x00000006
    • SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a
    • FULL_WAKE_LOCK = 0x0000001a
    • PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020
    • DOZE_WAKE_LOCK = 0x00000040
    • DRAW_WAKE_LOCK = 0x00000080
    • ACQUIRE_CAUSES_WAKEUP = 0x10000000
    • ON_AFTER_RELEASE = 0x20000000

    2.2.1 四大天王-level

    对于PARTIAL_WAKE_LOCK、SCREEN_DIM_WAKE_LOCK、SCREEN_BRIGHT_WAKE_LOCK和FULL_WAKE_LOCK而言,不考虑Power键的话,随着等级的提高,权限也相应增大,即持有高等级的锁,能够激活的部分越多;如果考虑Power键的话,PARTIAL_WAKE_LOCK可以保证CPU不休眠,反而是权限最大的。

    level 值CPUScreenKeyboard备注
    PARTIAL_WAKE_LOCKOnOffOff不受Power键影响
    SCREEN_DIM_WAKE_LOCKOnDimOff按下电源键,仍然可进入休眠
    SCREEN_BRIGHT_WAKE_LOCKOnBrightoff按下电源键,仍然可进入休眠
    FULL_WAKE_LOCKOnBrightOn按下电源键,仍然可进入休眠

    上述看,如果滥用下,很容易导致耗电异常。

    2.2.1 levelAndFlags

    levelAndFlags作用
    PROXIMITY_SCREEN_OFF_WAKE_LOCK无法阻止系统休眠。当系统处于唤醒态时,传感器发觉终端某个物体比较近时,关闭屏幕。重新拉个某个物体距离后,点亮屏幕。例如通话时,贴耳通话灭屏,远离耳朵亮屏
    DOZE_WAKE_LOCK终端处于Dozing state时,使能CPU挂起,屏幕处于低电量模式。
    DRAW_WAKE_LOCK终端处于Dozeing state 时,使应用获取足够的时间完成绘制。
    ACQUIRE_CAUSES_WAKEUP正常情况下,获取WakeLock并不会点亮屏幕(即acquire之前机器处于息屏状态,无法点亮屏幕)。加上这个Flag后,acquire Wakelock同时能够点亮屏幕
    ON_AFTER_RELEASE和用户体验有关。正常情况下当wakelock释放后,如果没有该标志位,那么系统会立即息屏。如果有该标志位,系统可以延长一段时间再息屏。

    3. WakeLock

    frameworks/base/core/java/android/os/PowerManager.java

    WakeLock是PowerManager中的内部类

    public final class WakeLock {
      ...
      @UnsupportedAppUsage
      private int mFlags;
      @UnsupportedAppUsage
      private String mTag;
      private final String mPackageName;
      private final IBinder mToken;
      private int mInternalCount;
      ...
    }
    

    3.1 PowerManager.WakeLock.acquire()

    在这里插入图片描述

    我们知道一个进程创建的WakeLock,实际上表明了该进程执行某个工作时对电量的需求,例如声明该工作需要保持屏幕处于点亮状态,或该工作需要CPU处于唤醒态等。
    因此,进程创建了WakeLock后,需要将WakeLock发送到PMS中,让PMS明白该进程的需求。
    这种将WakeLock通知到PMS的过程,就被称为acquire WakeLock。

    frameworks/base/core/java/android/os/PowerManager.java

        public void acquire() {
            synchronized (mToken) {
                acquireLocked();
            }
        }
        
        private void acquireLocked() {
            ...
            // 工作流程将通过Binder通信进入到PMS中
            mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,mHistoryTag, mDisplayId);
            ...
        }
    

    PowerManager.WakeLock.acquire() 通过Binder调用到PowerManagerService

        @Override // Binder call
        public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
            ...
            acquireWakeLockInternal(lock, displayId, flags, tag, packageName, ws, historyTag,uid, pid);
            ...
        }
        
        private void acquireWakeLockInternal(IBinder lock, int displayId, int flags, String tag,
                String packageName, WorkSource ws, String historyTag, int uid, int pid) {
            ...
            //PMS中维持了一个ArrayList,记录当前已申请的WakeLock
            int index = findWakeLockIndexLocked(lock);
            ...
            //如果index大于0,说明此时Acquire的是一个旧的WakeLock
            if (index >= 0) {
                wakeLock = mWakeLocks.get(index);
                //这是判断WakeLock对应的成员变量是否发生改变
                if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
                        // 改变则更新
                    wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid);
                }
            } else {
                ...
                // 监控申请WakeLock的进程是否死亡
                lock.linkToDeath(wakeLock, 0);
                ...
                //创建一个新的WakeLock,例如RIL第一次调用send就会进入该分支
                wakeLock = new WakeLock(lock, displayId, flags, tag, packageName, ws, historyTag,
                            uid, pid, state);
               //添加到wakelock列表
               mWakeLocks.add(wakeLock);
               // 特殊处理PARTIAL_WAKE_LOCK,根据Doze模式的白名单更新wakelock的disabled变量,可以定制:即使该应用申请了PARTIAL_WAKE_LOCK,也不能阻止系统进入休眠状态。
               setWakeLockDisabledStateLocked(wakeLock);
            }
            
            // 处理WakeLock对应的Flag
            // 判断WakeLock是否有ACQUIRE_CAUSES_WAKEUP,在必要时唤醒屏幕
            applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
            mDirty |= DIRTY_WAKE_LOCKS;
            
            //更新电源状态
            updatePowerStateLocked();
            // 通知wakeLock发生变化,电量统计服务做相关统计
            // 同时适合功耗异常埋点
            notifyWakeLockAcquiredLocked(wakeLock);
        }
    

    3.2 PowerManager.WakeLock.release()

    frameworks/base/core/java/android/os/PowerManager.java
    在这里插入图片描述

        public void release() {
            release(0);
        }
    
        public void release(int flags) {
            ...
            // 工作流程将通过Binder通信进入到PMS中
            mService.releaseWakeLock(mToken, flags);
            ...
        }
    

    PowerManager.WakeLock.release() 通过Binder调用到PowerManagerService

        private void releaseWakeLockInternal(IBinder lock, int flags) {
            ...
            releaseWakeLockInternal(lock, flags);
            ...
        }
        
        private void releaseWakeLockInternal(IBinder lock, int flags) {
            ...
            //根据Binder代理,从存储的ArrayList中找到对应WakeLock的序号
            int index = findWakeLockIndexLocked(lock);
            
            //RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY,表示当sensor判断终端离物体较远时,才真正释放PROXIMITY_SCREEN_OFF_WAKE_LOCK等级的WakeLock
            if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {
                    mRequestWaitForNegativeProximity = true;
            }
            //PMS不再关注客户端进程是否死亡
            wakeLock.mLock.unlinkToDeath(wakeLock, 0);
            removeWakeLockLocked(wakeLock, index);
        }
        
        private void removeWakeLockLocked(WakeLock wakeLock, int index) {
            mWakeLocks.remove(index);
            ...
            //通知BatteryStatsService,可作为功耗异常埋点
            notifyWakeLockReleasedLocked(wakeLock);
    
            applyWakeLockFlagsOnReleaseLocked(wakeLock);
            mDirty |= DIRTY_WAKE_LOCKS;
            updatePowerStateLocked();
        }
    

    3. 华为的wakeLock功耗异常埋点调研

    Hw的WakeLock埋点

    PowerManagerService Notifier Utils LogPower notifyWakeLockAcquiredLocked notifyWakeLockReleasedLocked notifyWakeLockChangingLocked onWakeLockAcquired(160) onWakeLockReleased(161) onWakeLockChanging noteWakelock push(160/161) PowerManagerService Notifier Utils LogPower

    Hw的埋点数据处理

    DeviceMonitor WakelockStats createAllStats handleScrState handleStatsEvent(160/161) 1. getWkTimeByUidPid 2. getWkTimeByUid 3. getWkHoldingTime 4. getWkTimeByUidPidTAG 5. getWkTagByUidPid 6. getWkTimeByTag 7. getWkUidsByTag 8. getWkPidsByTag 9. getHoldingWkPidsByUid 10. isHoldWkByTag 11. getLastReleaseAudioMixUid 12. getLastReleaseAudioInUid 13. getHoldingJobWkTime DeviceMonitor WakelockStats

    即HW也是根据电量服务的notifyWakeLockAcquiredLocked/notifyWakeLockReleasedLocked/notifyWakeLockChangingLocked 进行wakeLock的埋点,从而建立wakeLock状态的最小模型,方便获取各种定制化接口。

    展开全文
  • Android powermanger wakelock

    2014-08-25 16:36:10
    Android 电源管理 -- wakelock机制,通过控制wakelock 实现保持pad 禁止休眠状态; Wake Lock是一种锁的机制, 只要有人拿着这个锁,系统就无法进入休眠, 可以被用户态程序和内核获得. 这个锁可以是有超时的 或者 是...
  •     从Android实战角度来分析分析WakeLock锁机制 前言   好久没有写点实战类型的博客了,最近一直都在捣鼓源码分析和项目相关事情,是时候来点实战类型的博客了。捯饬点啥实战的呢,正好前两天有一个同事询问...

      从Android应用层及Framework层的角度分析WakeLock锁机制


    本篇博客编写思路总结和关键点说明:
    在这里插入图片描述
    为了更加方便的读者阅读博客,通过导读思维图的形式将本博客的关键点列举出来,从而方便读者取舍和阅读!



    引言

      好久没有写点偏重实战类型的博客了,最近一直都在捣鼓源码分析和项目相关事情,是时候来点偏重实战类型的博客了。捯饬点啥实战的呢,正好前两天有一个同事询问我关于Android的WakeLock锁相关的问题,虽然网上说有不少关于WakeLock锁相关分析的博客但是都不是很完善,基本只侧重了某一个点,这里我们从Android应用层及Framework层的角度出发来对Android的WakeLock锁机制分析一番。

    注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:

    frameworks/base/core/java/android/os/PowerManager.java
    frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
    frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
    hardware/libhardware_legacy/power/power.c
    

    在开启本篇博客正式分析前,先奉上关于WakeLock锁在Android源码中的整个层次关系,以便读者先从整体脉络上把握一下Android是怎么设计WakeLock锁相关架构的。

    在这里插入图片描述




    一.WakeLock锁机制概述和设计用途

    通常我们在使用新事物之前,都有必有先对其有个大概了解,然后才能决定是否使用以及怎么使用!所以对于WakeLock锁我们也遵循如上的逻辑进行处理。

    1.1 WakeLock锁机制概述

      在Android的世界中被叫做锁的有很多种,譬如文件锁啊,线程锁啊等!那么这里的WakeLock锁又是一个啥东东呢,从字面意思理解就是休眠唤醒锁,但是站在Android的设计者高度以及角度来看WakeLock确实也是一种锁,它是Android框架层提供的一套机制(需要从kernel到framework层的一起配合),无论内核空间或者用户空间只要持有了WakeLock锁,就可以达到控制Android设备运行状态的目的。这里的设备运行状态主要指屏幕的常亮灭屏,键盘灯的常亮,CPU等保持运行的。如果一定要对WakeLock锁有一个定义,那就是Android提供的一种机制使Android终端保持一种运行状态,不至于CPU完全睡眠“清醒”剂!

    1.2 WakeLock锁设计用途

      那么Android为社么要设计这么一种机制呢,也许读者会说了存在即合理了(哥不带这么玩的吗)。我们想象一下,当我们吃着火锅唱着歌,吃得正嗨的时候突然停电了或者没有菜了,估计读者此时会有骂娘的冲动了。在Android的现实世界里也会存在着这种情况,在某些场景下我们需要我们的Android终端在灭屏以后后台任务还依然能够运行,譬如音乐,后台下载等,但是通常情况下手机灭屏状态下保持一段时间后,系统会进入休眠,上述的任务就不能够完美的执行了。而WakeLock正是为了解决这类问题应运而生的,只要我们申请了WakeLock,那么在释放WakeLock之前,系统不会进入休眠,即使在灭屏的状态下,应用要执行的任务依旧不会被打断。

    这里我们从实际使用角度出发简单概括一下WakeLock锁的各种使用场景:

    • 灭屏后,要保持CPU一直运转,然后可以正常执行后台任务,通常是在Service中执行
    • 通知、闹钟来临之后,想点亮屏幕通知用户
    • 在某些情况下,应用需要保持屏幕高亮



    二.WakeLock锁分类

      WakeLock锁机制概述和设计用途我们已经介绍清楚了,这个就好像媒婆给你介绍男女朋友,开场白已经好了,是时候开始真正的了解了不是。WakeLock锁根据不同的使用场景可以划分为如下几类情况(这个没有必要记住,只要我们能在合适的场景下使用和合适的WakeLock锁就OK了):

    • 根据WakeLock锁有效时间划分:WakeLock可以分为永久锁和超时锁,永久锁表示只要获取了WakeLock锁,必须显式的进行释放,否则系统会一直持有该锁,对于这种锁一定要记得显示释放,否则会造成Android终端功耗过大等问题;超时锁则是在到达给定时间后,若没有显示释放锁,则会启动自动释放WakeLock锁的,其实现原理为方法内部维护了一个Handler来实现的。

    • 根据释放原则划分:WakeLock可以分为计数锁和非计数锁,默认为计数锁,如果一个WakeLock对象为计数锁,则一次申请必须对应一次释放;如果为非计数锁,则不管申请多少次,一次就可以释放该WakeLock,如果我们在创建的时候不特殊指定通常创建的是非计数锁。

    在创建了 PowerManager.WakeLock 后,有两种机制,第一种是不计数锁机制,另一种是计数锁机制。可以通过 setReferenceCounted(boolean value) 来指定,一般默认为计数机制。这两种机制的区别在于,前者无论 acquire() 了多少次,只要通过一次 release()即可解锁。而后者正真解锁是在( --count == 0 )的时候,同样当 (count == 0) 的时候才会去申请加锁,其他情况 isHeld 状态是不会改变的。所以 PowerManager.WakeLock 的计数机制并不是正真意义上的对每次请求进行申请/释放每一把锁,它只是对同一把锁被申请/释放的次数进行了统计再正真意义上的去操作。一下进行了永久锁的测试: 从测试我们可以看到使用计数和计数锁的区别。

    • 根据持锁层级划分:分为用户空间层透过PowerManager拿锁,以及kernel层直接持有Wakelock锁(这里小伙们先有一个概念,后边的分析就知道了)



    三.WakeLock锁类常用的方法和变量

      在正式开始介绍WakeLock锁的使用前,我们先从源码角度介绍一下WakeLock锁,它是一个PowerManager的一个内部类,其类图如下:

    在这里插入图片描述

    其常用的的几个方法和功能如下所示:

    	public void setReferenceCounted(boolean value)//设置锁的类型是否为计数锁,和我们前面介绍的锁的类型对应
    	public void acquire()//获取锁
    	public void acquire(long timeout);//获取锁的类型为计时锁
    	public void release();//释放获取的锁
    	public void release(int flags);//释放所示带标志,只有唯一一个取值为RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY
    	public boolean isHeld();//判断当前的WakeLock对象是否只持有锁
    



    四.WakeLock锁的使用以及相关的参数

      好吗,前面啰嗦了一大截!读者也许会说这个和我们的标题是不是有冲突了,说好的实战,实战呢(本人承诺绝对不挂羊头卖狗肉)!这不实战就来了,我们这里从上层应用以及Native层使用来介绍!


    4.1 Android应用层使用WakeLock锁

    Android应用层使用WakeLock锁的过程比较简单,可以按照如下流程进行:

    • 首先在AndroidManifest.xml中申请WakeLock锁相关的权限,如下:
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    
    • 接着根据具体应用场景,申请WakeLock锁,并使用WakeLock锁(一定不要滥用),如下:
    package com.example.test;
    import android.content.Context;
    import android.os.PowerManager;
    public class WakeLockUtils {
    
        private static WakeLockUtils instance = null;
        private PowerManager mPowerManager = null;
        private PowerManager.WakeLock mWakeLock = null;
    
        public static WakeLockUtils getInstance(Context mContext,
                final int levelAndFlags, final String tag) {
            if (instance == null) {
                synchronized (WakeLockUtils.class) {
                    if (instance == null) {
                        instance = new WakeLockUtils(mContext, levelAndFlags, tag);
                    }
                }
            }
            return instance;
        }
    
        private WakeLockUtils(Context mContext, final int levelAndFlags,
                final String tag) {
    
            mPowerManager = (PowerManager) mContext
                    .getSystemService(Context.POWER_SERVICE);//获取PowerManager建立和PowerManagerService的Binder通信通道
            mWakeLock = mPowerManager.newWakeLock(levelAndFlags, tag);//获取锁
        }
    
        //持有锁
        public void accquire(final long timeout){
            if(timeout >= 0){
                mWakeLock.acquire(timeout);
            }else{
                mWakeLock.acquire();
            }
        }
        
        //释放锁
        public void release(){
            if(mWakeLock.isHeld()){//判断是否持有锁
                mWakeLock.release();
            }
        }    
    }
    
    

    上述的流程肯定是难不倒各位读者的了,但是这里我们需要重点关注的是newWakeLock(final int levelAndFlags, final String tag)这个方法的使用,因为传入参数的不同那么获取的WakeLock锁就不同,这我们放在后面再细说!
    如果觉得上面的封装有点复杂,那么下面的代码可能会更加得直接明了:

        private void wakeLockFun(){        
            PowerManager mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);        
            PowerManager.WakeLock mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WakeLock_FUN");
            
            mWakeLock.acquire();//获取锁      
            mWakeLock.release();//释放锁
        }
    

    4.2 Android的Native层使用WakeLock锁

    Android的Native层使用WakeLock锁也不复杂,这里就不来什么具体步骤了,主要就是对wakelock的节点直接操作,写入数据就OK了!

    #define WAKE_LOCK  "/sys/power/wake_lock"
    #define RELEASE_WAKE_LOCK "/sys/power/wake_unlock"
    static int gfd_wake_lock = -1;
    static int gfd_wake_unlock = -1;
    const char * wake_lock_cmd = "rpc_wake_lock_timeout";
    static long long wake_lock_timeout_s = 10000000000;
    
    //这里直接操作节点,向/sys/power/wake_lock写入数据
    static int wake_lock_fun(const char* id,int lock_type = 0, int time = 0)
    {
        if(gfd_wake_lock <=0)
        {
            gfd_wake_lock = open(WAKE_LOCK, 0x02);
        }
    
        if (gfd_wake_lock < 0)
        {
            fprintf(stderr, "fatal error opening \"%s\"\n", WAKE_LOCK);
            LOGE(TAG,"fatal error opening \"%s\"\n", WAKE_LOCK);
            return -1;
        }
    
        if(strlen(id) > 64)
        {
            LOGE(TAG, "rpc_wake_lock failed");
            return -83;
        }
    
        int result = 0;
        char wake_lock_str[256];
        memset(wake_lock_str, 0, sizeof(wake_lock_str));
        //默认时间是10秒钟
        if(lock_type == 0)
        {
            sprintf(wake_lock_str,"%s  %lld", id, wake_lock_timeout_s);
        }
        //此处表示是我们要执行自动释放锁
        else
        {
            long actual_time = 10000 + time; //计算出毫秒
            char* ns_suffix = "000000"; //毫秒转纳秒的后缀
            sprintf(wake_lock_str,"%s %ld%s", id, actual_time, ns_suffix);
        }
        result =  write(gfd_wake_lock, wake_lock_str, strlen(wake_lock_str));
        if(result < 0)
        {
            LOGE(TAG,"rpc_wake_lock The error result = %d,errno is = %d\n",errno);
            return result;
        }
        return 0;
    }
    
    
    
    
    static int wake_unlock_fun(const char* id)
    {
        if(gfd_wake_unlock <= 0)
        {
            gfd_wake_unlock = open(RELEASE_WAKE_LOCK, 0x02);
        }
        if (gfd_wake_unlock < 0)
        {
            fprintf(stderr, "fatal error opening \"%s\"\n", RELEASE_WAKE_LOCK);
            LOGE(TAG,"fatal error opening \"%s\"\n", RELEASE_WAKE_LOCK);
            return -1;
        }
    
        if(strlen(id) > 64)
        {
            LOGE(TAG, "rpc_wake_unlock failed");
            return -83;
        }
    
        int result = 0;
        result = write(gfd_wake_unlock, id, strlen(id));
        if(result < 0)
        {
            LOGE(TAG,"rpc_wake_unlock The error result = %d,errno is = %d\n",errno);
            return result;
        }
        return 0;
    }
    
    int main(void){
    	wake_lock_fun("native_wake_lock", 110000000000)sleep(5000000000);
    	wake_unlock_fun("native_wake_lock");
    }
    

    4.3 Android应用层获取WakeLock锁时参数详解

    还记得在3.1章节的时候说newWakeLock这个方法的使用是,因为传入参数的不同那么获取的WakeLock锁就不同吗,其中具体的指代的是levelAndFlags这个参数的值,和tag没有啥关系(这个只是相当于用户对这个WakeLock锁的一个别名而已)!通过获取不同的WakeLock锁,从而影响CPU,屏幕,以及键盘灯的状态的目的!

    //[PowerManager.java]
    	public WakeLock newWakeLock(final int levelAndFlags, final String tag) {
    		validateWakeLockParameters(levelAndFlags, tag);
    		return new WakeLock(levelAndFlags, tag,
    				this.mContext.getOpPackageName());
    	}
    

    上述的场景也比较也比较好理解,譬如有的App界面希望一直不要灭屏的运行着,有些App可以灭屏然后只需要保持CPU运转就可以了。那这里的levelAndFlags参数既然这么重要,看来我们有必要深挖挖了!

    如果读者只是想快速的获取想要的锁,那么看这里就够了,而不需要下面的从源码角度理解了,但是本人还是建议读者从源码角度出发理解,毕竟别人给你的永远是别人的不是你的!

    各种锁的类型对CPU 、屏幕、键盘的影响:
    PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。
    SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
    SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
    FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
    ACQUIRE_CAUSES_WAKEUP:强制使屏幕亮起,这种锁主要针对一些必须通知用户的操作.
    ON_AFTER_RELEASE:当锁被释放时,保持屏幕亮起一段时间

    从newWakeLock的第一个入参的名称就可以看出,它分为两部分即level(级别)和Flags(标记),我们来一一捯饬捯饬一下!

    4.3.1 WakeLock锁级别

    WakeLock锁的级别都被定义在PowerManager中,它的每个参数取值有何意思,或者蹊跷呢,让我们来探究一番(这里留下英文注释,读者可以自行理解,在最后我会加上自己的理解!最后可以比对比对,我们的理解是否一致)!

    //[PowerManager.java]
        /**
         * Wake lock level: Ensures that the CPU is running; the screen and keyboard
         * backlight will be allowed to go off.
         * <p>
         * If the user presses the power button, then the screen will be turned off
         * but the CPU will be kept on until all partial wake locks have been released.
         * </p>
         */
        public static final int PARTIAL_WAKE_LOCK = 0x00000001;
    
        /**
         * Wake lock level: Ensures that the screen is on (but may be dimmed);
         * the keyboard backlight will be allowed to go off.
         * <p>
         * If the user presses the power button, then the {@link #SCREEN_DIM_WAKE_LOCK} will be
         * implicitly released by the system, causing both the screen and the CPU to be turned off.
         * Contrast with {@link #PARTIAL_WAKE_LOCK}.
         * </p>
         *
         * @deprecated Most applications should use
         * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead
         * of this type of wake lock, as it will be correctly managed by the platform
         * as the user moves between applications and doesn't require a special permission.
         */
        @Deprecated
        public static final int SCREEN_DIM_WAKE_LOCK = 0x00000006;
    
        /**
         * Wake lock level: Ensures that the screen is on at full brightness;
         * the keyboard backlight will be allowed to go off.
         * <p>
         * If the user presses the power button, then the {@link #SCREEN_BRIGHT_WAKE_LOCK} will be
         * implicitly released by the system, causing both the screen and the CPU to be turned off.
         * Contrast with {@link #PARTIAL_WAKE_LOCK}.
         * </p>
         *
         * @deprecated Most applications should use
         * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead
         * of this type of wake lock, as it will be correctly managed by the platform
         * as the user moves between applications and doesn't require a special permission.
         */
        @Deprecated
        public static final int SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a;
    
        /**
         * Wake lock level: Ensures that the screen and keyboard backlight are on at
         * full brightness.
         * <p>
         * If the user presses the power button, then the {@link #FULL_WAKE_LOCK} will be
         * implicitly released by the system, causing both the screen and the CPU to be turned off.
         * Contrast with {@link #PARTIAL_WAKE_LOCK}.
         * </p>
         *
         * @deprecated Most applications should use
         * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead
         * of this type of wake lock, as it will be correctly managed by the platform
         * as the user moves between applications and doesn't require a special permission.
         */
        @Deprecated
        public static final int FULL_WAKE_LOCK = 0x0000001a;
    
        /**
         * Wake lock level: Turns the screen off when the proximity sensor activates.
         * <p>
         * If the proximity sensor detects that an object is nearby, the screen turns off
         * immediately.  Shortly after the object moves away, the screen turns on again.
         * </p><p>
         * A proximity wake lock does not prevent the device from falling asleep
         * unlike {@link #FULL_WAKE_LOCK}, {@link #SCREEN_BRIGHT_WAKE_LOCK} and
         * {@link #SCREEN_DIM_WAKE_LOCK}.  If there is no user activity and no other
         * wake locks are held, then the device will fall asleep (and lock) as usual.
         * However, the device will not fall asleep while the screen has been turned off
         * by the proximity sensor because it effectively counts as ongoing user activity.
         * </p><p>
         * Since not all devices have proximity sensors, use {@link #isWakeLockLevelSupported}
         * to determine whether this wake lock level is supported.
         * </p><p>
         * Cannot be used with {@link #ACQUIRE_CAUSES_WAKEUP}.
         * </p>
         */
        public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;
    
        /**
         * Wake lock level: Put the screen in a low power state and allow the CPU to suspend
         * if no other wake locks are held.
         * <p>
         * This is used by the dream manager to implement doze mode.  It currently
         * has no effect unless the power manager is in the dozing state.
         * </p><p>
         * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
         * </p>
         *
         * {@hide}
         */
        public static final int DOZE_WAKE_LOCK = 0x00000040;
    
        /**
         * Wake lock level: Keep the device awake enough to allow drawing to occur.
         * <p>
         * This is used by the window manager to allow applications to draw while the
         * system is dozing.  It currently has no effect unless the power manager is in
         * the dozing state.
         * </p><p>
         * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
         * </p>
         *
         * {@hide}
         */
        public static final int DRAW_WAKE_LOCK = 0x00000080;
    
        /**
         * Mask for the wake lock level component of a combined wake lock level and flags integer.
         *
         * @hide
         */
        public static final int WAKE_LOCK_LEVEL_MASK = 0x0000ffff;
    

    好了上面原版的英文注释给出了,先给读者5分钟看看,我们接着引入我对上述 WakeLock锁级别的理解,如下:

    //[PowerManager.java]
    	/*
    		当我们创建的WakeLock持有该类型的锁时候,即使我们按power按键使我们的Android
    		终端熄灭屏幕和键盘灯,CPU也不会进入休眠状态从而达到保持后台任务完美运行的目的
    		这种模式也是我们最经常用到的,如果对该锁特点用一句话概述就是:
    		保持CPU运转,但是键盘灯和屏幕可以关闭(人为,系统控制的譬如设置了多久没有用户操作)
            
            注意:屏幕和键盘灯不受该锁影响,可以正常熄灭不会导致该锁释放
    	*/
    	public static final int PARTIAL_WAKE_LOCK = 0x00000001;	
    	
    	
    	/*
    		注意:该WakeLock锁级别已经被标注为废弃
    		当我们创建的WakeLock持有该类型的锁时候,会保持屏幕亮着(此时屏幕也
    		可能会进入dimed状态,即我们屏幕在灭屏前的一种渐暗的状态),此时键盘可能会关闭
    		但是但是但是,当用户按power按键熄灭屏幕后也会释放该WakeLock锁,从而CPU会进入休眠状态
    		
    		如果对该锁特点用一句话概述就是:
    		保持CPU运转,屏幕会常亮(但是可能会进入渐暗状态),键盘灯可能关闭
    		
        	假如Android App应用想通过此种锁保持屏幕常亮,Android系统推荐如下方法(当Activity或view可见时,屏幕才保持常亮):
            在Activity.onCreate()中:  getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
            或在xml布局中: android:keepScreenOn="true"
            或对View设置:  view.setKeepScreenOn(true);
      
            屏幕相关的其它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   屏幕打开时允许锁屏
    	*/
        @Deprecated
        public static final int SCREEN_DIM_WAKE_LOCK = 0x00000006;
    
    
    	/*
    		注意:该WakeLock锁级别已经被标注为废弃
    		并且该类型的锁和前面的SCREEN_DIM_WAKE_LOCK非常类似,唯一的区别就是持有该锁屏幕
    		会一直保持最亮的模式,不会进入渐暗的模式
    		并且当用户按power按键熄灭屏幕后也会释放该WakeLock锁,从而CPU会进入休眠状态
    		
    		如果对该锁特点用一句话概述就是:
    		保持CPU运转,屏幕会常亮,键盘灯可能关闭
    
    		并且Android官方也是推荐替代的方案和SCREEN_DIM_WAKE_LOCK一样,这里就复制粘贴了
    	*/
        @Deprecated
        public static final int SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a;
    
    
    
    	/*
    		注意:该WakeLock锁级别已经被标注为废弃
    		持有该类锁的最大特点是键盘灯和屏幕保持常亮的状态
    		并且当用户按power按键熄灭屏幕后也会释放该WakeLock锁,从而CPU会进入休眠状态
    
    		如果对该锁特点用一句话概述就是:
    		保持CPU运转,屏幕会常亮,键盘灯都常亮
    
    		并且Android官方也是推荐替代的方案和SCREEN_BRIGHT_WAKE_LOCK一样,这里就复制粘贴了
    	*/
    	@Deprecated
    	public static final int FULL_WAKE_LOCK = 0x0000001a;
    
    	/*
    		该锁比较特殊,用于和距离传感器配合使用
    		持有该类型锁的特点是:当距离传感器检测到有物体(包括)靠近,会将屏幕熄灭
    		相反,当检测到物体远离后会点亮屏幕
    		上述锁不会影响终端的正常进入休眠状态,只有当前屏幕由该wakelock锁灭掉,才不会进入休眠状态
    		应用场景在通话中比较常见		
    	*/
    	public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;
    
    	/**************************************************************/
    	//上面的几个锁类型都是公开的,第三方App可以调用到的,下面的两个比较特殊是隐藏的
    	
    	/*
    		如果持有该锁,则会使屏幕处于DOZE状态,同时允许CPU挂起,该锁用于DreamManager实现Doze模式,
    		如SystemUI的DozeService
    		
    		Doze模式是在Android M中,Google就引入了Doze模式。它定义了一种全新的、低能耗的状态。
     		在该状态,后台只有部分任务被允许运行,其它任务都被强制停止
    	*/
    	public static final int DOZE_WAKE_LOCK = 0x00000040;
    
    	/*
    		如果持有该锁,则会使设备保持唤醒状态,以进行绘制屏幕,该锁常用于WindowManager中,
    		允许应用在系统处于Doze状态下时进行绘制
    	*/
    	public static final int DRAW_WAKE_LOCK = 0x00000080;
    

    上面咔咔一顿讲,自我感觉有点啰嗦了,但是我觉得吧,既然是写博客就应该整清楚,不能搞那种意犹未尽个的感觉。我们对上面的几种WakeLock锁整理一番,标注重点:

    • 如果想保持CPU一直运转不进入休眠(那怕是用户按power键主动灭屏),请使用PARTIAL_WAKE_LOCK级别类型锁

    • 如果是想保持屏幕常量,Android建议尽量使用getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)的方法,而不是使用WakeLock类型的锁了

    4.3.2 WakeLock锁几个常用的flag标志

    通过前面我们知道WakeLock锁不仅有各种级别,而且在同一个级别的时候采取不同的flag标志其表现形式也是不同的。让我们来探究一番(这里留下英文注释,读者可以自行理解,在最后我会加上自己的理解!最后可以比对比对,我们的理解是否一致)!

    //[PowerManager.java]
        /**
         * Mask for the wake lock level component of a combined wake lock level and flags integer.
         *
         * @hide
         */
        public static final int WAKE_LOCK_LEVEL_MASK = 0x0000ffff;
    
        /**
         * Wake lock flag: Turn the screen on when the wake lock is acquired.
         * <p>
         * Normally wake locks don't actually wake the device, they just cause
         * the screen to remain on once it's already on.  Think of the video player
         * application as the normal behavior.  Notifications that pop up and want
         * the device to be on are the exception; use this flag to be like them.
         * </p><p>
         * Cannot be used with {@link #PARTIAL_WAKE_LOCK}.
         * </p>
         */
        public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
    
        /**
         * Wake lock flag: When this wake lock is released, poke the user activity timer
         * so the screen stays on for a little longer.
         * <p>
         * Will not turn the screen on if it is not already on.
         * See {@link #ACQUIRE_CAUSES_WAKEUP} if you want that.
         * </p><p>
         * Cannot be used with {@link #PARTIAL_WAKE_LOCK}.
         * </p>
         */
        public static final int ON_AFTER_RELEASE = 0x20000000;
    
        /**
         * Wake lock flag: This wake lock is not important for logging events.  If a later
         * wake lock is acquired that is important, it will be considered the one to log.
         * @hide
         */
        public static final int UNIMPORTANT_FOR_LOGGING = 0x40000000;
    
        /**
         * Flag for {@link WakeLock#release WakeLock.release(int)}: Defer releasing a
         * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor
         * indicates that an object is not in close proximity.
         */
        public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1;
    

    好了上面原版的英文注释给出了,先给读者5分钟看看,我们接着引入我对上述 WakeLock的flag标志的的理解,如下:

    //[PowerManager.java]
    	
    	/*
    		注意此变量被标注为hide,则代表只能在系统内部使用
    		用于根据flag判断Wakelock的级别,如:
    		如内部方法中的validateWakeLockParameters判定WakeLock传入的的是否正确
    		levelAndFlags & WAKE_LOCK_LEVEL_MASK
    	*/
    	public static final int WAKE_LOCK_LEVEL_MASK = 0x0000ffff;
    
    	/*
    		通常wakelock锁并不会真的主动去点亮屏幕,它们只会导致屏幕打开后将保持打开状态
    		如果带有这个flag,则会在申请wakelock时就点亮屏幕,如常见通知来时屏幕亮,该flag不能和PowerManager.PARTIAL_WAKE_LOCE一起使用
    		这个flag标志通常用于,当我们用户在没有进入深休眠时,接到一个广播或者通知,主动来电量屏幕提醒用户某些通知
    
    	*/
    	public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
    
    	/*
    		
    		当我们盛情的锁,在被释放锁时(主动或者被动),如果wakelock带有该标志,则会小亮一会再灭屏(注意并不是说会点亮屏幕,而是说如果释放锁的时候屏幕是亮的),
    		该flag不能和PowerManager.PARTIAL_WAKE_LOCE一起使用。
    	*/
    	public static final int ON_AFTER_RELEASE = 0x20000000;
    
    	/*	
    		和其他标记不同,该标记是作为release()方法的参数,且仅仅用于释放PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK类型的
    	锁,如果带有该参数,则会延迟释放锁,直到传感器不再感到对象接近
    	*/
    	public static final int UNIMPORTANT_FOR_LOGGING = 0x40000000;
    

    关于WakeLock锁的flag标志位的不是很多,这几个flag主要起辅助的作用,WakeLock锁的关键还是由它的(level)级别决定的。那么WakeLock锁的级别和flag标志放在一起应该怎么使用呢,当然是通过"|"的操作了,实例如下:

    		mWakeLock = powerMg.newWakeLock(PowerManager.FULL_WAKE_LOCK
    				| PowerManager.ACQUIRE_CAUSES_WAKEUP
    				| PowerManager.ON_AFTER_RELEASE, "mWakeLock");
    

    4.4 WakeLock各种类型锁以及特点

    经过前面的一番猛烈攻击,我想读者对于WakeLock的各种锁应该有了初步的了解了,但是估计也还是有点云里雾里的,秉着撸到到底的原则,我们乘热打铁,将各种WakeLock各种类型锁整理成表格的形式(主要是持有该锁时,CPU工作状态,屏幕表现,键盘灯等的表现形式),突出重点直捣黄龙!

    levelAndFlagsCPU运行状态屏幕状态键盘灯状态锁的释放
    是否受Power
    按键影响
    备注以及需要注意地地方
    PARTIAL_WAKE_LOCK OnOn/OffOn/Off没有影响该锁比较特殊,是系列锁中释放状态唯一一个
    不受power按键影响的,必须主动或者待持锁时间到来才会释放
    SCREEN_DIM_WAKE_LOCK OnDim(低亮度)OffreleaseAPI17以后已经被弃用,改用WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
    用来替代该类型的锁
    SCREEN_BRIGHT_WAKE_LOCK OnBrightOffrelease同上
    SCREEN_BRIGHT_WAKE_LOCK OnBrightOffrelease同上
    FULL_WAKE_LOCK OnBrightBrightrelease同上
    PROXIMITY_SCREEN_OFF_WAKE_LOCK On/OfffBright/Offrelease不能和ACQUIRE_CAUSES_WAKEUP一起使用
    DOZE_WAKE_LOCK On/OffOffrelease@hide标注,允许在doze状态下使cpu进入suspend状态,仅在doze状态下有效,需要android.Manifest.permission.DEVICE_POWER权限
    DRAW_WAKE_LOCK On/OffOffNo@hide,允许在doze状态下进行屏幕绘制,仅在doze状态下有效,需要DEVICE_POWER权限
    ACQUIRE_CAUSES_WAKEUPWakelock 标记,一般情况下,获取wakelock并不能唤醒设备,加上这个标志后,申请wakelock后也会唤醒屏幕。如通知、闹钟… 不能和PARTIAL_WAKE_LOCK一起使用
    ON_AFTER_RELEASEWakelock 标记,当释放该标记的锁时,会亮一小会再灭屏(注意必须是释放之前屏幕的状态是亮的,而不是主动点亮),并且不能和PARTIAL_WAKE_LOCK一起使用

    是不是有点整懵了的感觉,其实我们只需记住一条一切只要从实际出发,抓取重点即可:

    • 假如想后台的某个任务一直运行申请PARTIAL_WAKE_LOCK的锁即可
    • 假如是想屏幕常量,使用getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)即可

    总之对于上述锁的类型,我们在获得WakeLock对象后,可以根据自己的需求来申请不同形式的锁,从而达到我们的最终目的即可!

    这里感觉还是有必要对上述表格解释一下:
    其中CPU运行状态:表示持有该锁的时候CPU会不会进入休眠状态
    屏幕状态:表示持有该类型锁的时候,屏幕的表现形式,譬如亮,灭,或者亮的时候状态
    键盘灯状态:表示持有该类型锁的时候,键盘灯的表现状态
    锁的释放是否受Power按键影响:表示按power按键,是否会导致持有的WakeLock锁被释放

    对于应用开发者来说,上述的锁只能申请非@hide的锁,即PARTIAL_WAKE_LOCK、SCREEN_DIM_WAKE_LOCK、SCREEN_BRIGHT_WAKE_LOCK、FULL_WAKE_LOCK四类,这个需要留意一下




    五.WakeLock锁调用流程分析

    本来是将调用流程放在这篇博客中进行相关的分析,然后一网打尽的!但是分析分析着,一看这内容有点多啊,所以这个章节放在后面单独成一个博客来分析!但是我们可以简单的看下其整体框架调用流程图,如下:

    在这里插入图片描述
    总之WakeLock锁从用户空间下发设置操作,然后进入kernel空间,最终写入到了/sys/power/wake_lock文件节点,和我们的章节4.2的Native层使用WakeLock锁徐途同归!

    并且我们这里需要注意地是上层应用获取锁时传递个wake_lock的信息为PowerManagerService.WakeLocks

    //[power.c]
    enum {
        ACQUIRE_PARTIAL_WAKE_LOCK = 0,
        RELEASE_WAKE_LOCK,
        OUR_FD_COUNT
    };
    
    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",
    };
    
    //XXX static pthread_once_t g_initialized = THREAD_ONCE_INIT;
    static int g_initialized = 0;
    static int g_fds[OUR_FD_COUNT];
    static int g_error = -1;
    
    static int
    open_file_descriptors(const char * const paths[])
    {   
        int i;
        for (i=0; i<OUR_FD_COUNT; i++) {
            int fd = open(paths[i], O_RDWR | O_CLOEXEC);
            if (fd < 0) { 
                g_error = -errno;
                fprintf(stderr, "fatal error opening \"%s\": %s\n", paths[i],
                    strerror(errno));
                return -1;
            }
            g_fds[i] = fd;
        }
    
        g_error = 0;
        return 0;
    }
    
    static inline void
    initialize_fds(void)
    {
        // XXX: should be this:
        //pthread_once(&g_initialized, open_file_descriptors);
        // XXX: not this:
        if (g_initialized == 0) {
            if(open_file_descriptors(NEW_PATHS) < 0)
                open_file_descriptors(OLD_PATHS);
            g_initialized = 1;
        }
    }
    
    //获取锁
    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;
        size_t len;
        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;
    }
    
    //释放锁
    int
    release_wake_lock(const char* id)
    {
        initialize_fds();
    
    //    ALOGI("release_wake_lock id='%s'\n", id);
    
        if (g_error) return g_error;
    
        ssize_t len = write(g_fds[RELEASE_WAKE_LOCK], id, strlen(id));
        if (len < 0) {
            return -errno;
        }
        return len;
    }
    



    六.WakeLock相关问题的debug调试方法

    在本篇博客的第三节中我们有详细介绍了WakeLock锁的使用方法,那么在使用使用过程中,我们除开根据实际使用效果确定WakeLock锁是否有生效外,还有没有更加快捷的方法呢?这个肯定有,这里就给大伙安排上!


    6.1 应用层使用WakeLock锁的Debug调试

    只能说Android为了我们的开发能流畅的进行,为我们提供了强大的命令工具dumpsys,我们可以借助它实现监控应用层WakeLock锁的功能。我们先看下没有执行任何锁的前提下的情况:

    λ adb shell dumpsys power | grep -i wake
      mWakefulness=Dozing
      mWakefulnessChanging=false
      mWakeLockSummary=0x40
      mLastWakeTime=4068623 (137029 ms ago)
      mHoldingWakeLockSuspendBlocker=false
      mWakeUpWhenPluggedOrUnpluggedConfig=true
      mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
      mDoubleTapWakeEnabled=false
    Wake Locks: size=1			
      DOZE_WAKE_LOCK                 'DreamManagerService' ACQ=-1m16s43ms (uid=1000 pid=4346)
      PowerManagerService.WakeLocks: ref count=0
    

    可以看到上述持有一个DOZE_WAKE_LOCK 类型的锁,这个后面会介绍到!

    下面我们来申请一个锁,执行代码如下:

    public class WakeLockTest extends Activity {
        PowerManager.WakeLock mWakeLock;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.viewtest);
    
            PowerManager mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
            mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                    "WakeLock_FUN");
            mWakeLock.acquire();// 获取锁
        }
    
        @Override
        protected void onPause() {
            // TODO Auto-generated method stub
            super.onPause();
            if (mWakeLock.isHeld())
                mWakeLock.release();// 获取锁
        }
    }
    

    我们来看下此时的实际情况如何:

    λ adb shell dumpsys power | grep -i wake
      mWakefulness=Awake
      mWakefulnessChanging=false
      mWakeLockSummary=0x1
      mLastWakeTime=4353954 (17858 ms ago)
      mHoldingWakeLockSuspendBlocker=true
      mWakeUpWhenPluggedOrUnpluggedConfig=true
      mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
      mDoubleTapWakeEnabled=false
    Wake Locks: size=1
      PARTIAL_WAKE_LOCK              'WakeLock_FUN' ACQ=-6s372ms (uid=1000 pid=7182)
      PowerManagerService.WakeLocks: ref count=1
    

    这里可以看到申请到了一个PARTIAL_WAKE_LOCK类型的锁,并且其tag为WakeLock_FUN’和我们代码申请的对上了。


    6.2 Native层使用WakeLock锁的Debug调试

    这个就没有好说的了,简单明了直接通过cat查看wake_lock节点即可,如下:

    xxx:/ # cat /sys/power/wake_lock
    PowerManagerService.Display native_wake_lock
    

    6.3 Android系统层的WakeLock锁的Debug调试

    系统层的WakeLock锁Debug级别调试起来就比较复杂了,这个涉及的知识层面比较多,并且需要对PowerManagerService有比较深入的了解和掌握了,这个属于高阶的范畴了,但是我们的dumpsy power依然能排上用场,并且最好将PowerManagerService中的调试DEBUG打开!

    关于这个我就不过多的介绍了,感兴趣的读者可以详读如何分析WakeLock持锁问题




    写在最后

      到这里,本篇从Android应用层及Framework层的角度分析WakeLock锁机制就到这里了,通过这篇博客我想读者应该对WakeLock有了一个比较深入的了解了,无论是从它的设计角度出发,使用场景,具体的使用应该都是得心应手的了。限于篇幅这里还有所欠缺的是WakeLock锁的调用流程的详细分析,这个我们将会在后面的博客中补上。如果本篇博客对你有所帮助,欢迎点赞和评论,当然也可以拍砖,总之欢迎留下你的脚步!

    展开全文
  • 固然也能够在挪用IntentFilter工具的setPriority()要领举行设置 Wakelock 锁机制: 运用程序可以通过要求 wakelock 锁的机制来对系统是否待机作出投票,当有任何一个运用要求了 wakelock 锁,待机时没有开释掉,系统...

    少许手机app(如微信、QQ等)有新消息来到达,手机屏幕即使在锁屏状况下也会亮起,并提示用户有新消息。不过,普通环境动手机锁屏后,Android系统为了省电以及削减CPU花消,在一段光阴后会使系统进入休眠状况,这时,Android系统中CPU会保持在一个相对较低的功耗状况,而收到新消息必定有网页要求,而网页要求是花消CPU的操纵,辣么若何在锁屏状况甚至系统进入休眠后,仍旧保持系统的网页状况以及通过程序唤醒手机呢?答案即是Android中的WakeLock机制。

    官方对付WakeLock的解释:

    PowerManager:This class gives you control of the power state of the device.

    PowerManager.WakeLock: lets you say that you need to have the device on.

    Android 系统支撑运用程序及服无在待机前留存程序运行状况,如待机前关闭文件读写、usb 操纵、停息音乐播放;也支撑唤醒后的程序状况恢复,如恢复翻开文件举行读写操纵,恢复 usb 操纵、恢复音乐播放等。这些状况的留存和恢复功效可以包管系统在待机唤醒后能平常事情。

    要紧供应两种方式:

    1、待机播送消息和唤醒播送消息。

    2、Wakelock 锁机制。

    分为两个片面申明一下:

    1、android 系统待机处分机制

    待机播送消息和唤醒播送消息

    系统在 PowerManagerService 类中注册了 2 个播送分别用于待机前和唤醒后发送。

    void initInThread(){

    //唤醒后:

    mScreenOnIntent=newIntent(Intent.ACTION_SCREEN_ON);//唤醒后发送

    mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);

    //待机前:

    mScreenOffIntent=newIntent(Intent.ACTION_SCREEN_OFF);//待机时发送

    mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);

    }

    这里顺带申明一下播送汲取的优先级问题:

    汲取者按照在 Manifest.xml 文件中设置的汲取挨次顺次汲取Intent,挨次实行的,汲取的优先级可以在系统配置文件中设置:

    申明在intent-filter元素的android:priority 属性中,数值越大优先级别越高,其取值局限为-1000到1000。固然也能够在挪用IntentFilter工具的setPriority()要领举行设置

    Wakelock 锁机制:

    运用程序可以通过要求 wakelock 锁的机制来对系统是否待机作出投票,当有任何一个运用要求了 wakelock 锁,待机时没有开释掉,系统是不会进入待机的,直到全部运用的 wakelock 锁都开释掉了,才会进入待机。

    2、运用程序运用要领:

    实例代码:

    [java] view plaincopyprint?

      private WakeLock wakeLock = null;

    /**

    * 获取电源锁,保持该服无在屏幕熄灭时仍旧获取CPU时,保持运行

    */

    private void acquireWakeLock() {

    if (null == wakeLock) {

    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);

    wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK

    | PowerManager.ON_AFTER_RELEASE, getClass()

    .getCanonicalName());

    if (null != wakeLock) {

    Log.i(TAG, "call acquireWakeLock");

    wakeLock.acquire();

    }

    }

    }

    // 开释建筑电源锁

    private void releaseWakeLock() {

    if (null != wakeLock && wakeLock.isHeld()) {

    Log.i(TAG, "call releaseWakeLock");

    wakeLock.release();

    wakeLock = null;

    }

    }

    private WakeLock wakeLock = null;

    /**

    * 获取电源锁,保持该服无在屏幕熄灭时仍旧获取CPU时,保持运行

    */

    private void acquireWakeLock() {

    if (null == wakeLock) {

    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);

    wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK

    | PowerManager.ON_AFTER_RELEASE, getClass()

    .getCanonicalName());

    if (null != wakeLock) {

    Log.i(TAG, "call acquireWakeLock");

    wakeLock.acquire();

    }

    }

    }

    // 开释建筑电源锁

    private void releaseWakeLock() {

    if (null != wakeLock && wakeLock.isHeld()) {

    Log.i(TAG, "call releaseWakeLock");

    wakeLock.release();

    wakeLock = null;

    }

    }

    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:当锁被开释时,保持屏幕亮起一段光阴

    末了 AndroidManifest.xml 申明权限:

    运用程序中如果要在待机前留存数据状况的话,要包管此过程当中不会进入待机。可以在 onResume() 大概 onStart() 中要求 wakelock 锁,即挪用acquireWakeLock()要领。

    在 onPause() 大概 onDistroy() 中处分运用待机后再开释掉 wakelock 锁,此时挪用releaseWakeLock()要领

    末了一点必要留意下:

    另外WakeLock的设置是 Activiy 级另外,不是针对全部Application运用的。以是application下有多个activity必然必要留意下!

    展开全文
  • step_counter_with_wakeLock 尝试让唤醒锁保持 step_counter 唤醒的测试,因为它实际上在屏幕关闭后立即关闭。 我已经修改了的代码,以检查 WakeLock 是否对我的三星 S4 有帮助:没有任何人可以帮忙吗?
  • Android中的WakeLock使用

    2021-05-27 01:47:57
    android系统在手机屏幕锁定之后一般会让手机休眠,以提高电池的使用时间...WakeLock可以做到这一点。###WakeLock的创建是:PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);Wakelock w...
  • 如果是通过`acquire(long timeout)`方法申请的超时锁,则会在到达时间后自动去释放,如果是通过`acquire()`方法申请的永久锁,则必须进行显式的释放,否则由于系统一直持有`wakelock`锁,将导致无法进入休眠状态,...
  • Android wakeLock 分析

    万次阅读 2019-01-17 09:17:15
    应用中获取wakelock对象,获取的是位于PowerManager中的内部类——WakeLock的实例,在PowerManager中看看相关方法: public WakeLock newWakeLock(int levelAndFlags, String tag) { ...
  • java.lang.RuntimeException: WakeLock under-locked target at android.os.PowerManager$WakeLock.release(PowerManager.java:2665) at android.os.PowerManager$WakeLock.release(PowerManager.java:2627) at ...
  • 该APP作用:存在2个wakeLock,旨在触发功耗异常中的wakeLock频繁唤醒的检测 永久不释放wakeLock 定时申请和释放wakeLock 测试方法: H手机和T手机、其他手机进行安装该apk. 所有手机都需要设置应用为白名单。 H...
  • 1、PowerManager.WakeLock WakeLock翻译过来意思为:唤醒锁。作用就是用于保持设备运行,如手机熄屏后可能CPU就停止运转了,通过获取唤醒锁,就可以保持CPU不停止。此功能需要android.permission.WAKE_LOCK权限。 ...
  • 前面我们介绍Doze模式的时候介绍过WakeLock白名单,WakeLock进入Doze接口等。这篇博客我们详细分析下,WakeLock在Doze模式下如何生效。设置白名单在DeviceIdleController中我们调用PowerManagerService的如下接口,...
  • Android中的WakeLock

    2020-12-30 10:55:50
    一种锁机制 当应用申请了WakeLock,WakeLock会阻止AP挂起,系统无法进入休眠,即使在灭屏的状态下,应用要执行的任务依然不会被打断。当所有WakeLock被释放(解锁/超时),系统会挂起启动休眠机制进入休眠。 使用...
  • Android WakeLock简介

    千次阅读 2021-02-07 21:24:33
    WakeLock简介 WakeLock是一种表示应用程序需要让设备继续运行的机制,下载文件或者听音乐等等,设备在灭屏状态下,还需要继续运行,如果设备进入休眠,听音乐突然停止了,不符合使用场景。Android设备通过WakeLock...
  • WakeLock是android系统中一种锁的机制,只要有进程持有这个锁,系统就无法进入休眠状态。应用程序要申请WakeLock时,需要在清单文件中配置android.Manifest.permission.WAKE_LOCK 权限。
  • Android WakeLock版本坑

    2021-05-27 01:46:34
    今天发现之前用的这个方法val pm = getSystemService(Context.POWER_SERVICE) as PowerManagerpm.newWakeLock(FLAG_KEEP_SCREEN_ON, "KEEP")在6.0以下的机子会报错,报了如下错误...去看了源码:public WakeLock new...
  • Android wakelock && suspend

    2020-10-27 22:07:13
    suspend一、Wakelock1.1 WakeLock说明1.2 WakeLock使用1.3 PMS下WaeLock从上到下流程图1.4 wakelock sysfs节点1.5 wakeup_sources1.6 wakelock architecture二、Suspend2.1 Suspend从上到下流程图总结 由于博主...
  • android wakelock

    2019-12-05 09:49:39
    1.android休眠控制锁 powermanager.acquir();...2.在powerManagerService中,有检测当前framework层中的wakelock锁的,并判断当前锁的状态。 private void updateWakeLockSummaryLocked(int dirty) { ...
  • Android Wake Lock机制

    2021-01-12 18:21:23
    PowerManager.WakeLockpublic final class PowerManager.WakeLockextends Objectjava.lang.Object↳android.os.PowerManager.WakeLockA wake lock is a mechanism to indicate that your application needs to have ...
  • 不让应用持有wakelock锁,主要是注释掉请求锁和释放锁 实现 diff --git a/frameworks/base/core/java/android/os/PowerManager.java b/frameworks/base/core/java/android/os/PowerManager.java index 87b856d.....
  • Android WakeLock使用的一个注意点

    千次阅读 2022-03-07 20:43:29
    先看看下面这个函数写的有没有问题? public void wakeUpTest(Context context) { ... PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "awakelock"); wl.acquire(); }.
  • WakeLock的使用

    2019-11-19 00:05:40
    参考 Android WakeLock详解
  • 一.使用PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_...PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyTAG");wakeLock.acquire();在Manife...
  • private PowerManager.WakeLock sCpuWakeLock;private void acquireCpuWakeLock(Context context) {if (sCpuWakeLock != null) {return;}Log.v(TAG3, "acquireCpuWakeLock");sCpuWakeLock = createPartialWakeLock(c...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 44,934
精华内容 17,973
关键字:

wakeLock