13.1
Android
LCD可以降低亮度或灭掉;
状态;
“关机”之前的状态。
13.2
电源管理机制的源代码主要在 kernel/power/文件夹下面。
main.c文件是整个框架的入口。用户可以通过读写 sys文件/sys/power/state 实现控制系统进
入低功耗状态。用户对于/sys/power/state 的读写会调用到 main.c中的state_store(),用户可
以写入const char * const pm_states[]
“disk”。
state_store()首先判断用户写入的是否是“disk”字符串,如果是则调用hibernate()函数命令
系统进入hibernation状态。如果是其他字符串则调用 request_suspend_state()(如果未定义
CONFIG_EARLYSUSPEND)或者调用enter_state()(如果未定义 CONFIG_EARLYSUSPEND)。
request_suspend_state()函数是 android 相对标准 linux改动的地方,它实现在earlysuspend.c
中。在标准linux内核中, 用户通过
进入suspend模式,但在 android中则会调用request_suspend_state()函数进入earlysuspend
状态。request_suspend_state()函数代码如下:
void request_suspend_state(suspend_state_t new_state)
{
}
early_suspend_work和 late_resume_work定义为
static DECLARE_WORK(early_suspend_work, early_suspend);
static DECLARE_WORK(late_resume_work, late_resume);
可见实际工作的是 early_suspend 和 late_resume 这两个函
register_early_suspend 和 unregister_early_suspend两个函数供驱动调用,分别完成设备
earlysuspend的注册和注销。系统将所有注册支持early_suspend的设备驱动对应的
挂在一个称为early_suspend_handler 的链表上。函数early_suspend和late_resume完成的事
情很简单,就是遍历这个链表,依次调用每个设备注册的handler,late_resume 是唤醒处于
early_suspend的那些设备。代码如下:
static void early_suspend(struct work_struct *work)
{
abort:
}
static void late_resume(struct work_struct *work)
{
abort:
}
register_early_suspend 函数完成的功能就是把驱动提供的 earlysuspend handler挂到
early_suspend_handler链表上。unregister_early_suspend则相反,从链表上摘下handler。
fbearlysuspend.c 和 consoleearlysuspend.c 这两个文件实现了针对 lcd framebuffer的
earlysuspend 支持和 console 的 earlysuspend 支持。实际上这两个文件就是利用上面
earlysuspend.c提供的接口注册了针对 framebuffer 和console的 early suspendhandler,并提
供相应的handler函数。
Hibernate.c 文件实现 hibernation 低功耗状态,是最彻底的低功耗模式,它把所有内存镜像
都写入磁盘中,然后系统关机。该文件还在 sysfs 文件系统中创建了多个 entry,分别是
/sys/power/disk,/sys/power/resume和/sys/power/image_size,这样用户可以直接通过
来控制系统进出hibernation状态。这块代码跟标准 Linux内核没有什么区别。
Android改动较大的另一处是增加了wakelock机制。实现在wakelock.c和userwakelock.c中。
wakelock可以阻止处于正常运行(active)或者空闲(idle)状态的系统进入睡眠等低功耗状
态。直到所持有的wakelock 全部被释放,系统才能进入睡眠等低功耗的状态。
wakelock有加锁和解锁两种状态,加锁的方式有两种,一种是永久的锁住,这样的锁除非显
示的放开,是不会解锁的。第二种是超时锁,这种锁会锁定系统一段时间,如果这个时间过
去了,这个锁会自动解除。
锁有两种类型:
WAKE_LOCK_AUTO_EXPIRE属性,具有这种属性的锁称为超时锁(timeout)。
low power的状态。
Android使用两条双向链表 active_wake_locks[WAKE_LOCK_TYPE_COUNT]分别保存处于active
状态的suspend lock和
锁。
在系统启动的时候,会调用 wakelocks_init函数来完成 wakelock的初始化,但别的驱动程序
也可以再单独创建自用的wakelock,这里初始化的是系统默认的wake lock以及该机制依赖
的功能。
wakelocks_init函数做了以下事情:
(如果CONFIG_WAKELOCK_STAT 被定义)三个 WAKE_LOCK_SUSPEND型的锁
wake_lock_init()函数初始化一个锁,就是初始化表示一个 wakelock 的数据结构 struct
wake_lock,并将其挂到 inactive_locks链表上。
*lock,
锁住) ;
这两个函数内部都是通过调用wake_lock_internal()函数完成具体功能的。
wake_lock_internal()函数流程:
成员变量
锁的flag|=WAKE_LOCK_AUTO_EXPIRE,否则取消WAKE_LOCK_AUTO_EXPIRE标志。如果锁
是 WAKE_LOCK_SUSPEND型的,则继续下面的步骤。
查所有处于活动状态的 WAKE_LOCK_SUSPEND 锁(即在 active_wake_locks 链表上的
WAKE_LOCK_SUSPEND 锁,或者说当前被加锁了的 WAKE_LOCK_SUSPEND锁) ,是否有超期
锁已经过期,如果有则把过期超期锁从 active_wake_locks 上删除,挂到 inactive_locks 上。
同时它还检查链表上有没有非超期锁,如果有则直接返回-1,否则它最终返回的是所有超
期锁过期时间的最大值
示所有活动锁都是超时锁,且全已经超时) ,则删除expire_timer,并排队一个 suspend工作
到 suspend_work_queue 工作队列,最终系统会 suspend
static long has_wake_lock_locked(int type)
{
}
expire_timer定义为:
static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
其handler expire_wake_locks 是实现超时锁机制的关键,定时器的expire时间被设置为当前
所有处于活动状态的WAKE_LOCK_SUSPEND锁超时值的最大值, 如果没有超时锁则设置 stop
它。当定时器expire的时候,会在其处理函数expire_wake_locks中调用has_wake_lock_locked
函数把所有过期的锁全部解锁, 并排队一个suspend工作到suspend_work_queue工作队列,
最终系统会suspend。
static void expire_wake_locks(unsigned long data)
{
}
suspend 函数完成 suspend 系统的任务,它是 suspend_work 这个工作的处理函数,
suspend_workk 排队到 suspend_work_queue 工作队列中,最终系统会处理这个 work,调用
其 handler 即 suspend 函 数 。 该 函 数 首 先 sync 文 件 系 统 , 然 后 调 用
pm_suspend(request_suspend_state),接下来pm_suspend()就会调用
linux的 suspend流程。
static void suspend(struct work_struct *work)
{
}
解锁由 wake_unlock 函数实现。该函数首先将该锁从 active 链表转移到 inactive 链表中。如
果是WAKE_LOCK_IDLE锁,就结束退出了。如果是WAKE_LOCK_SUSPEND 锁,则继续查看所
有处于 active 状态并且具有自动过期属性的锁(超时锁) ,遍历找到最晚过期时间,然后修
改expire_timer 的到期时间 (expire_timer 到期后会调用 suspend函数使系统进入suspend状
态) ;否则,如果存在一个不具有 auto-expire属性的锁(非超期锁) ,则会导致 expire_timer
被 stop(或者说不再处于 active 的工作状态) 。另外,如果检查的过程中发现所有锁均处于
过期状态,则直接使用 queue_work启动 suspend过程。
userwakelock.c 文件实现的是 wakelock 机制的 sysfs
加锁或解锁。它通过struct user_wake_lock
为user_wake_locks。
该文件是标准的sysfs接口函数, 提供了wake_lock_show、 wake_lock_store、wake_unlock_show
和wake_unlock_store 四个函数, 这样用户可以通过echo, cat等命令写入或读出系统中 wake
lock。
因为 wakelock 在实现的过程中,默认初始化并添加一个 suspend lock 类型的非过期型锁
main_wake_lock(wakelocks_init
的存在而正常运行。也就是说如果不添加新锁,将 main_wake_lock
眠状态。
13.3
电源管理内核层给应用层提供的接口就是sysfs
Android上层frameworks也是基于sysfs做了包装, 最终提供给Android java应用程序的是java
类的形式。
Android系统会在sysfs里面创建以entry:
/sys/power/state
/sys/power/wake_lock
/sys/power/wake_unlock
echo mem > /sys/power/state
或者
echo standby > /sys/power/state
命令系统进入earlysuspend 状态,那些注册了early suspend handler 的驱动将依次进入各自
的earlysuspend
echo on > /sys/power/state
将退出early suspend状态
echo disk > /sys/power/state
命令系统进入hibernation状态
echo lockname > /sys/power/wake_lock
加锁“lockname”
echo lockname > /sys/power/wake_unlock
解锁“lockname”
上述是分别加锁和解锁的命令,一旦系统中所有 wakelock 被解锁,系统就会进入 suspend
状态,可见Android中原本使系统 suspend
换成使系统进入early suspend;而wake lock
一途径。