Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作。wake_lock一般在关闭lcd、tp但系统仍然需要正常运行的情况下使用,比如听歌、传输很大的文件等。本文主要分析driver层wake_lock的实现。
一、wake_lock 定义和接口
- enum {
- WAKE_LOCK_SUSPEND, // 阻止进入深度休眠模式
- WAKE_LOCK_IDLE, // 阻止进入空闲模式
- WAKE_LOCK_TYPE_COUNT
- };
- struct wake_lock {
- #ifdef CONFIG_HAS_WAKELOCK
- struct list_head link; // 链表节点
- int flags; // 标志
- const char *name; // 名称
- unsigned long expires; // 超时时间
- #ifdef CONFIG_WAKELOCK_STAT
- struct {
- int count; // 使用计数
- int expire_count; // 超时计数
- int wakeup_count; // 唤醒计数
- ktime_t total_time; // 锁使用时间
- ktime_t prevent_suspend_time; // 锁阻止休眠的时间
- ktime_t max_time; // 锁使用时间最长的一次
- ktime_t last_time; // 锁上次操作时间
- } stat;
- #endif
- #endif
- };
可以看到wake_lock按功能分为休眠锁和空闲锁两种类型,用于阻止系统进入深度休眠模式或者空闲模式。wake_lock的主要部件有锁名称、链表节点、标志位、超时时间,另外还有一个内嵌的结构用于统计锁的使用信息。接下来我们看看wake_lock对外提供的操作接口:
1、内核空间接口
- void wake_lock_init(struct wake_lock *lock, int type, const char *name);
- void wake_lock_destroy(struct wake_lock *lock);
- void wake_lock(struct wake_lock *lock);
- void wake_lock_timeout(struct wake_lock *lock, long timeout);
- void wake_unlock(struct wake_lock *lock);
- int wake_lock_active(struct wake_lock *lock);
- long has_wake_lock(int type);
其中wake_lock_active()用于判断锁当前是否有效,如果有效则返回非0值;has_wake_lock()用于判断系统中是否还存在有效的type型锁,如果存在超时锁则返回最长的一个锁的超时时间,如果存在永久锁则返回-1,如果系统中不存在有效锁则返回0。
2、用户空间接口
wake_lock向用户空间提供了两个文件节点用于申请锁和解锁:
- // wack_lock文件的读函数,显示用户空间定义的有效锁
- ssize_t wake_lock_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf)
- {
- char *s = buf;
- char *end = buf + PAGE_SIZE;
- struct rb_node *n;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
- l = rb_entry(n, struct user_wake_lock, node);
- if (wake_lock_active(&l->wake_lock))
- s += scnprintf(s, end - s, "%s ", l->name);
- }
- s += scnprintf(s, end - s, "\n");
- mutex_unlock(&tree_lock);
- return (s - buf);
- }
- // wack_lock文件的写函数,初始化并激活用户空间定义的锁
- ssize_t wake_lock_store(
- struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- long timeout;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- l = lookup_wake_lock_name(buf, 1, &timeout);
- if (IS_ERR(l)) {
- n = PTR_ERR(l);
- goto bad_name;
- }
- if (debug_mask & DEBUG_ACCESS)
- pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);
- if (timeout)
- wake_lock_timeout(&l->wake_lock, timeout);
- else
- wake_lock(&l->wake_lock);
- bad_name:
- mutex_unlock(&tree_lock);
- return n;
- }
- // wack_unlock文件的读函数,显示用户空间的无效锁
- ssize_t wake_unlock_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf)
- {
- char *s = buf;
- char *end = buf + PAGE_SIZE;
- struct rb_node *n;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
- l = rb_entry(n, struct user_wake_lock, node);
- if (!wake_lock_active(&l->wake_lock))
- s += scnprintf(s, end - s, "%s ", l->name);
- }
- s += scnprintf(s, end - s, "\n");
- mutex_unlock(&tree_lock);
- return (s - buf);
- }
- // wack_unlock文件的写函数,用于用户空间解锁
- ssize_t wake_unlock_store(
- struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- l = lookup_wake_lock_name(buf, 0, NULL);
- if (IS_ERR(l)) {
- n = PTR_ERR(l);
- goto not_found;
- }
- if (debug_mask & DEBUG_ACCESS)
- pr_info("wake_unlock_store: %s\n", l->name);
- wake_unlock(&l->wake_lock);
- not_found:
- mutex_unlock(&tree_lock);
- return n;
- }
- power_attr(wake_lock);
- power_attr(wake_unlock);
二、wake_lock 实现
在linux/kernel/power/wakelock.c中我们可以看到wake_lock的实现代码,首先看看其定义的一些初始化信息:
- #define WAKE_LOCK_TYPE_MASK (0x0f) // 锁类型标志掩码
- #define WAKE_LOCK_INITIALIZED (1U << 8) // 锁已经初始化标志
- #define WAKE_LOCK_ACTIVE (1U << 9) // 锁有效标志
- #define WAKE_LOCK_AUTO_EXPIRE (1U << 10) // 超时锁标志
- #define WAKE_LOCK_PREVENTING_SUSPEND (1U << 11) // 正在阻止休眠标志
- static DEFINE_SPINLOCK(list_lock); // 读写锁链表的自旋锁
- static LIST_HEAD(inactive_locks); // 内核维护的无效锁链表
- static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT]; // 有效锁链表
- static int current_event_num; // 休眠锁使用计数器
- struct workqueue_struct *suspend_work_queue; // 执行系统休眠的工作队列
- struct workqueue_struct *sys_sync_work_queue; // 执行系统同步的工作队列
- struct wake_lock main_wake_lock; // 内核休眠锁
- struct wake_lock sys_sync_wake_lock; // 缓存同步锁
- suspend_state_t requested_suspend_state = PM_SUSPEND_MEM; // 系统休眠状态
- static struct wake_lock unknown_wakeup; // 未知锁
在后面的分析中我们会看到这些变量的具体用途。
1、wake_lock系统初始化
- static int __init wakelocks_init(void)
- {
- int ret;
- int i;
- // 初始化有效锁链表,内核维护了2个有效锁链表
- // WAKE_LOCK_SUSPEND 用于阻止进入深度休眠模式
- // WAKE_LOCK_IDLE 用于阻止进入空闲模式
- for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
- INIT_LIST_HEAD(&active_wake_locks[i]);
- #ifdef CONFIG_WAKELOCK_STAT
- // 初始化deleted_wake_locks
- wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
- "deleted_wake_locks");
- #endif
- // 初始化内核休眠锁
- wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
- // 初始化同步锁
- wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync");
- // 激活内核休眠锁
- wake_lock(&main_wake_lock);
- // 初始化未知锁
- wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
- // 注册power_device,power_driver
- ret = platform_device_register(&power_device);
- if (ret) {
- pr_err("wakelocks_init: platform_device_register failed\n");
- goto err_platform_device_register;
- }
- ret = platform_driver_register(&power_driver);
- if (ret) {
- pr_err("wakelocks_init: platform_driver_register failed\n");
- goto err_platform_driver_register;
- }
- // 创建fs_sync内核进程
- sys_sync_work_queue = create_singlethread_workqueue("fs_sync");
- if (sys_sync_work_queue == NULL) {
- pr_err ("fs_sync workqueue create failed.\n");
- }
- // 创建suspend内核进程
- suspend_work_queue = create_singlethread_workqueue("suspend");
- if (suspend_work_queue == NULL) {
- ret = -ENOMEM;
- goto err_suspend_work_queue;
- }
- #ifdef CONFIG_WAKELOCK_STAT
- // 在proc下创建wakelocks文件
- proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
- #endif
- return