摘要:
android系统的待机,是在linux原生待机enter_state的基础上,添加wakelock-wakeunlock机制,对象场景是增加对屏灭但系统仍后台运行得支持。
linux原生待机
我们是linux开发者,用code沟通最直接吧。
在linux-2.6.32以后,/sys/power节点下,创建state节点,在文件系统调用上,write此节点,将会调用state_store函数,read此节点,将会调用state_show函数。
#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);
android新增待机
android对linux待机机制的修改,是对移动便携设备省电的支持。
在code上,可以追踪红定义HAS_EARLYSUSPEND,可以发现这个宏的开关就是wakelock-wakeunlock机制的开关。
待机的入口节点没变,同linux原生待机一致,在/sys/power/state下,
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;
/* First, check if we are requested to hibernate */
if (len == 4 && !strncmp(buf, "disk", len)) {
error = hibernate();
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 = enter_state(state);
#endif
#endif
Exit:
return error ? error : n;
}
一级待机提供一种机制,使得某些应用可以在屏幕暗下来以后,后台继续运行,如USB transfer、music play、wifi downloade/upload、blooth transfer。
EARLYSUSPEND
那么,如果正确地给你的某一个模块或者应用,注册一级待机回调函数呢?我们以backlight为例
需要包含的头文件:#include
定义一个一级待机结构体 XX_early_suspend
static struct early_suspend bl_early_suspend = {
.suspend = bl_earlysuspend,
.resume = bl_lateresume,
.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 1,
};
这个结构体的suspend与resume回调,就是在request_suspend_state(state)中调用,在enter_state(state)之前调用的。
level成员称为函数优先级,earlysuspend实际上就是一个list,在系统启动过程中往这个list上注册了很多的回调函数,但是这些函数的调用需要有一个先后关系;level值越大,优先级越低,函数越靠后被调用。
那么,XX_earlysuspend和XX_lateresume回调,要注意函数参数,还是以backlight为例
static void bl_earlysuspend(struct early_suspend *h)
{
}
static void bl_lateresume(struct early_suspend *h)
{
}
在驱动的_probe函数中,一般在靠后位置添加
#ifdef CONFIG_HAS_EARLYSUSPEND
register_early_suspend(&bl_early_suspend);
#endif
对应的要在_remove函数中,在靠前位置
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&bl_early_suspend);
#endif
wake lock/ wake unlock
接下来,如果给一个需要锁的驱动,添加一把锁呢?
和android上层看到的锁类似,锁有超时锁与非超时锁两种。超时锁我们以USB为例
需要包含的头文件:#include
在初始化函数或者_probe函数中,
wake_lock_init(&usb_wakelock, WAKE_LOCK_SUSPEND, "usb_detect");
在锁的初始化上,是不区分超时锁与非超时锁的,而是在申请与释放锁。
我们下面申请一个超时锁,目的是在USB拔掉之后几秒时间内,系统不要进入深度睡眠。
static irqreturn_t usb_detect_irq_handler(int irq, void *dev_id)
{
wake_lock_timeout(&usb_wakelock, 3 * HZ);//3秒的超时时间
schedule_delayed_work(&wakeup_work, HZ / 10);
return IRQ_HANDLED;
}
可以在串口输入cat proc/wakelocks查看当前系统所有锁情况。
非超时锁,需要手动申请,手动释放,而且需要注意匹配使用申请与释放。我们以alarm为例
同样,先在_probe中初始化一个锁
wake_lock_init(&hym8563->wake_lock, WAKE_LOCK_SUSPEND, "rtc_hym8563");
wake_lock_destroy(&hym8563->wake_lock);
wake_lock(&hym8563->wake_lock)
wake_unlock(&hym8563->wake_lock)