Android共支持3种suspend的模式:
early_suspend、suspned、hibernation
1,earlysuspend是一种低功耗的状态,某些设备可以选择进入某种功耗较低的状态,比如LCD可以降低亮度或灭掉;
2,suspend是指除电源管理以外的其他外围模块以及cpu均不工作,只有内存保持自刷新的状态;
3,hibernation是指所有内存镜像都被写入磁盘中,然后系统关机,恢复后系统将能恢复到“关机”之前的状态.
power manager的suspend状态有4种,可从suspend.h中查看
typedef int __bitwise suspend_state_t;
#define PM_SUSPEND_ON ((__force suspend_state_t) 0)
#define PM_SUSPEND_STANDBY ((__force suspend_state_t) 1)
#define PM_SUSPEND_MEM ((__force suspend_state_t) 3)
#define PM_SUSPEND_MAX ((__force suspend_state_t) 4)
其中在suspend.c中只为前三种定义了可操作的宏:
const char *const pm_states[PM_SUSPEND_MAX] = {
#ifdef CONFIG_EARLYSUSPEND
[PM_SUSPEND_ON] = "on",
#endif
[PM_SUSPEND_STANDBY] = "standby",
[PM_SUSPEND_MEM] = "mem",
};
至于第四种应该就是hibernation功能,目前所知道的android设备支持的很少;
#define power_attr(_name) \
static struct kobj_attribute _name##_attr = { \
.attr = { \
.name = __stringify(_name), \
.mode = 0644, \
}, \
.show = _name##_show, \
.store = _name##_store, \
}
power_attr(state);
在power maneger main.c中定义了电源管理的接口属性
static int __init pm_init(void)
{
int error = pm_start_workqueue();
if (error)
return error;
hibernate_image_size_init();
hibernate_reserved_size_init();
power_kobj = kobject_create_and_add("power", NULL);
if (!power_kobj)
return -ENOMEM;
error = sysfs_create_group(power_kobj, &attr_group);
if (error)
return error;
return pm_autosleep_init();
}
将该属性文件注册到/sys下面,之后用户层可以通过/sys/power/state来控制系统的休眠与唤醒,当用户层对该接口进行访问时,会调用store函数:
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
#ifdef CONFIG_SUSPEND
#ifdef CONFIG_EARLYSUSPEND
suspend_state_t state = PM_SUSPEND_ON;
#else
suspend_state_t state = PM_SUSPEND_STANDBY;
#endif
const char * const *s;
#endif
char *p;
int len;
int error = -EINVAL;
p = memchr(buf, '\n', n);
len = p ? p - buf : n;
#ifdef CONFIG_MTK_HIBERNATION
state = decode_state(buf, n);
hib_log("entry (%d)\n", state);
#endif
if (no_suspend && len == 3 && !strncmp(buf, "mem", len))
{
printk("suspend disabled\n");
goto Exit;
}
#ifdef CONFIG_MTK_HIBERNATION
if (len == 8 && !strncmp(buf, "hibabort", len)) {
hib_log("abort hibernation...\n");
error = mtk_hibernate_abort();
goto Exit;
}
#endif
/* First, check if we are requested to hibernate */
if (len == 4 && !strncmp(buf, "disk", len)) {
#ifdef CONFIG_MTK_HIBERNATION
hib_log("trigger hibernation...\n");
#ifdef CONFIG_EARLYSUSPEND
if (PM_SUSPEND_ON == get_suspend_state()) {
hib_warn("\"on\" to \"disk\" (i.e., 0->4) is not supported !!!\n");
error = -EINVAL;
goto Exit;
}
#endif
if (!pre_hibernate()) {
error = 0;
error = mtk_hibernate();
}
#else // !CONFIG_MTK_HIBERNATION
error = hibernate();
#endif
goto Exit;
}
#ifdef CONFIG_SUSPEND
for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
break;
}
if (state < PM_SUSPEND_MAX && *s) {
#ifdef CONFIG_EARLYSUSPEND
if (state == PM_SUSPEND_ON || valid_state(state)) {
error = 0;
request_suspend_state(state);
} else
error = -EINVAL;
#else
error = enter_state(state);
#endif
}
#endif
Exit:
return error ? error : n;
}
CONFIG_MTK_HIBERNATION用来判断是否有开启hibernation状态
for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
break;
}
用来侦测目前powwer manager的状态,是on还是mem,还是suspened.
valid_state(state):用来判断该android的power manager是否支持该state,之后再进入request_suspend_state.
如果是标准的linux内核就会走enter_state(state)
void request_suspend_state(suspend_state_t new_state)
{
unsigned long irqflags;
int old_sleep;
int wait_flag = 0;
spin_lock_irqsave(&state_lock, irqflags);
old_sleep = state & SUSPEND_REQUESTED;
if (earlysuspend_debug_mask & DEBUG_USER_STATE) {
struct timespec ts;
struct rtc_time tm;
getnstimeofday(&ts);
rtc_time_to_tm(ts.tv_sec, &tm);
pm_warn("%s (%d->%d) at %lld "
"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",
requested_suspend_state, new_state,
ktime_to_ns(ktime_get()),
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
}
if (!old_sleep && new_state != PM_SUSPEND_ON) {
state |= SUSPEND_REQUESTED;
pm_warn("sys_sync_work_queue early_sys_sync_work\n");
queue_work(sys_sync_work_queue, &early_sys_sync_work);
pm_warn("suspend_work_queue early_suspend_work\n");
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);
///cun
if (queue_work(suspend_work_queue, &late_resume_work)) {
/*
* In order to synchronize the backlight turn on timing,egou
* block the thread and wait for fb driver late_resume()
* callback function is completed
*/
wait_flag = 1;
}
}
requested_suspend_state = new_state;
spin_unlock_irqrestore(&state_lock, irqflags);
if (wait_flag == 1) {
wait_for_completion(&fb_drv_ready);
pr_warn("wait done\n");
}
}
通过上面的两条判断语句根据不同的power manager状态将对应的suspend、resume操作函数加入对应的工作队列中去;
先来看看suspend的操作函数:
queue_work(suspend_work_queue, &early_suspend_work):调度执行指定的工作对列suspend_work_queue中的任务,early_suspend_work是指定的任务指针
DECLARE_WORK(early_suspend_work, early_suspend)静态的创建工作对列结构,其中early_suspend是队列中的任务所对应的function;
suspend_work_queue是在什么时候创建的呢?
static int __init org_wakelocks_init(void)
{
int ret;
wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync");
sys_sync_work_queue = create_singlethread_workqueue("fs_sync");
if (sys_sync_work_queue == NULL) {
pr_err("[wakelocks_init] fs_sync workqueue create failed\n");
}
suspend_work_queue = create_singlethread_workqueue("suspend");
if (suspend_work_queue == NULL) {
ret = -ENOMEM;
goto err_suspend_work_queue;
}
return 0;
err_suspend_work_queue:
return ret;
}
整个suspend的核心就是在创建suspend_work_queue的工作队列中完成
static void early_suspend(struct work_struct *work)
{
struct early_suspend *pos;
unsigned long irqflags;
int abort = 0, count = 0;
pr_warn("@@@@@@@@@@@@@@@@@@@@@@@\n@@@__early_suspend__@@@\n@@@@@@@@@@@@@@@@@@@@@@@\n");
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 (earlysuspend_debug_mask & DEBUG_SUSPEND)
pm_warn("abort, state %d\n", state);
mutex_unlock(&early_suspend_lock);
goto abort;
}
pr_warn("early_suspend_count = %d, forbid_id = 0x%x\n", early_suspend_count, forbid_id);
if (earlysuspend_debug_mask & DEBUG_SUSPEND)
pm_warn("call handlers\n");
list_for_each_entry(pos, &early_suspend_handlers, link) {
if (pos->suspend != NULL) {
if (!(forbid_id & (0x1 << count))) {
//if (earlysuspend_debug_mask & DEBUG_VERBOSE)
pr_warn("ES handlers %d: [%pf], level: %d\n", count, pos->suspend, pos->level);
pos->suspend(pos);
}
count++;
}
}
mutex_unlock(&early_suspend_lock);
/* Remove sys_sync from early_suspend, and use work queue to complete sys_sync */
abort:
if (state == SUSPEND_REQUESTED_AND_SUSPENDED) {
//wake_unlock(&main_wake_lock);
#ifdef CONFIG_MTK_HIBERNATION
suspend_state_t susp_state = get_suspend_state();
pm_warn("calling pm_autosleep_set_state() with parameter: %d\n", susp_state);
pm_autosleep_set_state(susp_state);
#else
pm_autosleep_set_state(PM_SUSPEND_MEM);
#endif
}
}
关键性的函数: list_for_each_entry(pos, &early_suspend_handlers, link),会遍历early_suspend_handlers
链表中的所有handler,然后回调所有加入该链表中的模块的suspend handle函数,最后会释放main lock,到此early_suspend结束,每个模块又是如何加入到该early_suspend_handlers链表中的呢
每个模块如果需要进入suspend,就需要将对应的处理函数加入到handles的链表中,register_early_suspend(&obj->early_drv),该函数就是用来将处理函数注册到handles链表中
obj->early_drv.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1,
obj->early_drv.suspend = bma220_early_suspend,
其中level是表示该结构在handlers链表中的位置,suspend时该level值越小那么在回调函数中执行的就越早,resume则反过来
android在earlysuspened.h中先定义了如下几个level值:
enum {
EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50,
EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100,
EARLY_SUSPEND_LEVEL_DISABLE_FB = 150,
};
struct early_suspend {
#ifdef CONFIG_HAS_EARLYSUSPEND
struct list_head link;
int level;
void (*suspend)(struct early_suspend *h);
void (*resume)(struct early_suspend *h);
#endif
};
如果需要将suspend的顺序调到这其中之前的话,只需将level值改成比这个小就可以了
下面看看register_early_suspend这个函数的处理过程:
void register_early_suspend(struct early_suspend *handler)
{
struct list_head *pos;
mutex_lock(&early_suspend_lock);
list_for_each(pos, &early_suspend_handlers) {
struct early_suspend *e;
e = list_entry(pos, struct early_suspend, link);
if (e->level > handler->level)
break;
}
list_add_tail(&handler->link, pos);
early_suspend_count++;
if ((state & SUSPENDED) && handler->suspend)
handler->suspend(handler);
mutex_unlock(&early_suspend_lock);
}
可以到source code详细查看这段函数体的实现过程,大意如下;
通过扫描链表中的每一项来与将要注册的handle的level进行比较,将level小的这项加入到与之对比的链表项的后面
下面看看有关suspend的hal层代码;
const char * const NEW_PATHS[] = {
"/sys/power/wake_lock",
"/sys/power/wake_unlock",
"/sys/power/state"
};
首先定义了操作的接口,这些接口在kernel起来后就已注册好,任何一个要操作的接口,首先就需先打开:
static int
open_file_descriptors(const char * const paths[])
{
int i;
for (i=0; i
int fd = open(paths[i], O_RDWR);
if (fd < 0) {
fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]);
g_error = errno;
return -1;
}
g_fds[i] = fd;
}
g_error = 0;
return 0;
}
用户空间的电源管理系统会通过调用set_screen_state来触发底层的suspend流程
int
set_screen_state(int on)
{
QEMU_FALLBACK(set_screen_state(on));
LOGI("*** set_screen_state %d", on);
initialize_fds();
//LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime,
// systemTime(), strerror(g_error));
if (g_error) return g_error;
char buf[32];
int len;
if(on)
len = snprintf(buf, sizeof(buf), "%s", on_state);
else
len = snprintf(buf, sizeof(buf), "%s", off_state);
buf[sizeof(buf) - 1] = '\0';
len = write(g_fds[REQUEST_STATE], buf, len);
if(len < 0) {
LOGE("Failed setting last user activity: g_error=%d\n", g_error);
}
return 0;
}
该函数实质上是往接口中写men或on等字符串命令