1. 程式人生 > >Android的休眠與喚醒 && 例項

Android的休眠與喚醒 && 例項

      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晶片)釋放喚醒鎖。