Android PM autosleep浅析

1.autosleep文件与state文件类似

autosleep可切换电源状态 如 同电源管理状态,往节点写则autosleep切换至指定状态 linux电源状态详见Android电源基础知识

kernel/kernel/power/autosleep.c 提供了autosleep模块的两大接口
(1)pm_autosleep_state 获取autosleep_state全局变量(见autosleep.c)
(2)pm_autosleep_set_state 设置autosleep_state全局变量

static ssize_t autosleep_show(struct kobject *kobj,
			      struct kobj_attribute *attr,
			      char *buf)
{
	suspend_state_t state = pm_autosleep_state();

	if (state == PM_SUSPEND_ON)
		return sprintf(buf, "off\n");

#ifdef CONFIG_SUSPEND
	if (state < PM_SUSPEND_MAX)
		return sprintf(buf, "%s\n", valid_state(state) ?
						pm_states[state] : "error");
#endif
#ifdef CONFIG_HIBERNATION
	return sprintf(buf, "disk\n");
#else
	return sprintf(buf, "error");
#endif
}

static ssize_t autosleep_store(struct kobject *kobj,
			       struct kobj_attribute *attr,
			       const char *buf, size_t n)
{
	suspend_state_t state = decode_state(buf, n);
	int error;

	if (state == PM_SUSPEND_ON
	    && strcmp(buf, "off") && strcmp(buf, "off\n"))
		return -EINVAL;

	error = pm_autosleep_set_state(state);
	return error ? error : n;
}

power_attr(autosleep); //源码实现见下
#define power_attr(_name) \
static struct kobj_attribute _name##_attr = {	\
	.attr	= {				\
		.name = __stringify(_name),	\
		.mode = 0644,			\
	},					\
	.show	= _name##_show,			\
	.store	= _name##_store,		\
}

节点创建
见kernel/kernel/power/main.c中pm_init

static int __init pm_init(void)
{
    ...
	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();
}

2.概念
结论:基于 wakeup_source 的wakelock ,基于wakelock的autosleep(针对新版本内核 )
依据:
(1)为什么说基于wakeup_source 的wakelock呢?
linux 内核 3.4 wakeup_source机制 取代 wakelock 机制,同时为了上层接口的兼容性
便将其封装其为wakelock 见下
wakelock

(2)为什么又说基于wakelock的autosleep呢?
autosleep
如上可见 autosleep基于wakeup_count(目前)基于wakelock是之前的老说法,为什么可这么说呢?
见 struct wakelock 中 wakeup_source 是不是有点感觉了,autosleep机制在 切换至低功耗 (freeze standy STR STD)时系统产生新的wakeup event 事件 会 中断 进入suspend 状态(pm_suspend) 重新处理工作项(queue_work)工作项为 try_to_suspend,从如下try_to_suspend源码清晰可见如上逻辑

static DECLARE_WORK(suspend_work, try_to_suspend);

void queue_up_suspend_work(void)
{
	if (autosleep_state > PM_SUSPEND_ON)
		queue_work(autosleep_wq, &suspend_work);
}

至此呼应了Opportunistic suspend 系统一但无wakeup event 产生 即可执行 pm_suspend,也就是通俗意义上的逮着机会就suspend
针对这一低功耗策略,就有了如下的机制
opportunistic sleep

static void try_to_suspend(struct work_struct *work)
{
	unsigned int initial_count, final_count;

	if (!pm_get_wakeup_count(&initial_count, true))
		goto out;

	mutex_lock(&autosleep_lock);

	if (!pm_save_wakeup_count(initial_count) ||
		system_state != SYSTEM_RUNNING) {
		mutex_unlock(&autosleep_lock);
		goto out;
	}
    
	if (autosleep_state == PM_SUSPEND_ON) {
		mutex_unlock(&autosleep_lock);
		return;
	}
	if (autosleep_state >= PM_SUSPEND_MAX)
		hibernate();
	else
		pm_suspend(autosleep_state);

	mutex_unlock(&autosleep_lock);

	if (!pm_get_wakeup_count(&final_count, false))
		goto out;

	/*
	 * If the wakeup occured for an unknown reason, wait to prevent the
	 * system from trying to suspend and waking up in a tight loop.
	 */
	if (final_count == initial_count)
		schedule_timeout_uninterruptible(HZ / 2);

 out:
	queue_up_suspend_work();
}

其中的pm_get_wakeup_count 于 pm_save_wakeup_count 来检测系统 wakeup event 事件的产生
到这,不知道小伙伴理解了为什么可以说基于wakelock的autosleep 吗?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值