參考:
Optimizing for Doze and App Standby
android M新特性Doze and App Standby模式詳解
深入android6.0 設備 idle狀態
Android M 的 Doze 模式下第三方推送服務還能用嗎?
一、Optimizing for Doze and App Standby
從Android6.0開始,Android提供了兩種省電延長電池壽命的功能:Doze和App Standby;
表現形式:當設備沒有連接到電源,設備進入Doze模式時,系統將通過延遲最近用戶沒有使用的應用程序的後臺CPU運作及網絡活動,讓應用程序處於App Standby狀態,以此來減少電池消耗。谷歌表示,在Nexus5和Nexus6上測試,當屏幕處於關閉狀態,平均續航時間提高30%;
版本要求:Android6.0(API level 23)及其更高版本;
開發者影響:為了保證用戶的最佳體驗,開發者有必要在Doze和App Standby模式下測試應用程序,及其對代碼進行相應的調整。
二、Understanding Doze
1.設備進入Doze睡眠模式時機:
用戶不操作設備一段時間
屏幕關閉
設備未連接電源充電
2.Doze模式下應用程序有什麽變化:
系統試圖通過限制應用程序訪問網絡和CPU密集型服務節省電池;
防止應用程序訪問網絡,推延應用程序的工作,同步,和標準的警報;
系統定期提供一個短暫的時間讓應用程序完成延遲的工作活動,之後再次進入Doze模式。在這個時間片裏,系統將提供維持性窗口(maintenance window)應用程序可以在此時執行訪問網絡,同步,和報警等活動。
Doze模式的五種狀態,分別如下:
ACTIVE:手機設備處於激活活動狀態
INACTIVE:屏幕關閉進入非活動狀態
IDLE_PENDING:每隔30分鐘讓App進入等待空閑預備狀態
IDLE:空閑狀態
IDLE_MAINTENANCE:處理掛起任務
如下圖所示,Doze期間提供間隔一小段時間(30s)供應用程序使用網絡和處理掛起的活動。
從這張圖我們可以看到,系統進入Doze模式後,系統會隔一段時間處理正在掛起的任務,隨著時間推移,後面間隔的時間會越來越長,以此來減少電量消耗。
3.退出Doze模式:
- 移動設備
- 打開屏幕
- 設備連接電源
以上三種情況會退出Doze模式,之後apps回復正常模式。
4.Doze有哪些限制?
網絡連接會被禁止
Wake Lock會被屏蔽
AlarmManager定時任務延遲到下一個maintenance window進行處理,除非使用AlarmManager提供的方法:setAndAllowWhileIdle() 或者setExactAndAllowWhileIdle()
系統將不掃描熱點WIFI
同步工作將被禁止
不允許JobScheduler進行任務調度
5.適配Doze模式有什麽方法?
Doze影響到AlarmManager鬧鐘和定時器管理活動,在Android6.0引入了兩個新方法:setAndAllowWhileIdle() 和setExactAndAllowWhileIdle(),調用兩個方法可以在Doze模式下讓系統響應定時任務。
Doze模式下限制了網絡的連接,如果應用程序依賴於實時信息,那麽這個將影響App的體驗。那麽你需要使用Google Cloud Messaging (GCM)谷歌雲消息(後面詳細講解)
三、Understanding App Standby
當用戶不觸摸使用應用程序一段時間時,該應用程序處於App Standby狀態,系統將把該App標誌為空閑狀態(idle)。除非觸發以下任意條件,應用程序將退出App Standby狀態:
用戶主動啟動該App;
該App當前有一個前臺進程(或包含一個活動的前臺服務,或被另一個activity或前臺service使用);
App生成一個用戶所能在鎖屏或通知托盤看到的Notification, 而當用戶設備插入電源時,系統將會釋放App的待機狀態,允許他們自由的連接網絡及其執行未完成的工作和同步。如果設備空閑很長一段時間,系統將允許空閑App一天一次訪問網絡。
四、Doze和App Standby的區別:
Doze模式需要屏幕關閉(通常晚上睡覺或長時間屏幕關閉才會進入),而App Standby不需要屏幕關閉,App進入後臺一段時間也會受到連接網絡等限制。
五、DeviceIdleController
DeviceIdleController是Doze模式的主要驅動。接下來,我將使用device idle mode而不是doze mode來描述“Doze”,因為它更符合代碼的實際情況。
5.1、deviceidle——新的系統服務
如果你已經閱讀了官方文檔,你可能已經註意到下面的命令,開發者可以通過這些命令得知當下設備的應用行為:
adb shell dumpsys battery unplug adb shell dumpsys deviceidle step
對於上面的命令你可能並不熟悉,dumpsys是用來與系統服務交互的(查看它們的狀態)。deviceidle是我們之前沒有看到過的,它是一個新的系統服務。用來檢測是否進入idle mode(Doze模式)
$ adb shell service list | grep deviceidle 59 deviceidle: [android.os.IDeviceIdleController]
我們可以使用‘-h’看到所有的deviceidle的所有選項:
$ adb shell dumpsys deviceidle -h Device idle controller (deviceidle) dump options: [-h] [CMD] -h: print this help text. commands: step Immediately step to next state, without waiting for alarm. disable Completely disable device idle mode. enable Re-enable device idle mode after it had previously been disabled. whitelist Add (prefix with +) or remove (prefix with -) packages.
5.2、DeviceIdleController的五種狀態
DeviceIdleController維持著設備包含的五種狀態,和上面介紹的Doze的五種狀態是一樣的:
- ACTIVE – 設備在使用中,或者連接著電源。
- INACTIVE – 設備已經從ACTIVE狀態中出來一段時間了(使用者關閉了屏幕或者拔掉了電源)
- IDLE_PENDING – 請留意,我們將進入idle mode.
- IDLE – 設備進入idle mode.
- IDLE_MAINTENANCE – 應用窗口已經打開去做處理.
1、當設備被喚醒和正在使用中,控制器就處於ACTIVE狀態,
2、不活躍時間超時,用戶關閉屏幕等等,將會使設備狀態進入到INACTIVE.
3、INACTIVE狀態下,DeviceIdleController將會通過AlarmManager來設置他自己的alarm來驅動進程:
一個alarm會被設置在一個預設的時刻(這個時間在M的預覽中是30分鐘)。
當這個alarm生效後,DeviceIdleController 會進入到IDLE_PENDING然後再次設置同樣的alarm。
4、當觸發下一個alarm後,控制器會進入到IDLE 狀態,進入到這個狀態後,應用特性會被完全限制。
5、IDLE 狀態後,會在IDLE 和IDLE_MAINTENANCE兩個狀態之間周期性的跳轉。IDLE_MAINTENANCE也就是Doze中提到的maintenance window,在這個狀態下,應用程序可以在此時執行訪問網絡,同步,和報警等活動。
這些服務的公共API(由IDeviceIdleController 接口展現)持有全部方法訪問白名單。應用(系統應用或其它第三方應用)任何情況下都不能驅動控制器狀態。
5.3、DeviceIdleController 維護著一個應用白名單
正如你在上面的幫助菜單中看到的一樣,DeviceIdleController 維護著一個應用白名單,不需要額外的參數,通過dump服務的狀態,我們能夠看到現在的這個列表:
$ adb shell dumpsys deviceidle Whitelist system apps: com.android.providers.downloads com.android.vending com.google.android.gms Whitelist app uids: UID=10012: true UID=10016: true UID=10026: true …
這個名單分為兩個部分:系統應用和第三方應用。
系統應用
系統應用會被平臺制作者通過配置定義列在白名單中。下面這個是從Nexus 6中得到的一個配置定義例子,它將GMS核心(在GCM中使用),應用商店,以及一個任意的用於電源監控的app白名單化:
<?xml version="1.0" encoding="utf-8"?> <!-- These are configurations that must exist on all GMS devices. --> <config> <allow-in-power-save package="com.google.android.gms" /> <allow-in-power-save package="com.android.vending" /> <allow-in-power-save package="com.google.android.volta" /> </config>
其它的系統服務可以通過SystemConfig的實例訪問到這些值。DeviceIdleController使用SystemConfig.getAllowInPowerSave()將這些系統定義的元素放到白名單中。
註意:當設備處於“省電模式”時,同樣也是這個配置文件決定哪個系統應用可以在後臺開啟服務。
第三方應用
白名單中剩下的部分是用戶定義的,這些項可以通過兩種方式被增加和刪除。
第一種:開發者可以通過dumpsys接口使用白名單命令:
$ adb shell dumpsys deviceidle whitelist +com.example.myapplication $ adb shell dumpsys deviceidle Whitelist system apps: com.android.providers.downloads com.android.vending com.google.android.gms Whitelist user apps: com.example.myapplication Whitelist app uids: UID=10012: true
第二種:用戶可以通過設置(Settings -> Battery -> Ignore optimizations)來修改白名單。
另外:在小米手機中,神隱模式中把應用設置為無限制或者在近期任務中下拉鎖定,就會出現在上述的白名單中。
六、測試Doze和App Standby模式的方法(Adb命令)
測試Doze模式
1、 首先確保你的硬件或虛擬設備是Android6.0或更高版本系統;
2、 連接設備到開發機上並安裝你的app;
3、 運行app並讓其運行活動;
4、 關閉設備的屏幕;
5、運行以下adb命令使系統進入Doze模式:
$ adb shell dumpsys battery unplug $ adb shell dumpsys deviceidle step
你可能需要多次執行第二條命令,直到設備處於idle 狀態。註意,第一條命令的意思是,拔去電源,即使現在正在插著usb調試,也不會充電。建議運行
$ adb shell dumpsys battery reset,否則會出現手機充不上電的情況。
6、 觀察你的app表現行為是否有需優化改進的地方。
測試App Standby模式
步驟1-3同測試Doze模式
4、 運行以下adb命令迫使系統進入App Standby模式:
$ adb shell dumpsys battery unplug $ adb shell am set-inactive <packageName> true
5、 模擬喚醒你的應用程序使用以下命令:
$ adb shell am set-inactive <packageName> false $ adb shell am get-inactive <packageName>
6、 觀察你的App,確保應用程序可以從standby mode優雅得恢復,應該檢查App的通知及後臺能按預期的繼續工作。
七、客戶端使用方法:
App程序可發送action為ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS的intent引導用戶進入設置界面將應用程序設置進白名單列表裏。
應用程序還可以使用AREQUEST_IGNORE_BATTERY_OPTIMIZATIONS 權限來觸發一個系統對話來讓用戶添加到白名單裏,而無需進入設置界面去設置。
當然,官方也提供用戶把你的App移除電池優化白名單的選項。這個白名單也會被Android M的另一個新特性 App Standby使用,所以用戶只能簡單的進行控制,也就是說設備並不會完全相信這個白名單。
這個白名單只是谷歌的一個建議,就是說在下面這些情況下,你可以使用上面兩張方法,來引導用戶把你的app設為白名單
官方舉了一下白名單例子:
總結:
我認為Doze 模式和 APP Standby模式,限制app的權限種類都是一樣的。都是進入idle狀態。只是各自模式的進入和退出所需要的條件不一樣、進入模式後控制APP的周期也不一樣。
Doze模式的推出本身是為了減少電池的消耗,且Google希望統一使用GCM來傳遞消息進行通訊,而對於國內開發來講,確實帶來了很大的麻煩:
國內開發的一些消息推送機制(PUSH)將受到影響;
若使用GCM,在國內使用GCM延遲高,對於即時通訊產品來說選擇還需勇氣啊;
國內第三方手機廠商如華為、小米、三星,定制的Rom也將使用定制的推送消息機制。這讓同一款App如何選擇哪種推送機制才能兼容呢?
解決方法:
用戶添加應用程序到電池優化白名單列表;
開發者使用Google提供的ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS意圖和AREQUEST_IGNORE_BATTERY_OPTIMIZATIONS權限設置以此忽略(推薦);
使用Google提供的GCM;
通過so繞過Doze模式。
我使用MIUI 7.5(Android 6.0.1)測試過程中發現,自己維持長連接一進入standby模式,網絡就斷了(手機其它app網絡正常),但是運行在後臺的代碼還是一直在跑,log也能正常輸出到手機的文件上,就是連不上網。按照官方的描述進入standby模式,工作應該被掛起,但是為什麽後臺代碼還是正常運行呢??請高人指點一下
- 微信的主進程可以手動設置為standby 模式,
- APP的子進程都是無法設置為standby 模式,但是如果主進程是standby 模式,子進程也會是standby 模式。即使使用命令查看子進程的standby 狀態也是false。
- 在正常使用手機的情況下,微信的主進程無法進入standby 模式,感覺是使用so繞過standby模式。具體so文件是怎麽實現的,還請大神指點一下。
Tags: Android 應用程序 window 谷歌 第三方
文章來源: