【Android休眠】之Android休眠機制
一、休眠概述
休眠,簡而言之就是裝置在不需要工作的時候把一些部件、外設關掉(掉電或讓它進入低功耗模式)。
為什麼要休眠呢?一言以蔽之:省電。
休眠分主動休眠和被動休眠。主動休眠:比如我電腦不用了,就通過設定讓系統進入休眠模式;被動休眠:系統檢測到自己閒的慌,為了節約故,自己就休眠去了。
廢話不敘。
二、Android休眠
休眠是核心的核心工作,而Android是基於Linux核心的,所以Android休眠和核心有著千絲萬縷的聯絡;由於Android的特殊應用場景:移動裝置,所以Android休眠和核心又有著特別的需求。
1、聯絡:
Android裝置停止使用,系統沒有什麼事情可做,進入休眠狀態的功能最終是由核心去實現的;每一類硬體都有自己的驅動,具體的驅動決定怎麼進入休眠以及處於何種層次的休眠。比如:對於platform_device,就按照platform_driver定義的規則,在suspend呼叫的時候,去做上面提到的事情:
struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; };
2、Android的特別需求:
比如對於自己的電腦,不用讓它休眠好了;但是對於我們形影不離的手機,在休眠的時候還要睜一隻眼:來電了要通知你,QQ啊微信啊什麼的由資訊了也要通知你,所以Android在Linux核心休眠機制之上,提出了“Opportunistic Suspend”。
三、休眠實踐
絮絮叨叨這麼多,下面讓我們切切實實體驗下休眠。
1、休眠模式
休眠是分好幾種模式的,不同模式實現方式、耗電量不同,以下來自Documentation/power/states.txt:
The kernel supports four power management states generically, though one is generic and the other three are dependent on platform support code to implement the low-level details for each state. This file describes each state, what they are commonly called, what ACPI state they map to, and what string to write to /sys/power/state to enter that state state: Freeze / Low-Power Idle ACPI state: S0 String: "freeze" This state is a generic, pure software, light-weight, low-power state. It allows more energy to be saved relative to idle by freezing user space and putting all I/O devices into low-power states (possibly lower-power than available at run time), such that the processors can spend more time in their idle states. This state can be used for platforms without Standby/Suspend-to-RAM support, or it can be used in addition to Suspend-to-RAM (memory sleep) to provide reduced resume latency. State: Standby / Power-On Suspend ACPI State: S1 String: "standby" This state offers minimal, though real, power savings, while providing a very low-latency transition back to a working system. No operating state is lost (the CPU retains power), so the system easily starts up again where it left off. We try to put devices in a low-power state equivalent to D1, which also offers low power savings, but low resume latency. Not all devices support D1, and those that don't are left on. State: Suspend-to-RAM ACPI State: S3 String: "mem" This state offers significant power savings as everything in the system is put into a low-power state, except for memory, which is placed in self-refresh mode to retain its contents. System and device state is saved and kept in memory. All devices are suspended and put into D3. In many cases, all peripheral buses lose power when entering STR, so devices must be able to handle the transition back to the On state. For at least ACPI, STR requires some minimal boot-strapping code to resume the system from STR. This may be true on other platforms. State: Suspend-to-disk ACPI State: S4 String: "disk" This state offers the greatest power savings, and can be used even in the absence of low-level platform support for power management. This state operates similarly to Suspend-to-RAM, but includes a final step of writing memory contents to disk. On resume, this is read and memory is restored to its pre-suspend state.
雖說kernel支援上述四種休眠模式,但具體哪幾種可用取決於你的硬體。那麼怎麼知道自己的Android裝置支援的休眠模式呢?
答案:通過/sys/檔案系統。查詢支援的休眠模式可以cat檔案/sys/power/state:
cat /sys/power/state
freeze mem
如果我們往/sys/power/state檔案echo上面的某一種模式的字串,系統就會進入相應的休眠模式:
echo "mem" > /sys/power/state
如果你搜索過Android休眠相關的內容,在老版本的Android(4.4版本之前)會見有提到PowerManager的setPowerState()方法,該方法即是通過以上方式使系統進入休眠。但自從引入Autosleep後,就不在這麼做了,setPowerState()方法也銷聲匿跡。
2、/sys/power/目錄下檔案
檔案簡介:
- /sys/power/state:用來控制系統的Power狀態。讀取該檔案可以獲取系統支援的休眠模式,寫入該檔案休眠模式的一種,系統進入到指定的休眠模式。如上所示例。
- /sys/power/autosleep:從Android wakelocks補丁集中演化而來,用於取代Android wakelocks中的自動休眠功能。向該檔案寫入/sys/power/state返回值的某一種,系統會在適當的時候進入指定的休眠的模式;讀取該檔案返回之前寫入的數值。
- /sys/power/wake_lock、/sys/power/wake_unlock:即我們常說的休眠鎖,如果應用持有休眠鎖,系統將無法進入休眠模式。在Android wakelocks時代,寫wake_lock獲取鎖,寫wake_unlock釋放鎖;在AutoSleep時代,具體參見【Android休眠】之AutoSleep
- wakeup_count:用於解決“system suspend和system wakeup events之間的同步問題”。
- /sys/power/pm_async:狀態切換開關,允許/禁止User空間對裝置進行非同步的suspend和resume操作。
- /sys/power/pm_freeze_timeout:系統在執行休眠動作的時候要凍結(freeze)使用者控制元件的程序和核心空間的允許凍結的核心執行緒,執行這些操作要耗時間吧?該檔案指定所需時間的最大值。
四、其他需要明瞭的問題
1、Android裝置螢幕暗下來的時候,並不是立即就進入了休眠模式;當所有喚醒源都處於de-avtive狀態後,系統才會進入休眠。
2、Android裝置連著adb線到其他裝置的情況下,裝置是不會進入休眠模式的。
3、有休眠操作就有喚醒,就需要喚醒源。喚醒源有很多種,在核心註冊,比如常用的Power按鍵。
4、曾經困惑的一個問題:系統怎麼知道自己應該進入休眠模式了?它的判斷依據是什麼?
- 在wakelock時代,系統休眠過程中去檢測休眠鎖;如果系統中沒有其他部件持有休眠鎖,就嘗試進入休眠模式,沒有異常事件發生的話就進入休眠模式。
- Android從4.4開始使用autosleep機制,只要不存在任何active的喚醒源(wakeup_source)了,就進入休眠模式。
5、系統Power Manager整體流程: