Deep Doze,也就是Android的Doze模式了,表示深度Doze,比起LightDoze,它将进行更多的限制:无法进行网络访问和 GPS/WLAN 扫描、唤醒被忽略、闹钟和作业/同步被延迟。当然,它的触发条件也将更加苛刻:灭屏、未充电、静止。
因此,如果要支持DeepDoze,则相应设备还必须具有大幅度动作检测器 (SMD),否则,无法探测到到底是静止还是移动。
DIC中也定义了七个用来表示Deep Doze模式的值:
//表示doze模式
private int mState;
//mState值,表示设备处于活动状态
private static final int STATE_ACTIVE = 0;
//mState值,表示设备处于不交互状态,灭屏、静止
private static final int STATE_INACTIVE = 1;
//mState值,表示设备刚结束不交互状态,等待进入IDLE状态
private static final int STATE_IDLE_PENDING = 2;
//mState值,表示设备正在感应动作
private static final int STATE_SENSING = 3;
//mState值,表示设备正在定位
private static final int STATE_LOCATING = 4;
//mState值,表示设备处于空闲状态,也即Doze模式
private static final int STATE_IDLE = 5;
//mState值,表示设备正处于Doze模式,紧接着退出Doze进入维护状态
private static final int STATE_IDLE_MAINTENANCE = 6;
和Light Doze一样,DeepDoze模式也从becomeInactiveIfAppropriateLocked()
方法开始,这点已经在分析LightDoze时分析了,这里再来看一遍,该方法中涉及到Doze模式的代码如下:
void becomeInactiveIfAppropriateLocked() {
if ((!mScreenOn && !mCharging) || mForceIdle) {
if (mState == STATE_ACTIVE && mDeepEnabled) {
//Doze模式状态由ACTIVE变为INACTIVE
mState = STATE_INACTIVE;
//重置Doze模式相关标记值、定时器
resetIdleManagementLocked();
//设置一个30mins的定时
scheduleAlarmLocked(mInactiveTimeout, false);//30mins
}
.......................
}
当DeepDoze处于活动状态,并且Doze模式可用时,会通过Alarm一步步进入IDLE状态。首先会由交互状态变为不交互状态时,会重置所有数据后发送一个定时Alarm操作,重置操作如下:
void resetIdleManagementLocked() {
mNextIdlePendingDelay = 0;
mNextIdleDelay = 0;
//下次LightDoze的定时时间
mNextLightIdleDelay = 0;
//取消DeepDoze发送的定时Alarm
cancelAlarmLocked();
//取消用于STATE_SENSING状态时长的Alarm
cancelSensingTimeoutAlarmLocked();
//取消GPS定位和Generic定位的更新
cancelLocatingLocked();
//取消、解绑接收传感器的触发事件
stopMonitoringMotionLocked();
//停止检测器检测
mAnyMotionDetector.stop();
}
重置后会重新设置一个定时Alarm,时长为15分钟,代码如下:
void scheduleAlarmLocked(long delay, boolean idleUntil) {
if (mMotionSensor == null) {
//如果没有运动传感器,则返回,因为无法判断设备是否保持静止
if (mMotionSensor == nullr) {
return;
}
//设置DeepDoze的定时Alarm
mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
if (idleUntil) {
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep",
mDeepAlarmListener, mHandler);
} else {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep",
mDeepAlarmListener, mHandler);
}
}
当到达定时后,回调mDeepAlarmListener
的onAlarm()方法,该方法如下:
void scheduleAlarmLocked(long delay, boolean idleUntil) {
if (mMotionSensor == null) {
//如果没有运动传感器,则返回,因为无法判断设备是否保持静止
if (mMotionSensor == nullr) {
return;
}
//设置DeepDoze的定时Alarm
mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
if (idleUntil) {
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep",
mDeepAlarmListener, mHandler);
} else {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep",
mDeepAlarmListener, mHandler);
}
}
当到达定时后,回调mDeepAlarmListener的onAlarm()方法,该方法如下:
private final AlarmManager.OnAlarmListener mDeepAlarmListener
= new AlarmManager.OnAlarmListener() {
@Override
public void onAlarm() {
synchronized (DeviceIdleController.this) {
///每次Doze状态转换都会在该方法中进行
stepIdleStateLocked("s:alarm");
}
}
};
stepIdleStateLocked()
方法中会通过Alarm在不同的阶段流转,该方法如下:
void stepIdleStateLocked(String reason) {
final long now = SystemClock.elapsedRealtime();
//说明1小时内有Alarm定时时间到,暂不进入IDLE状态,30min后再进入
if ((now+mConstants.MIN_TIME_TO_ALARM) >
mAlarmManager.getNextWakeFromIdleTime()) {
if (mState != STATE_ACTIVE) {
//将当前设备变为活动状态,LightDoze和DeepDoze都为Active状态
becomeActiveLocked("alarm", Process.myUid());
becomeInactiveIfAppropriateLocked();
}
return;
}
switch (mState) {
case STATE_INACTIVE:
//启动Sensor
startMonitoringMotionLocked();
//设置STATE_IDLE_PENDING状态时长的定时Alarm,30mins
scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT,
false);
// Reset the upcoming idle delays.
mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;//5mins
mNextIdleDelay = mConstants.IDLE_TIMEOUT;//60mins
//此时状态变为PENDING状态
mState = STATE_IDLE_PENDING;
break;
case STATE_IDLE_PENDING:
//此时状态变为SENSING状态
mState = STATE_SENSING;
//设置STATE_SENSING状态超时时长的定时Alarm,DEBUG?1:4mins
scheduleSensingTimeoutAlarmLocked(mConstants.SENSING_TIMEOUT);
//取消通用位置更新和GPS位置更新
cancelLocatingLocked();
mNotMoving = false;
mLocated = false;
mLastGenericLocation = null;
mLastGpsLocation = null;
//开始检测是否有移动
mAnyMotionDetector.checkForAnyMotion();
break;
case STATE_SENSING:
//取消用于STATE_SENSING状态超时时长的Alarm
cancelSensingTimeoutAlarmLocked();
//此时状态变为LOCATING
mState = STATE_LOCATING;
//设置STATE_LOCATING状态时长的Alarm
scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT,
false);//DEBUG?15:30
//请求通用位置
if (mLocationManager != null
&& mLocationManager.getProvider(LocationManager.
NETWORK_PROVIDER) != null) {
mLocationManager.requestLocationUpdates(mLocationRequest,
mGenericLocationListener, mHandler.getLooper());
mLocating = true;
} else {
mHasNetworkLocation = false;
}
//请求GPS位置
if (mLocationManager != null
&& mLocationManager.getProvider(LocationManager.
GPS_PROVIDER) != null) {
mHasGps = true;
mLocationManager.requestLocationUpdates(LocationManager.
GPS_PROVIDER, 1000, 5,
mGpsLocationListener, mHandler.getLooper());
mLocating = true;
} else {
mHasGps = false;
}
//如果true,则break,因为在Location的Listener中会进入下一个状态,
//否则进入下一步状态
if (mLocating) {
break;
}
// Otherwise, we have to move from locating into idle maintenance.
case STATE_LOCATING:
//取消DeepDoze的Alarm
cancelAlarmLocked();
//取消位置更新
cancelLocatingLocked();
//Sensor停止检测
mAnyMotionDetector.stop();
case STATE_IDLE_MAINTENANCE:
//设置STATE_IDLE状态时长的定时Alarm,到时后将退出IDLE状态
scheduleAlarmLocked(mNextIdleDelay, true);
//设置下次IDLE时间
mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {
mNextIdleDelay = mConstants.IDLE_TIMEOUT;
}
mState = STATE_IDLE;
//进入DeepDoze的IDLE后,覆盖LightDoze
if (mLightState != LIGHT_STATE_OVERRIDE) {
mLightState = LIGHT_STATE_OVERRIDE;
//取消LightDoze的定时Alarm
cancelLightAlarmLocked();
}
//申请wakelock保持CPU唤醒
mGoingIdleWakeLock.acquire();
//handler中处理idle状态后各个模块的限制工作
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
break;
case STATE_IDLE:
mActiveIdleOpCount = 1;//表示现在有正在活动的操作
//申请wakelock锁保持cpu唤醒
mActiveIdleWakeLock.acquire();
//设置STATE_IDLE_MAINTENANCE状态时长的定时Alarm,
//到时后将退出维护状态
scheduleAlarmLocked(mNextIdlePendingDelay, false);
mMaintenanceStartTime = SystemClock.elapsedRealtime();
mNextIdlePendingDelay =
Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,
(long)(mNextIdlePendingDelay *
mConstants.IDLE_PENDING_FACTOR));
if (mNextIdlePendingDelay < mConstants.IDLE_PENDING_TIMEOUT) {
mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
}
mState = STATE_IDLE_MAINTENANCE;
//Handler中处理退出idle状态进入维护状态后取消限制的工作
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
break;
}
}
整个方法比较繁琐,具体作用都在代码中进行了注释,这样可能比较好理解点,这里再说明一点,由于设备是根据灭屏、设备静止来决定是否进入DeepDoze模式的,这其中有关于Sensor、AnyMotionDector相关逻辑,因此太细节的步骤就不分析了。
这里我们再根据上述方法分析,当DeepDoze进入IDLE状态时,通过Handler对网络、JobScheduler等进行限制的逻辑,Handler中DeepDoze进入IDLE状态和LightDoze进入IDLE状态的实现都在一个代码块中,在分析LightDoze时已经分析了大部分,这里删减只保留DeepDoze相关进行分析:
case MSG_REPORT_IDLE_ON:
case MSG_REPORT_IDLE_ON_LIGHT: {
.......................................
deepChanged = mLocalPowerManager.setDeviceIdleMode(true);
try {
mNetworkPolicyManager.setDeviceIdleMode(true);
mBatteryStats.noteDeviceIdleMode(msg.what == MSG_REPORT_IDLE_ON
? BatteryStats.DEVICE_IDLE_MODE_DEEP
: BatteryStats.DEVICE_IDLE_MODE_LIGHT, null, Process.myUid());
} catch (RemoteException e) {
}
if (deepChanged) {
getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
}
.......................................
} break;
DeepDoze进入IDLE状态时,Handler中做了三件事:
其中第一点就可以进行网络的限制。再来看看第三点,mIdIntent如下:
mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
涉及模块有:JobScheduler,GNSS,UsageStatsService,Wifi,这些模块收到广播后,进行相应操作,从而对各自的功能进行限制。
再来看看当DeepDoze退出IDLE状态进入维护状态(matinenance)时的相关操作,和进入IDLE时的操作恰好相反,部分代码如下:
case MSG_REPORT_IDLE_OFF: {
........................................
final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
try {
mNetworkPolicyManager.setDeviceIdleMode(false);
mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_OFF,
null, Process.myUid());
} catch (RemoteException e) {
}
if (deepChanged) {
incActiveIdleOps();
getContext().sendOrderedBroadcastAsUser(mIdleIntent, UserHandle.ALL,
null, mIdleStartedDoneReceiver, null, 0, null, null);
}
........................................
} break;
整个DeepDoze的原理就是这样。
在进入DeepDoze Idle状态时有:
final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(true);
进入PowerManagerService中:
@Override
public boolean setDeviceIdleMode(boolean enabled) {
return setDeviceIdleModeInternal(enabled);
}
boolean setDeviceIdleModeInternal(boolean enabled) {
synchronized (mLock) {
if (mDeviceIdleMode == enabled) {
return false;
}
mDeviceIdleMode = enabled;
updateWakeLockDisabledStatesLocked();
}
return true;
}
再来看updateWakeLockDisabledStatesLocked()
方法:
private void updateWakeLockDisabledStatesLocked() {
boolean changed = false;
final int numWakeLocks = mWakeLocks.size();
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
== PowerManager.PARTIAL_WAKE_LOCK) {
//更新wakelock.disable
if (setWakeLockDisabledStateLocked(wakeLock)) {
changed = true;
if (wakeLock.mDisabled) {
// This wake lock is no longer being respected.
notifyWakeLockReleasedLocked(wakeLock);
} else {
notifyWakeLockAcquiredLocked(wakeLock);
}
}
}
}
if (changed) {
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();
}
}
最终通过设置wakelock.disable
完成wakelock的忽略。