Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作。wake_lock一般在关闭lcd、tp但系统仍然需要正常运行的情况下使用,比如听歌、传输很大的文件等。
Wake lock - wakelock在android的电源管理系统中扮演一个核心的角色,wakelock是一种锁的机制, 只要有task拿着这个锁, 系统就无法进入休眠, 可以被用户态进程和内核线程获得。这个锁可以是有超时的或者是没有超时的, 超时的锁会在时间过去以后自动解锁。如果没有锁了或者超时了, 内核就会启动标准linux的那套休眠机制机制来进入休眠。
wakelock在android的休眠唤醒机制中扮演着及其重要的角色,主要源码位于文件:kernel/kernel/power/wakelock.c,kernel/include/linux/wakelock.h中。
本文主要分析driver层wake_lock的实现。
一、wake_lock 定义和接口
1. enum {
2. // 阻止进入深度休眠模式
3. // 阻止进入空闲模式
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. long expires; // 超时时间
13. #ifdef CONFIG_WAKELOCK_STAT
14. struct {
15. int count; // 使用计数
16. int expire_count; // 超时计数
17. int wakeup_count; // 唤醒计数
18. // 锁使用时间
19. // 锁阻止休眠的时间
20. // 锁使用时间最长的一次
21. // 锁上次操作时间
22. } stat;
23. #endif
24. #endif
25. };
可以看到wake_lock按功能分为休眠锁和空闲锁两种类型,用于阻止系统进入深度休眠模式或者空闲模式。wake_lock的主要部件有锁名称、链表节点、标志位、超时时间,另外还有一个内嵌的结构用于统计锁的使用信息。接下来我们看看wake_lock对外提供的操作接口:
1、内核空间接口
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()用于解锁使之成为无效锁。另外还有两个接口:
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向用户空间提供了两个文件节点用于申请锁和解锁:
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. struct user_wake_lock, node);
14. if (wake_lock_active(&l->wake_lock))
15. "%s ", l->name);
16. }
17. "\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. "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. struct user_wake_lock, node);
63. if (!wake_lock_active(&l->wake_lock))
64. "%s ", l->name);
65. }
66. "\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. "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的实现代码,首先看看其定义的一些初始化信息:
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系统初始化
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 // 初始化wakelock deleted_wake_locks,同时将其加入到非活动锁链表中
13. wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
14. "deleted_wake_locks");
15. #endif
16. // 初始化内核休眠锁
17. "main");
18. // 初始化同步锁
19. "sys_sync");
20. // 激活内核休眠锁
21. wake_lock(&main_wake_lock);
22. // 初始化未知锁
23. "unknown_wakeups");
24.
25. // 注册power_device,power_driver
26. ret = platform_device_register(&power_device);
27. if (ret) {
28. "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. "wakelocks_init: platform_driver_register failed\n");
34. goto err_platform_driver_register;
35. }
36. // 创建fs_sync内核进程
37. "fs_sync");
38. if (sys_sync_work_queue == NULL) {
39. "fs_sync workqueue create failed.\n");
40. }
41. // 创建suspend内核进程
42. "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. "wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
51. #endif
52.
53. return 0;
54.
55. err_suspend_work_queue:
56. platform_driver_unregister(&power_driver);
57. err_platform_driver_register:
58. platform_device_unregister(&power_device);
59. err_platform_device_register:
60. wake_lock_destroy(&unknown_wakeup);
61. wake_lock_destroy(&main_wake_lock);
62. #ifdef CONFIG_WAKELOCK_STAT
63. wake_lock_destroy(&deleted_wake_locks);
64. #endif
65. return ret;
66. }
67. 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初始化
1. void wake_lock_init(struct wake_lock *lock, int type, const char *name)
2. {
3. long irqflags = 0;
4. // 初始化名称
5. if (name)
6. lock->name = name;
7. BUG_ON(!lock->name);
8.
9. if (debug_mask & DEBUG_WAKE_LOCK)
10. "wake_lock_init name=%s\n", lock->name);
11. #ifdef CONFIG_WAKELOCK_STAT
12. lock->stat.count = 0;
13. lock->stat.expire_count = 0;
14. lock->stat.wakeup_count = 0;
15. lock->stat.total_time = ktime_set(0, 0);
16. lock->stat.prevent_suspend_time = ktime_set(0, 0);
17. lock->stat.max_time = ktime_set(0, 0);
18. lock->stat.last_time = ktime_set(0, 0);
19. #endif
20. // 初始化flag
21. lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
22. // 初始化链表节点
23. INIT_LIST_HEAD(&lock->link);
24. spin_lock_irqsave(&list_lock, irqflags);
25. // 将锁加入无效锁链表
26. list_add(&lock->link, &inactive_locks);
27. spin_unlock_irqrestore(&list_lock, irqflags);
28. }
29. EXPORT_SYMBOL(wake_lock_init);
其中参数lock为被初始化对象,type代表锁的类型,name表示锁的名称, 函数主要初始化锁的名称并设置 WAKE_LOCK_INITIALIZED 标志位,并将锁加入无效锁链表inactive_locks,当需要使用锁的时候通过wake_lock()或者wake_lock_timeout()激活该锁:
1. // 根据参数激活锁
2. static void wake_lock_internal(
3. struct wake_lock *lock, long timeout, int has_timeout)
4. {
5. int type;
6. long irqflags;
7. long expire_in;
8.
9. spin_lock_irqsave(&list_lock, irqflags);
10. // 获取锁的类型
11. type = lock->flags & WAKE_LOCK_TYPE_MASK;
12. BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
13. BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
14. #ifdef CONFIG_WAKELOCK_STAT
15. if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
16. if (debug_mask & DEBUG_WAKEUP)
17. "wakeup wake lock: %s\n", lock->name);
18. wait_for_wakeup = 0;
19. lock->stat.wakeup_count++;
20. }
21. if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
22. long)(lock->expires - jiffies) <= 0) {
23. wake_unlock_stat_locked(lock, 0);
24. lock->stat.last_time = ktime_get();
25. }
26. #endif
27. // 设置锁有效的标志位
28. if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
29. lock->flags |= WAKE_LOCK_ACTIVE;
30. #ifdef CONFIG_WAKELOCK_STAT
31. lock->stat.last_time = ktime_get();
32. #endif
33. }
34. // 将锁从无效锁链表中删除
35. list_del(&lock->link);
36. // 如果是超时锁
37. if (has_timeout) {
38. if (debug_mask & DEBUG_WAKE_LOCK)
39. "wake_lock: %s, type %d, timeout %ld.%03lu\n",
40. lock->name, type, timeout / HZ,
41. (timeout % HZ) * MSEC_PER_SEC / HZ);
42. // 设置锁超时时间,以当前jiffies为基准
43. lock->expires = jiffies + timeout;
44. // 设置锁的超时锁标志
45. lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
46. // 将锁加入有效锁链表
47. list_add_tail(&lock->link, &active_wake_locks[type]);
48. else { // 如果是永久锁
49. if (debug_mask & DEBUG_WAKE_LOCK)
50. "wake_lock: %s, type %d\n", lock->name, type);
51. // 设置超时时间为极限
52. lock->expires = LONG_MAX;
53. // 清除超时锁标志
54. lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
55. // 将锁加入有效锁链表
56. list_add(&lock->link, &active_wake_locks[type]);
57. }
58. // 如果是休眠锁
59. if (type == WAKE_LOCK_SUSPEND) {
60. // 休眠锁使用计数器加1
61. #ifdef CONFIG_WAKELOCK_STAT
62. // 如果是内核休眠锁
63. if (lock == &main_wake_lock)
64. update_sleep_wait_stats_locked(1);
65. // 如果内核休眠锁无效
66. else if (!wake_lock_active(&main_wake_lock))
67. update_sleep_wait_stats_locked(0);
68. #endif
69. // 如果是超时锁
70. if (has_timeout)
71. expire_in = has_wake_lock_locked(type);
72. else
73. expire_in = -1;
74. // 当前存在有效超时锁,并且最长的一个到期时间间隔为expire_in
75. if (expire_in > 0) {
76. if (debug_mask & DEBUG_EXPIRE)
77. "wake_lock: %s, start expire timer, "
78. "%ld\n", lock->name, expire_in);
79. mod_timer(&expire_timer, jiffies + expire_in);
80. else { // 如果有永久锁或者无有效锁
81. if (del_timer(&expire_timer))
82. if (debug_mask & DEBUG_EXPIRE)
83. "wake_lock: %s, stop expire timer\n",
84. lock->name);
85. if (expire_in == 0) // 无有效锁
86. queue_work(suspend_work_queue, &suspend_work);
87. }
88. }
89. spin_unlock_irqrestore(&list_lock, irqflags);
90. }
91.
92. // 激活永久锁
93. void wake_lock(struct wake_lock *lock)
94. {
95. wake_lock_internal(lock, 0, 0);
96. }
97. EXPORT_SYMBOL(wake_lock);
98.
99. // 激活超时锁
100. void wake_lock_timeout(struct wake_lock *lock, long timeout)
101. {
102. wake_lock_internal(lock, timeout, 1);
103. }
104. 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
1. static void expire_wake_locks(unsigned long data)
2. {
3. long has_lock;
4. long irqflags;
5. if (debug_mask & DEBUG_EXPIRE)
6. "expire_wake_locks: start\n");
7. spin_lock_irqsave(&list_lock, irqflags);
8. // 打印当前的有效锁
9. if (debug_mask & DEBUG_SUSPEND)
10. print_active_locks(WAKE_LOCK_SUSPEND);
11. // 检测系统是否持有休眠锁
12. has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
13. if (debug_mask & DEBUG_EXPIRE)
14. "expire_wake_locks: done, has_lock %ld\n", has_lock);
15. // 如果系统当前没有持有有效地休眠锁
16. if (has_lock == 0)
17. // 则启动深度休眠工作队列
18. queue_work(suspend_work_queue, &suspend_work);
19. spin_unlock_irqrestore(&list_lock, irqflags);
20. }
21. // 定义timer,运行函数为expire_wake_locks
22. static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
该timer会在多个地方用到,在激活锁的函数中注册用于超时锁到期后检测系统的有效锁状态,如果系统不存在有效锁了则启动suspend进程。
4、suspend_work
1. static void suspend(struct work_struct *work)
2. {
3. int ret;
4. int entry_event_num;
5.
6. // 判断系统是否还持有有效锁,如果有则直接返回
7. if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
8. if (debug_mask & DEBUG_SUSPEND)
9. "suspend: abort suspend\n");
10. return;
11. }
12.
13. // 记录函数进入时休眠锁的使用次数
14. entry_event_num = current_event_num;
15. // 将缓存中的数据写入磁盘
16. if (debug_mask & DEBUG_SUSPEND)
17. "suspend: enter suspend\n");
18. // 开始深度休眠
19. ret = pm_suspend(requested_suspend_state);
20. // 退出深度休眠,打印信息
21. if (debug_mask & DEBUG_EXIT_SUSPEND) {
22. struct timespec ts;
23. struct rtc_time tm;
24. getnstimeofday(&ts);
25. tm);
26. "suspend: exit suspend, ret = %d "
27. "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
28. tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
29. tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
30. }
31. // 如果深度休眠前和深度休眠后锁的使用次数一致,即唤醒过程中没有激活新的锁
32. if (current_event_num == entry_event_num) {
33. if (debug_mask & DEBUG_SUSPEND)
34. "suspend: pm_suspend returned with no event\n");
35. // 激活unknown_wakeup,0.5s超时
36. wake_lock_timeout(&unknown_wakeup, HZ / 2);
37. }
38. }
39. // 声明工作队列,运行函数为suspend
40. static DECLARE_WORK(suspend_work, suspend);
声明工作队列用于内核深度休眠,可以看到一个正常的休眠流程会三次调用sys_sync()用于同步缓存(之前一次在浅度休眠,之后一次在深度休眠),然后调用pm_suspend()开始执行深度休眠流程。
5、has_wake_lock
1. // 移除过期超时锁
2. static void expire_wake_lock(struct wake_lock *lock)
3. {
4. #ifdef CONFIG_WAKELOCK_STAT
5. wake_unlock_stat_locked(lock, 1);
6. #endif
7. // 清除锁有效和超时锁标志
8. lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
9. // 从当前链表中删除
10. list_del(&lock->link);
11. // 加入无效锁链表
12. list_add(&lock->link, &inactive_locks);
13. if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE))
14. "expired wake lock %s\n", lock->name);
15. }
16.
17. // 打印有效锁信息,调用者需持有list_lock
18. static void print_active_locks(int type)
19. {
20. struct wake_lock *lock;
21. bool print_expired = true;
22.
23. BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
24. // 遍历有效锁链表
25. list_for_each_entry(lock, &active_wake_locks[type], link) {
26. // 如果是超时锁
27. if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
28. // 计算超时剩余时间
29. long timeout = lock->expires - jiffies;
30. if (timeout > 0)
31. "active wake lock %s, time left %ld\n",
32. lock->name, timeout);
33. else if (print_expired)
34. "wake lock %s, expired\n", lock->name);
35. else { // 如果不是超时锁
36. "active wake lock %s\n", lock->name);
37. if (!debug_mask & DEBUG_EXPIRE)
38. false;
39. }
40. }
41. }
42.
43. static long has_wake_lock_locked(int type)
44. {
45. struct wake_lock *lock, *n;
46. long max_timeout = 0;
47.
48. BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
49. // 遍历有效锁链表
50. list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {
51. // 如果是超时锁
52. if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
53. // 计算超时剩余时间
54. long timeout = lock->expires - jiffies;
55. // 如果锁已经过期
56. if (timeout <= 0)
57. // 移除过期锁
58. expire_wake_lock(lock);
59. else if (timeout > max_timeout) // 如果锁没有过期
60. // 得到最长的一个超时时间
61. max_timeout = timeout;
62. else // 如果不是超时锁则返回-1
63. return -1;
64. }
65. return max_timeout;
66. }
67.
68. // 判断系统是否还持有有效锁
69. long has_wake_lock(int type)
70. {
71. long ret;
72. long irqflags;
73. spin_lock_irqsave(&list_lock, irqflags);
74. // 开始判断流程
75. ret = has_wake_lock_locked(type);
76. // 如果还有休眠锁有效则打印状态信息
77. if (ret && (debug_mask & DEBUG_SUSPEND) && type == WAKE_LOCK_SUSPEND)
78. print_active_locks(type);
79. spin_unlock_irqrestore(&list_lock, irqflags);
80. return ret;
81. }
has_wake_lock()为系统判断当前是否存在指定类型有效锁的接口,在has_wake_lock_locked()中遍历有效锁链表,返回前面我们已经说明的值;并且打印所有有效锁的状态信息。
6、wake_unlock
1. void wake_unlock(struct wake_lock *lock)
2. {
3. int type;
4. long irqflags;
5. spin_lock_irqsave(&list_lock, irqflags);
6. type = lock->flags & WAKE_LOCK_TYPE_MASK;
7. #ifdef CONFIG_WAKELOCK_STAT
8. // 更新锁的状态
9. wake_unlock_stat_locked(lock, 0);
10. #endif
11. if (debug_mask & DEBUG_WAKE_LOCK)
12. "wake_unlock: %s\n", lock->name);
13. // 清楚有效锁和超时锁标志
14. lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
15. // 将锁从有效锁链表中移除加入无效锁链表
16. list_del(&lock->link);
17. list_add(&lock->link, &inactive_locks);
18. // 如果是休眠锁
19. if (type == WAKE_LOCK_SUSPEND) {
20. // 判断系统当前是否还持有锁
21. long has_lock = has_wake_lock_locked(type);
22. // 如果还持有锁,设置timer到超时时间点触发
23. if (has_lock > 0) {
24. if (debug_mask & DEBUG_EXPIRE)
25. "wake_unlock: %s, start expire timer, "
26. "%ld\n", lock->name, has_lock);
27. mod_timer(&expire_timer, jiffies + has_lock);
28. else {
29. if (del_timer(&expire_timer)) // 删除timer
30. if (debug_mask & DEBUG_EXPIRE)
31. "wake_unlock: %s, stop expire "
32. "timer\n", lock->name);
33. if (has_lock == 0) // 启动深度休眠工作队列
34. queue_work(suspend_work_queue, &suspend_work);
35. }
36. // 如果是内核锁
37. if (lock == &main_wake_lock) {
38. if (debug_mask & DEBUG_SUSPEND)
39. // 打印当前有效锁信息
40. print_active_locks(WAKE_LOCK_SUSPEND);
41. #ifdef CONFIG_WAKELOCK_STAT
42. update_sleep_wait_stats_locked(0);
43. #endif
44. }
45. }
46. spin_unlock_irqrestore(&list_lock, irqflags);
47. }
48. EXPORT_SYMBOL(wake_unlock);
该函数用于释放一个锁,首先将锁从有效锁链表中移除并加入无效锁链表,并判断系统是否还持有有效锁,如果没有则进入深度休眠流程。
7、wake_lock_active
1. // 判断锁是否有效
2. int wake_lock_active(struct wake_lock *lock)
3. {
4. return !!(lock->flags & WAKE_LOCK_ACTIVE);
5. }
6. EXPORT_SYMBOL(wake_lock_active);
8、wake_lock_destroy
1. void wake_lock_destroy(struct wake_lock *lock)
2. {
3. long irqflags;
4. if (debug_mask & DEBUG_WAKE_LOCK)
5. "wake_lock_destroy name=%s\n", lock->name);
6. spin_lock_irqsave(&list_lock, irqflags);
7. // 清除已经初始化的标志
8. lock->flags &= ~WAKE_LOCK_INITIALIZED;
9. #ifdef CONFIG_WAKELOCK_STAT
10. if (lock->stat.count) {
11. deleted_wake_locks.stat.count += lock->stat.count;
12. deleted_wake_locks.stat.expire_count += lock->stat.expire_count;
13. deleted_wake_locks.stat.total_time =
14. ktime_add(deleted_wake_locks.stat.total_time,
15. lock->stat.total_time);
16. deleted_wake_locks.stat.prevent_suspend_time =
17. ktime_add(deleted_wake_locks.stat.prevent_suspend_time,
18. lock->stat.prevent_suspend_time);
19. deleted_wake_locks.stat.max_time =
20. ktime_add(deleted_wake_locks.stat.max_time,
21. lock->stat.max_time);
22. }
23. #endif
24. // 从当前链表中删除
25. list_del(&lock->link);
26. spin_unlock_irqrestore(&list_lock, irqflags);
27. }
28. EXPORT_SYMBOL(wake_lock_destroy);
该函数用于注销wake_lock,首先清除 WAKE_LOCK_INITIALIZED 标志位,然后更新统计信息,最后将锁从链表中删除。
9、proc节点
1. // 获取锁的剩余超时时间,通过*expire_time传递
2. int get_expired_time(struct wake_lock *lock, ktime_t *expire_time)
3. {
4. struct timespec ts;
5. struct timespec kt;
6. struct timespec tomono;
7. struct timespec delta;
8. long seq;
9. long timeout;
10.
11. // 如果不是超时锁则直接返回
12. if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE))
13. return 0;
14.
15. do {
16. seq = read_seqbegin(&xtime_lock);
17. // 计算超时时间点与当前时间的差值
18. timeout = lock->expires - jiffies;
19. // 如果时间没有到期,返回0
20. if (timeout > 0)
21. return 0;
22. // 获取当前时间
23. kt = current_kernel_time();
24. tomono = wall_to_monotonic;
25. while (read_seqretry(&xtime_lock, seq));
26. // 时间格式转换
27. jiffies_to_timespec(-timeout, &delta);
28. // 设置timespec的成员
29. set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,
30. kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);
31. // 返回ts值
32. *expire_time = timespec_to_ktime(ts);
33. return 1;
34. }
35.
36. // 打印出锁的状态信息
37. static int print_lock_stat(struct seq_file *m, struct wake_lock *lock)
38. {
39. int lock_count = lock->stat.count;
40. int expire_count = lock->stat.expire_count;
41. ktime_t active_time = ktime_set(0, 0);
42. ktime_t total_time = lock->stat.total_time;
43. ktime_t max_time = lock->stat.max_time;
44.
45. ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time;
46. // 如果锁有效
47. if (lock->flags & WAKE_LOCK_ACTIVE) {
48. ktime_t now, add_time;
49. // 获取超时剩余时间
50. int expired = get_expired_time(lock, &now);
51. if (!expired)
52. now = ktime_get();
53. // 计算当前时间和上次操作时间的差值
54. add_time = ktime_sub(now, lock->stat.last_time);
55. // 使用计数加1
56. if (!expired) // 如果没有到期
57. active_time = add_time;
58. else // 锁已经到期
59. // 超时计数加1
60. // 锁使用时间增加
61. if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND)
62. prevent_suspend_time = ktime_add(prevent_suspend_time,
63. ktime_sub(now, last_sleep_time_update));
64. if (add_time.tv64 > max_time.tv64)
65. max_time = add_time;
66. }
67.
68. return seq_printf(m,
69. "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
70. lock->name, lock_count, expire_count,
71. lock->stat.wakeup_count, ktime_to_ns(active_time),
72. ktime_to_ns(total_time),
73. ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
74. ktime_to_ns(lock->stat.last_time));
75. }
76.
77. // 打印锁状态
78. static int wakelock_stats_show(struct seq_file *m, void *unused)
79. {
80. long irqflags;
81. struct wake_lock *lock;
82. int ret;
83. int type;
84.
85. spin_lock_irqsave(&list_lock, irqflags);
86. // 输出菜单
87. "name\tcount\texpire_count\twake_count\tactive_since"
88. "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
89. // 遍历无效锁链表并打印锁的状态信息
90. list_for_each_entry(lock, &inactive_locks, link)
91. ret = print_lock_stat(m, lock);
92. // 遍历有效锁链表并打印锁的状态信息
93. for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {
94. list_for_each_entry(lock, &active_wake_locks[type], link)
95. ret = print_lock_stat(m, lock);
96. }
97. spin_unlock_irqrestore(&list_lock, irqflags);
98. return 0;
99. }
100.
101. // proc文件打开函数,调用show函数显示当前所有的锁信息
102. static int wakelock_stats_open(struct inode *inode, struct file *file)
103. {
104. return single_open(file, wakelock_stats_show, NULL);
105. }
106.
107. // proc文件系统操作函数
108. static const struct file_operations wakelock_stats_fops = {
109. .owner = THIS_MODULE,
110. .open = wakelock_stats_open,
111. .read = seq_read,
112. .llseek = seq_lseek,
113. .release = single_release,
114. };
以上是proc节点的操作接口,在wakelocks_init中注册。
总结:通过以上分析我们可以看到启动深度休眠流程有四个可能的地方,分别为expire_timer、wake_lock、wake_lock_timeout、wake_unlock,其中expire_timer和wake_unlock最常见。
标签:struct,lock,time,wake,LOCK,WAKE,android From: https://blog.51cto.com/u_14523369/6963864