Android7.0 Doze模式流程分析

Android7.0 Doze模式流程分析,Doze模式的主要實現是在framework中的DeviceIdleController類:分為Deep Idle 和 Light Idle模式兩種。

Deep Idle模式

先說下用到的幾個時間常量值(括號類的是原生的時間,右邊的是項目中實際用到的值)

INACTIVE_TIMEOUT(30min/3min) 6min

Inactive狀態的時長;

MOTION_INACTIVE_TIMEOUT(10min/1min) 1min

運動傳感器監測改變之後,進入Inactive的持續時長。

IDLE_AFTER_INACTIVE_TIMEOUT(30min/3min) 3min

Pend狀態的時長;

SENSING_TIMEOUT(4min/1min) 60s

Sensing狀態持續時長;

LOCATING_TIMEOUT(30s/15s) 15s

Locating狀態最多持續時長;

IDLE_TIMEOUT(60min/6min) 60min(實際每次都是60min)

Idle狀態持續時長,可變。

MAX_IDLE_TIMEOUT(6h/30min) 30min

Idle狀態持續時長最大值,但是持續時長最小不小於初始值。

IDLE_PENDING_TIMEOUT(5min/30s) 30s

Idle_Maintenance狀態持續時長,可變;

MAX_IDLE_PENDING_TIMEOUT(10min/60s) 60s

Idle_Maintenance狀態持續時長最大值,最小不小於初始值。

deep idle模式的7個狀態:

1 Active

2 InActive

3 Idle_Pending

4 Sensing

5 Locating

6 Idle

7 Idle_Maintenance

下面分析各個狀態

1 手機亮屏或者插上USB,都是處於Active狀態

2 手機滅屏且沒有連上USB,通過對Battery_Changed的廣播接收和對Dispaly屏幕變化的監聽最後都是調用becomeInactiveIfAppropriateLocked方法進入InActive狀態。在這個方法中,先是將State置為InActive,然後調用resetIdleManagementLocked方法重置各種狀態,包括重置Alarm,取消傳感器,位置監測等。最後調用scheduleAlarmLocked方法設置一個Alarm定時一段時間執行stepIdleStateLocked方法。

3 當上一步的定時到瞭開始執行stepIdleStateLocked方法,進入stepIdleStateLocked判斷,首先,startMonitoringMotionLocked()註冊一個特殊運動傳感器,監測手機有沒有特殊移動,然後scheduleAlarmLocked設置Alarm一段時間後再次調用本方法,隨後將State設為Idle_Pending狀態,並將Idle和Idle_Maintenance的時間間隔設為初始值。

4當上一步的Alarm時間到瞭以後,回調stepIdleStateLocked方法,執行stepIdleStateLocked選擇,首先將State置為Sensing狀態。接著調用scheduleSensingTimeoutAlarmLocked方法設置Alarm定時調用becomeInactiveIfAppropriateLocked這個方法,取消位置監聽;調用mAnyMotionDetector.checkForAnyMotion()方法註冊加速度傳感器,監測各個方向上有沒有運動,之後通過mCallback.onAnyMotionResult(status)將結果返回給DeviceIdleControler,若沒有運動,則調用stepIdleStateLocked進入下個一狀態,否則調用handleMotionDetectedLocked進入InActive狀態。

5 當上一步監測到沒有運動時,調用stepIdleStateLocked方法,進入STATE_SENSING選擇,首先,調用cancelSensingTimeoutAlarmLocked取消上一步的定時調用。接著將state置為Locating,然後設置一個Alarm定時調用本方法,接著,註冊基於網絡和基於GPS的位置監聽,但是前提是打開瞭定位服務,並且GPS使用的是網絡和GPS定位,若都沒有滿足,則直接進入下一個case狀態。在兩個位置監聽中都是在LocationChanged方法中,若有一次位置精度小於一個值(20m),則再根據上一步的傳感器監測判斷位置有沒有變換,沒有則直接回調本方法進入下一個狀態,否則就是等到設置的Alarm到瞭之後才回調本方法。

6 當上一步再次調用stepIdleStateLocked方法之後,進入Locating選擇,取消定位服務監測,取消Alarm定時,取消加速度傳感器監測,接著由於沒有break,則直接進入STATE_IDLE_MAINTENANCE選擇。在這個選擇中,先設置一個定時的Alarm,這個Alarm是通過setIdleUntil方法設置,比較特殊,可以重置系統中其他Alarm。然後計算下一次的Idle時間,將state狀態置為Idle狀態,然後將LightState狀態置為LIGHT_STATE_OVERRIDE,取消Light Idle模式的Alarm定時,最後通過Handler發送消息,通知各個服務進入Idle狀態。

7 當設置的Alarm的Idle持續時間到瞭以後,調用stepIdleStateLocked方法,進入STATE_IDLE選擇,首先喚醒系統,設置一個時間為 mNextIdlePendingDelay的Alarm定時回調本方法,然後重新計算下mNextIdlePendingDelay的值,將state狀態置為Idle_Maintenance,然後通過Handler發送消息通知各服務退出Idle模式。

當mNextIdlePendingDelay時間到瞭以後再次調用本方法,進入Idle狀態,依次循環。但是在此期間若有USB連接或者屏幕電量則退出當前模式,直接進入Active狀態。

Light Idle模式

LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT(5min/15s):5s

Light Idle模式從inactive到pre_idle狀態的時間。

LIGHT_PRE_IDLE_TIMEOUT(10min/30s): 5s

pre_idle到idle狀態的時間。

LIGHT_IDLE_TIMEOUT(5min/15s): 5min

Light idle持續的時長初始值,light idle模式的持續時長是會變的

LIGHT_MAX_IDLE_TIMEOUT(15min/60s): 60s

Light idle模式持續時長的最大值,但是持續時長最小不小於初始值

LIGHT_IDLE_FACTOR(2):

Light idle模式持續時長的比例因子,即沒經過一次light idle模式持續時長都要乘以這個比例因子,但是最長不能超過最大持續時間。

LIGHT_IDLE_MAINTENANCE_MIN_BUDGET(1min/15s): 15s

Light idle maintenance的持續時間的最小值。

LIGHT_IDLE_MAINTENANCE_MAX_BUDGET(5min/30s): 30s

Light idle maintenance的持續時間的最大值。

Light Idle模式的狀態

1 LIGHT_STATE_ACTIVE

2 LIGHT_STATE_INACTIVE

3 LIGHT_STATE_PRE_IDLE

4 LIGHT_STATE_IDLE

5 LIGHT_STATE_WAITING_FOR_NETWORK

6 LIGHT_STATE_IDLE_MAINTENANCE

7 LIGHT_STATE_OVERRIDE

下面分析各個狀態

1 手機亮屏或者處於USB連接狀態

2 手機滅屏並且沒有USB連接,通過滅屏和Battery_Changed廣播監聽,將Light State狀態置為LIGHT_STATE_INACTIVE,resetLightIdleManagementLocked重置各個狀態,並設置(5min/15s)的Alarm,時間到瞭執行stepLightIdleStateLocked方法。

3 上一步的alarm到瞭,執行stepLightIdleStateLocked方法,進入LIGHT_STATE_INACTIVE選擇,判斷當前系統是否有ops執行,若有,則將狀態置為LIGHT_STATE_PRE_IDLE,繼續執行任務,並設置(10min/30s)的Alarm繼續執行stepLightIdleStateLocked方法。若沒有ops執行,則直接進入LIGHT_STATE_IDLE模式。

4 上一步的Alarm到瞭之後,執行stepLightIdleStateLocked方法,將Light State置為LIGHT_STATE_IDLE,並設置(5min/15s,可變)的Alarm調用本方法,發送消息執行進入Light Idle模式的操作。

5 上一步Alarm到瞭以後,執行stepLightIdleStateLocked方法,首先判斷是否有網絡連接。若沒有網絡連接,則將狀態置為LIGHT_STATE_WAITING_FOR_NETWORK,設置一個Light Idle時間的Alarm等待網絡連接。若有網絡連接,則將Light State置為LIGHT_STATE_IDLE_MAINTENANCE,執行掛起操作,設置一個定時Alarm。

6 上一步的的判斷中若沒有網絡連接,等待時間到瞭以後,將狀態置為LIGHT_STATE_IDLE_MAINTENANCE,接著執行掛起操作,設置一個定時Alarm。當這個Alarm到瞭以後,將狀態置為LIGHT_STATE_IDLE,依次循環。

7 在進入deep idle的之後,會將Light State的狀態置為LIGHT_STATE_OVERRIDE,這樣每次調用stepLightIdleStateLocked都是直接返回,而不執行任何操作,即進入Deep Idle之後就取消Light Idle的一切操作。

從目前的feature來看,進入Light Idle之後,網絡會和deep dle模式一樣中斷,但是Alarm不會重置,PowerManager對wake lock的操作不一樣,別的服務通過發送 不同的廣播,操作也應該是不一樣的。

對於進入Idle模式後,app應該怎麼做?

1 考慮引導用戶將app加入白名單,即電池不優化名單

2 Idle模式會忽略wake lock並且設置的Alarm也會被重置,但AlarmManger提供方法setAndAllowWhileIdle和setExactAndAllowWhileIdle,即使在Idle模式下該Alarm也可以運行。setAlarmClock設定的Alarm也能夠運行。

對於網絡服務,若滅屏情況下應用優先級仍然很高(<=4 前臺服務,這個優先級是在AlarmManager裡面定義的Process_State的優先級),則即使不在白名單裡面,也是不會禁止網絡連接的。但是實測百度瀏覽器下載的時候,瀏覽器優先級為2,一旦滅屏就變成瞭5,然後網絡就被禁止瞭。滅屏情況下優先級<=4的有圖庫,谷歌搜索。。。。。

設置裡面的電池優化選項中,將app置為未優化,就是在doze模式下允許運行,最終是調用到DeviceIdleControler中的addPowerSaveWhitelistAppInternal方法,將應用加入到mPowerSaveWhitelistUserApps這個集合中去瞭。並且會將改應用寫入到配置文件deviceidle.xml中去,方便下次讀取。該文件目錄為data/system/deviceidle.xml。

doze模式的白名單還可以通過framework/base/data/etc/platform.xml添加標記為allow-in-power-save的項設置。在編譯時期添加白名單。

最後來張圖片,是Deep Idle模式的,Liight Idle模式類似。

You May Also Like