[Android Framework] 8.1 Doze模式分析(三)——Deep Doze模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/FightFightFight/article/details/81367516

概述

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中做了三件事:

  • 1.通知PMS、NetworkPolicyManager中DeepDoze处于IDLE状态。
  • 2.BatteryStatsService中开始统计。
  • 3.发送Intent为mIdleIntent的广播。

其中第一点就可以进行网络的限制。再来看看第三点,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的原理就是这样。

1.如何忽略唤醒锁?

在进入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的忽略。

猜你喜欢

转载自blog.csdn.net/FightFightFight/article/details/81367516