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()); }
Voice-search
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 系统过于内存碎片化,或者准确识别夜间模式,而不是通过时间进行考量。
阅读全文
0 0
- Android O Doze模式的状态
- Android O 的Doze模式白名单路径
- Android Doze模式下的AlarmManager策略
- Android Doze模式分析
- Android Doze模式
- Android 6.0 Doze模式
- Android Doze模式调试
- Android doze模式分析
- Android 6.0 Doze状态切换
- Android 7.0 Doze模式分析
- Android系统休眠机制和doze模式的关系
- Android 6.0新特性之Doze模式
- Android 6.0新特性之Doze模式
- Android 6.0新特性之Doze模式
- Android 6.0 Doze模式请求禁止联网
- Android M 优化电池性能的 Doze 模式工作原理是怎样的?
- Android M新特性Doze and App Standby模式详解
- Android M新特性Doze and App Standby模式详解
- android开发游记:RecycleView 实现复杂首页布局三种方式
- 正、反向代理的总结
- 安装Element-UI
- 安装PyInstaller失败
- 字母转换 进栈出栈
- Android O Doze模式的状态
- springmvc跳转不能获取静态资源
- IDEA Spring-Boot没有JSP
- TypeError: 'bool' object is not callable
- 使用mybatis-generator自动生成实体类,接口实现类和Mapper映射配置文件
- Java导出excel文件简单实现
- C语言实验——圆周率
- Linux——高性能服务器编程——select&poll&epoll
- 线程的一些入门知识