前言
在学习Android系统待机模块前,想先把和电源管理相关基础知识整理下,以及linux系统底层待机和Android系统待机的对应关系,以及Android系统各个待机状态之间的关系。
参考文献
(1) https://www.jianshu.com/p/cc553c9c75b0
(2) http://www.wowotech.net/pm_subsystem/237.html
(3) https://blog.csdn.net/feifei_csdn/article/details/80831373
(4) https://source.android.google.cn/devices/tech/power/mgmt?hl=zh-cn#exempt-apps
ACPI简介
ACPI是一种规范(包含软件与硬件),用来供操作系统应用程序管理所有电源接口。
ACPI将计算机系统的状态划分为四个全局状态(G0-G3),共7个状态,其中G0对应S0;G1将低功耗状态细分为四个状态,对应S1-S4;G2、G3代表关机状态分别对应S5、S6。
ACPI State | Description |
---|---|
S0 | 正常工作状态 |
S1 | CPU和内存正常供电,但是CPU不执行指令 |
S2 | 一种比S1更深的睡眠状态,停止CPU的电源供应,这种模式通常并不被采用 |
S3 | 挂起到内存, RAM是唯一的有电源供应的组件 |
S4 | 挂起到硬盘,所有内存的内容被储存在硬盘,存储操作系统当前的状态 |
S5 | Soft Off,CPU、外设等断电,但电源依旧会为部分极低耗设备供电 |
S6 | Mechanical Off,全部断电 |
Linux电源状态
在Linux系统中,电源管理划分为如下几个状态
ACPI State | Linux State | Description |
---|---|---|
S0 | On(on) | Warking |
S1 | Standby(standby) | CPU and RAM are powered but not executed |
S2 | ------ | ------- |
S3 | Suspend to RAM(mem) | CPU is Off,RAM is powered and the running content is saved to RAM |
S4 | Suspend to Disk(disk) | All content is saved to Disk and power down |
S5 | Shutdown | Shutdown the system |
On: 正常工作状态
STR(Suspend to RAM):
挂起到内存,俗称待机、睡眠(Sleep),进入该状态,系统的主要工作如下:
1、将系统当前的运行状态等数据保存在内存中,此时仍需要向RAM供电,以保证后续快速恢复至工作状态
2、冻结用户态的进程和内核态的任务(进入内核态的进程或内核自己的task)
3、关闭外围设备,如显示屏、鼠标等,中断唤醒外设不会关闭,如电源键
4、CPU停止工作
Standby也属于睡眠的一种方式,属于浅睡眠。该模式下CPU并未断电,依旧可以接收处理某些特定事件,视具体设备而定,恢复至正常工作状态的速度也比STR更快,但也更为耗电。举个例子来说,以该方式进入睡眠时,后续通过点击键盘也能将系统唤醒。而以mem进入的睡眠为深度睡眠,只能通过中断唤醒设备唤醒系统,如电源键(此时按电源键,不会经过正常的开机流程的BIOS、BOOTLOAD等),此时按键盘是无法唤醒系统的。
STD(Suspend to Disk):
挂起到硬盘,俗称休眠(Hibernation)将系统当前的运行状态等数据保存到硬盘上,并自动关机。下次开机时便从硬盘上读取之前保存的数据,恢复到休眠关机之前的状态。
譬如在休眠关机时,桌面打开了一个应用,那么下一次开机启动时,该应用也处于打开状态。而正常的关机-开机流程,该应用是不会打开的。
freeze、standby、mem、disk四个电源状态##
从linux用户角度看,设置系统待机对应的ACPI状态,这样会熟悉些。
ACPI State | Linux State | Linux kernel Label | Description |
---|---|---|---|
S0 | freeze | s2idle | Suspend-To-Idle |
S1 | standby | shallow | Standby / Power-On Suspend |
S3 | mem | deep | Suspend-to-RAM |
S4 | disk | --- | Suspend-to-disk |
S5 | Shutdown | --- | Shutdown the system |
Linux内核代码声明如下,位于kernel/power/suspend.c
44 const char * const pm_labels[] = {
45 [PM_SUSPEND_TO_IDLE] = "freeze",
46 [PM_SUSPEND_STANDBY] = "standby",
47 [PM_SUSPEND_MEM] = "mem",
48 };
49 const char *pm_states[PM_SUSPEND_MAX];
50 static const char * const mem_sleep_labels[] = {
51 [PM_SUSPEND_TO_IDLE] = "s2idle",
52 [PM_SUSPEND_STANDBY] = "shallow",
53 [PM_SUSPEND_MEM] = "deep",
54 };
Android电源管理
Android系统是有非常多的系统服务和应用,所以Android系统电源管理主要集中在应用电源管理上,Google也添加了很多限制措施,限制不良应用。
应用限制 | 平台可以提示哪些应用会对电池续航时间产生不利影响,以便用户可以对这些应用施加限制,防止它们消耗资源。默认情况下,应用不会在后台受到限制。 |
---|---|
应用待机模式 | 平台会使未使用的应用进入应用待机模式,从而暂时限制此类应用访问网络,并延迟其同步和作业。 |
低电耗模式 | 如果用户长时间没有主动使用其设备(处于静止状态且屏幕已关闭),则平台会使设备进入深度休眠状态(定期恢复正常操作)。此外,当用户关闭设备屏幕但仍处于移动状态时,Android 7.0 及更高版本还会启用低电耗模式,以触发一系列轻度优化。 |
豁免 | 默认情况下,预加载的系统应用和云消息传递服务通常能够获得豁免,不会进入应用待机模式和低电耗模式。应用开发者可以使用 Intent 将这些设置应用于其应用。用户可以在“设置”菜单中豁免无需进入应用待机和低电耗节电模式的应用。 |
- 应用显示和应用待机模式有时间在研究它的实现原理,先聚焦分析下系统低电耗模式,Android6.0开始引入低电耗和应用待机模式。
-
在屏幕关闭期间、设备处于空闲状态之前,Android 7.0 及更高版本通过启用轻度休眠模式来延长设备处于低电耗模式的时间。
低功耗模式 - 低电耗模式,应该就是系统休眠,唤醒,Cpu Idle,限制网络...等系系列管理实现的,我们重点研究下系统低电耗模式的实现,先了解下Idle State。
Idle State
Android上的Idle状态分为二类:Cpu Idle和Device Idle
Cpu Idle
Linux系统运行的基础是基于进程调度,实际上内核调度的线程(task),内核并不会区分线程与进程,都将他们当做一个线程(task)来处理;当所有的进程都没事儿干的时候,系统就会启用idle进程,使系统进入低功耗状态(如关闭一些服务、模块功能,降低CPU工作频率等),即idle状态,以达到省电的目的。
idle状态又可以划分为不同的层级,以MTK的芯片为例,通常划分为以下几个状态:
状态 | 描述 |
---|---|
soidle(screen on idle) | 亮屏 Idle 模式,该模式下与正常工作状态差别不大,唯一的区别就cpu处于空闲状态 |
rgidle | 浅度 Idle 模式,cpu处于 WFI(wait for interrupt),屏幕熄灭,同时关闭一些不需要的服务及模块,注意此状态cpu的时钟源与RTC模块是工作正常的,此时是可以通过TimerTask的定时触发激活系统的,TimerTask依赖于CPU的RTC模块,而Alarm则依赖于PMIC的RTC模块 |
dpidle(deep idle) | 深度idle模式,该模式下cpu的时钟源和hrtimer(高精度定时器模块(RTC))被关闭,所有进程(包括系统进程)被冻结,即进入上文所述的睡眠状态 |
idle进程是由原始进程(pid=0)在初始化init进程(pid=1)之后演变而来,可以说是init进程的祖先,关于其详细介绍可参考如下链接:
Linux Idle基础
魅族内核团队:CPUIDLE 之低功耗定时器
Device Idle
Device Idle属于Doze模式中概念,即指当手机屏幕熄屏、不充电、静置不动,有网友分析了源码,指出6.0手机需要静置1时4分30秒才能进入Doze模式。
Doze模式的限制 |
---|
网络接入被暂停 |
系统忽略wake locks |
标准的AlarmManager alarms(包括setExact()和setWindow())被延缓到下一个maintenance window |
如果你需要在Doze状态下启动设置的alarms,使用setAndAllowWhileIdle()或者setExactAndAllowWhileIdle()。当有setAlarmClock()的alarms启动时,系统会短暂退出Doze模式 |
系统不会扫描Wi-Fi |
系统不允许sync adapters运行 |
系统不允许JobScheduler运行 |
结合上文分析的cpu idle不难发现Doze模式中的idle状态在概念属于浅idle状态,只是关闭了一些特定服务和模块,并非立即进入睡眠,当然这个过程当中依旧有可能满足睡眠条件而进入睡眠状态
Android电源管理框架
Android电源管理框架WakeLock
唤醒锁,一种锁机制,用于阻止系统进入睡眠状态,只要有应用获取到改锁,那么系统就无法进入睡眠状态。
该机制起初是早期Android为Linux内核打得一个补丁,并想合入到linux内核,但被Linux社区拒绝,后续Linux内核引入自己的Wakelock机制,Android系统也使用的是linux的Wakelock机制,所以该机制并非Android特有的机制。
Android系统提供了两种类型的锁,每一个类型又可分为超时锁与普通锁,超时锁,超时会自动释放,而普通锁则必需要手动释放:
类型 描述
WAKE_LOCK_SUSPEND | 阻止系统进入睡眠状态(STR) |
---|---|
WAKE_LOCK_IDLE | 阻止系统从idle进程进入那些具有较大中断时延、禁用了较多中断源的低功耗状态(睡眠除外),持有该类型的锁,不影响系统进入睡眠状态。自Android API-17(对应android linux内核版本3.4)移除了该类型的唤醒锁 |
应用层提供的锁类型如下,这些锁都需要手动释放:
FLAG | CPU | 屏幕 | 键盘 |
---|---|---|---|
PARTIAL_WAKE_LOCK | 开启 | 关闭 | 关闭 |
SCREEN_DIM_WAKE_LOCK | 开启 | 变暗 | 关闭 |
SCREEN_BRIGHT_WAKE_LOCK | 开启 | 变亮 | 关闭 |
FULL_WAKE_LOCK | 开启 | 变亮 | 变亮 |
网友评论