Android7.0 Doze模式流程

时间:2024-03-25 14:26:18

Doze模式的主要实现是在framework中的DeviceIdleController类:分为Deep Idle 和 Light Idle模式两种


Deep Idle模式

先说下用到的几个时间常量值(括号类的是原生的时间,右边的是项目中实际用到的值)

INACTIVE_TIMEOUT30min/3min 6min

Inactive状态的时长;

 

MOTION_INACTIVE_TIMEOUT10min/1min) 1min

运动传感器监测改变之后,进入Inactive的持续时长。

 

IDLE_AFTER_INACTIVE_TIMEOUT30min/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状态,并将IdleIdle_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 当设置的AlarmIdle持续时间到了以后,调用stepIdleStateLocked方法,进入STATE_IDLE选择,首先唤醒系统,设置一个时间为 mNextIdlePendingDelayAlarm定时回调本方法,然后重新计算下mNextIdlePendingDelay的值,将state状态置为Idle_Maintenance,然后通过Handler发送消息通知各服务退出Idle模式。

当mNextIdlePendingDelay时间到了以后再次调用本方法,进入Idle状态,依次循环。但是在此期间若有USB连接或者屏幕电量则退出当前模式,直接进入Active状态。

 


Light Idle模式

LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT(5min/15s)5s

Light Idle模式从inactivepre_idle状态的时间。

 

LIGHT_PRE_IDLE_TIMEOUT(10min/30s) 5s

pre_idleidle状态的时间。

 

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不会重置,PowerManagerwake 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模式类似。点击查看大图



Android7.0 Doze模式流程

Android7.0 Doze模式流程Android7.0 Doze模式流程