Doze和App Standby模式

900 阅读3分钟

全部摘抄自Android7.0 Doze模式

项目中关于定时任务, 使用的是AlarmManager, 记录AlarmManager使用中遇到的一些坑, Doze模式, App Standby模式

Doze模式和App Standby模式的区别

**Doze模式: ** Doze模式通过延缓应用在设备长时间待机状态下对CPU和网络资源的使用来实现节能.

**App Standby模式: ** App Standby则是通过延缓最近未被使用的后台应用对于网络的请求来达到同样的目的

一、基本原理

一旦设备进入Doze模式, 系统就减少(延缓)应用对网络的访问、对CPU的占用, 来节省电池电量

设备进入Doze睡眠模式时机:

  • 1、停止充电
  • 2、屏幕关闭
  • 3、手机处于静止状态(位置没有发生相对移动)

Doze模式还定义了maintenance window, 在maintenance window中, 系统允许应用完成它们被延缓的动作, 即可以使用CPU资源及访问网络.

当进入Doze模式的条件一直满足时, Doze模式会定期的进入到maintenance window, 但进入的间隔越来越长. 通过这种方式, Doze模式可以使终端处于较长时间的休眠状态.

需要注意的是: 一旦Doze模式的条件不再满足, 即用户充电、或打开屏幕、或终端的位置发生了移动, 终端就恢复到正常模式. 因此当用户频繁使用手机时, Doze模式几乎是没有什么实际用处的.

当终端处于Doze模式时, 进行了以下操作:

1、暂停网络访问

2、系统忽略所有的WakeLock

3、标准的AlarmManager alarms被延缓到下一个maintenance window. 但使用AlarmManager的setAndAllowWhileIdle、setExactAndAllowWhileIdle和setAlarmClock时, alarms定义事件仍会启动. 在这里alarms启动前, 系统会短暂的退出Doze模式.

4、系统不再进行WiFi扫描

5、系统不允许sync adapters运行

6、系统不允许JobScheduler运行

DeviceIdleController.stepIdleStateLocked
void stepIdleStateLocked(String reason) {
    EventLogTags.writeDeviceIdleStep();

    final long now = SystemClock.elapsedRealtime();
    /**
     * 1.如果在Idel状态收到Alarm, 将先唤醒终端, 然后重新判断是否需要进入idel状态进行工作
     * 2.如果应用调用AlarmManager的一些指定接口, 仍然可以在idel状态进行工作
     */
    if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
        if (mState != STATE_ACTIVE) {
            becomeActiveLocked("alarm", Process.myUid());
            becomeInactiveIfAppropriateLocked();
        }
        return;
    }
	// 2.以下是Doze模式的状态转变相关的代码
    switch (mState) {
        case STATE_INACTIVE:
        	/**
             * 3.保持屏幕熄灭, 同时未充电达到30min, 进入此分支
             * 4.注册一个mMotionListener, 检测是否移动, 如果检测到移动, 将重新进入到ACTIVE状态
             */
            startMonitoringMotionLocked();
            /**
             * 5.再次调用scheduleAlarmLocked函数, 此次时间仍为30min, 也就是说如果不发生退出
             *   Doze模式的事件, 30min后将再次进入到stepIdleStateLocked函数, 不过届时的mState
             *   已经变为STATE_IDLE_PENDING
             */
            scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
            // Reset the upcoming idle delays.
            mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
            mNextIdleDelay = mConstants.IDLE_TIMEOUT;
            mState = STATE_IDLE_PENDING;
            EventLogTags.writeDeviceIdle(mState, reason);
            break;
        case STATE_IDLE_PENDING:
        	// 6.保持息屏、未充电、静止状态, 经过30min后进入此分支.
            mState = STATE_SENSING;
            EventLogTags.writeDeviceIdle(mState, reason);
            // 7.保持Doze模式条件, 4min后再次进入stepIdleStateLocked
            scheduleSensingTimeoutAlarmLocked(mConstants.SENSING_TIMEOUT);
            // 8.停止定位相关的工作
            cancelLocatingLocked();
            mNotMoving = false;
            mLocated = false;
            mLastGenericLocation = null;
            mLastGpsLocation = null;
            // 9.开始检测手机是否发生运动, 若手机运动过, 则重新变为active状态
            mAnyMotionDetector.checkForAnyMotion();
            break;
        case STATE_SENSING:
        case STATE_LOCATING:
        case STATE_IDLE_MAINTENANCE:
        case STATE_IDLE:
        break;
    }
}