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 见下
(2)为什么又说基于wakelock的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
针对这一低功耗策略,就有了如下的机制
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 吗?