Android O Doze模式的状态

来源:互联网 发布:北京云计算学校 编辑:程序博客网 时间:2024/05/16 06:45

现象

以下是BugReport日志
这里写图片描述

日志

STATE_ACTIVE2,006: 11-17 10:24:59.876137   900   900 I DeviceIdleController: updateChargingLocked: charging=true 2,007: 11-17 10:24:59.876244   900   900 I DeviceIdleController: becomeActiveLocked, reason = charging 2,258: 11-17 10:25:35.586856   900  1037 D DeviceIdleController: handleMessage(7) 2,285: 11-17 10:25:35.629342   900  1037 D DeviceIdleController: handleMessage(7) 2,663: 11-17 10:26:04.366455   900   900 I DeviceIdleController: updateChargingLocked: charging=false 3,823: 11-17 10:26:08.494908   900   900 D DeviceIdleController: updateDisplayLocked: screenOn=false STATE_ACTIVE to STATE_INACTIVE 条件:暗屏,不充电即可3,824: 11-17 10:26:08.495002   900   900 D DeviceIdleController: becomeInactiveIfAppropriateLocked() 3,825: 11-17 10:26:08.495032   900   900 D DeviceIdleController: Moved from STATE_ACTIVE to STATE_INACTIVE 3,826: 11-17 10:26:08.495209   900   900 D DeviceIdleController: stopMonitoringMotionLocked() // 3 分钟 INACTIVE_TIMEOUT3,827: 11-17 10:26:08.495311   900   900 D DeviceIdleController: scheduleAlarmLocked(180000, false) 3,829: 11-17 10:26:08.495907   900   900 D DeviceIdleController: Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE // 15 秒3,830: 11-17 10:26:08.495967   900   900 D DeviceIdleController: scheduleLightAlarmLocked(15000) 3,831: 11-17 10:26:08.498412   900   900 V AlarmManager: APP set with listener(DeviceIdleController.light) : type=2 triggerAtTime=3649013 win=-1 tElapsed=3649013 maxElapsed=3660261 interval=0 flags=0x8 // 11-17 10:26:25 减去 11-17 10:26:08 过了17秒3,987: 11-17 10:26:25.015547   900  1064 D AlarmManager: wakeup alarm = Alarm{2ef114b type 2 when 3649013 android}; listener package = DeviceIdleController.lightneedGrouping = false /** Device is inactive (screen off) and we are waiting to for the first light idle. */// private static final int LIGHT_STATE_INACTIVE = 1;3,988: 11-17 10:26:25.015989   900  1037 D DeviceIdleController: stepLightIdleStateLocked: mLightState=1 // 15 秒3,990: 11-17 10:26:25.016176   900  1037 D DeviceIdleController: scheduleLightAlarmLocked(15000) 3,992: 11-17 10:26:25.017253   900  1037 V AlarmManager: APP set with listener(DeviceIdleController.light) : type=2 triggerAtTime=3665533 win=-1 tElapsed=3665533 maxElapsed=3676782 interval=0 flags=0x8 /** Device is in the light idle state, trying to stay asleep as much as possible. */// private static final int LIGHT_STATE_IDLE = 4;3,994: 11-17 10:26:25.017778   900  1037 D DeviceIdleController: Moved to LIGHT_STATE_IDLE. // private static final int MSG_REPORT_IDLE_ON_LIGHT = 3;3,996: 11-17 10:26:25.018157   900  1037 D DeviceIdleController: handleMessage(3) // 11-17 10:26:41 减去 11-17 10:26:25 过了6秒4,786: 11-17 10:26:41.010752   900  1064 D AlarmManager: wakeup alarm = Alarm{fc74c41 type 2 when 3665533 android}; listener package = DeviceIdleController.lightneedGrouping = false 4,790: 11-17 10:26:41.017345   900  1037 D DeviceIdleController: stepLightIdleStateLocked: mLightState=4 4,791: 11-17 10:26:41.017503   900  1037 D DeviceIdleController: scheduleLightAlarmLocked(30000) 4,792: 11-17 10:26:41.017854   900  1037 V AlarmManager: APP set with listener(DeviceIdleController.light) : type=2 triggerAtTime=3696534 win=-1 tElapsed=3696534 maxElapsed=3719033 interval=0 flags=0x8 // We'd like to do maintenance, but currently don't have network// connectivity...  let's try to wait until the network comes back.// We'll only wait for another full idle period, however, and then give up./** Device is in the light idle state, we want to go in to idle maintenance but are* waiting for network connectivity before doing so. */// private static final int LIGHT_STATE_WAITING_FOR_NETWORK = 5;4,793: 11-17 10:26:41.018638   900  1037 D DeviceIdleController: Moved to LIGHT_WAITING_FOR_NETWORK. 4,868: 11-17 10:27:12.026656   900  1064 D AlarmManager: wakeup alarm = Alarm{aedfc2c type 2 when 3696534 android}; listener package = DeviceIdleController.lightneedGrouping = false //LIGHT_STATE_WAITING_FOR_NETWORK = 5;4,870: 11-17 10:27:12.027149   900  1037 D DeviceIdleController: stepLightIdleStateLocked: mLightState=5 // 15 秒4,872: 11-17 10:27:12.028098   900  1037 D DeviceIdleController: scheduleLightAlarmLocked(15000) 4,873: 11-17 10:27:12.028447   900  1037 V AlarmManager: APP set with listener(DeviceIdleController.light) : type=2 triggerAtTime=3712545 win=-1 tElapsed=3712545 maxElapsed=3723795 interval=0 flags=0x8 // 等待应用窗口事件被触发4,876: 11-17 10:27:12.028905   900  1037 D DeviceIdleController: Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE. // private static final int MSG_REPORT_IDLE_OFF = 4;4,879: 11-17 10:27:12.032376   900  1037 D DeviceIdleController: handleMessage(4) // private static final int MSG_REPORT_MAINTENANCE_ACTIVITY = 7;5,620: 11-17 10:27:12.509524   900  1037 D DeviceIdleController: handleMessage(7) 5,651: 11-17 10:27:12.516501   900  1037 D DeviceIdleController: handleMessage(7) // private static final int MSG_FINISH_IDLE_OP = 8;5,652: 11-17 10:27:13.517743   900  1037 D DeviceIdleController: handleMessage(8) 5,653: 11-17 10:27:13.517875   900  1037 D DeviceIdleController: Exit: start=+1h1m37s545ms now=+1h1m39s35ms /** Device is in the idle state, but temporarily out of idle to do regular maintenance. */// private static final int STATE_IDLE_MAINTENANCE = 6;5,654: 11-17 10:27:13.517936   900  1037 D DeviceIdleController: stepLightIdleStateLocked: mLightState=6 5,655: 11-17 10:27:13.518107   900  1037 D DeviceIdleController: scheduleLightAlarmLocked(30000) 5,656: 11-17 10:27:13.518371   900  1037 V AlarmManager: APP set with listener(DeviceIdleController.light) : type=2 triggerAtTime=3729035 win=-1 tElapsed=3729035 maxElapsed=3751535 interval=0 flags=0x8 // IDLE_MAINTENANCE 和 STATE_IDLE 是不断交替进行的,IDLE下应用特性会被限制5,661: 11-17 10:27:13.523054   900  1037 D DeviceIdleController: Moved to LIGHT_STATE_IDLE. 5,663: 11-17 10:27:13.523870   900  1037 D DeviceIdleController: handleMessage(3) 

时间设定

package com.android.server;/** * Keeps track of device idleness and drives low power mode based on that. */public class DeviceIdleController extends SystemService        implements AnyMotionDetector.DeviceIdleCallback {    private static final boolean DEBUG = true;    private static final boolean COMPRESS_TIME = true;    private void updateConstants() {            synchronized (DeviceIdleController.this) {                try {                    mParser.setString(Settings.Global.getString(mResolver,                            mHasWatch ? Settings.Global.DEVICE_IDLE_CONSTANTS_WATCH                                      : Settings.Global.DEVICE_IDLE_CONSTANTS));                } catch (IllegalArgumentException e) {                    // Failed to parse the settings string, log this and move on                    // with defaults.                    Slog.e(TAG, "Bad device idle settings", e);                }                // 5 分钟 或者 15 秒                LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(                        KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,                        !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);                // 10 分钟 或者 30 秒                LIGHT_PRE_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_PRE_IDLE_TIMEOUT,                        !COMPRESS_TIME ? 10 * 60 * 1000L : 30 * 1000L);                // 5 分钟 或者 15 秒                LIGHT_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_IDLE_TIMEOUT,                        !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);                LIGHT_IDLE_FACTOR = mParser.getFloat(KEY_LIGHT_IDLE_FACTOR,                        2f);                // 15 分钟 或者 60 秒                LIGHT_MAX_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_MAX_IDLE_TIMEOUT,                        !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L);                // 1 分钟 或者 15 秒                LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mParser.getLong(                        KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET,                        !COMPRESS_TIME ? 1 * 60 * 1000L : 15 * 1000L);                // 5 分钟 或者 30 秒                LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mParser.getLong(                        KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET,                        !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);                // 5 分钟 或者 1 秒                MIN_LIGHT_MAINTENANCE_TIME = mParser.getLong(                        KEY_MIN_LIGHT_MAINTENANCE_TIME,                        !COMPRESS_TIME ? 5 * 1000L : 1 * 1000L);                // 30 秒 或者 5 秒                MIN_DEEP_MAINTENANCE_TIME = mParser.getLong(                        KEY_MIN_DEEP_MAINTENANCE_TIME,                        !COMPRESS_TIME ? 30 * 1000L : 5 * 1000L);                long inactiveTimeoutDefault = (mHasWatch ? 15 : 30) * 60 * 1000L;                // 30 分钟 或者 3 分钟                INACTIVE_TIMEOUT = mParser.getLong(KEY_INACTIVE_TIMEOUT,                        !COMPRESS_TIME ? inactiveTimeoutDefault : (inactiveTimeoutDefault / 10));                // 4 分钟 或者 15 秒                SENSING_TIMEOUT = mParser.getLong(KEY_SENSING_TIMEOUT,                        !DEBUG ? 4 * 60 * 1000L : 60 * 1000L);                // 30 秒 或者 15 秒                LOCATING_TIMEOUT = mParser.getLong(KEY_LOCATING_TIMEOUT,                        !DEBUG ? 30 * 1000L : 15 * 1000L);                LOCATION_ACCURACY = mParser.getFloat(KEY_LOCATION_ACCURACY, 20);                // 10 分钟 或者 60 秒                MOTION_INACTIVE_TIMEOUT = mParser.getLong(KEY_MOTION_INACTIVE_TIMEOUT,                        !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);                long idleAfterInactiveTimeout = (mHasWatch ? 15 : 30) * 60 * 1000L;                // 30 分钟 或者 3 分钟                IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(KEY_IDLE_AFTER_INACTIVE_TIMEOUT,                        !COMPRESS_TIME ? idleAfterInactiveTimeout                                       : (idleAfterInactiveTimeout / 10));                // 5 分钟 或者 30 秒                IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_IDLE_PENDING_TIMEOUT,                        !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);                // 10 分钟 或者 60 秒                MAX_IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_PENDING_TIMEOUT,                        !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);                IDLE_PENDING_FACTOR = mParser.getFloat(KEY_IDLE_PENDING_FACTOR,                        2f);                // 60 分钟 或者 6 分钟                IDLE_TIMEOUT = mParser.getLong(KEY_IDLE_TIMEOUT,                        !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);                // 60 小时 或者 30 分钟                MAX_IDLE_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_TIMEOUT,                        !COMPRESS_TIME ? 6 * 60 * 60 * 1000L : 30 * 60 * 1000L);                IDLE_FACTOR = mParser.getFloat(KEY_IDLE_FACTOR,                        2f);                // 60 分钟 或者 6 分钟                MIN_TIME_TO_ALARM = mParser.getLong(KEY_MIN_TIME_TO_ALARM,                        !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);                MAX_TEMP_APP_WHITELIST_DURATION = mParser.getLong(                        KEY_MAX_TEMP_APP_WHITELIST_DURATION, 5 * 60 * 1000L);                MMS_TEMP_APP_WHITELIST_DURATION = mParser.getLong(                        KEY_MMS_TEMP_APP_WHITELIST_DURATION, 60 * 1000L);                SMS_TEMP_APP_WHITELIST_DURATION = mParser.getLong(                        KEY_SMS_TEMP_APP_WHITELIST_DURATION, 20 * 1000L);                NOTIFICATION_WHITELIST_DURATION = mParser.getLong(                        KEY_NOTIFICATION_WHITELIST_DURATION, 30 * 1000L);            }        }

状态变化

我截取的日志,只有以下状态
ACTIVE
INACTIVE
IDLE:doze 省电模式,应用的特性将受到抑制
IDLE_MAINTENANCE:应用窗口期,间隔退出doze模式让应用数据刷新

STATE_ACTIVE

以下任一条件
1.Motion传感器检测到运动或者未知状态
2.Voice-search事件触发
3.亮屏
4.充电
5.命令行 disable

Motion传感器检测到运动或者未知状态

    /** Device is currently active. */    private static final int STATE_ACTIVE = 0;    void handleMotionDetectedLocked(long timeout, String type) {        ....        mState = STATE_ACTIVE;        ...    }

亮屏或亮屏

    void becomeActiveLocked(String activeReason, int activeUid) {        ....        mState = STATE_ACTIVE;        ...    }    查看调用关系    void exitForceIdleLocked() {        if (mForceIdle) {            mForceIdle = false;            if (mScreenOn || mCharging) {                becomeActiveLocked("exit-force", Process.myUid());            }        }    }    void updateDisplayLocked() {        mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);        // We consider any situation where the display is showing something to be it on,        // because if there is anything shown we are going to be updating it at some        // frequency so can't be allowed to go into deep sleeps.        boolean screenOn = mCurDisplay.getState() == Display.STATE_ON;        if (DEBUG) Slog.d(TAG, "updateDisplayLocked: screenOn=" + screenOn);        if (!screenOn && mScreenOn) {            mScreenOn = false;            if (!mForceIdle) {                becomeInactiveIfAppropriateLocked();            }        } else if (screenOn) {            mScreenOn = true;            if (!mForceIdle) {                becomeActiveLocked("screen", Process.myUid());            }        }    }    void updateChargingLocked(boolean charging) {        if (DEBUG) Slog.i(TAG, "updateChargingLocked: charging=" + charging);        if (!charging && mCharging) {            mCharging = false;            if (!mForceIdle) {                becomeInactiveIfAppropriateLocked();            }        } else if (charging) {            mCharging = charging;            if (!mForceIdle) {                becomeActiveLocked("charging", Process.myUid());            }        }    }

命令行 disable

    void becomeActiveLocked(String activeReason, int activeUid) {        ....        mState = STATE_ACTIVE;        ...    }    查看调用关系                    if (becomeActive) {                        becomeActiveLocked((arg == null ? "all" : arg) + "-disabled",                                Process.myUid());                    }
    public void exitIdleInternal(String reason) {        synchronized (this) {            becomeActiveLocked(reason, Binder.getCallingUid());        }    }          @Override public void exitIdle(String reason) {            getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,                    null);            long ident = Binder.clearCallingIdentity();            try {                exitIdleInternal(reason);            } finally {                Binder.restoreCallingIdentity(ident);            }        }SourceInsight的搜索结果,为voice-searchDeviceIdleController.java (base\services\core\java\com\android\server):        @Override public void exitIdle(String reason) {IDeviceIdleController.aidl (base\core\java\android\os):    void exitIdle(String reason);PhoneWindowManager.java (base\services\core\java\com\android\server\policy):                            dic.exitIdle("voice-search");PhoneWindowManager.java (base\services\core\java\com\android\server\policy): 

STATE_ACTIVE to STATE_INACTIVE

同时满足条件:
暗屏,不充电即可

    /** Device is inactive (screen off, no motion) and we are waiting to for idle. */    private static final int STATE_INACTIVE = 1;        void becomeInactiveIfAppropriateLocked() {        if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");        if ((!mScreenOn && !mCharging) || mForceIdle) {            // Screen has turned off; we are now going to become inactive and start            // waiting to see if we will ultimately go idle.            if (mState == STATE_ACTIVE && mDeepEnabled) {                mState = STATE_INACTIVE;                if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");                resetIdleManagementLocked();                scheduleAlarmLocked(mInactiveTimeout, false);                EventLogTags.writeDeviceIdle(mState, "no activity");            }            if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {                mLightState = LIGHT_STATE_INACTIVE;                if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");                resetLightIdleManagementLocked();                scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);                EventLogTags.writeDeviceIdleLight(mLightState, "no activity");            }        }    }    // 查看时间    mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;    // mHasWatch == false,即 30 分钟 或者 3分钟                    long inactiveTimeoutDefault = (mHasWatch ? 15 : 30) * 60 * 1000L;                INACTIVE_TIMEOUT = mParser.getLong(KEY_INACTIVE_TIMEOUT,                        !COMPRESS_TIME ? inactiveTimeoutDefault : (inactiveTimeoutDefault / 10));

Moved to LIGHT_STATE_IDLE

该模式下应用特性会被限制

日志

3,994: 11-17 10:26:25.017778 900 1037 D DeviceIdleController: Moved to LIGHT_STATE_IDLE.

===============================================================/** Device is in the light idle state, trying to stay asleep as much as possible. */// private static final int LIGHT_STATE_IDLE = 4;===============================================================case LIGHT_STATE_IDLE: return "IDLE";            case LIGHT_STATE_PRE_IDLE:            case LIGHT_STATE_IDLE_MAINTENANCE:                if (mMaintenanceStartTime != 0) {                    long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;                    if (duration < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {                        // We didn't use up all of our minimum budget; add this to the reserve.                        mCurIdleBudget += (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET-duration);                    } else {                        // We used more than our minimum budget; this comes out of the reserve.                        mCurIdleBudget -= (duration-mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);                    }                }                mMaintenanceStartTime = 0;                scheduleLightAlarmLocked(mNextLightIdleDelay);                mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,                        (long)(mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));                if (mNextLightIdleDelay < mConstants.LIGHT_IDLE_TIMEOUT) {                    mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;                }                if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");                mLightState = LIGHT_STATE_IDLE;                EventLogTags.writeDeviceIdleLight(mLightState, reason);                addEvent(EVENT_LIGHT_IDLE);                mGoingIdleWakeLock.acquire();                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);                break;===============================================================    /** Device is about to go idle for the first time, wait for current work to complete. */    private static final int LIGHT_STATE_PRE_IDLE = 3;    /** Device is in the light idle state, but temporarily out of idle to do regular maintenance. */    private static final int LIGHT_STATE_IDLE_MAINTENANCE = 6;===============================================================                        LIGHT_PRE_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_PRE_IDLE_TIMEOUT,                        !COMPRESS_TIME ? 10 * 60 * 1000L : 30 * 1000L);

Moved to LIGHT_WAITING_FOR_NETWORK 本质还是IDLE

4,793: 11-17 10:26:41.018638 900 1037 D DeviceIdleController: Moved to LIGHT_WAITING_FOR_NETWORK.

===============================================================            case LIGHT_STATE_IDLE:            case LIGHT_STATE_WAITING_FOR_NETWORK:            if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {                    // We have been idling long enough, now it is time to do some work.                    ..........            } else {                    // We'd like to do maintenance, but currently don't have network                    // connectivity...  let's try to wait until the network comes back.                    // We'll only wait for another full idle period, however, and then give up.                    scheduleLightAlarmLocked(mNextLightIdleDelay);                    if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK.");                    mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;                    EventLogTags.writeDeviceIdleLight(mLightState, reason);                }                break;===============================================================    /** Device is in the light idle state, trying to stay asleep as much as possible. */    private static final int LIGHT_STATE_IDLE = 4;    /** Device is in the light idle state, we want to go in to idle maintenance but are     * waiting for network connectivity before doing so. */    private static final int LIGHT_STATE_WAITING_FOR_NETWORK = 5;

LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE

            case LIGHT_STATE_IDLE:            case LIGHT_STATE_WAITING_FOR_NETWORK:                if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {                    // We have been idling long enough, now it is time to do some work.                    mActiveIdleOpCount = 1;                    mActiveIdleWakeLock.acquire();                    mMaintenanceStartTime = SystemClock.elapsedRealtime();                    if (mCurIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {                        mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;                    } else if (mCurIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {                        mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;                    }                    scheduleLightAlarmLocked(mCurIdleBudget);                    if (DEBUG) Slog.d(TAG,                            "Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");                    mLightState = LIGHT_STATE_IDLE_MAINTENANCE;                    EventLogTags.writeDeviceIdleLight(mLightState, reason);                    addEvent(EVENT_LIGHT_MAINTENANCE);                    mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);

Doze模式的完整状态转换

这里写图片描述

具体解释看源码

   void stepIdleStateLocked(String reason) {        if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);        EventLogTags.writeDeviceIdleStep();        final long now = SystemClock.elapsedRealtime();        if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {            // Whoops, there is an upcoming alarm.  We don't actually want to go idle.            if (mState != STATE_ACTIVE) {                becomeActiveLocked("alarm", Process.myUid());                becomeInactiveIfAppropriateLocked();            }            return;        }        switch (mState) {            case STATE_INACTIVE:                // We have now been inactive long enough, it is time to start looking                // for motion and sleep some more while doing so.                startMonitoringMotionLocked();// 运动检测            // 5 分钟                scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);                // Reset the upcoming idle delays.                // 30 分钟                mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;                mNextIdleDelay = mConstants.IDLE_TIMEOUT;                // 切换当前状态为STATE_IDLE_PENDING                mState = STATE_IDLE_PENDING;                if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");                EventLogTags.writeDeviceIdle(mState, reason);                break;            case STATE_IDLE_PENDING:            // 切换当前状态为STATE_SENSING            // IDLE_PENDING_TIMEOUT 30 分钟后才可以到这个条件哦                mState = STATE_SENSING;                if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING.");                EventLogTags.writeDeviceIdle(mState, reason);                // 4 分钟                scheduleSensingTimeoutAlarmLocked(mConstants.SENSING_TIMEOUT);                cancelLocatingLocked();                mNotMoving = false;                mLocated = false;                mLastGenericLocation = null;                mLastGpsLocation = null;                mAnyMotionDetector.checkForAnyMotion();                break;            case STATE_SENSING:                cancelSensingTimeoutAlarmLocked();                // 切换当前状态为STATE_LOCATING            // 不移动且达到 IDLE_AFTER_INACTIVE_TIMEOUT 5 分钟才可以到这个条件哦                mState = STATE_LOCATING;                if (DEBUG) Slog.d(TAG, "Moved from STATE_SENSING to STATE_LOCATING.");                EventLogTags.writeDeviceIdle(mState, reason);                // 30 秒                scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT, false);                if (mLocationManager != null                        && mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {                    mLocationManager.requestLocationUpdates(mLocationRequest,                            mGenericLocationListener, mHandler.getLooper());                    mLocating = true;                } else {                    mHasNetworkLocation = false;                }                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;                }                // If we have a location provider, we're all set, the listeners will move state                // forward.                if (mLocating) {                    break;                }                // Otherwise, we have to move from locating into idle maintenance.            case STATE_LOCATING:            // 切换当前状态为STATE_LOCATING                // 角度无改变持续且4分钟才可以到这个状态                cancelAlarmLocked();                cancelLocatingLocked();                mAnyMotionDetector.stop();            case STATE_IDLE_MAINTENANCE:             // 切换当前状态为STATE_IDLE_MAINTENANCE                // GPS无变化且30秒才可以到这个状态                scheduleAlarmLocked(mNextIdleDelay, true);                if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +                        " ms.");                mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);                if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);                mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);                if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {                    mNextIdleDelay = mConstants.IDLE_TIMEOUT;                }                mState = STATE_IDLE;                if (mLightState != LIGHT_STATE_OVERRIDE) {                    mLightState = LIGHT_STATE_OVERRIDE;                    cancelLightAlarmLocked();                }                EventLogTags.writeDeviceIdle(mState, reason);                addEvent(EVENT_DEEP_IDLE);                mGoingIdleWakeLock.acquire();                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);                break;            case STATE_IDLE:            // 系统会在这个两个状态下(STATE_IDLE与STATE_IDLE_MAINTENANCE)进行交替切换                // We have been idling long enough, now it is time to do some work.                mActiveIdleOpCount = 1;                mActiveIdleWakeLock.acquire();                scheduleAlarmLocked(mNextIdlePendingDelay, false);                if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +                        "Next alarm in " + mNextIdlePendingDelay + " ms.");                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;                EventLogTags.writeDeviceIdle(mState, reason);                addEvent(EVENT_DEEP_MAINTENANCE);                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);                break;        }    }

结语

Doze模式的省电效果毋庸置疑,我们关注这个模式切换的好处,就是能否借鉴这个思路,进行精确的空闲模式识别。新增一些静默重启的操作,来解决android 系统过于内存碎片化,或者准确识别夜间模式,而不是通过时间进行考量。

原创粉丝点击