android提供了四种类型的闹钟:
❑ ELAPSED_REALTIME
在指定的延时过后,发送广播,但不唤醒设备。
❑ ELAPSED_REALTIME_WAKEUP
在指定的演示后,发送广播,并唤醒设备延时是要把系统启动的时
间SystemClock.elapsedRealtime()算进去的,具体用法看代码。
❑ RTC
在指定的时刻,发送广播,但不唤醒设备
❑ RTC_WAKEUP
在指定的时刻,发送广播,并唤醒设备.
public static final int ELAPSED_REALTIME
// 当系统进入睡眠状态时,这种类型的闹铃不会唤醒系统。直到系统下次被唤醒才传递它,该闹铃所用的时间是相对时间
,是从系统启动后开始计时的,包括睡眠时 间,可以通过调用SystemClock.elapsedRealtime()获得。系统值是3 (0x00000003)。
public static final int ELAPSED_REALTIME_WAKEUP
//能唤醒系统,用法同ELAPSED_REALTIME,系统值是2 (0x00000002) 。
public static final int RTC
//当系统进入睡眠状态时,这种类型的闹铃不会唤醒系统。直到系统下次被唤醒才传递它,该闹铃所用的时间是绝对时间,所用时间是UTC
时间,可以通过调用 System.currentTimeMillis()获得。系统值是1 (0x00000001) 。
public static final int RTC_WAKEUP
//能唤醒系统,用法
同RTC类型,系统值为 0 (0x00000000) 。
Public static final int POWER_OFF_WAKEUP
//能唤醒系统,它是一种关机闹铃,就是说设备在关机状态下
也可以唤醒系统,所以我们把它称之为关机闹铃。使用方法同RTC类型,系统值为4(0x00000004)。
————————————————
2.4 wakeup debug mask
调试wakeup问题,可以使能debug功能,然后抓取log。Log中会增加一些debug信息。
mount -t debugfs none /sys/kernel/debug
echo 1 > /sys/kernel/debug/clk/debug_suspend
echo 1 > /sys/module/msm_show_resume_irq/parameters/debug_mask
echo 4 > /sys/module/wakelock/parameters/debug_mask
echo 1 > /sys/module/lpm_levels/parameters/debug_mask
echo 0x16 > /sys/module/smd/parameters/debug_mask
1、wakeup_sources
kernel wakelock和userspace wakelock都有可能阻止系统睡眠。所有的wakeup_sources均保存在sys节点/sys/kernel/debug/wakeup_sources里面。
该文件包含了如下信息:
(1)the total amount of time a wakeup source has prevented suspend
(2)the amount of time a wakelock has been active since the last activation etc. The unit of time is milliseconds.
active_count: 对应wakeup source被激活的次数.
event_count: 被信号唤醒的次数
wakeup_count: 中止suspend的次数.
expire_count: 对应wakeup source超时的次数.
active_since: 上一次还活跃的时间点.时间单位跟kernel log前缀时间是一样(kernel单调递增时间).
total_time: 对应wakeup source活跃的总时长.
max_time: 对应的wakeup source持续活跃最长的一次时间.
last_change: 上一次wakeup source变化的时间(从持锁到释放or释放到持锁),时间单位跟kernel log前缀时间是一样(kernel单调递增时间).
prevent_suspend_time: 对应wakeup source阻止进入autosleep的总累加时间.
Sleep 、suspend
这里的suspend确切的说是MCU(ARM )的 suspend,也就是cpu进入Wait for interrupt 状态(WFI);因为对整个系统来说,CPU进WFI是整个系统睡眠的先决条件,我们debug也是从CPU是否进入WFI
开始,从Linux的角度来说,CPU进入suspend就是SW完全不跑了,停在suspend workqueue里面。
因为整个系统不只是AP(MCU),还包括modem、connectivity等子系统;
CPU 进入 WFI 后,整个系统就依靠一颗 SCP:SPM 来控制睡眠/唤醒的流程,它会去关注各个子系统的状态
SPM =System Power Manager
它掌控着cpu suspend之后系统是否能掉到最小电流的关键逻辑,你可以把它理解成一个投票机制,当系统的关键资源(memory、clock)没有任何人使用的时候,它就会让系统进入一个真正的深睡状
态(最小电流)只要它检测到有任何资源请求还没释放,系统就无法降到底电
所以在底电问题上的debug流程中,我们不仅仅要看cpu有没有suspend成功,还要看SPM的状态是否正确,SPM里面有一个可编程控制器PCM(Programmable Command Master)。CPU在进去WFI之前会把
SPM的firmware写入PCM,然后PCM就依据firmware的逻辑来控制SPM的工作
跟SPM强相关的一个东西就是系统中的时钟请求信号,也就是26M时钟开关的控制逻辑;因为系统工作在最小电流的时候,SPM只依靠32K时钟工作;因此要判断系统是不是已经到深睡状态,就要看26M有
没有关闭
Deep idle 基本概念
首先顾名思义,这是一种CPU进入空闲后的状态,也就是在idle进程中执行的
简单地说,Mediatek会在CPU进入空闲的情况下,再去关闭一些不必要的power domain,以达到最省电的目的,因为CPU空闲的时候,其实系统中有不少的domain也是不需要运行的,不这样做的话,就
仅仅是CPU这块的电省下来 ,达不到省电的目的。
Mediatek的做法是在CPU在进入idle进程后,会去判断当前系统的状态是否满足进入更省电状态的条件,首先就会检查是否能进入deep idle,因为dpidle最省电
系统进入dpidle需要满足的条件是
单核(BY_CPU)
预设的能block deep idle的所有clock都已经关闭(BY_CLOCK)
CPU在2ms内没有从idle task调度出去的需求(BY_TMR)
BY_VTG / BY_OTH的case很少(BY_OTH在个别平台跟TEE(SPI指纹模块)有关)
我们可以从波形上检查系统是否进入deep idle
如何看SPM的状态是否正确
待机被唤醒之后,确认:大部分debug_flag最后的bit位是不是 f or ff, 说明系统还有模块咬住26M,系统并没有最后进入真正的suspend.
譬如下面的log 最后bit 位是 0 都是有问题的:
<4>[ 250.874040] -(0)[1244:system_server][SPM] wake up byCONN2AP, timer_out = 8635, r13 = 0x20045038, debug_flag = 0x9 0
<4>[ 600.704307] -(0)[2722:system_server][SPM] wake up by R12_EINT_EVENT_B, timer_out = 81779, r13 = 0xe040000, debug_flag = 0x113f0
影响手机功耗的主要是wakelock,JobScheduler,alarm,GPS,wifi等,针对这些情况功耗优化可以从以下几个方面入手
-
使能doze模式(需要motion sensor支持,doze第一阶段不需要motion sensor),在手机处于完全禁止待机的时候,doze模式对手机的功耗很有帮助,doze模式下会影响全局的wakelock,alarm,job
,网络等
-
将有限制条件出发的service更换为JobScheduler,因为在创建JobScheduler时可以设置相应的触发条件才执行(比如条件 需要连网状态、需要充电状态),触发条件交由系统来管理
-
wakelock.acquice()方法最好带超时参数,因为有些网络请求很慢导致系统一直持续wake状态
- 监听电池电量和充电状态来决定后台更新
-
监测联网状态,重复闹铃和后台服务的一些最常见用途是安排定期从互联网资源、缓存数据更新应用数据,或者执行长时间下载,如果监测到没有网络连接就不要唤醒设备
-
对于流氓软件频繁后台唤醒可以采用心跳对齐(alarm)
————————————————