当前位置: 代码迷 >> Android >> android待机详细组合代码分析(一)
  详细解决方案

android待机详细组合代码分析(一)

热度:18   发布时间:2016-05-01 14:47:16.0
android待机详细结合代码分析(一)

摘要:

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,		\}

在/kernel/power/main.c中

power_attr(state);

linux原生待机的入口函数就在这里,接下来往state_store函数深入,就是待机过程。


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;}

request_suspend_state(state);函数最后也会调用到linux原生待机入口函数enter_state(state),不过在调用之前需要先完成earlysuspend,所谓的一级待机。

一级待机提供一种机制,使得某些应用可以在屏幕暗下来以后,后台继续运行,如USB transfer、music play、wifi downloade/upload、blooth transfer。


EARLYSUSPEND

那么,如果正确地给你的某一个模块或者应用,注册一级待机回调函数呢?我们以backlight为例

需要包含的头文件:#include <linux/earlysuspend.h>

定义一个一级待机结构体 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){}

这样,回调函数和结构体就写好了,为了规范代码,最好能加上ealrysuspend机制的宏开关, 接下来就是注册结构体到list

在驱动的_probe函数中,一般在靠后位置添加

#ifdef CONFIG_HAS_EARLYSUSPENDregister_early_suspend(&bl_early_suspend);#endif

对应的要在_remove函数中,在靠前位置

#ifdef CONFIG_HAS_EARLYSUSPENDunregister_early_suspend(&bl_early_suspend);#endif


wake lock/ wake unlock

接下来,如果给一个需要锁的驱动,添加一把锁呢?

和android上层看到的锁类似,锁有超时锁与非超时锁两种。超时锁我们以USB为例

需要包含的头文件:#include <linux/wakelock.h>

在初始化函数或者_probe函数中,

wake_lock_init(&usb_wakelock, WAKE_LOCK_SUSPEND, "usb_detect");

这样就注册上一个name为"usb_detect"的锁,此锁属性是WAKE_LOCK_SUSPEND,区别与WAKE_LOCK_IDLE。

在锁的初始化上,是不区分超时锁与非超时锁的,而是在申请与释放锁。

我们下面申请一个超时锁,目的是在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;}

在拔掉和插入USB后,会出发这个handler,从而申请 "usb_detect"的超时锁,超时时间是3秒,3秒后,自动释放这个锁。

可以在串口输入cat proc/wakelocks查看当前系统所有锁情况。


非超时锁,需要手动申请,手动释放,而且需要注意匹配使用申请与释放。我们以alarm为例

同样,先在_probe中初始化一个锁

wake_lock_init(&hym8563->wake_lock, WAKE_LOCK_SUSPEND, "rtc_hym8563");

在_remove中反初始化

wake_lock_destroy(&hym8563->wake_lock);

然后在set_alarm的时候,申请锁

wake_lock(&hym8563->wake_lock)

在alarm结束后释放这个锁

wake_unlock(&hym8563->wake_lock)

  相关解决方案