android 休眠喚醒機制分析(一)----wake_lock (自用 學習記錄)

Android的休眠喚醒主要基於wake_lock機制,只要系統中存在任一有效的wake_lock,系統就不能進入深度休眠,但可以進行設備的淺度休眠操作。wake_lock一般在關閉lcd、tp但系統仍然需要正常運行的情況下使用,比如聽歌、傳輸很大的文件等。本文主要分析driver層wake_lock的實現。

一、wake_lock 定義和接口

  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、內核空間接口

  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.         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的實現代碼,首先看看其定義的一些初始化信息:

  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  
  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;  
  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.     unsigned 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.         pr_info("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.     unsigned 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.             pr_info("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.             pr_info("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.             pr_info("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.         current_event_num++;  // 休眠鎖使用計數器加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.                 pr_info("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.                     pr_info("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.     unsigned long irqflags;  
  5.     if (debug_mask & DEBUG_EXPIRE)  
  6.         pr_info("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.         pr_info("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.             pr_info("suspend: abort suspend\n");  
  10.         return;  
  11.     }  
  12.   
  13.     // 記錄函數進入時休眠鎖的使用次數  
  14.     entry_event_num = current_event_num;  
  15.     sys_sync();  // 將緩存中的數據寫入磁盤  
  16.     if (debug_mask & DEBUG_SUSPEND)  
  17.         pr_info("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.         rtc_time_to_tm(ts.tv_sec, &tm);  
  26.         pr_info("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.             pr_info("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.         pr_info("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.                 pr_info("active wake lock %s, time left %ld\n",  
  32.                     lock->name, timeout);  
  33.             else if (print_expired)  
  34.                 pr_info("wake lock %s, expired\n", lock->name);  
  35.         } else {  // 如果不是超時鎖  
  36.             pr_info("active wake lock %s\n", lock->name);  
  37.             if (!debug_mask & DEBUG_EXPIRE)  
  38.                 print_expired = 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.     unsigned 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.     unsigned 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.         pr_info("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.                 pr_info("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.                     pr_info("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.     unsigned long irqflags;  
  4.     if (debug_mask & DEBUG_WAKE_LOCK)  
  5.         pr_info("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.     unsigned 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.         lock_count++;  // 使用計數加1  
  56.         if (!expired)  // 如果沒有到期  
  57.             active_time = add_time;  
  58.         else  // 鎖已經到期  
  59.             expire_count++;  // 超時計數加1  
  60.         total_time = ktime_add(total_time, add_time);  // 鎖使用時間增加  
  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.     unsigned long irqflags;  
  81.     struct wake_lock *lock;  
  82.     int ret;  
  83.     int type;  
  84.   
  85.     spin_lock_irqsave(&list_lock, irqflags);  
  86.     // 輸出菜單  
  87.     ret = seq_puts(m, "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最常見。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章