Android Doze mode source code analysis, androiddoze
We are inspired by the ubiquitous nature of the technology. In order to prolong the battery life, google learned from the sleep of snakes, that is, in some cases, the mobile phone enters the sleep-like hibernation, thus introducing the topic of today, in Doze mode, Doze is a Chinese NAP, which of course saves energy than the activity.
What will happen when the mobile phone gets a nap?
According to google's official statement, ipvlocks, network access, jobshedule, alarm clock, and GPS/WiFi scanning will all stop. After these stops, the power consumption will be reduced by 30%.
When will the mobile phone start to nap?
It is Google's Doze time series. It can be seen that three conditions must be met when a mobile phone gets a nap.
1. The screen is off
2. No power insertion
3. Static
Is this a concept that is very bionic? Turn off the screen-> close your eyes, do not plug in power-> do not eat, do not move-> quietly become a sleeping beauty. Does a creature not need to satisfy these conditions to take a nap? Wonderful!
Just breathe a nap? The maintenance window in is for you to breathe !! When breathing locks, network access, jobshedule, alarm clock, GPS/WiFi scan will be restored. Please take a breath of fresh air! As time passes, the interval of breathing increases, and the interval of breathing increases. Of course, it will not be infinitely long, man !! At last, it will be attributed to a fixed value. The source code will be analyzed below, biu!
No source code.
The following is a mobile phone quietly placed on the desktop. Over time, the process of entering the doze mode will analyze the source code.
Source code path:/frameworks/base/services/core/java/com/android/server/DeviceIdleController. java
The system uses a global integer variable to indicate the current doze status.
1 private int mState;
The status value may take the following values. The initial status is STATE_ACTIVE. The status goes through 1, 2, 3, and 4, and then enters 5, namely, STATE_IDLE.
1 private static final int STATE_ACTIVE = 0;2 private static final int STATE_INACTIVE = 1;3 private static final int STATE_IDLE_PENDING = 2;4 private static final int STATE_SENSING = 3;5 private static final int STATE_LOCATING = 4;6 private static final int STATE_IDLE = 5;7 private static final int STATE_IDLE_MAINTENANCE = 6;
First, the screen is extinguished, and the callback function is used to process the screen.
1 private final DisplayManager. displayListener mDisplayListener 2 = new DisplayManager. displayListener () {3 @ Override public void onDisplayAdded (int displayId) {4} 5 6 @ Override public void onDisplayRemoved (int displayId) {7} 8 9 @ Override public void onDisplayChanged (int displayId) {10 if (displayId = Display. DEFAULT_DISPLAY) {11 synchronized (DeviceIdleController. this) {12 updateDisplayLocked (); // The Screen status changes 13} 14} 15} 16 };
Go to updateDisplayLocked
1 void updateDisplayLocked () {2... 3 becomeInactiveIfAppropriateLocked (); // check whether it can enter Inactive status 4... 5} 6}
Then we pull out the usb. If it is not charged, the charging function will be called back.
1 private final BroadcastReceiver mReceiver = new BroadcastReceiver () {2 @ Override public void onReceive (Context context, Intent intent) {3 if (Intent. ACTION_BATTERY_CHANGED.equals (intent. getAction () {4 int plugged = intent. getIntExtra ("plugged", 0); 5 updateChargingLocked (plugged! = 0); // The charging status changes 6} else if (ACTION_STEP_IDLE_STATE.equals (intent. getAction () {7 synchronized (DeviceIdleController. this) {8 stepIdleStateLocked (); 9} 10} 11} 12 };
Go to updateChargingLocked
1 void updateChargingLocked (boolean charging) {2... 3 becomeInactiveIfAppropriateLocked (); // check whether it can enter Inactive status 4 ...... 5}
After the device is not powered on or off, it enters becomeInactiveIfAppropriateLocked. The status of mState changes to STATE_INACTIVE, and a timer is enabled.
1 void becomeInactiveIfAppropriateLocked () {2 if (DEBUG) Slog. d (TAG, "becomeInactiveIfAppropriateLocked ()"); 3 // The conditions for no power insertion and screen shutdown are met by 4 if (((! MScreenOn &&! MCharging) | mForceIdle) & mEnabled & mState = STATE_ACTIVE) {5 ..... 6 mState = STATE_INACTIVE; 7 scheduleAlarmLocked (mInactiveTimeout, false); 8 ...... 9} 10} 11 12 the scheduled duration is constant 30 minutes 13 INACTIVE_TIMEOUT = mParser. getLong (KEY_INACTIVE_TIMEOUT, 14! COMPRESS_TIME? 30*60 * 1000L: 3*60 * 1000L );
30 minutes after the phone is quietly lying on the desktop, the pendingintent will be sent and the broadcast receiver will process the timer time.
1 Intent intent = new Intent (ACTION_STEP_IDLE_STATE) 2. setPackage ("android") 3. setFlags (Intent. FLAG_RECEIVER_REGISTERED_ONLY); 4 mAlarmIntent = PendingIntent. getBroadcast (getContext (), 0, intent, 0); 5 6 private final BroadcastReceiver mReceiver = new BroadcastReceiver () {7 @ Override public void onReceive (Context context, Intent intent) {8 if (Intent. ACTION_BATTERY_CHANGED.equals (intent. getActi On () {9 int plugged = intent. getIntExtra ("plugged", 0); 10 updateChargingLocked (plugged! = 0); 11} else if (ACTION_STEP_IDLE_STATE.equals (intent. getAction () {12 synchronized (DeviceIdleController. this) {13 stepIdleStateLocked (); // receives broadcast 14} 15} 16} 17 };
Go to stepIdleStateLocked. This function is the main function for State Conversion Processing.
1 void stepIdleStateLocked () {2 if (DEBUG) Slog. d (TAG, "stepIdleStateLocked: mState =" + mState); 3 EventLogTags. writeDeviceIdleStep (); 4 5 final long now = SystemClock. elapsedRealtime (); 6 if (now + mConstants. MIN_TIME_TO_ALARM)> mAlarmManager. getNextWakeFromIdleTime () {7 // Whoops, there is an upcoming alarm. we don't actually want to go idle. 8 if (mState! = STATE_ACTIVE) {9 becomeActiveLocked ("alarm", Process. myUid (); 10} 11 return; 12} 13 14 switch (mState) {15 case STATE_INACTIVE: 16 // We have now been inactive long enough, it is time to start looking17 // for significant motion and sleep some more while doing so.18 startMonitoringSignificantMotion (); // check whether there is a small action 19 scheduleAlarmLocked (mConstants. fail, false); // sets the length of time for observing small actions. 20 mState = STATE_IDLE_PENDING; // The status is updated to STATE_IDLE_PENDING21 break; 22 case STATE_IDLE_PENDING: // The small action is over, there are no minor actions all the time. Here 23 mState = STATE_SENSING; // The status is updated to STATE_SENSING24 scheduleSensingAlarmLocked (mConstants. SENSING_TIMEOUT); // set the sensor sensing duration to 25 mAnyMotionDetector. checkForAnyMotion (); // sensor: 26 break; 27 case STATE_SENSING, check if GPS has changed to 28 mState = STATE_LOCATING; // The status is changed to STATE_LOCATING29 scheduleSensingAlarmLocked (mConstants. LOCATING_TIMEOUT); // sets the GPS observation duration of 30 mLocationManager. requestLocationUpdates (mLocationRequest, mGenericLocationListener, 31 mHandler. getLooper (); // GPS starts to sense 32 break; 33 case STATE_LOCATING: // GPS also finds 34 cancelSensingAlarmLocked (); 35 cancelLocatingLocked (); 36 mAnyMotionDetector. stop (); // if there is no break, go directly to the next case37 case STATE_IDLE_MAINTENANCE: 38 scheduleAlarmLocked (mNextIdleDelay, true); // set how long it will take to breathe 39 mNextIdleDelay =) (mNextIdleDelay * mConstants. IDLE_FACTOR); // update how long it will take to breathe after the next NAP 40 if (DEBUG) Slog. d (TAG, "Setting mNextIdleDelay =" + mNextIdleDelay); 41 mNextIdleDelay = Math. min (mNextIdleDelay, mConstants. MAX_IDLE_TIMEOUT); 42 mState = STATE_IDLE; // zookeeper finally enters STATE_IDLE43 mHandler. sendEmptyMessage (MSG_REPORT_IDLE_ON); 44 break; 45 case STATE_IDLE: // when the NAP is complete, take a breath. Here 46 scheduleAlarmLocked (unlock, false); 47 mState = STATE_IDLE_MAINTENANCE; // Status updated to STATE_IDLE_MAINTENANCE48 mNextIdlePendingDelay = Math. min (mConstants. MAX_IDLE_PENDING_TIMEOUT, 49 (long) (mNextIdlePendingDelay * mConstants. IDLE_PENDING_FACTOR); 50 // update the next breathing time 51 mHandler. sendEmptyMessage (MSG_REPORT_IDLE_OFF); 52 break; 53} 54}
Math. min (mConstants. MAX_IDLE_PENDING_TIMEOUT,
(Long) (mNextIdlePendingDelay * mConstants. IDLE_PENDING_FACTOR ));
Have you seen this sentence? The minimum value ensures that the idle and window time are not infinitely large.
To give you a sensory experience, let me list the time above.
Without power-off, the device enters the INACTIVE time. The last 30 minutes are used to observe small movements. The time is 30 minutes. IDLE_AFTER_INACTIVE_TIMEOUT = mParser. getLong (KEY_IDLE_AFTER_INACTIVE_TIMEOUT ,! COMPRESS_TIME? 30*60 * 1000L: 3*60 * 1000L); observe the sensor time for 4 minutes SENSING_TIMEOUT = mParser. getLong (KEY_SENSING_TIMEOUT ,! DEBUG? 4*60 * 1000L: 60 * 1000L); observe the GPS time for 30 seconds LOCATING_TIMEOUT = mParser. getLong (KEY_LOCATING_TIMEOUT ,! DEBUG? 30 * 1000L: 15 * 1000L );
So the total time for entering the idle is 30 minutes + 30 minutes + 4 minutes + 30 s = 1 hour 4 minutes 30 seconds, hahaha !!
The following shows the status transition diagram. Before the status of the idle is reached, the status changes to ACTIVE. After the status changes to IDLE, the IDLE status can only be switched on or switched on. It is like a person who is easy to be woken up before going to bed. After going to bed, it is estimated that only the alarm clock will wake you up !!
What is the relationship between my application development and so on?
In fact, it doesn't matter much. It doesn't matter if you look at the source code.
However, as a new mechanism, it is best to test whether your application can run normally in these statuses.
Google provides adb commands to forcibly change the status, so you don't have to wait for it to change its status.
1 adb shell dumpsys battery unplug // equivalent to no power-in 2 adb shell dumpsys device idle step // convert the status