Android电源管理基础知识整理
前言
- 待机、睡眠与休眠的区别?
- Android开发者官网当中提到“idle states”,该如何理解,这个状态会对设备及我们的程序造成何种影响?
- 进入Doze模式中的idle状态,我们的程序还能运行吗?
- 手机睡眠之后,为何我们写Alarm程序、来电显示程序依旧会生效?
如果你也有以上疑问,那么本文会对你解开疑惑有一定的帮助
ACPI简介
要理解第一个问题,得先从ACPI(高级配置与电源接口)说起,ACPI是一种规范(包含软件与硬件),用来供操作系统应用程序管理所有电源接口。
ACPI将计算机系统的状态划分为四个全局状态(G0-G3),共7个状态,其中G0对应S0;G1将低功耗状态细分为四个状态,对应S1-S4;G2、G3代表关机状态分别对应S5、S6。
| ACPI State | Description |
|---|---|
| S0 | 正常工作状态 |
| S1 | CPU与RAM供电正常,但CPU不执行指令 |
| S2 | 比S1更深的一个睡眠层次,这种模式通常不采用 |
| S3 | 挂起到内存 |
| S4 | 挂起到硬盘 |
| S5 | Soft Off,CPU、外设等断电,但电源依旧会为部分极低耗设备供电 |
| S6 | Mechanical Off,全部断电 |
这里只需要对ACPI的七个状态有个大致了解即可,下一节会有具体的例子来说明各个状态。
Linux系统电源状态
在Linux操作系统中,将电源划分为如下几个状态:
| ACPI | State | Linux State Description |
|---|---|---|
| S0 | On(on) | Working |
| 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)将系统当前的运行状态等数据保存到硬盘上,并自动关机。下次开机时便从硬盘上读取之前保存的数据,恢复到休眠关机之前的状态。
譬如在休眠关机时,桌面打开了一个应用,那么下一次开机启动时,该应用也处于打开状态。而正常的关机-开机流程,该应用是不会打开的。
Linux内核代码声明如下,位于kernel/power/suspend.c

在新版内核中,进程freeze的功能被单独抽离出来作为一个电源状态,该状态仅仅是冻结进程,并不会使系统进入低功耗状态(如切断CPU时钟源、关闭外设供电等)。
相关宏定义位于:linux/include/linux/suspend.h

其中状态4就是STD,所谓的休眠状态(Hibernation)
小结:
至此,我们可以知道,睡眠与休眠是2个不同的概念,睡眠属于STR,而休眠属于STD,切勿混为一谈。
网上也有很多关于“Android休眠”的文章,事实上,Android手机压根儿就不支持休眠模式。
查看Linux支持的电源模式
#查看系统支持的电源模式
$ cat /sys/power/state
#休眠系统命令
$ sudo pm-hibernate

看来Ubuntu-17.0.4版本是不支持休眠功能了,state当中并没有disk,执行休眠命令也提示找不到。
在公司测试Ubuntu-16.0.4是支持休眠的,休眠时会将当前RAM中的数据保持至swap分区,以供后续恢复。

查看Android支持的电源模式

这里我使用的是模拟器查看的,真机也一样,Android手机是不支持休眠模式的,休眠模式需要一块与RAM大小一致存储空间,这在移动设备上可是个不小的开销。
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进程的祖先,关于其详细介绍可参考如下链接:
Device Idle
Device Idle属于Doze模式中概念,即指当手机屏幕熄屏、不充电、静置不动,有网友分析了源码,指出6.0手机需要静置1时4分30秒才能进入Doze模式。
| Doze模式的限制 |
|---|
| 网络接入被暂停 |
| 系统忽略wake locks |
| 标准的AlarmManager |
| 如果你需要在Doze状态下启动设置的alarms,使用setAndAllowWhileIdle()或者setExactAndAllowWhileIdle()。当有setAlarmClock()的alarms启动时,系统会短暂退出Doze模式 |
| 系统不会扫描Wi-Fi |
| 系统不允许sync adapters运行 |
| 系统不允许JobScheduler运行 |
结合上文分析的cpu idle不难发现Doze模式中的idle状态在概念属于浅idle状态,只是关闭了一些特定服务和模块,并非立即进入睡眠,当然这个过程当中依旧有可能满足睡眠条件而进入睡眠状态,至于如何进入请参考下文【睡眠触发入口】一节。
Android电源管理框架
Android采用linux内核,所以电源状态整体上是与linux操作系统相同,下图是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)移除了该类型的唤醒锁。 |
中断时延:计算机接收到中断信号到操作系统作出响应,并完成转入中断服务程序(ISR)的时间。
内核当中关于WakeLock的主要源码位于:
kernel_common/include/linux/wakelock.h
kernel_common/kernel/power/wakelock.c

Android Linux内核3.0版本

Android Linux内核3.4版本
应用层提供的锁类型如下,这些锁都需要手动释放:
| FLAG | CPU | 屏幕 | 键盘 |
|---|---|---|---|
| PARTIAL_WAKE_LOCK | 开启 | 关闭 | 关闭 |
| SCREEN_DIM_WAKE_LOCK | 开启 | 变暗 | 关闭 |
| SCREEN_BRIGHT_WAKE_LOCK | 开启 | 变亮 | 关闭 |
| FULL_WAKE_LOCK | 开启 | 变亮 | 变亮 |
锁的释放
Linux3.4内核中摒弃了之前的wakelock机制,引入wakeup source机制来进行睡眠管理,为了保证上层接口不变,Android的Linux内核便将wakeup source包装成wakelock,WakeLock的数据结构如下:

wakelock数据结构
当我们应用层释放锁之后,它并不会马上消失。wakelock分为激活和非激活状态,非激活状态300S之内,无人在申请wakelock,那么它将从红黑二叉树,LRU链表当中删除,如此便可复用锁,节省系统开销。
睡眠触发入口
在wakelock中,有3个地方可以让系统从early_suspend进入suspend状态。
wake_unlock,系统每释放一个锁,就会检查是否还存其他激活的wakelock,若不存在则执行Linux的标准suspend流程进入睡眠状态
在超时锁的超时回调函数,判断是否存在其他激活的wakelock,若不存在,则进入睡眠状态
autosleep机制,android 4.1引入该机制,亮屏时会向autosleep节点写入off,熄屏则会写入mem。Android一灭屏,就会尝试进入睡眠,失败之后系统处于idle进程超过一定时间,则又尝试进入睡眠,判断标准同上,若存在wakelock则进入失败

关于autosleep机制的内核源码分析,可以参考如下文章:
Early Suspend
预挂起机制是Android特有的挂起机制, 这个机制作用是关闭一些与显示相关的外设,比如LCD背光、重力感应器、 触摸屏,但是其他外设如WIFI、蓝牙等模块等并未关闭。
此时,系统依旧可以处理事件,如音乐播放软件,息屏后依旧能播放音乐。
需要注意的是Early Suspend机制与WakeLock机制相互独立,就算有应用持有wakelock锁,系统依旧可以通过Early Suspend机制关闭与显示相关的外设。
注意:
Android 4.4起,也就是引入ART的版本,摒弃了early suspend机制,改用了fb event通知机制,即后续版本只有suspend、resume以及runtime suspend、runtime resume。
Late Resume
迟唤醒机制,用于唤醒预挂起的设备
睡眠状态转换
一般情况下,当我们息屏后,系统将先通过Early Suspend机制进入Idle状态,如果满足进入睡眠的条件(没有进程持有唤醒锁)则会通过Linux的Suspend机制进入Sleep(睡眠)状态。

内核源码流程分析可参考如下文章:
源码位于kernel_common/kernel/power/main.c:
Android中休眠与唤醒之wake_lock, early_suspend, late_resume
看到这儿,不知你是否疑问,既然系统睡眠了,CPU断电不执行指令了,为何我们定的Alarm会生效以及能接收到来电?
手机来电与Alarm为何能唤醒系统
原来Android在硬件架构上将处理器分为二类:Application Processor(AP)和Baseband Processor(BP),AP是ARM架构的处理器,用于运行Linux+Android系统,耗电量高;BP用于运行实时操作系统(RTOS),用于处理手机通信,耗电量低。

当AP进入睡眠,有来电时,Modem(调制解调器)将唤醒AP;而我们平时所用的Alarm在硬件上则是依赖PMIC(电源管理芯片)中的RTC模块,所以即使AP断电进入睡眠,我们定的闹钟依旧会生效。

若想更深入的了解,则可参考Android RIL机制相关的文章。
总结
- 待机、睡眠与休眠的区别
实际上待机(standby)与睡眠(mem)属于不同模式,但现在大多操作系统都不支持待机模式了,我们也习惯将待机等同于睡眠,睡眠属于STR,休眠属于STD,Android手机不支持休眠!!!
- Android开发者官网当中提到“idle state”,该如何理解,这个状态会对设备及我们的程序造成何种影响
所谓的idle状态,就是指系统进入某个低功耗状态,以MTK为例,常见的状态有soidle、rgidle以及dpidle。rgidle只是限制我们程序使用某些模块,如Doze模式中不能访问网络;而dpidle则会冻结所有进程,系统进入睡眠。
- 进入Doze模式中的idle状态,我们的程序还能运行吗?
Doze模式中的idle概念上属于rgidle状态,此时我们的程序是能运行的,只是不能访问网络等,但是在这个过程中,系统可能会满足进入睡眠条件,冻结所有进程,这样我们的程序就不会得到执行。
可以自己写个死循环的线程(普通线程,非looper线程),强制手机进入Doze的idle模式,你会发现你的程序依旧在执行,但是静置在哪儿一段时间后,你会发现你的线程被冻结,不会执行,当你点亮屏幕,你的线程又会继续工作。
- 手机睡眠之后,为何我们写Alarm程序、来电显示程序依旧会生效?
Android在硬件架构上将处理器分为AP与BP,应用程序运行与AP之中,睡眠只是将AP断电,BP(Modem)不会断电,当有来电时,BP将会唤醒AP。
Alarm在硬件上依赖的是Modem中的PMIC的RTC模块,而不是AP中的RTC模块,当定时器触发时,可以唤醒AP,使我们的Alarm程序依旧会得到执行
Android电源管理基础知识整理的更多相关文章
- Kali Linux渗透基础知识整理(四):维持访问
Kali Linux渗透基础知识整理系列文章回顾 维持访问 在获得了目标系统的访问权之后,攻击者需要进一步维持这一访问权限.使用木马程序.后门程序和rootkit来达到这一目的.维持访问是一种艺术形式 ...
- 【OGG】OGG基础知识整理
[OGG]OGG基础知识整理 一.GoldenGate介绍 GoldenGate软件是一种基于日志的结构化数据复制软件.GoldenGate 能够实现大量交易数据的实时捕捉.变换和投递,实现源数据库与 ...
- Kali Linux渗透基础知识整理(二)漏洞扫描
Kali Linux渗透基础知识整理系列文章回顾 漏洞扫描 网络流量 Nmap Hping3 Nessus whatweb DirBuster joomscan WPScan 网络流量 网络流量就是网 ...
- java部分基础知识整理----百度脑图版
近期发现,通过百度脑图可以很好的归纳总结和整理知识点,本着学习和复习的目的,梳理了一下java部分的知识点,不定期更新,若有不恰之处,请指正,谢谢! 脑图链接如下:java部分基础知识整理----百度 ...
- wifi基础知识整理
转自 :http://blog.chinaunix.net/uid-9525959-id-3326047.html WIFI基本知识整理 这里对wifi的802.11协议中比较常见的知识做一个基本的总 ...
- Oracle ASM 磁盘组基础知识整理(收藏版)
转至:https://cloud.tencent.com/developer/article/1494403 为什么要写这么一篇基础知识呢?还是有那么一点点原因的,不是胡编乱造还真是有真实存在的事件的 ...
- Linux基础知识整理
一.基础知识 1.Linux简介 Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件 ...
- JavaScript基础知识整理
只整理基础知识中关键技术,旨在系统性的学习和备忘. 1.在 JScript 中 null 和 undefined 的主要区别是 null 的操作象数字 0,而 undefined 的操作象特殊值NaN ...
- Android电源管理-休眠简要分析
一.开篇 1.Linux 描述的电源状态 - On(on) S0 - Working - Standb ...
随机推荐
- ARTS Week 8
Dec 16, 2019 ~ Dec 22, 2019 Algorithm Problem 53 Maximum Subarray 最大子数组 题目链接 题目描述:给定一个数组,在所有连续的子数组中, ...
- python学习(2)关于字符编码
关于字符编码的学习内容笔记如下: 1.计算机只能用0和1来进行记录和存储.计算机是二进制. 2.ASCII(American Standard Code for Information Interch ...
- 从Golang中open的实现方式看Golang的语言设计
Golang有很多优点: 开发高效:(C语言写一个hash查找很麻烦,但是go很简单) 运行高效:(Python的hash查找好写,但比Python高效很多) 很少的系统库依赖:(环境依赖少,一般不依 ...
- Linux(CentOS 7)修改max open files的值
新安装的linux系统允许每个程序的最大打开文件数默认是1024,可以通过ulimit -n命令来查看,查看全部限制,则可以使用命令ulimit -a [root@test ~]# ulimit -a ...
- php-fpm.conf.default配置文件
;;;;;;;;;;;;;;;;;;;;; ; FPM Configuration ; ;;;;;;;;;;;;;;;;;;;;; ; All relative paths in this confi ...
- 2,简单的Python爬虫
前言 根据上一篇 1,Python爬虫环境的安装我们已经在本地安装好了Python环境,那么这一篇就开始学习如何用Python来爬虫! 环境:操作系统:Windows10 IDE: PyCharm ...
- Magicodes.IE基础教程之导出Pdf
原文作者:hueifeng 说明 本教程主要说明如何使用Magicodes.IE.Pdf完成Pdf收据导出 要点 导出PDF数据 自定义PDF模板 导出单据 如何批量导出单据 导出特性说明 PdfEx ...
- [MongoDB]评估使用mongodb的五个因素
企业选择 NOSQL 或非表格结构数据库,评估时应从以下五个关键维度来考虑:• 数据模型的类型• 查询模型是否能满足灵活的查询需求• 事务模型类型,以及一致性属于强一致性还是最终一致性• APIs 的 ...
- Redis-位图
关于位图,可能大家不太熟悉, 那么位图能干啥呢?位图的内容其实就是普通的字符串,也就是byte数组,我们都知道 byte 8 位无符号整数 0 到 255 说个场景.比如你处理一些业务时候,往往会存在 ...
- MySQL 8 InnoDB Table 和 Page 压缩
压缩用一点CPU换取磁盘IO.内存空间.磁盘空间. 在有Secondary Indexes 的表中,使用压缩更加明显,相关索引数据也会压缩. InnoDB 表压缩 对表压缩只需要在Create Tab ...