歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android在標准Linux基礎上對休眠喚醒的實現

一、新增特性介紹

實際上,Android仍然是利用了標准linux的休眠喚醒系統,只不過添加了一些使用上的新特性,early suspend、late resume、wake lock。

Early suspend - 這個機制定義了在suspend的早期,關閉顯示屏的時候,一些和顯示屏相關的設備,比如背光、重力感應器和觸摸屏等設備都應該被關掉,但是此時系統可能還有持有wake lock的任務在運行,如音樂播放,電話,或者掃描sd卡上的文件等,這個時候整個系統還不能進入真正睡眠,直到所有的wake lock都沒釋放。在嵌入式設備中,悲觀是一個很大的電源消耗,所有android加入了這種機制。

Late resume - 這個機制定義了在resume的後期,也就是喚醒源已經將處理器喚醒,標准linux的喚醒流程已經走完了,在android上層系統識別出這個物理上的喚醒源是上層定義的,那麼上層將會發出late resume的命令給下層,這個時候將會調用相關設備注冊的late resume回調函數。

Wake lock - wakelock在android的電源管理系統中扮演一個核心的角色,wakelock是一種鎖的機制, 只要有task拿著這個鎖, 系統就無法進入休眠, 可以被用戶態進程和內核線程獲得。這個鎖可以是有超時的或者是沒有超時的, 超時的鎖會在時間過去以後自動解鎖。如果沒有鎖了或者超時了, 內核就會啟動標准linux的那套休眠機制機制來進入休眠。

二、kernel層源碼解析 - early suspend 和 late resume實現

相關源碼:

kernel/kernel/power/main.c

kernel/kernel/power/earlysuspend.c

kernel/kernel/power/wakelock.c

kernel/kernel/power/userwakelock.c

kernel/kernel/power/suspend.c

之前標准的linux的sysfs的接口只需要一個state就夠了,現在至少需要3個接口文件:state、wake_lock、wake_unlock。現在為了配合android為休眠喚醒添加的幾種新特性,可以填入文件state的模式又多了一種:on, 標准android系統中只支持state的on和mem模式,其余的暫不支持。wake_lock和wake_unlock接口對應的讀寫函數在文件userwakelock.c中,對wakelock.c中的create wakelock或者release wakelock進行了封裝,供用戶空間來使用。

如果上層用戶執行:echo xxx(on or mem) > sys/power/state的話,將會調用到如下函數:

  1. static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,  
  2.   
  3. const char *buf, size_t n)  
  4.   
  5. {  
  6.   
  7. #ifdef CONFIG_SUSPEND // set   
  8.   
  9. #ifdef CONFIG_EARLYSUSPEND    //set   
  10.   
  11.        suspend_state_t state = PM_SUSPEND_ON;   // for early suspend and late resume   
  12.   
  13. #else   
  14.   
  15.        suspend_state_t state = PM_SUSPEND_STANDBY;  
  16.   
  17. #endif   
  18.   
  19.        const char * const *s;  
  20.   
  21. #endif   
  22.   
  23.        char *p;  
  24.   
  25.        int len;  
  26.   
  27.        int error = -EINVAL;  
  28.   
  29.    
  30.   
  31.        p = memchr(buf, '/n', n);  
  32.   
  33.        len = p ? p - buf : n;  
  34.   
  35.    
  36.   
  37.        /* First, check if we are requested to hibernate */  
  38.   
  39.        if (len == 4 && !strncmp(buf, "disk", len)) {  
  40.   
  41.               error = hibernate();  // 檢查是否要求進入disk省電模式,暫時不支持   
  42.   
  43.   goto Exit;  
  44.   
  45.        }  
  46.   
  47.    
  48.   
  49. #ifdef CONFIG_SUSPEND        // def   
  50.   
  51.        for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {  
  52.   
  53.               if (*s && len == strlen(*s) && !strncmp(buf, *s, len))  
  54.   
  55.                      break;  
  56.   
  57.        }  
  58.   
  59.        if (state < PM_SUSPEND_MAX && *s)  
  60.   
  61. #ifdef CONFIG_EARLYSUSPEND   
  62.   
  63.               if (state == PM_SUSPEND_ON || valid_state(state)) {  
  64.   
  65. // 需要經過平台pm.c文件定義的模式支持檢查函數,mtk只支持mem,同時如果是android發送出來的late resume命令(on),這裡也會放行,往下執行   
  66.   
  67.                      error = 0;  
  68.   
  69.                      request_suspend_state(state);     // android休眠喚醒的路線   
  70.   
  71.               }  
  72.   
  73. #else   
  74.   
  75.               error = enter_state(state);// 標准linux休眠喚醒的路線   
  76.   
  77. #endif   
  78.   
  79. #endif   
  80.   
  81.    
  82.   
  83.  Exit:  
  84.   
  85.        return error ? error : n;  
  86.   
  87. }  
  88.   
  89.    
  90.   
  91. @ kernel/kernel/power/earlysuspend.c  
  92.   
  93. enum {  
  94.   
  95.        DEBUG_USER_STATE = 1U << 0,  
  96.   
  97.        DEBUG_SUSPEND = 1U << 2,  
  98.   
  99. };  
  100.   
  101. int Earlysuspend_debug_mask = DEBUG_USER_STATE;  
  102.   
  103. module_param_named(Earlysuspend_debug_mask, Earlysuspend_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);  
  104.   
  105.    
  106.   
  107. static DEFINE_MUTEX(early_suspend_lock);  
  108.   
  109. static LIST_HEAD(early_suspend_handlers);  
  110.   
  111. static void early_sys_sync(struct work_struct *work);  
  112.   
  113. static void early_suspend(struct work_struct *work);  
  114.   
  115. static void late_resume(struct work_struct *work);  
  116.   
  117. static DECLARE_WORK(early_sys_sync_work, early_sys_sync);  
  118.   
  119. static DECLARE_WORK(early_suspend_work, early_suspend);  
  120.   
  121. static DECLARE_WORK(late_resume_work, late_resume);  
  122.   
  123. static DEFINE_SPINLOCK(state_lock);  
  124.   
  125. enum {  
  126.   
  127.        SUSPEND_REQUESTED = 0x1,  
  128.   
  129.        SUSPENDED = 0x2,  
  130.   
  131.        SUSPEND_REQUESTED_AND_SUSPENDED = SUSPEND_REQUESTED | SUSPENDED,  
  132.   
  133. };  
  134.   
  135. static int state;             // 初始化為0   
  136.   
  137.    
  138.   
  139. static DECLARE_COMPLETION(fb_drv_ready);  
  140.   
  141.    
  142.   
  143. void request_suspend_state(suspend_state_t new_state)  
  144.   
  145. {  
  146.   
  147.        unsigned long irqflags;  
  148.   
  149.        int old_sleep;  
  150.   
  151.    
  152.   
  153.        spin_lock_irqsave(&state_lock, irqflags);  
  154.   
  155.        old_sleep = state & SUSPEND_REQUESTED; // state = 1 or 3   
  156.   
  157. // state的值會在0->1->3->2->0循環變化,後面分析代碼都可以看出這些值代表系統目前處於什麼階段,簡單得說就是:正常->准備進early suspend->開始early suspend並且對名為mian的wakelock解鎖,如果此時沒有其余wakelock處於lock狀態,那麼系統就走linux的休眠喚醒路線讓整個系統真正休眠,直到喚醒源發生,然後將處理器和linux層喚醒。之後android層判斷本次底層醒來是由於我所定義的喚醒源引起的嗎?如果不是,android將不予理會,過段時間沒有wakelock鎖,系統會再次走linux的休眠路線進入休眠。如果是,那麼android上層就會寫一個on的指令到state接口中,同樣是會調用到函數request_suspend_state() -> 准備執行late resume -> 開始執行late resume,之後整個系統就這樣被喚醒了。   
  158.   
  159.        if (Earlysuspend_debug_mask & DEBUG_USER_STATE) {  
  160.   
  161.               struct timespec ts;        // 打印出debug信息   
  162.   
  163.               struct rtc_time tm;  
  164.   
  165.               getnstimeofday(&ts);  
  166.   
  167.               rtc_time_to_tm(ts.tv_sec, &tm);  
  168.   
  169.               pr_info("[request_suspend_state]: %s (%d->%d) at %lld "  
  170.   
  171.                      "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)/n",  
  172.   
  173.                      new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",  
  174.   
  175.                      requested_suspend_state, new_state,  
  176.   
  177.                      ktime_to_ns(ktime_get()),  
  178.   
  179.                      tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,  
  180.   
  181.                      tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);  
  182.   
  183.        }  
  184.   
  185. // eg: [request_suspend_state]: sleep (0->3) at 97985478409 (2010-01-03 09:52:59.637902305 UTC), 這裡對時間的獲取和處理,在其他地方可以參考   
  186.   
  187.        // ready to enter earlysuspend   
  188.   
  189.        if (!old_sleep && new_state != PM_SUSPEND_ON) { // SUSEpnd會進入這裡   
  190.   
  191.               state |= SUSPEND_REQUESTED;    // state = 1   
  192.   
  193.               pr_info("[request_suspend_state]:  
  194.   
  195. sys_sync_work_queue early_sys_sync_work/n");  
  196.   
  197.               queue_work(sys_sync_work_queue, &early_sys_sync_work);  
  198.   
  199.               pr_info("[request_suspend_state]: suspend_work_queue early_suspend_work/n");  
  200.   
  201.               queue_work(suspend_work_queue, &early_suspend_work);  
  202.   
  203. // 在wakelocks_init()函數(wakelock.c)中會創建這兩個工作隊列和工作者線程來專門負責處理sys_sync和early suspend的工作。關於工作隊列的詳情參考我工作隊列的文章   
  204.   
  205.        }  
  206.   
  207.        // ready to enter lateresume   
  208.   
  209.        else if (old_sleep && new_state == PM_SUSPEND_ON) {  
  210.   
  211.               state &= ~SUSPEND_REQUESTED; // state = 2   
  212.   
  213.               wake_lock(&main_wake_lock);         // 對main wakelock上鎖   
  214.   
  215.               pr_info("[request_suspend_state]: suspend_work_queue late_resume_work/n" );  
  216.   
  217.               if (queue_work(suspend_work_queue, &late_resume_work)) {  
  218.   
  219. // 提交late resume的工作項   
  220.   
  221.             //   
  222.   
  223.             //  In order to synchronize the backlight turn on timing,   
  224.   
  225.             //  block the thread and wait for fb driver late_resume()   
  226.   
  227.                   //  callback function is completed   
  228.   
  229.                   //   
  230.   
  231.             wait_for_completion(&fb_drv_ready);       
  232.   
  233. // 等待完成量fb_drv_ready,他會在late resume結束之後完成   
  234.   
  235.         }  
  236.   
  237.        }  
  238.   
  239.        requested_suspend_state = new_state;       
  240.   
  241. // 存儲本次休眠或者是喚醒的狀態,供下次休眠或者喚醒使用   
  242.   
  243.        spin_unlock_irqrestore(&state_lock, irqflags);  
  244.   
  245. }  

在系統suspend的時候提交的兩個工作項會陸續被執行到,那麼下面就來看一下執行early suspend的關鍵函數。

  1. static void early_sys_sync(struct work_struct *work)  
  2.   
  3. {  
  4.   
  5.        wake_lock(&sys_sync_wake_lock);  
  6.   
  7.        printk("[sys_sync work] start/n");  
  8.   
  9.        sys_sync();    // 同步文件系統   
  10.   
  11.        printk("[sys_sync wrok] done/n");  
  12.   
  13.        wake_unlock(&sys_sync_wake_lock);  
  14.   
  15. }  
  16.   
  17.    
  18.   
  19. static void early_suspend(struct work_struct *work)  
  20.   
  21. {  
  22.   
  23.        struct early_suspend *pos;  
  24.   
  25.        unsigned long irqflags;  
  26.   
  27.        int abort = 0;  
  28.   
  29.    
  30.   
  31.        mutex_lock(&early_suspend_lock);  
  32.   
  33.        spin_lock_irqsave(&state_lock, irqflags);  
  34.   
  35.        if (state == SUSPEND_REQUESTED)  
  36.   
  37.               state |= SUSPENDED; // state = 3   
  38.   
  39.        else  
  40.   
  41.               abort = 1;  
  42.   
  43.        spin_unlock_irqrestore(&state_lock, irqflags);  
  44.   
  45.    
  46.   
  47.        if (abort) {     // suspend 中止退出   
  48.   
  49.               if (Earlysuspend_debug_mask & DEBUG_SUSPEND)  
  50.   
  51.                      pr_info("[early_suspend]: abort, state %d/n", state);  
  52.   
  53.               mutex_unlock(&early_suspend_lock);  
  54.   
  55.               goto abort;  
  56.   
  57.        }  
  58.   
  59.    
  60.   
  61.        if (Earlysuspend_debug_mask & DEBUG_SUSPEND)  
  62.   
  63.               pr_info("[early_suspend]: call handlers/n");  
  64.   
  65.        list_for_each_entry(pos, &early_suspend_handlers, link) {  
  66.   
  67.               if (pos->suspend != NULL)  
  68.   
  69.                      pos->suspend(pos);  
  70.   
  71.        }  
  72.   
  73. // 函數register_early_suspend()會將每一個early suspend項以優先級大小注冊到鏈表early_suspend_handlers中,這裡就是一次取出,然後執行對應的early suspend回調函數   
  74.   
  75.        mutex_unlock(&early_suspend_lock);  
  76.   
  77.    
  78.   
  79.        // Remove sys_sync from early_suspend,   
  80.   
  81.        // and use work queue to complete sys_sync   
  82.   
  83.    
  84.   
  85. abort:  
  86.   
  87.        spin_lock_irqsave(&state_lock, irqflags);  
  88.   
  89.        if (state == SUSPEND_REQUESTED_AND_SUSPENDED)  
  90.   
  91.        {  
  92.   
  93.               pr_info("[early_suspend]: wake_unlock(main)/n");  
  94.   
  95.               wake_unlock(&main_wake_lock);  
  96.   
  97. // main wakelock 解鎖。看到這裡,好像系統執行了early suspend之後就沒有往下執行標准linux的suspend流程了,其實不是,android的做法是,不是你執行完了early suspend  的回調就可以馬上走標准linux的suspend流程,而是會檢查還有沒有wakelock被持有,如果所有wakelock全是解鎖狀態,那麼就會執行標准linux的suspend步驟。   
  98.   
  99. }  
  100.   
  101.        spin_unlock_irqrestore(&state_lock, irqflags);  
  102.   
  103. }  
  104.   
  105.    
  106.   
  107. static void late_resume(struct work_struct *work)  
  108.   
  109. {  
  110.   
  111.        struct early_suspend *pos;  
  112.   
  113.        unsigned long irqflags;  
  114.   
  115.        int abort = 0;  
  116.   
  117.     int completed = 0;  
  118.   
  119.    
  120.   
  121.        mutex_lock(&early_suspend_lock);  
  122.   
  123.        spin_lock_irqsave(&state_lock, irqflags);  
  124.   
  125.    
  126.   
  127.     // return back from suspend   
  128.   
  129.        if (state == SUSPENDED)  
  130.   
  131.               state &= ~SUSPENDED;    // state = 0   
  132.   
  133.        else  
  134.   
  135.               abort = 1;  
  136.   
  137.        spin_unlock_irqrestore(&state_lock, irqflags);  
  138.   
  139.    
  140.   
  141.        if (abort) {  
  142.   
  143.               if (Earlysuspend_debug_mask & DEBUG_SUSPEND)  
  144.   
  145.                      pr_info("[late_resume]: abort, state %d/n", state);  
  146.   
  147.               goto abort;  
  148.   
  149.        }  
  150.   
  151.        if (Earlysuspend_debug_mask & DEBUG_SUSPEND)  
  152.   
  153.               pr_info("[late_resume]: call handlers/n");  
  154.   
  155.        list_for_each_entry_reverse(pos, &early_suspend_handlers, link)  
  156.   
  157.     {  
  158.   
  159.         if (!completed && pos->level < EARLY_SUSPEND_LEVEL_DISABLE_FB) {  
  160.   
  161.             complete(&fb_drv_ready);  
  162.   
  163.             completed = 1;  
  164.   
  165.         }  
  166.   
  167.               if (pos->resume != NULL)  
  168.   
  169.                      pos->resume(pos);  
  170.   
  171.     }  
  172.   
  173. // 以和early suspend的逆序執行鏈表early_suspend_handlers上的late resume回調函數   
  174.   
  175. if (Earlysuspend_debug_mask & DEBUG_SUSPEND)  
  176.   
  177.               pr_info("[late_resume]: done/n");  
  178.   
  179. abort:  
  180.   
  181.     if (!completed)  
  182.   
  183.         complete(&fb_drv_ready);   // 設置完成量ok   
  184.   
  185.      mutex_unlock(&early_suspend_lock);  
  186.   
  187. }  
Copyright © Linux教程網 All Rights Reserved