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 ...
随机推荐
- 清晰架构(Clean Architecture)的Go微服务
我用Go和gRPC创建了一个微服务项目,并试图找出最好的程序结构,它可以作为我其他项目的模板.我还将程序设计和编程的最佳实践应用于Go Microservice程序,例如清晰架构(Clean Arch ...
- Luinx安装RocketMQ
一.RocketMQ环境 准备两台虚拟机,分别为master01 和master02 二.安装JDK(两台虚拟机相同步骤) 1. 检查当前虚拟机环境有没有JDK rpm -qa|grep java ( ...
- 第3章 JDK并发包(三)
3.2 线程复用:线程池 一种最为简单的线程创建和回收的方法类似如下代码: new Thread(new Runnable() { @Override public void run() { // d ...
- Optional类包含的方法介绍及其示例
Optional类的介绍 javadoc中的介绍 这是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回> 该对象. 使用场景 用于避免 ...
- C++ 日期 & 时间(转)
C++ 标准库没有提供所谓的日期类型.C++ 继承了 C 语言用于日期和时间操作的结构和函数. 为了使用日期和时间相关的函数和结构,需要在 C++ 程序中引用 头文件.有四个与时间相关的类型:cloc ...
- 《Head first设计模式》之工厂模式
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个.工厂方法让类把实例化推迟到了子类. 预定披萨 假设你有一个披萨店,预定披萨的代码可能是这么写的: Pizza orderPizz ...
- Python 调用 Shell命令
python程序中调用shell命令,是件很酷且常用的事情今天来总结一下 1.使用os模块 的 system 此函数会启动子进程,在子进程中执行command,并返回comman ...
- 和内嵌的iframe进行通讯
利用内置iframe进行通讯 1. 在当前网页设置iframe网页(监听iframe发来postmessage消息事件) a. 外部网页接收数据: 回调方法,其中e.data为传入数据: const ...
- js能力测评——查找元素的位置
查找元素的位置 题目描述: 找出元素 item 在给定数组 arr 中的位置 输出描述: 如果数组中存在 item,则返回元素在数组中的位置,否则返回 -1 示例1 输入 [ 1, 2, 3, 4 ] ...
- Python3标准库:pprint美观打印数据结构
1. pprint美观打印数据结构 pprint模块包含一个“美观打印机”,用于生成数据结构的一个美观的视图.格式化工具会生成数据结构的一些表示,不仅能够由解释器正确地解析,还便于人阅读.输出会尽可能 ...