Android 低电耗/Doze原理---设备运动状态和位置对Doze模式的影响
基础知识
Android 6.0以后引入的Doze机制(也叫低电耗模式)在于节省系统耗电量,延长设备的使用时间。当设备息屏,未连接至电源,且长时间处于静置状态时,系统进入idle状态,也就是doze状态。
Doze模式分为Light Idle(Android 7.0引入)和Deep Idle。设备进入两种状态花费的时长不一样,且对应用的限制程度也不一样。
本文基于Android 12代码讲述的是DeviceidleController通过哪些方式判断设备处于静置状态,以及运动状态和位置对设备进入Deep Idle过程的影响。
Deep Idle的状态机
Deep Idle中的状态机主要有以下六种。
/** Device is currently active. */
static final int STATE_ACTIVE = 0;
/** Device is inactive (screen off, no motion) and we are waiting to for idle. */
static final int STATE_INACTIVE = 1;
/** Device is past the initial inactive period, and waiting for the next idle period. */
static final int STATE_IDLE_PENDING = 2;
/** Device is currently sensing motion. */
static final int STATE_SENSING = 3;
/** Device is currently finding location (and may still be sensing). */
static final int STATE_LOCATING = 4;
/** Device is in the idle state, trying to stay asleep as much as possible. */
static final int STATE_IDLE = 5;
/** Device is in the idle state, but temporarily out of idle to do regular maintenance. */
static final int STATE_IDLE_MAINTENANCE = 6;
进入Deep Idle过程中,对于位置和运行状态的检测逻辑在STATE_IDLE_PENDING 、STATE_SENSING、STATE_LOCATING实现。以下基于这三种状态机进行讲解。
状态 | 动作 | 状态持续时长 |
---|---|---|
STATE_ACTIVE | / | / |
STATE_INACTIVE | / | 30mins |
STATE_IDLE_PENDING | 监听运动状态变化 | 30mins |
STATE_SENSING | 晃动检测 | 最多5mins,通常为3s |
STATE_LOCATING | 停止晃动检测,监听位置变化 | 30s |
STATE_IDLE | 断网、限制alarm、禁止wifi scan… | 最短1hour,最长6hours |
STATE_IDLE_MAINTENANCE | 恢复网络、取消alarm限制、允许wifi scan… | 至少30s |
STATE_IDLE_PENDING----监听运动状态变化
状态机进入到STATE_IDLE_PENDING,调用startMonitoringMotionLocked监听运动状态变化。监听运动状态变化过程是一直持续的。
下面两种情况时,会停止监听:
- 当状态机mState变成ACTIVE 或者STATE_INACTIVE
- 运动状态变化,回调函数onSensorChanged / onTrigger调用handleMotionDetectedLocked
void startMonitoringMotionLocked() {
if (DEBUG) Slog.d(TAG, "startMonitoringMotionLocked()");
if (mMotionSensor != null && !mMotionListener.active) {
mMotionListener.registerLocked();
}
}
在DeviceidleController的内部MotionListener类中根据sensor类型注册监听。当运动状态变化时,不同的sensor类型对应不同的回调函数。
public boolean registerLocked() {
boolean success;
//根据初始化时 获取到mMotionSensor的sensor类型,决定应该调用监听运动状态的方法
if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
//运动状态变化时,回调onTrigger方法
success = mSensorManager.requestTriggerSensor(mMotionListener, mMotionSensor);
} else {
//运动状态变化时,回调onSensorChanged方法
success = mSensorManager.registerListener(
mMotionListener