首页 > 其他分享 >android 休眠唤醒机制分析— wake_lock

android 休眠唤醒机制分析— wake_lock

时间:2023-08-04 16:03:01浏览次数:43  
标签:struct lock time wake LOCK WAKE android


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

      相关文章

      • 自己开发的Android 软件发布贴(11月6日)
        Android开发其实去年就开始了,只是当时还只会用ActionScript因为原生Android开发需要学习java语言。从使用下来看,ActionScript运行效能不高做出来的软件基本没法用。经过几个月学习java现在已经能掌握Android开发给大家带来一些自己写的软件,希望能给大家带来帮助所有软件没有......
      • AndroidStudio2021.3logcat工具无法显示日志解决办法
        AndroidStudio2021.3logcat工具无法显示日志解决办法 https://blog.csdn.net/weixin_43623271/article/details/127876964  1.File->setting2.搜索logcat,->ExperimentalunChkEnablenewLogcattoolwindow以后提示时Dismissit ......
      • VMware ESXi 7.0 U3n macOS Unlocker & OEM BIOS (标准版和厂商定制版) 2023年8月更新
        VMwareESXi7.0U3nmacOSUnlocker&OEMBIOS(标准版和厂商定制版)2023年8月更新ESXi7.0标准版和Dell(戴尔)、HPE(慧与)、Lenovo(联想)、Inspur(浪潮)、Cisco(思科)定制版镜像请访问原文链接:https://sysin.org/blog/vmware-esxi-7-u3-oem/,查看最新版。原创作品,转......
      • Android开发 Jetpack Compose Button
        前言  此篇博客讲解Button按钮一个简单的例子快速了解一下效果图代码@ComposablefunAPage(){Column(Modifier.fillMaxSize(),horizontalAlignment=Alignment.CenterHorizontally,verticalArrangement=Arrangement.Center){......
      • Android布局容器&视图元素
        1.界面布局简介在Android中,界面布局是指如何组织和排列用户界面中的视图(View)元素,以形成用户所看到的界面。Android提供了多种布局容器(LayoutContainer)和视图元素(ViewElement),用于实现各种不同类型的用户界面。常用的Android界面布局容器有以下几种:LinearLayout:线性布局容器,......
      • Android Dex文件详解
        前言==相信大家都熟悉dex文件,把一个apk给解压缩,就会得到一堆dex文件,但是这些dex文件是怎么来的,又有什么用,为什么这样设计,有进行思考过吗俗话说知其然,知其所以然,本篇文章开始探究一下这些底层实现细节。正文==不同的虚拟机JVMJVM是JavaVirtualMachine的简称,即Java虚拟机,它本质是......
      • Android 打印调用栈的方法
        转载1.Java层调用栈打印:(1)打印本地调用堆栈Log.i(TAG,Log.getStackTraceString(newThrowable()));//打印本地调用堆栈(2)打印远程调用堆栈importandroid.os.Binder;importandroid.app.IActivityManager;importandroid.util.Log;StringprocessName="";intpid=......
      • 【金九银十面试冲刺】Android岗面试题每日分享
        已经进入八月份了,我看到了许多朋友在焦急的准备“金九银十”跳槽面试,甚至很多即将毕业的大学生都在备战秋招,对于学历还算优秀的大学生来说,这是一次离大厂最近的机会,毕竟是应届毕业生,不会对技术有非常严格的要求。而对于工作了一两年的Android开发朋友来说,这段时间加强技术能力,多掌......
      • Android平台如何实时叠加电量信息和设备信号状态到GB28181接入端
        技术背景我们在Android平台实现GB28181设备接入,把摄像头和麦克风数据,采集过去,用于移动单兵、智能车载、智慧安防、智能家居、工业仿真等行业时,发现大多场景对视频水印的要求越来越高,从之前的固定位置静态文字水印、png水印等慢慢过渡到动态水印需求。本文,我们要探讨的是,除了常规的......
      • filelock-文件锁的使用
        filelock用于文件锁定用于多进程或多线程对同一文件的操作用法:fromfilelockimportFileLocklock=FileLock("file.lock")withlock:#Dosomethingwiththefile说明:1.如果文件不存在,会自动创建2.如果文件已经被锁定,会等待锁定释放后再执行3.如果文件已经被......