Android电源管理基础知识整理

前言

  1. 待机、睡眠与休眠的区别?
  2. Android开发者官网当中提到“idle states”,该如何理解,这个状态会对设备及咱们的程序形成何种影响?
  3. 进入Doze模式中的idle状态,咱们的程序还能运行吗?
  4. 手机睡眠以后,为什么咱们写Alarm程序、来电显示程序依旧会生效?

若是你也有以上疑问,那么本文会对你解开疑惑有必定的帮助html

ACPI简介

要理解第一个问题,得先从ACPI(高级配置与电源接口)提及,ACPI是一种规范(包含软件与硬件),用来供操做系统应用程序管理全部电源接口。linux

ACPI将计算机系统的状态划分为四个全局状态(G0-G3),共7个状态,其中G0对应S0;G1将低功耗状态细分为四个状态,对应S1-S4;G二、G3表明关机状态分别对应S五、S6。android

ACPI State Description
S0 正常工做状态
S1 CPU与RAM供电正常,但CPU不执行指令
S2 比S1更深的一个睡眠层次,这种模式一般不采用
S3 挂起到内存
S4 挂起到硬盘
S5 Soft Off,CPU、外设等断电,但电源依旧会为部分极低耗设备供电
S6 Mechanical Off,所有断电

这里只须要对ACPI的七个状态有个大体了解便可,下一节会有具体的例子来讲明各个状态。git

Linux系统电源状态

在Linux操做系统中,将电源划分为以下几个状态:github

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),进入该状态,系统的主要工做以下:数据结构

一、将系统当前的运行状态等数据保存在内存中,此时仍须要向RAM供电,以保证后续快速恢复至工做状态架构

二、冻结用户态的进程和内核态的任务(进入内核态的进程或内核本身的task)框架

三、关闭外围设备,如显示屏、鼠标等,中断唤醒外设不会关闭,如电源键函数

四、CPU中止工做

Standby也属于睡眠的一种方式,属于浅睡眠。该模式下CPU并未断电,依旧能够接收处理某些特定事件,视具体设备而定,恢复至正常工做状态的速度也比STR更快,但也更为耗电。举个例子来讲,以该方式进入睡眠时,后续经过点击键盘也能将系统唤醒。而以mem进入的睡眠为深度睡眠,只能经过中断唤醒设备唤醒系统,如电源键(此时按电源键,不会通过正常的开机流程的BIOS、BOOTLOAD等),此时按键盘是没法唤醒系统的。

STD(Suspend to Disk):

挂起到硬盘,俗称休眠(Hibernation)将系统当前的运行状态等数据保存到硬盘上,并自动关机。下次开机时便从硬盘上读取以前保存的数据,恢复到休眠关机以前的状态。

譬如在休眠关机时,桌面打开了一个应用,那么下一次开机启动时,该应用也处于打开状态。而正常的关机-开机流程,该应用是不会打开的。

Linux内核代码声明以下,位于kernel/power/suspend.c
image

在新版内核中,进程freeze的功能被单独抽离出来做为一个电源状态,该状态仅仅是冻结进程,并不会使系统进入低功耗状态(如切断CPU时钟源、关闭外设供电等)。

相关宏定义位于:linux/include/linux/suspend.h

image

其中状态4就是STD,所谓的休眠状态(Hibernation)

小结:

至此,咱们能够知道,睡眠与休眠是2个不一样的概念,睡眠属于STR,而休眠属于STD,切勿混为一谈。

网上也有不少关于“Android休眠”的文章,事实上,Android手机压根儿就不支持休眠模式。

查看Linux支持的电源模式

#查看系统支持的电源模式
$ cat /sys/power/state
#休眠系统命令
$ sudo pm-hibernate

image

看来Ubuntu-17.0.4版本是不支持休眠功能了,state当中并无disk,执行休眠命令也提示找不到。

在公司测试Ubuntu-16.0.4是支持休眠的,休眠时会将当前RAM中的数据保持至swap分区,以供后续恢复。

image

查看Android支持的电源模式

image

这里我使用的是模拟器查看的,真机也同样,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进程的祖先,关于其详细介绍可参考以下连接:

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 Doze模式源码分析

Android电源管理框架

Android采用linux内核,因此电源状态总体上是与linux操做系统相同,下图是Android的电源管理框架:

image

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

image

Android Linux内核3.0版本

image

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的数据结构以下:

image

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则进入失败

image

关于autosleep机制的内核源码分析,能够参考以下文章:

Android 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(睡眠)状态。

image

内核源码流程分析可参考以下文章:
源码位于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),用于处理手机通讯,耗电量低。

image

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

image

若想更深刻的了解,则可参考Android RIL机制相关的文章。

总结

  1. 待机、睡眠与休眠的区别

实际上待机(standby)与睡眠(mem)属于不一样模式,但如今大多操做系统都不支持待机模式了,咱们也习惯将待机等同于睡眠,睡眠属于STR,休眠属于STD,Android手机不支持休眠!!!

  1. Android开发者官网当中提到“idle state”,该如何理解,这个状态会对设备及咱们的程序形成何种影响

所谓的idle状态,就是指系统进入某个低功耗状态,以MTK为例,常见的状态有soidle、rgidle以及dpidle。rgidle只是限制咱们程序使用某些模块,如Doze模式中不能访问网络;而dpidle则会冻结全部进程,系统进入睡眠。

  1. 进入Doze模式中的idle状态,咱们的程序还能运行吗?

Doze模式中的idle概念上属于rgidle状态,此时咱们的程序是能运行的,只是不能访问网络等,可是在这个过程当中,系统可能会知足进入睡眠条件,冻结全部进程,这样咱们的程序就不会获得执行。
能够本身写个死循环的线程(普通线程,非looper线程),强制手机进入Doze的idle模式,你会发现你的程序依旧在执行,可是静置在哪儿一段时间后,你会发现你的线程被冻结,不会执行,当你点亮屏幕,你的线程又会继续工做。

  1. 手机睡眠以后,为什么咱们写Alarm程序、来电显示程序依旧会生效?

Android在硬件架构上将处理器分为AP与BP,应用程序运行与AP之中,睡眠只是将AP断电,BP(Modem)不会断电,当有来电时,BP将会唤醒AP。

Alarm在硬件上依赖的是Modem中的PMIC的RTC模块,而不是AP中的RTC模块,当定时器触发时,能够唤醒AP,使咱们的Alarm程序依旧会获得执行

相关文章
相关标签/搜索