android 休眠唤醒机制分析(一)

Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作。wake_lock一般在关闭lcd、tp但系统仍然需要正常运行的情况下使用,比如听歌、传输很大的文件等。本文主要分析driver层wake_lock的实现。

一、wake_lock 定义和接口

[cpp]  view plain copy
  1. enum {  
  2.     WAKE_LOCK_SUSPEND, // 阻止进入深度休眠模式  
  3.     WAKE_LOCK_IDLE,    // 阻止进入空闲模式  
  4.     WAKE_LOCK_TYPE_COUNT  
  5. };  
  6.   
  7. struct wake_lock {  
  8. #ifdef CONFIG_HAS_WAKELOCK  
  9.     struct list_head    link;     // 链表节点  
  10.     int                 flags;    // 标志  
  11.     const char         *name;     // 名称  
  12.     unsigned long       expires;  // 超时时间  
  13. #ifdef CONFIG_WAKELOCK_STAT  
  14.     struct {  
  15.         int             count;         // 使用计数  
  16.         int             expire_count;  // 超时计数  
  17.         int             wakeup_count;  // 唤醒计数  
  18.         ktime_t         total_time;    // 锁使用时间  
  19.         ktime_t         prevent_suspend_time;  // 锁阻止休眠的时间  
  20.         ktime_t         max_time;      // 锁使用时间最长的一次  
  21.         ktime_t         last_time;     // 锁上次操作时间  
  22.     } stat;  
  23. #endif  
  24. #endif  
  25. };  

可以看到wake_lock按功能分为休眠锁和空闲锁两种类型,用于阻止系统进入深度休眠模式或者空闲模式。wake_lock的主要部件有锁名称、链表节点、标志位、超时时间,另外还有一个内嵌的结构用于统计锁的使用信息。接下来我们看看wake_lock对外提供的操作接口:

1、内核空间接口

[cpp]  view plain copy
  1. void wake_lock_init(struct wake_lock *lock, int type, const char *name);  
  2. void wake_lock_destroy(struct wake_lock *lock);  
  3. void wake_lock(struct wake_lock *lock);  
  4. void wake_lock_timeout(struct wake_lock *lock, long timeout);  
  5. void wake_unlock(struct wake_lock *lock);  
其中wake_lock_init()用于初始化一个新锁,type参数指定了锁的类型;wake_lock_destroy()则注销一个锁;wake_lock()和wake_lock_timeout()用于将初始化完成的锁激活,使之成为有效的永久锁或者超时锁;wake_unlock()用于解锁使之成为无效锁。另外还有两个接口:

[cpp]  view plain copy
  1. int wake_lock_active(struct wake_lock *lock);  
  2. long has_wake_lock(int type);  

其中wake_lock_active()用于判断锁当前是否有效,如果有效则返回非0值;has_wake_lock()用于判断系统中是否还存在有效的type型锁,如果存在超时锁则返回最长的一个锁的超时时间,如果存在永久锁则返回-1,如果系统中不存在有效锁则返回0。

2、用户空间接口

wake_lock向用户空间提供了两个文件节点用于申请锁和解锁:

[cpp]  view plain copy
  1. // wack_lock文件的读函数,显示用户空间定义的有效锁  
  2. ssize_t wake_lock_show(  
  3.     struct kobject *kobj, struct kobj_attribute *attr, char *buf)  
  4. {  
  5.     char *s = buf;  
  6.     char *end = buf + PAGE_SIZE;  
  7.     struct rb_node *n;  
  8.     struct user_wake_lock *l;  
  9.   
  10.     mutex_lock(&tree_lock);  
  11.   
  12.     for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {  
  13.         l = rb_entry(n, struct user_wake_lock, node);  
  14.         if (wake_lock_active(&l->wake_lock))  
  15.             s += scnprintf(s, end - s, "%s ", l->name);  
  16.     }  
  17.     s += scnprintf(s, end - s, "\n");  
  18.   
  19.     mutex_unlock(&tree_lock);  
  20.     return (s - buf);  
  21. }  
  22.   
  23. // wack_lock文件的写函数,初始化并激活用户空间定义的锁  
  24. ssize_t wake_lock_store(  
  25.     struct kobject *kobj, struct kobj_attribute *attr,  
  26.     const char *buf, size_t n)  
  27. {  
  28.     long timeout;  
  29.     struct user_wake_lock *l;  
  30.   
  31.     mutex_lock(&tree_lock);  
  32.     l = lookup_wake_lock_name(buf, 1, &timeout);  
  33.     if (IS_ERR(l)) {  
  34.         n = PTR_ERR(l);  
  35.         goto bad_name;  
  36.     }  
  37.   
  38.     if (debug_mask & DEBUG_ACCESS)  
  39.         pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);  
  40.   
  41.     if (timeout)  
  42.         wake_lock_timeout(&l->wake_lock, timeout);  
  43.     else  
  44.         wake_lock(&l->wake_lock);  
  45. bad_name:  
  46.     mutex_unlock(&tree_lock);  
  47.     return n;  
  48. }  
  49.   
  50. // wack_unlock文件的读函数,显示用户空间的无效锁  
  51. ssize_t wake_unlock_show(  
  52.     struct kobject *kobj, struct kobj_attribute *attr, char *buf)  
  53. {  
  54.     char *s = buf;  
  55.     char *end = buf + PAGE_SIZE;  
  56.     struct rb_node *n;  
  57.     struct user_wake_lock *l;  
  58.   
  59.     mutex_lock(&tree_lock);  
  60.   
  61.     for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {  
  62.         l = rb_entry(n, struct user_wake_lock, node);  
  63.         if (!wake_lock_active(&l->wake_lock))  
  64.             s += scnprintf(s, end - s, "%s ", l->name);  
  65.     }  
  66.     s += scnprintf(s, end - s, "\n");  
  67.   
  68.     mutex_unlock(&tree_lock);  
  69.     return (s - buf);  
  70. }  
  71.   
  72. // wack_unlock文件的写函数,用于用户空间解锁  
  73. ssize_t wake_unlock_store(  
  74.     struct kobject *kobj, struct kobj_attribute *attr,  
  75.     const char *buf, size_t n)  
  76. {  
  77.     struct user_wake_lock *l;  
  78.   
  79.     mutex_lock(&tree_lock);  
  80.     l = lookup_wake_lock_name(buf, 0, NULL);  
  81.     if (IS_ERR(l)) {  
  82.         n = PTR_ERR(l);  
  83.         goto not_found;  
  84.     }  
  85.   
  86.     if (debug_mask & DEBUG_ACCESS)  
  87.         pr_info("wake_unlock_store: %s\n", l->name);  
  88.   
  89.     wake_unlock(&l->wake_lock);  
  90. not_found:  
  91.     mutex_unlock(&tree_lock);  
  92.     return n;  
  93. }  
  94.   
  95. power_attr(wake_lock);  
  96. power_attr(wake_unlock);  
这两个文件节点分别为"/sys/power/wake_lock"和"/sys/power/wake_unlock",应用程序可以根据HAL层的接口读写这两个节点。
二、wake_lock 实现
在linux/kernel/power/wakelock.c中我们可以看到wake_lock的实现代码,首先看看其定义的一些初始化信息:

[cpp]  view plain copy
  1. #define WAKE_LOCK_TYPE_MASK              (0x0f)     // 锁类型标志掩码  
  2. #define WAKE_LOCK_INITIALIZED            (1U << 8)  // 锁已经初始化标志  
  3. #define WAKE_LOCK_ACTIVE                 (1U << 9)  // 锁有效标志  
  4. #define WAKE_LOCK_AUTO_EXPIRE            (1U << 10) // 超时锁标志  
  5. #define WAKE_LOCK_PREVENTING_SUSPEND     (1U << 11) // 正在阻止休眠标志  
  6.   
  7. static DEFINE_SPINLOCK(list_lock);  // 读写锁链表的自旋锁  
  8. static LIST_HEAD(inactive_locks);   // 内核维护的无效锁链表  
  9. static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];  // 有效锁链表  
  10. static int current_event_num;       // 休眠锁使用计数器  
  11. struct workqueue_struct *suspend_work_queue;  // 执行系统休眠的工作队列  
  12. struct workqueue_struct *sys_sync_work_queue; // 执行系统同步的工作队列  
  13. struct wake_lock main_wake_lock;              // 内核休眠锁  
  14. struct wake_lock sys_sync_wake_lock;          // 缓存同步锁  
  15. suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;  // 系统休眠状态  
  16. static struct wake_lock unknown_wakeup;       // 未知锁  

在后面的分析中我们会看到这些变量的具体用途。

1、wake_lock系统初始化

[cpp]  view plain copy
  1. static int __init wakelocks_init(void)  
  2. {  
  3.     int ret;  
  4.     int i;  
  5.     // 初始化有效锁链表,内核维护了2个有效锁链表  
  6.     // WAKE_LOCK_SUSPEND 用于阻止进入深度休眠模式  
  7.     // WAKE_LOCK_IDLE    用于阻止进入空闲模式  
  8.     for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)  
  9.         INIT_LIST_HEAD(&active_wake_locks[i]);  
  10.   
  11. #ifdef CONFIG_WAKELOCK_STAT  
  12.     // 初始化deleted_wake_locks  
  13.     wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,  
  14.             "deleted_wake_locks");  
  15. #endif  
  16.     // 初始化内核休眠锁  
  17.     wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");  
  18.     // 初始化同步锁  
  19.     wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync");  
  20.     // 激活内核休眠锁  
  21.     wake_lock(&main_wake_lock);  
  22.     // 初始化未知锁  
  23.     wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");  
  24.   
  25.     // 注册power_device,power_driver  
  26.     ret = platform_device_register(&power_device);  
  27.     if (ret) {  
  28.         pr_err("wakelocks_init: platform_device_register failed\n");  
  29.         goto err_platform_device_register;  
  30.     }  
  31.     ret = platform_driver_register(&power_driver);  
  32.     if (ret) {  
  33.         pr_err("wakelocks_init: platform_driver_register failed\n");  
  34.         goto err_platform_driver_register;  
  35.     }  
  36.     // 创建fs_sync内核进程  
  37.     sys_sync_work_queue = create_singlethread_workqueue("fs_sync");  
  38.     if (sys_sync_work_queue == NULL) {  
  39.         pr_err ("fs_sync workqueue create failed.\n");  
  40.     }  
  41.     // 创建suspend内核进程  
  42.     suspend_work_queue = create_singlethread_workqueue("suspend");  
  43.     if (suspend_work_queue == NULL) {  
  44.         ret = -ENOMEM;  
  45.         goto err_suspend_work_queue;  
  46.     }  
  47.   
  48. #ifdef CONFIG_WAKELOCK_STAT  
  49.     // 在proc下创建wakelocks文件  
  50.     proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);  
  51. #endif  
  52.   
  53.     return
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值