Android 休眠(suspend),在一個打過android補丁的核心中,state_store()函數會走另外一條路,會進入到request_suspend_state()中,這個檔案在earlysuspend.c中。這些功能都是android系統加的,後面會對earlysuspend和late resume 進行介紹。涉及到的檔案:
linux_source/kernel/power/main.c
linux_source/kernel/power/earlysuspend.c
linux_source/kernel/power/wakelock.c
(1)特性介紹
Early Suspend:Early suspend 是android 引進的一種機制,這種機制在上遊備受爭議,這裡不做評論。這個機製作用在關閉顯示的時候。一些和顯示有關的裝置,比如LCD背光,比如重力感應器、觸控螢幕、這些裝置都會關掉。但是系統可能還是在運行狀態(這時候還有wake lock)進行任務的處理,例如在掃描SD卡上的檔案等。在嵌入式裝置中,背光是一個很大的電源消耗,所以 android會加入這樣一種機制。
Late Resume:Late Resume 是和suspend 配套的一種機制,是在核心喚醒完畢開始執行的。主要就是喚醒在Early Suspend的時候休眠的裝置。
Wake Lock:Wake Lock 在Android的電源管理系統中扮演一個核心的角色。Wake Lock是一種鎖的機制,只要有人拿著這個鎖,系統就無法進入休眠,可以被使用者態程式和核心獲得。這個鎖可以是有逾時的或者是沒有逾時的,逾時的鎖會在時間過去以後自動解鎖。如果沒有鎖了或者逾時了,核心就會啟動休眠的那套機制來進入休眠。
(2)過程
A,Android Suspend,當使用者寫入mem 或者standby到/sys/power/state中的時候,state_store()會被調用,然後Android會在這裡調用request_suspend_state(),而標準的Linux會在這裡進入enter_state()這個函數。如果請求的是休眠,那麼early_suspend這個workqueue就會被調用,並且進入early_suspend狀態。
B,Early Suspend,在early_suspend()函數中,首先會檢查現在請求的狀態還是否是suspend,來防止suspend的請求會在這個時候取消掉(因為這個時候使用者進程還在運行),如果需要退出,就簡單的退出了。如果沒有,這個函數就會把early suspend中註冊的一系列的回調都調用一次,然後同步檔案系統,然後放棄掉 main_wake_lock。這個wake lock是一個沒有逾時的鎖,如果這個鎖不釋放,那 麼系統就無法進入休眠。
C,Late Resume,當所有的喚醒已經結束以後,使用者進程都已經開始運行了。喚醒通常會是以下的幾種原因:
1)來電:如果是來電,那麼Modem會通過發送命令給rild來讓rild通知WindowManager有來電響應,這樣就會遠程調用PowerManagerService來寫"on" 到 /sys/power/state 來執行late resume的裝置,比如點亮螢幕等。
2)使用者按鍵:使用者按鍵事件會送到WindowManager中,WindowManager會處理這些按鍵事件。按鍵分為幾種情況,如果案例不是喚醒鍵(能夠喚醒系統的按鍵) 那麼WindowManager會主動放棄wakeLock來使系統進入再次休眠;如果按鍵是喚醒鍵,那麼WindowManger就會調用PowerManagerService中的介面來執行 Late Resume。Late Resume會依次喚醒前面調用了Early Suspend的裝置.
(3)術語
Wake Lock:我們接下來看一看wake lock的機制是怎麼運行和起作用的,主要關注wakelock.c檔案就可以了。wake lock 有加鎖和解鎖兩種狀態,加鎖的方式有兩種,一種是永久的鎖住,這樣的鎖除非顯示的放開,是不會解鎖的,所以這種鎖的使用是非常小心的;第二種是逾時鎖,這種鎖會鎖定系統喚醒一段時間,如果這個時間過去了,這個鎖會自動解除。鎖有兩種類型:
1)WAKE_LOCK_SUSPEND 這種鎖會防止系統進入睡眠
2)WAKE_LOCK_IDLE 這種鎖不會影響系統的休眠
在wake lock中,會有3個地方讓系統直接開始suspend(),分別是:在wake_unlock()中,如果發現解鎖以後沒有任何其他的wake lock了,就開始休眠。在定時器都到時間以後,定時器的回呼函數會查看是否有其他的wake lock;如果沒有,就在這裡讓系統進入睡眠。在wake_lock() 中,對一個wake lock加鎖以後,會再次檢查一下有沒有鎖。
Suspend:當wake_lock 運行 suspend()以後,在wakelock.c的suspend()函數會被調用,這個函數首先sync檔案系統,然後調用pm_suspend(request_suspend_state),接下來pm_suspend()就會調用enter_state()來進入Linux的休眠流程。
(4)Android於標準Linux休眠的區別
pm_suspend() 雖然會調用enter_state()來進入標準的Linux休眠流程,但是還是有一些區別:當進入凍結進程的時候,android首先會檢查有沒有wake lock。如果沒有,才會凍結這些進程,因為在開始suspend和凍結進程期間有可能有人申請了wake lock,如果是這樣,凍結進程會被中斷。
(5) Wake Lock執行個體
在調試一款手機時,發現這樣一個BUG:在通話時手機接近耳朵後,距離感應器(PS)會使得LCD睡眠關屏,但是手機拿開後LCD也不會再亮了,懷疑是PS晶片沒有從睡眠中喚醒導致的。採取添加一個喚醒鎖的方法,這樣在通話過程中PS始終無法進入睡眠狀態就可以正常相應外部的狀態變化了。注意:就算手機接近耳朵關屏,此時PS並沒有DISABLE掉,在整個通話過程中,PS都是ENABLE的,只有當手機睡眠待機時,才會真正處於DISABLE。
這樣的話,只需要初始化PS時,初始化一個wake_lock,在手機正常工作時(ENABLE PS晶片)獲得喚醒鎖,在手機睡眠時(DISABLE PS晶片)釋放喚醒鎖。
參考原文:http://edu.codepub.com/2010/0626/23815_2.php
參考原文:http://elinux.org/Android_Power_Management