Doze的退出,说的更严格一点,就是当Doze模式的状态由其他状态变为ACTIVE状态。简而言之,退出Doze模式有三种情况:屏幕亮屏、插入充电器、设备有移动。下面就这三种情况进行下分析。
在前面的分析中我们有见到过becomeActiveLocked()方法,这个方法当时没有进行分析,这个方法就是用来退出Doze的,严格来说,是将Doze状态置为了ACTIVE状态,从而退出IDLE状态或MAINTENANCE状态。因此,不管是何种方式退出Doze,都会调用这个方法。该方法如下:
void becomeActiveLocked(String activeReason, int activeUid) { if (mState != STATE_ACTIVE || mLightState != STATE_ACTIVE) { //设置一个Handler,在Handler中通知PMS、发送idle changed 广播 scheduleReportActiveLocked(activeReason, activeUid); //将DeepDoze状态值置为STATE_ACTIVE mState = STATE_ACTIVE; //将LightDoze状态值置为LIGHT_STATE_ACTIVE mLightState = LIGHT_STATE_ACTIVE; //多久后进入INACTIVE状态 mInactiveTimeout = mConstants.INACTIVE_TIMEOUT; mCurIdleBudget = 0; mMaintenanceStartTime = 0; //重置DeepDoze相关属性值、alarm、listener等 resetIdleManagementLocked(); //重置LightDoze相关属性值、alarm、listener等 resetLightIdleManagementLocked(); }} 1.屏幕亮灭屏当亮屏或灭屏时,PMS发送亮灭屏广播,DIC中监听了亮灭屏的广播,负责接受该广播并进行屏幕状态改变后的操作:
注册广播:
接收到广播后进行处理:
private final BroadcastReceiver mInteractivityReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { synchronized (DeviceIdleController.this) { updateInteractivityLocked(); } }};在updateInteractivityLocked()方法中更新LightDoze和DeepDoze的状态,这个方法在第一篇文章中分析过了。
2.充电状态改变当电池状态时,在BatteryService中会发送广播,DIC也对该广播进行了监听:
IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_BATTERY_CHANGED);getContext().registerReceiver(mReceiver, filter);接收到广播后进行处理:
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { ............ case Intent.ACTION_BATTERY_CHANGED: { synchronized (DeviceIdleController.this) { int plugged = intent.getIntExtra("plugged", 0); updateChargingLocked(plugged != 0); } } break; .................... } }};当接收到该广播后,调用updateChargingLocked(plugged != 0)来更新状态,参数表示是否插有充电线,该方法如下:
void updateChargingLocked(boolean charging) { //由充电转变为放电 if (!charging && mCharging) { mCharging = false; if (!mForceIdle) { //进入INACTIVE状态,开始Doze模式 becomeInactiveIfAppropriateLocked(); } } else if (charging) {//由放电转变为充电 mCharging = charging; if (!mForceIdle) { //Doze状态退出ACTIVE状态,退出Doze模式 becomeActiveLocked("charging", Process.myUid()); } }}最终,也会调用becomeActiveLocked()退出Doze模式。
3.其他服务通过Binder调用DeviceIdleController内部Binder也提供了用于退出Doze的接口:
@Override public void exitIdle(String reason) { getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER, null); long ident = Binder.clearCallingIdentity(); try { exitIdleInternal(reason); } finally { Binder.restoreCallingIdentity(ident); }}其内部也是通过调用becomeActiveLocked()方法退出Doze的:
public void exitIdleInternal(String reason) { synchronized (this) { becomeActiveLocked(reason, Binder.getCallingUid()); }} 4.MotionSensor检测状态发生这种情况和以上几种情况略不同,这种情况下Doze的退出是瞬时的,会将两个状态值都转换为STATE_ACTIVE后,又会立即调用becomeInactiveIfAppropriateLocked()方法进入INACTIVE状态,可以说是个“瞬时”退出。当MotionSensor检测到有移动时,则会退出Doze,处理逻辑在handleMotionDetectedLocked()中:
void handleMotionDetectedLocked(long timeout, String type) { boolean becomeInactive = false; if (mState != STATE_ACTIVE) { //通过Handler通知PMS、NetworkPolicy、发送IDLE_CHANGED广播等 scheduleReportActiveLocked(type, Process.myUid()); mState = STATE_ACTIVE;//将DeepDoze状态变为ACTIVE状态 mInactiveTimeout = timeout; mCurIdleBudget = 0; mMaintenanceStartTime = 0; becomeInactive = true; } if (mLightState == LIGHT_STATE_OVERRIDE) { mLightState = STATE_ACTIVE;//将LightDoze状态变为ACTIVE状态 becomeInactive = true; } if (becomeInactive) { //进入INACTIVE状态 becomeInactiveIfAppropriateLocked(); }}