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

定义一个一级待机结构体 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_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");

这样就注册上一个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)

你可能感兴趣的:(linux,kernel,android待机)