1. 電源管理的狀態
Android的Linux核心為系統提供了4種電源狀態,核心的原始碼為其中的3種定義了名字和對應的宏定義,名字定義在kernel/power/suspend.c中:
const char *const pm_states[PM_SUSPEND_MAX] = {#ifdef CONFIG_EARLYSUSPEND[PM_SUSPEND_ON]= "on",#endif[PM_SUSPEND_STANDBY]= "standby",[PM_SUSPEND_MEM]= "mem",};
對應的宏定義在:include/linux/suspend.h中:
typedef int __bitwise suspend_state_t;#define PM_SUSPEND_ON((__force suspend_state_t) 0)#define PM_SUSPEND_STANDBY((__force suspend_state_t) 1)#define PM_SUSPEND_MEM((__force suspend_state_t) 3)#define PM_SUSPEND_MAX((__force suspend_state_t) 4)
很奇怪的是,第四種狀態(disk)沒有具體的定義,而是寫入程式碼在代碼中,不明白為什麼會這樣做,至少我現在看的版本是這樣(2.6.35),這種就是所謂的suspend to disk或者叫hibernate。不過這不是重點,再說,目前也很少有Android的裝置支援hibernate。
顧名思義:
PM_SUSPEND_ON -- 裝置處於全電源狀態,也就是正常工作狀態;
PM_SUSPEND_STANDBY -- 裝置處於省電狀態,但還可以接收某些事件,具體的行為取決與具體的裝置;
PM_SUSPEND_MEM -- suspend to memory,裝置進入睡眠狀態,但所有的資料還儲存在記憶體中,只有某些外部中斷才可以喚醒裝置;
目前,大多數的Android裝置都只支援其中的兩種:PM_SUSPEND_ON 和 PM_SUSPEND_MEM,所以下面的討論說道suspend的地方,均是指PM_SUSPEND_MEM。
2. Early Suspend、Late Resume
Early Suspend和Late Resume是Android在標準Linux的基礎上增加的一項特性。當使用者空間的向核心請求進入suspend時,這時候會先進入early suspend狀態,驅動程式可以註冊early suspend的回呼函數,當進入該狀態時,核心會逐一地調用這些回呼函數。例如顯示屏的驅動程式通常會註冊early suspend,在他的回呼函數中,驅動程式會把螢幕和背光都關閉。在這種狀態下,所有的後台進程都還在活動中,該播放歌曲的播放歌曲,該下載資料的依然在下載,只是顯示屏不良而已。進入early
suspend狀態以後,一旦所有的電源鎖(wake lock)被釋放,系統馬上會進入真正的suspend流程,直到最後系統停止工作,等待外來事件的喚醒。
圖2.1 電源狀態的轉換
3. Android的電源鎖機制:wake lock
Android相比標準的Linux核心,在電源管理中加入了wake lock機制。一旦申請了某種類型的鎖,電源管理模組將會“鎖住”某一種電源狀態,目前,Android提供了兩種類型的鎖:
WAKE_LOCK_SUSPEND -- 阻止系統進入suspend狀態;
WAKE_LOCK_IDLE -- 阻止系統進入idle狀態;
wake lock也可以設定逾時,時間一到,自動釋放該鎖。
有關wake lock的代碼在:kernel/power/wakelock.c中。
4. 電源狀態遷移
核心啟動完成以後,電源管理系統會在sysfs檔案系統中建立3個檔案:
- /sys/power/state
- /sys/power/wake_lock
- /sys/power/wake_unlock
電源狀態的遷移首先由使用者空間的應用程式發起,當系統應用檢測到一定時間內沒有使用者活動後(例如觸控螢幕、按鍵),可以向/sys/power/state檔案寫入相應的電源狀態名稱(請參考第一節內容),如果寫入“mem”,將會觸發核心啟動suspend的流程,核心將會按照圖2.1進行狀態的遷移。應用程式也可以通過/sys/power/wake_lock申請一個WAKE_LOCK_SUSPEND 類型的鎖,相應地,通過/sys/power/wake_unlock則可以釋放一個鎖。核心在進入suspend之前如果檢測到某個鎖沒有釋放,則會放棄本次的suspend過程,直到這個鎖釋放為止。
更詳細的分析將會在後續的博文中介紹。