Android休眠機制

Android休眠機制,最近修復一個遺留的bug,定時檢測,超過多長時間則彈出一個Tip,在debug跟進這個bug的時候,並沒有發現問題,Timer和TimerTask實現的定時任務,但是在實際使用的時候,產品等很多人都遇到不彈Tip的問題。回過神來一想,應該是掉進瞭Android休眠機制的坑裡瞭。趁此機會對Android的休眠機制進行一個總結。
 

Linux的休眠機制


Android是基於Linux的,要理解Android的休眠機制,那就需要先瞭解Linux系統的電源狀態。Linux系統的電源狀態可以分為四種:On,Standby,Suspend-to-RAM,Suspend-to-disk.

On:表示處於工作狀態(working),CPU、RAM等設備都處於工作狀態。

Standby:CPU、RAM等設備依然處於通電狀態,但是並沒有進行工作,此時還是需要損耗小部分電。

Suspend-to-RAM:掛起到內存,簡稱待機。計算機將目前的運行狀態等數據存放在內存,關閉硬 盤、外設等設備,進入等待狀態。此時內存仍然需要電力維持其數據,但整機耗電很少;恢復時計算機從內存讀出數據,回到掛起前的狀態,恢復速度較快。

Suspend-to-disk:掛起到硬盤,簡稱休眠。把運行狀態等數據存放在硬盤上某個文件或者某個特定的區域,關閉硬盤、外設等設備,進入關機狀態。此時計算機完全關閉,不耗電。恢復時計算機從休眠文件/分區中讀出數據,回到休眠前的狀態,恢復速度較慢。

Linux支持的電源狀態都記錄在/sys/power/state中,Root的手機可以通過ADB進行查看,我的手機沒有Root,隻能看到目錄,無法看到裡面的內容。

這裡寫圖片描述

 

AutoSleep


Android系統包含AP和BP兩個處理器,應用程序等都運行在AP處理器中,因此下面所說的Android休眠指的是AP。
Android系統雖然是基於Linux的,但是它的AutoSleep並不支持上述所有的四種電源狀態。首先,On 肯定是需要支持的,因為我們使用手機的時候正是出於On的電源狀態,同時還支持Suspend-to-RAM的電源狀態,Android系統休眠就是處於Suspend-to-RAM電源狀態,根據上面的介紹,從Suspend-to-RAM恢復數據比Suspend-to-disk快,而耗電有點Standby少。
 

early_suspend與late_resume

當我們的手機從亮屏到滅屏時,此時我們的應用還需要處於活躍的狀態,但是為瞭節省電量,觸摸屏、LCD等設備此時可以關閉瞭。而當我們的手機處於休眠狀態時收到網絡數據,需要應用程序處理時我們不希望觸摸屏、LCD等設備開啟;因此Android引入瞭early_suspend和late_resume.

early_suspend:當滅屏時,LCD、觸摸屏等設備就會通過對應驅動,使其進入suspend狀態,減少電量的損耗。

late_resume:對應early_suspend關閉的設備。系統休眠時,當應用收到網絡數據,進行處理時,不會執行late_resume。
 

wake_lock 與 wake_unlock

某些情況下,我們應用在後臺需要處理一些數據,在處理數據的時候,不希望系統進入休眠,當處理完數據之後才能進入休眠狀態。因此引入瞭wake_lock與wake_unlock機制。wake_lock機制一開始並不是Linux所支持的,而是由Android層實現的,後面由於Android的普及,Linux才進行支持。

這裡寫圖片描述

wake_lock:當應用有數據需要處理,不希望系統馬上進入休眠時,可以通過wake_lock,當有應用持有wake_lock時,系統不會進入休眠。當應用申請一個XXX的wake_lock時,會將XXX寫入wake_lock文件中,,並標記為active。

wake_unlock:當應用處理完數據後,需要釋放其所有持有的wake_lock,不然無法使系統進入休眠狀態,耗費大量的電。當應用釋放一個XXX的wake_lock時,會在wake_unlock中寫入XXX,並將其標記的deactive.
 

AutoSleep流程

這裡寫圖片描述
 

AlarmManager


回到文章開頭的那個bug,在系統休眠的時候,CPU已經停止工作瞭,應用的代碼也沒法被執行,如何定時彈出Tip呢。第一種方式就是在回到應用的時候再次判斷時間,當超過時間就彈出Tip繼續及時,采用這種方法解決瞭問題。但是當IM等即時通訊時,在系統休眠的情況下也需要及時通知消息,此時就需要采用另外的方式解決問題瞭。
通過AlarmManager定時解決問題,前面提到在Android系統中,有兩個處理器AP與BP,系統休眠中的CPU停止指的是AP處理器,而BP處理器處於正常工作的狀態,當接受到網絡數據等時,BP處理器會喚醒AP處理器來進行處理,而AlarmManager也是同理,定時通過BP處理器喚醒AP處理器,從而讓AP處理器進行定時操作,然後AP處理器會在滿足條件的情況下再次休眠。
 

Doze


在Android 6.0時,引入瞭Doze模式。如果用戶設備未插接電源、處於靜止狀態一段時間且屏幕關閉,設備會進入低電耗模式。 在低電耗模式下,系統會嘗試通過限制應用對網絡和 CPU 密集型服務的訪問來節省電量。 這還可以阻止應用訪問網絡並推遲其作業、同步和標準鬧鈴。系統會定期退出低電耗模式一會兒,好讓應用完成其已推遲的 Activity。在此維護時段內,系統會運行所有待定同步、作業和鬧鈴並允許應用訪問網絡。

這裡寫圖片描述

在每個維護時段結束後,系統會再次進入低電耗模式,暫停網絡訪問並推遲作業、同步和鬧鈴。 隨著時間的推移,系統安排維護時段的次數越來越少,這有助於在設備未連接至充電器的情況下長期處於不活動狀態時降低電池消耗。一旦用戶通過移動設備、打開屏幕或連接到充電器喚醒設備,系統就會立即退出低電耗模式,並且所有應用都將返回到正常 Activity。

在低電耗模式下,您的應用會受到以下限制:

暫停訪問網絡

系統將忽略 wake locks

標準 AlarmManager 鬧鈴(包括 setExact() 和 setWindow())推遲到下一維護時段。如果您需要設置在低電耗模式下觸發的鬧鈴,請使用setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle(),觸發鬧鈴的時間間隔都不能超過 9 分鐘。一般情況下,使用 setAlarmClock() 設置的鬧鈴將繼續觸發,但系統會在這些鬧鈴觸發之前不久退出低電耗模式。

系統不執行 Wi-Fi 掃描

系統不允許運行同步適配器

系統不允許運行 JobScheduler

註意AlarmManager標準的鬧鈴也會被推遲,在定時執行任務不是均勻的執行,而是間隔時間越來越久。例如定時心跳推薦用setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle()。
 

總結


Android包含AP和BP兩個處理器,系統休眠時AP停止運行,但BP依舊執行

定時任務推薦用AlarmManager

Doze模式下,標準的Alarm會被推遲,推薦使用setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle()

Android系統淺休眠指early_suspend,此時AP處理器並沒有停止,應用可以執行;Android系統深度休眠指標準的Linux Suspend-to-RAM,系統的狀態保存在RAM中,AP處理器停止工作,應用也停止執行。

You May Also Like