Android的Linux核心的電源管理:Early Suspend

來源:互聯網
上載者:User

1. 使用者空間的介面
        在kernel/power/main.c中,定義了一組sysfs的屬性檔案,其中一個定義是:
        power_attr(state);

        把這個宏展開後:

 
static struct kobj_attribute state_attr = { \.attr ={ \.name = "state", \.mode = 0644, \}, \.show =state_show, \.store =state_store, \} 

 

我們再看看main.c的入口:

static int __init pm_init(void){power_kobj =kobject_create_and_add("power", NULL);if (!power_kobj)return -ENOMEM;return sysfs_create_group(power_kobj,&attr_group);} 

 

顯然,該函數執行後,會在產生/sys/power目錄,該目錄下會建立一系列屬性檔案,其中一個是/sys/power/state檔案。使用者空間向該檔案的寫入將會導致state_store被調用,讀取該檔案將會導致state_show函數被調用。

        現在回到Android的HAL層中,查看一下代碼:hardware/libhardware_legacy/power/power.c:

//定義寫入/sys/power/state的命令字串static const char *off_state = "mem";static const char *on_state = "on";//開啟/sys/power/state等屬性檔案,儲存相應的檔案描述符static intopen_file_descriptors(constchar * const paths[]){int i;for (i=0; i//最終,使用者空間的電源管理系統會調用set_screen_state函數來觸發suspend的流程,該函數實際上就是往/sys/power/state檔案寫入"mem"或"on"命令字串。<pre lang="c" line="1">intset_screen_state(inton){initialize_fds();char buf[32];int len;if(on)len = snprintf(buf, sizeof(buf),"%s", on_state);elselen = snprintf(buf, sizeof(buf),"%s", off_state);buf[sizeof(buf) - 1] = '\0';len = write(g_fds[REQUEST_STATE], buf,len);return 0;} 

 

 

2. 核心中資料結構和介面
        與earlysuspend相關的資料結構和介面都在earlysuspend.h中進行了定義。
        - early_suspend 結構

struct early_suspend {#ifdef CONFIG_HAS_EARLYSUSPENDstructlist_head link;int level;void(*suspend)(struct early_suspend *h);void(*resume)(struct early_suspend *h);#endif}; 

 

希望執行early suspend的裝置,他的裝置驅動程式需要向電源管理系統註冊,該結構體用於向電源管理系統註冊earlysuspend/lateresume,當電源管理系統啟動suspend流程時,回呼函數suspend會被調用,相反,resume的最後階段,回呼函數resume會被調用,level欄位用於調整該結構體在註冊鏈表中的位置,suspend時,level的數值越小,回呼函數的被調用的時間越早,resume時則反過來。Android預先定義了3個level等級:

enum {EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50,EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100,EARLY_SUSPEND_LEVEL_DISABLE_FB = 150,}; 

 

 如果你想你的裝置在FB裝置被禁止之前執行他的early suspend回調,裝置驅動程式應該把level值設定為小於150的某個數值,然後向系統註冊early_suspend結構。註冊和反註冊函數是:

void register_early_suspend(struct early_suspend *handler);void unregister_early_suspend(struct early_suspend *handler); 

 

 early_suspend_handlers鏈表
        所有註冊到系統中的early_suspend結構都會按level值按順序加入到全域鏈表early_suspend_handlers中。

3. 工作流程
       首先,我們從kernel/power/wakelock.c中的初始化函數開始:

static int __init wakelocks_init(void){int ret;int i;......for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)INIT_LIST_HEAD(&active_wake_locks[i]);......wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");wake_lock(&main_wake_lock);wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");......ret = platform_device_register(&power_device);ret = platform_driver_register(&power_driver);......suspend_work_queue = create_singlethread_workqueue("suspend");......return 0;} 

 

可以看到,顯示初始化active_wake_locks鏈表數組,然後初始化並且鎖住main_wake_lock,註冊平台裝置power_device,這些數組、鎖和power_device我們在後續文章再討論,這裡我們關注的最後一個動作:建立了一個工作隊列線程suspend_work_queue,該工作隊列是earlysuspend的核心所在。

       系統啟動完成後,相關的驅動程式通過register_early_suspend()函數註冊了early suspend特性,等待一段時間後,如果沒有使用者活動(例如按鍵、觸控等操作),使用者空間的電源管理服務最終會調用第一節提到的set_screen_state()函數,透過sysfs,進而會調用到核心中的state_store():

static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n){#ifdef CONFIG_SUSPEND#ifdef CONFIG_EARLYSUSPENDsuspend_state_t state = PM_SUSPEND_ON;#elsesuspend_state_t state = PM_SUSPEND_STANDBY;#endifconst char * const *s;#endifchar *p;int len;int error = -EINVAL;p = memchr(buf, '\n', n);len = p ? p - buf : n;/* First, check if we are requested to hibernate */if (len == 4 && !strncmp(buf, "disk", len)) {error = hibernate();goto Exit;}#ifdef CONFIG_SUSPENDfor (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {if (*s && len == strlen(*s) && !strncmp(buf, *s, len))break;}if (state < PM_SUSPEND_MAX && *s)#ifdef CONFIG_EARLYSUSPENDif (state == PM_SUSPEND_ON || valid_state(state)) {error = 0;request_suspend_state(state);}#elseerror = enter_state(state);#endif#endifExit:return error ? error : n;} 

 

  緊接著,通過pm_states數組,根據命令字串查詢得到請求的狀態,預設情況下,Android的核心都會配置了CONFIG_EARLYSUSPEND,所以會調用request_suspend_state()函數,不過在調用該函數之前會先valid_state()一下,這給了平台相關的代碼一個機會確認該平台是否支援所請求的電源狀態。valid_state()的具體實現請參考核心代碼樹。

void request_suspend_state(suspend_state_t new_state){unsigned long irqflags;int old_sleep;spin_lock_irqsave(&state_lock, irqflags);old_sleep = state & SUSPEND_REQUESTED;......if (!old_sleep && new_state != PM_SUSPEND_ON) {state |= SUSPEND_REQUESTED;if (queue_work(suspend_work_queue, &early_suspend_work))pr_info("early_suspend_work is in queue already\n");} else if (old_sleep && new_state == PM_SUSPEND_ON) {state &= ~SUSPEND_REQUESTED;wake_lock(&main_wake_lock);if (!queue_work(suspend_work_queue,&late_resume_work))pr_info("late_resume_work is in queue already\n");}requested_suspend_state = new_state;spin_unlock_irqrestore(&state_lock, irqflags);} 

 

 還記得前面初始化時建立的工作隊列suspend_woek_queue嗎?根據之前的電源狀態和請求的狀態, request_suspend_state()只是簡單地向suspend_work_queue中加入early_suspend_work或者是late_resume_work並調度他們執行。early_suspend_work的工作函數是early_suspend():

staticvoid early_suspend(struct work_struct *work){struct early_suspend *pos;unsigned long irqflags;int abort = 0;mutex_lock(&early_suspend_lock);spin_lock_irqsave(&state_lock,irqflags);if (state == SUSPEND_REQUESTED)state |= SUSPENDED;elseabort = 1;spin_unlock_irqrestore(&state_lock,irqflags);if (abort) {}list_for_each_entry(pos,&early_suspend_handlers, link) {if (pos->suspend != NULL) {if (debug_mask &DEBUG_SUSPEND)printk(KERN_DEBUG"pos->suspend: %pF begin\n", pos->suspend);pos->suspend(pos);if (debug_mask &DEBUG_SUSPEND)printk(KERN_DEBUG"pos->suspend: %pF finish\n", pos->suspend);}}mutex_unlock(&early_suspend_lock);if (debug_mask & DEBUG_SUSPEND)pr_info("early_suspend:sync\n");sys_sync();abort:spin_lock_irqsave(&state_lock,irqflags);if (state ==SUSPEND_REQUESTED_AND_SUSPENDED)wake_unlock(&main_wake_lock);spin_unlock_irqrestore(&state_lock,irqflags);} 

 

終於看到啦,early_suspend()遍曆early_suspend_handlers鏈表,從中取出各個驅動程式註冊的early_suspend結構,然後調用它的suspend回呼函數。最後,釋放main_wake_lock鎖,至此整個earlysuspend的流程完成。下面的順序圖表清晰地表明了整個調用的過程:

 

 其它相關:

http://blog.sina.com.cn/s/blog_55465b470100n9yx.html 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.