2024年3月9日发(作者:)

第十三章 Android内核驱动——电源管理

13.1 基本原理

Android 中定义了几种低功耗状态:earlysuspend,suspend,hibernation。

 earlysuspend是一种低功耗的状态,某些设备可以选择进入某种功耗较低的状态,比如

LCD可以降低亮度或灭掉;

 suspend是指除电源管理以外的其他外围模块以及cpu均不工作,只有内存保持自刷新的

状态;

 hibernation是指所有内存镜像都被写入磁盘中,然后系统关机,恢复后系统将能恢复到

“关机”之前的状态。

13.2 电源管理机制的实现

电源管理机制的源代码主要在kernel/power/文件夹下面。

main.c文件是整个框架的入口。用户可以通过读写sys文件/sys/power/state实现控制系统进

入低功耗状态。用户对于/sys/power/state的读写会调用到main.c中的state_store(),用户可

以写入const char * const pm_states[] 中定义的字符串, 比如“on”,“mem”,“standby”,

“disk”。

state_store()首先判断用户写入的是否是“disk”字符串,如果是则调用hibernate()函数命令

系统进入hibernation状态。如果是其他字符串则调用request_suspend_state()(如果未定义

CONFIG_EARLYSUSPEND)或者调用enter_state()(如果未定义CONFIG_EARLYSUSPEND)。

request_suspend_state()函数是android相对标准linux改动的地方,它实现在earlysuspend.c

中。在标准linux内核中,用户通过 sysfs 写入“mem”和“standby”时,会直接调用enter_state()

进入suspend模式,但在android中则会调用request_suspend_state()函数进入early suspend

状态。request_suspend_state()函数代码如下:

void request_suspend_state(suspend_state_t new_state)

{

unsigned long irqflags;

int old_sleep;

spin_lock_irqsave(&state_lock, irqflags);

old_sleep = state & SUSPEND_REQUESTED;

......

if (!old_sleep && new_state != PM_SUSPEND_ON) {

state |= SUSPEND_REQUESTED;

//判断是否为省电请求,如果是排队一个 early_suspend_work

queue_work(suspend_work_queue, &early_suspend_work);

} else if (old_sleep && new_state == PM_SUSPEND_ON) {

state &= ~SUSPEND_REQUESTED;

wake_lock(&main_wake_lock);

//否则,是唤醒请求,排队 late_resume_work

queue_work(suspend_work_queue, &late_resume_work);

}

Linux公社() 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。

requested_suspend_state = new_state;

spin_unlock_irqrestore(&state_lock, irqflags);

}

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这两个函 数。Android提供了

register_early_suspend和unregister_early_suspend两个函数供驱动调用,分别完成设备

earlysuspend的注册和注销。系统将所有注册支持early_suspend的设备驱动对应的 handler

挂在一个称为early_suspend_handler的链表上。函数early_suspend和late_resume完成的事

情很简单,就是遍历这个链表,依次调用每个设备注册的handler,late_resume是唤醒处于

early_suspend的那些设备。代码如下:

static void early_suspend(struct work_struct *work)

{

struct early_suspend *pos;

unsigned long irqflags;

int abort = 0;

mutex_lock(&early_suspend_lock);

spin_lock_irqsave(&state_lock, irqflags);

if (state == SUSPEND_REQUESTED)

state |= SUSPENDED;

else

abort = 1;

spin_unlock_irqrestore(&state_lock, irqflags);

if (abort) {

if (debug_mask & DEBUG_SUSPEND)

pr_info("early_suspend: abort, state %dn", state);

mutex_unlock(&early_suspend_lock);

goto abort;

}

if (debug_mask & DEBUG_SUSPEND)

pr_info("early_suspend: call handlersn");

//遍历链表依次调用每个驱动的 handler

list_for_each_entry(pos, &early_suspend_handlers, link) {

if (pos->suspend != NULL)

pos->suspend(pos);

}

mutex_unlock(&early_suspend_lock);

if (debug_mask & DEBUG_SUSPEND)

pr_info("early_suspend: syncn");

//同步文件系统

sys_sync();

abort:

spin_lock_irqsave(&state_lock, irqflags);

if (state == SUSPEND_REQUESTED_AND_SUSPENDED)

wake_unlock(&main_wake_lock);

spin_unlock_irqrestore(&state_lock, irqflags);

}

static void late_resume(struct work_struct *work)

{

struct early_suspend *pos;

unsigned long irqflags;

int abort = 0;

mutex_lock(&early_suspend_lock);

spin_lock_irqsave(&state_lock, irqflags);

if (state == SUSPENDED)

state &= ~SUSPENDED;

Linux公社() 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。