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.     char *s = buf; 
  5.     char *end = buf + PAGE_SIZE; 
  6.     struct rb_node *n; 
  7.     struct user_wake_lock *l; 
  8.  
  9.     mutex_lock(&tree_lock); 
  10.  
  11.     for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) { 
  12.         l = rb_entry(n, struct user_wake_lock, node); 
  13.         if (wake_lock_active(&l->wake_lock)) 
  14.             s += scnprintf(s, end - s, "%s ", l->name); 
  15.     } 
  16.     s += scnprintf(s, end - s, "\n"); 
  17.  
  18.     mutex_unlock(&tree_lock); 
  19.     return (s - buf); 
  20.  
  21. // wack_lock文件的写函数,初始化并激活用户空间定义的锁 
  22. ssize_t wake_lock_store( 
  23.     struct kobject *kobj, struct kobj_attribute *attr, 
  24.     const char *buf, size_t n) 
  25.     long timeout; 
  26.     struct user_wake_lock *l; 
  27.  
  28.     mutex_lock(&tree_lock); 
  29.     l = lookup_wake_lock_name(buf, 1, &timeout); 
  30.     if (IS_ERR(l)) { 
  31.         n = PTR_ERR(l); 
  32.         goto bad_name; 
  33.     } 
  34.  
  35.     if (debug_mask & DEBUG_ACCESS) 
  36.         pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout); 
  37.  
  38.     if (timeout) 
  39.         wake_lock_timeout(&l->wake_lock, timeout); 
  40.     else 
  41.         wake_lock(&l->wake_lock); 
  42. bad_name: 
  43.     mutex_unlock(&tree_lock); 
  44.     return n; 
  45.  
  46. // wack_unlock文件的读函数,显示用户空间的无效锁 
  47. ssize_t wake_unlock_show( 
  48.     struct kobject *kobj, struct kobj_attribute *attr, char *buf) 
  49.     char *s = buf; 
  50.     char *end = buf + PAGE_SIZE; 
  51.     struct rb_node *n; 
  52.     struct user_wake_lock *l; 
  53.  
  54.     mutex_lock(&tree_lock); 
  55.  
  56.     for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) { 
  57.         l = rb_entry(n, struct user_wake_lock, node); 
  58.         if (!wake_lock_active(&l->wake_lock)) 
  59.             s += scnprintf(s, end - s, "%s ", l->name); 
  60.     } 
  61.     s += scnprintf(s, end - s, "\n"); 
  62.  
  63.     mutex_unlock(&tree_lock); 
  64.     return (s - buf); 
  65.  
  66. // wack_unlock文件的写函数,用于用户空间解锁 
  67. ssize_t wake_unlock_store( 
  68.     struct kobject *kobj, struct kobj_attribute *attr, 
  69.     const char *buf, size_t n) 
  70.     struct user_wake_lock *l; 
  71.  
  72.     mutex_lock(&tree_lock); 
  73.     l = lookup_wake_lock_name(buf, 0, NULL); 
  74.     if (IS_ERR(l)) { 
  75.         n = PTR_ERR(l); 
  76.         goto not_found; 
  77.     } 
  78.  
  79.     if (debug_mask & DEBUG_ACCESS) 
  80.         pr_info("wake_unlock_store: %s\n", l->name); 
  81.  
  82.     wake_unlock(&l->wake_lock); 
  83. not_found: 
  84.     mutex_unlock(&tree_lock); 
  85.     return n; 
  86.  
  87. power_attr(wake_lock); 
  88. 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.     int ret; 
  3.     int i; 
  4.     // 初始化有效锁链表,内核维护了2个有效锁链表 
  5.     // WAKE_LOCK_SUSPEND 用于阻止进入深度休眠模式 
  6.     // WAKE_LOCK_IDLE    用于阻止进入空闲模式 
  7.     for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++) 
  8.         INIT_LIST_HEAD(&active_wake_locks[i]); 
  9.  
  10. #ifdef CONFIG_WAKELOCK_STAT 
  11.     // 初始化deleted_wake_locks 
  12.     wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND, 
  13.             "deleted_wake_locks"); 
  14. #endif 
  15.     // 初始化内核休眠锁 
  16.     wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main"); 
  17.     // 初始化同步锁 
  18.     wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync"); 
  19.     // 激活内核休眠锁 
  20.     wake_lock(&main_wake_lock); 
  21.     // 初始化未知锁 
  22.     wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups"); 
  23.  
  24.     // 注册power_device,power_driver 
  25.     ret = platform_device_register(&power_device); 
  26.     if (ret) { 
  27.         pr_err("wakelocks_init: platform_device_register failed\n"); 
  28.         goto err_platform_device_register; 
  29.     } 
  30.     ret = platform_driver_register(&power_driver); 
  31.     if (ret) { 
  32.         pr_err("wakelocks_init: platform_driver_register failed\n"); 
  33.         goto err_platform_driver_register; 
  34.     } 
  35.     // 创建fs_sync内核进程 
  36.     sys_sync_work_queue = create_singlethread_workqueue("fs_sync"); 
  37.     if (sys_sync_work_queue == NULL) { 
  38.         pr_err ("fs_sync workqueue create failed.\n"); 
  39.     } 
  40.     // 创建suspend内核进程 
  41.     suspend_work_queue = create_singlethread_workqueue("suspend"); 
  42.     if (suspend_work_queue == NULL) { 
  43.         ret = -ENOMEM; 
  44.         goto err_suspend_work_queue; 
  45.     } 
  46.  
  47. #ifdef CONFIG_WAKELOCK_STAT 
  48.     // 在proc下创建wakelocks文件 
  49.     proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops); 
  50. #endif 
  51.  
  52.     return 0; 
  53.  
  54. err_suspend_work_queue: 
  55.     platform_driver_unregister(&power_driver); 
  56. err_platform_driver_register: 
  57.     platform_device_unregister(&power_device); 
  58. err_platform_device_register: 
  59.     wake_lock_destroy(&unknown_wakeup); 
  60.     wake_lock_destroy(&main_wake_lock); 
  61. #ifdef CONFIG_WAKELOCK_STAT 
  62.     wake_lock_destroy(&deleted_wake_locks); 
  63. #endif 
  64.     return ret; 
  65. core_initcall(wakelocks_init); 

可以看到内核通过core_initcall调用了wake_lock系统的初始化函数,函数首先初始化了两个有效锁的链表,用于管理系统中的有效锁;接下来初始化了deleted_wake_locks用于处理统计信息,main_wake_lock用于锁定内核(系统启动时会激活这个锁,深度休眠时需要释放这个锁),sys_sync_wake_lock用于浅度休眠阶段同步缓存时阻止内核进入深度休眠,unknown_wakeup用于唤醒时延迟0.5s进入下一次可能的深度休眠;还注册了一个platform_device用于深度休眠阶段检测是否存在有效锁;后面创建了内核进程fs_sync用于浅度休眠阶段同步缓存,内核进程suspend用于进行浅度休眠和深度休眠;还在/proc下面创建了wakelocks节点用于显示wake_lock的统计信息。

2、wake_lock初始化

[cpp]  view plain copy
  1. void wake_lock_init(struct wake_lock *lock, int type, const char *name) 
  2.     unsigned long irqflags = 0; 
  3.     // 初始化名称 
  4.     if (name) 
  5.         lock->name = name; 
  6.     BUG_ON(!lock->name); 
  7.  
  8.     if (debug_mask & DEBUG_WAKE_LOCK) 
  9.         pr_info("wake_lock_init name=%s\n", lock->name); 
  10. #ifdef CONFIG_WAKELOCK_STAT 
  11.     lock->stat.count = 0; 
  12.     lock->stat.expire_count = 0; 
  13.     lock->stat.wakeup_count = 0; 
  14.     lock->stat.total_time = ktime_set(0, 0); 
  15.     lock->stat.prevent_suspend_time = ktime_set(0, 0); 
  16.     lock->stat.max_time = ktime_set(0, 0); 
  17.     lock->stat.last_time = ktime_set(0, 0); 
  18. #endif 
  19.     // 初始化flag 
  20.     lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED; 
  21.     // 初始化链表节点 
  22.     INIT_LIST_HEAD(&lock->link); 
  23.     spin_lock_irqsave(&list_lock, irqflags); 
  24.     // 将锁加入无效锁链表 
  25.     list_add(&lock->link, &inactive_locks); 
  26.     spin_unlock_irqrestore(&list_lock, irqflags); 
  27. EXPORT_SYMBOL(wake_lock_init); 
其中参数lock为被初始化对象,type代表锁的类型,name表示锁的名称, 函数主要初始化锁的名称并设置 WAKE_LOCK_INITIALIZED 标志位,并将锁加入无效锁链表inactive_locks,当需要使用锁的时候通过wake_lock()或者wake_lock_timeout()激活该锁:

[cpp]  view plain copy
  1. // 根据参数激活锁 
  2. static void wake_lock_internal( 
  3.     struct wake_lock *lock, long timeout, int has_timeout) 
  4.     int type; 
  5.     unsigned long irqflags; 
  6.     long expire_in; 
  7.  
  8.     spin_lock_irqsave(&list_lock, irqflags); 
  9.     // 获取锁的类型 
  10.     type = lock->flags & WAKE_LOCK_TYPE_MASK; 
  11.     BUG_ON(type >= WAKE_LOCK_TYPE_COUNT); 
  12.     BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED)); 
  13. #ifdef CONFIG_WAKELOCK_STAT 
  14.     if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) { 
  15.         if (debug_mask & DEBUG_WAKEUP) 
  16.             pr_info("wakeup wake lock: %s\n", lock->name); 
  17.         wait_for_wakeup = 0; 
  18.         lock->stat.wakeup_count++; 
  19.     } 
  20.     if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) && 
  21.         (long)(lock->expires - jiffies) <= 0) { 
  22.         wake_unlock_stat_locked(lock, 0); 
  23.         lock->stat.last_time = ktime_get(); 
  24.     } 
  25. #endif 
  26.     // 设置锁有效的标志位 
  27.     if (!(lock->flags & WAKE_LOCK_ACTIVE)) { 
  28.         lock->flags |= WAKE_LOCK_ACTIVE; 
  29. #ifdef CONFIG_WAKELOCK_STAT 
  30.         lock->stat.last_time = ktime_get(); 
  31. #endif 
  32.     } 
  33.     // 将锁从无效锁链表中删除 
  34.     list_del(&lock->link); 
  35.     // 如果是超时锁 
  36.     if (has_timeout) { 
  37.         if (debug_mask & DEBUG_WAKE_LOCK) 
  38.             pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n"
  39.                 lock->name, type, timeout / HZ, 
  40.                 (timeout % HZ) * MSEC_PER_SEC / HZ); 
  41.         // 设置锁超时时间,以当前jiffies为基准 
  42.         lock->expires = jiffies + timeout; 
  43.         // 设置锁的超时锁标志 
  44.         lock->flags |= WAKE_LOCK_AUTO_EXPIRE; 
  45.         // 将锁加入有效锁链表 
  46.         list_add_tail(&lock->link, &active_wake_locks[type]); 
  47.     } else {  // 如果是永久锁 
  48.         if (debug_mask & DEBUG_WAKE_LOCK) 
  49.             pr_info("wake_lock: %s, type %d\n", lock->name, type); 
  50.         // 设置超时时间为极限 
  51.         lock->expires = LONG_MAX; 
  52.         // 清除超时锁标志 
  53.         lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE; 
  54.         // 将锁加入有效锁链表 
  55.         list_add(&lock->link, &active_wake_locks[type]); 
  56.     } 
  57.     // 如果是休眠锁 
  58.     if (type == WAKE_LOCK_SUSPEND) { 
  59.         current_event_num++;  // 休眠锁使用计数器加1 
  60. #ifdef CONFIG_WAKELOCK_STAT 
  61.         // 如果是内核休眠锁 
  62.         if (lock == &main_wake_lock) 
  63.             update_sleep_wait_stats_locked(1); 
  64.         // 如果内核休眠锁无效 
  65.         else if (!wake_lock_active(&main_wake_lock)) 
  66.             update_sleep_wait_stats_locked(0); 
  67. #endif 
  68.         // 如果是超时锁 
  69.         if (has_timeout) 
  70.             expire_in = has_wake_lock_locked(type); 
  71.         else 
  72.             expire_in = -1; 
  73.         // 当前存在有效超时锁,并且最长的一个到期时间间隔为expire_in 
  74.         if (expire_in > 0) { 
  75.             if (debug_mask & DEBUG_EXPIRE) 
  76.                 pr_info("wake_lock: %s, start expire timer, " 
  77.                     "%ld\n", lock->name, expire_in); 
  78.             mod_timer(&expire_timer, jiffies + expire_in); 
  79.         } else {  // 如果有永久锁或者无有效锁 
  80.             if (del_timer(&expire_timer)) 
  81.                 if (debug_mask & DEBUG_EXPIRE) 
  82.                     pr_info("wake_lock: %s, stop expire timer\n"
  83.                         lock->name); 
  84.             if (expire_in == 0)  // 无有效锁 
  85.                 queue_work(suspend_work_queue, &suspend_work); 
  86.         } 
  87.     } 
  88.     spin_unlock_irqrestore(&list_lock, irqflags); 
  89.  
  90. // 激活永久锁 
  91. void wake_lock(struct wake_lock *lock) 
  92.     wake_lock_internal(lock, 0, 0); 
  93. EXPORT_SYMBOL(wake_lock); 
  94.  
  95. // 激活超时锁 
  96. void wake_lock_timeout(struct wake_lock *lock, long timeout) 
  97.     wake_lock_internal(lock, timeout, 1); 
  98. EXPORT_SYMBOL(wake_lock_timeout); 
可以看到激活过程都是通过调用wake_lock_internal()完成的,该函数首先完成一些统计信息的初始化,设置 WAKE_LOCK_ACTIVE 标志位并将锁从无效锁链表中移除;然后根据是否是超时锁设置 WAKE_LOCK_AUTO_EXPIRE 标志位,并设置超时锁的超时时间,再将锁加入有效锁链表;最后再根据锁的类型判断是否为休眠锁,如果是休眠锁且为超时锁则通过has_wake_lock_locked()获取系统中存在的超时锁中时间最长的到期时间值,并以此值设置expire_timer,has_wake_lock_locked()返回0则表示系统中不存在有效锁则启动suspend进程开始进入深度休眠状态。

3、expire_timer

[cpp]  view plain copy
  1. static void expire_wake_locks(unsigned long data) 
  2.     long has_lock; 
  3.     unsigned long irqflags; 
  4.     if (debug_mask & DEBUG_EXPIRE) 
  5.         pr_info("expire_wake_locks: start\n"); 
  6.     spin_lock_irqsave(&list_lock, irqflags); 
  7.     // 打印当前的有效锁 
  8.     if (debug_mask & DEBUG_SUSPEND) 
  9.         print_active_locks(WAKE_LOCK_SUSPEND); 
  10.     // 检测系统是否持有休眠锁 
  11.     has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND); 
  12.     if (debug_mask & DEBUG_EXPIRE) 
  13.         pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock); 
  14.     // 如果系统当前没有持有有效地休眠锁 
  15.     if (has_lock == 0) 
  16.         // 则启动深度休眠工作队列 
  17.         queue_work(suspend_work_queue, &suspend_work); 
  18.     spin_unlock_irqrestore(&list_lock, irqflags); 
  19. // 定义timer,运行函数为expire_wake_locks 
  20. static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0); 
该timer会在多个地方用到,在激活锁的函数中注册用于超时锁到期后检测系统的有效锁状态,如果系统不存在有效锁了则启动suspend进程。
4、suspend_work
[cpp]  view plain copy
  1. static void suspend(struct work_struct *work) 
  2.     int ret; 
  3.     int entry_event_num; 
  4.  
  5.     // 判断系统是否还持有有效锁,如果有则直接返回 
  6.     if (has_wake_lock(WAKE_LOCK_SUSPEND)) { 
  7.         if (debug_mask & DEBUG_SUSPEND) 
  8.             pr_info("suspend: abort suspend\n"); 
  9.         return
  10.     } 
  11.  
  12.     // 记录函数进入时休眠锁的使用次数 
  13.     entry_event_num = current_event_num; 
  14.     sys_sync();  // 将缓存中的数据写入磁盘 
  15.     if (debug_mask & DEBUG_SUSPEND) 
  16.         pr_info("suspend: enter suspend\n"); 
  17.     // 开始深度休眠 
  18.     ret = pm_suspend(requested_suspend_state); 
  19.     // 退出深度休眠,打印信息 
  20.     if (debug_mask & DEBUG_EXIT_SUSPEND) { 
  21.         struct timespec ts; 
  22.         struct rtc_time tm
  23.         getnstimeofday(&ts); 
  24.         rtc_time_to_tm(ts.tv_sec, &tm); 
  25.         pr_info("suspend: exit suspend, ret = %d " 
  26.             "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret, 
  27.             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 
  28.             tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); 
  29.     } 
  30.     // 如果深度休眠前和深度休眠后锁的使用次数一致,即唤醒过程中没有激活新的锁 
  31.     if (current_event_num == entry_event_num) { 
  32.         if (debug_mask & DEBUG_SUSPEND) 
  33.             pr_info("suspend: pm_suspend returned with no event\n"); 
  34.         // 激活unknown_wakeup,0.5s超时 
  35.         wake_lock_timeout(&unknown_wakeup, HZ / 2); 
  36.     } 
  37. // 声明工作队列,运行函数为suspend 
  38. static DECLARE_WORK(suspend_work, suspend); 
声明工作队列用于内核深度休眠,可以看到一个正常的休眠流程会三次调用sys_sync()用于同步缓存(之前一次在浅度休眠,之后一次在深度休眠),然后调用pm_suspend()开始执行深度休眠流程。
5、has_wake_lock

[cpp]  view plain copy
  1. // 移除过期超时锁 
  2. static void expire_wake_lock(struct wake_lock *lock) 
  3. #ifdef CONFIG_WAKELOCK_STAT 
  4.     wake_unlock_stat_locked(lock, 1); 
  5. #endif 
  6.     // 清除锁有效和超时锁标志 
  7.     lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE); 
  8.     // 从当前链表中删除 
  9.     list_del(&lock->link); 
  10.     // 加入无效锁链表 
  11.     list_add(&lock->link, &inactive_locks); 
  12.     if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE)) 
  13.         pr_info("expired wake lock %s\n", lock->name); 
  14.  
  15. // 打印有效锁信息,调用者需持有list_lock 
  16. static void print_active_locks(int type) 
  17.     struct wake_lock *lock; 
  18.     bool print_expired = true
  19.  
  20.     BUG_ON(type >= WAKE_LOCK_TYPE_COUNT); 
  21.     // 遍历有效锁链表 
  22.     list_for_each_entry(lock, &active_wake_locks[type], link) { 
  23.         // 如果是超时锁 
  24.         if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) { 
  25.             // 计算超时剩余时间 
  26.             long timeout = lock->expires - jiffies; 
  27.             if (timeout > 0) 
  28.                 pr_info("active wake lock %s, time left %ld\n"
  29.                     lock->name, timeout); 
  30.             else if (print_expired) 
  31.                 pr_info("wake lock %s, expired\n", lock->name); 
  32.         } else {  // 如果不是超时锁 
  33.             pr_info("active wake lock %s\n", lock->name); 
  34.             if (!debug_mask & DEBUG_EXPIRE) 
  35.                 print_expired = false
  36.         } 
  37.     } 
  38.  
  39. static long has_wake_lock_locked(int type) 
  40.     struct wake_lock *lock, *n; 
  41.     long max_timeout = 0; 
  42.  
  43.     BUG_ON(type >= WAKE_LOCK_TYPE_COUNT); 
  44.     // 遍历有效锁链表 
  45.     list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) { 
  46.         // 如果是超时锁 
  47.         if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) { 
  48.             // 计算超时剩余时间 
  49.             long timeout = lock->expires - jiffies; 
  50.             // 如果锁已经过期 
  51.             if (timeout <= 0) 
  52.                 // 移除过期锁 
  53.                 expire_wake_lock(lock); 
  54.             else if (timeout > max_timeout)  // 如果锁没有过期 
  55.                 // 得到最长的一个超时时间 
  56.                 max_timeout = timeout; 
  57.         } else // 如果不是超时锁则返回-1 
  58.             return -1; 
  59.     } 
  60.     return max_timeout; 
  61.  
  62. // 判断系统是否还持有有效锁 
  63. long has_wake_lock(int type) 
  64.     long ret; 
  65.     unsigned long irqflags; 
  66.     spin_lock_irqsave(&list_lock, irqflags); 
  67.     // 开始判断流程 
  68.     ret = has_wake_lock_locked(type); 
  69.     // 如果还有休眠锁有效则打印状态信息 
  70.     if (ret && (debug_mask & DEBUG_SUSPEND) && type == WAKE_LOCK_SUSPEND) 
  71.         print_active_locks(type); 
  72.     spin_unlock_irqrestore(&list_lock, irqflags); 
  73.     return ret; 
has_wake_lock()为系统判断当前是否存在指定类型有效锁的接口,在has_wake_lock_locked()中遍历有效锁链表,返回前面我们已经说明的值;并且打印所有有效锁的状态信息。
6、wake_unlock

[cpp]  view plain copy
  1. void wake_unlock(struct wake_lock *lock) 
  2.     int type; 
  3.     unsigned long irqflags; 
  4.     spin_lock_irqsave(&list_lock, irqflags); 
  5.     type = lock->flags & WAKE_LOCK_TYPE_MASK; 
  6. #ifdef CONFIG_WAKELOCK_STAT 
  7.     // 更新锁的状态 
  8.     wake_unlock_stat_locked(lock, 0); 
  9. #endif 
  10.     if (debug_mask & DEBUG_WAKE_LOCK) 
  11.         pr_info("wake_unlock: %s\n", lock->name); 
  12.     // 清楚有效锁和超时锁标志 
  13.     lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE); 
  14.     // 将锁从有效锁链表中移除加入无效锁链表 
  15.     list_del(&lock->link); 
  16.     list_add(&lock->link, &inactive_locks); 
  17.     // 如果是休眠锁 
  18.     if (type == WAKE_LOCK_SUSPEND) { 
  19.         // 判断系统当前是否还持有锁 
  20.         long has_lock = has_wake_lock_locked(type); 
  21.         // 如果还持有锁,设置timer到超时时间点触发 
  22.         if (has_lock > 0) { 
  23.             if (debug_mask & DEBUG_EXPIRE) 
  24.                 pr_info("wake_unlock: %s, start expire timer, " 
  25.                     "%ld\n", lock->name, has_lock); 
  26.             mod_timer(&expire_timer, jiffies + has_lock); 
  27.         } else { 
  28.             if (del_timer(&expire_timer))  // 删除timer 
  29.                 if (debug_mask & DEBUG_EXPIRE) 
  30.                     pr_info("wake_unlock: %s, stop expire " 
  31.                         "timer\n", lock->name); 
  32.             if (has_lock == 0)  // 启动深度休眠工作队列 
  33.                 queue_work(suspend_work_queue, &suspend_work); 
  34.         } 
  35.         // 如果是内核锁 
  36.         if (lock == &main_wake_lock) { 
  37.             if (debug_mask & DEBUG_SUSPEND) 
  38.                 // 打印当前有效锁信息 
  39.                 print_active_locks(WAKE_LOCK_SUSPEND); 
  40. #ifdef CONFIG_WAKELOCK_STAT 
  41.             update_sleep_wait_stats_locked(0); 
  42. #endif 
  43.         } 
  44.     } 
  45.     spin_unlock_irqrestore(&list_lock, irqflags); 
  46. EXPORT_SYMBOL(wake_unlock); 
该函数用于释放一个锁,首先将锁从有效锁链表中移除并加入无效锁链表,并判断系统是否还持有有效锁,如果没有则进入深度休眠流程。

7、wake_lock_active

[cpp]  view plain copy
  1. // 判断锁是否有效 
  2. int wake_lock_active(struct wake_lock *lock) 
  3.     return !!(lock->flags & WAKE_LOCK_ACTIVE); 
  4. EXPORT_SYMBOL(wake_lock_active); 
8、wake_lock_destroy

[cpp]  view plain copy
  1. void wake_lock_destroy(struct wake_lock *lock) 
  2.     unsigned long irqflags; 
  3.     if (debug_mask & DEBUG_WAKE_LOCK) 
  4.         pr_info("wake_lock_destroy name=%s\n", lock->name); 
  5.     spin_lock_irqsave(&list_lock, irqflags); 
  6.     // 清除已经初始化的标志 
  7.     lock->flags &= ~WAKE_LOCK_INITIALIZED; 
  8. #ifdef CONFIG_WAKELOCK_STAT 
  9.     if (lock->stat.count) { 
  10.         deleted_wake_locks.stat.count += lock->stat.count; 
  11.         deleted_wake_locks.stat.expire_count += lock->stat.expire_count; 
  12.         deleted_wake_locks.stat.total_time = 
  13.             ktime_add(deleted_wake_locks.stat.total_time, 
  14.                   lock->stat.total_time); 
  15.         deleted_wake_locks.stat.prevent_suspend_time = 
  16.             ktime_add(deleted_wake_locks.stat.prevent_suspend_time, 
  17.                   lock->stat.prevent_suspend_time); 
  18.         deleted_wake_locks.stat.max_time = 
  19.             ktime_add(deleted_wake_locks.stat.max_time, 
  20.                   lock->stat.max_time); 
  21.     } 
  22. #endif 
  23.     // 从当前链表中删除 
  24.     list_del(&lock->link); 
  25.     spin_unlock_irqrestore(&list_lock, irqflags); 
  26. EXPORT_SYMBOL(wake_lock_destroy); 
该函数用于注销wake_lock,首先清除 WAKE_LOCK_INITIALIZED 标志位,然后更新统计信息,最后将锁从链表中删除。

9、proc节点

[cpp]  view plain copy
  1. // 获取锁的剩余超时时间,通过*expire_time传递 
  2. int get_expired_time(struct wake_lock *lock, ktime_t *expire_time) 
  3.     struct timespec ts; 
  4.     struct timespec kt; 
  5.     struct timespec tomono; 
  6.     struct timespec delta; 
  7.     unsigned long seq; 
  8.     long timeout; 
  9.  
  10.     // 如果不是超时锁则直接返回 
  11.     if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE)) 
  12.         return 0; 
  13.  
  14.     do { 
  15.         seq = read_seqbegin(&xtime_lock); 
  16.         // 计算超时时间点与当前时间的差值 
  17.         timeout = lock->expires - jiffies; 
  18.         // 如果时间没有到期,返回0 
  19.         if (timeout > 0) 
  20.             return 0; 
  21.         // 获取当前时间 
  22.         kt = current_kernel_time(); 
  23.         tomono = wall_to_monotonic; 
  24.     } while (read_seqretry(&xtime_lock, seq)); 
  25.     // 时间格式转换 
  26.     jiffies_to_timespec(-timeout, &delta); 
  27.     // 设置timespec的成员 
  28.     set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec, 
  29.                 kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec); 
  30.     // 返回ts值 
  31.     *expire_time = timespec_to_ktime(ts); 
  32.     return 1; 
  33.  
  34. // 打印出锁的状态信息 
  35. static int print_lock_stat(struct seq_file *m, struct wake_lock *lock) 
  36.     int lock_count = lock->stat.count; 
  37.     int expire_count = lock->stat.expire_count; 
  38.     ktime_t active_time = ktime_set(0, 0); 
  39.     ktime_t total_time = lock->stat.total_time; 
  40.     ktime_t max_time = lock->stat.max_time; 
  41.  
  42.     ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time; 
  43.     // 如果锁有效 
  44.     if (lock->flags & WAKE_LOCK_ACTIVE) { 
  45.         ktime_t now, add_time; 
  46.         // 获取超时剩余时间 
  47.         int expired = get_expired_time(lock, &now); 
  48.         if (!expired) 
  49.             now = ktime_get(); 
  50.         // 计算当前时间和上次操作时间的差值 
  51.         add_time = ktime_sub(now, lock->stat.last_time); 
  52.         lock_count++;  // 使用计数加1 
  53.         if (!expired)  // 如果没有到期 
  54.             active_time = add_time; 
  55.         else  // 锁已经到期 
  56.             expire_count++;  // 超时计数加1 
  57.         total_time = ktime_add(total_time, add_time);  // 锁使用时间增加 
  58.         if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND) 
  59.             prevent_suspend_time = ktime_add(prevent_suspend_time, 
  60.                     ktime_sub(now, last_sleep_time_update)); 
  61.         if (add_time.tv64 > max_time.tv64) 
  62.             max_time = add_time; 
  63.     } 
  64.  
  65.     return seq_printf(m, 
  66.              "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n"
  67.              lock->name, lock_count, expire_count, 
  68.              lock->stat.wakeup_count, ktime_to_ns(active_time), 
  69.              ktime_to_ns(total_time), 
  70.              ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time), 
  71.              ktime_to_ns(lock->stat.last_time)); 
  72.  
  73. // 打印锁状态 
  74. static int wakelock_stats_show(struct seq_file *m, void *unused) 
  75.     unsigned long irqflags; 
  76.     struct wake_lock *lock; 
  77.     int ret; 
  78.     int type; 
  79.  
  80.     spin_lock_irqsave(&list_lock, irqflags); 
  81.     // 输出菜单 
  82.     ret = seq_puts(m, "name\tcount\texpire_count\twake_count\tactive_since" 
  83.             "\ttotal_time\tsleep_time\tmax_time\tlast_change\n"); 
  84.     // 遍历无效锁链表并打印锁的状态信息 
  85.     list_for_each_entry(lock, &inactive_locks, link) 
  86.         ret = print_lock_stat(m, lock); 
  87.     // 遍历有效锁链表并打印锁的状态信息 
  88.     for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) { 
  89.         list_for_each_entry(lock, &active_wake_locks[type], link) 
  90.             ret = print_lock_stat(m, lock); 
  91.     } 
  92.     spin_unlock_irqrestore(&list_lock, irqflags); 
  93.     return 0; 
  94.  
  95. // proc文件打开函数,调用show函数显示当前所有的锁信息 
  96. static int wakelock_stats_open(struct inode *inode, struct file *file) 
  97.     return single_open(file, wakelock_stats_show, NULL); 
  98.  
  99. // proc文件系统操作函数 
  100. static const struct file_operations wakelock_stats_fops = { 
  101.     .owner = THIS_MODULE, 
  102.     .open = wakelock_stats_open, 
  103.     .read = seq_read, 
  104.     .llseek = seq_lseek, 
  105.     .release = single_release, 
  106. }; 

以上是proc节点的操作接口,在wakelocks_init中注册。


总结:通过以上分析我们可以看到启动深度休眠流程有四个可能的地方,分别为expire_timer、wake_lock、wake_lock_timeout、wake_unlock,其中expire_timer和wake_unlock最常见

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值