Android Fk:[Doze] Android Doze Base on N

Keywords: network Android shell xml

Android Fk:[Doze] Android Doze (base on N)

I. overview

Base on Android N
When the system is out of screen and in a static state for a long time, the system will enter the Doze state.
(1) Restricting network access
(2) Restrict wakelock (cpu lock) applications
(3) The alarm set by alarm manger is delayed unless flag is set to allow it to work in idle state.
(4) wifi scan cancelled
(5) jobscheduler and sync are restricted

DeviceIdle Controller

2.1 DeviceIdleController

DIC architecture:

DIC initialization:

The most important thing to see in initialization is
1. Registered Broadcasting and Listener Monitor System Status (Charging and Screen Status)
2. Read the whitelist from deviceidle.xml, and then set the whitelist to the corresponding service.

2.2 Enter doze Mode

2.2.1 light Idle


Look at the code light idle, which only restricts network links when it comes in:

//frameworks/base/services/core/java/com/android/server/DeviceIdleController.java
 void stepLightIdleStateLocked(String reason) {
    switch (mLightState) {
            // Nothing active, fall through to immediately 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;
            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);
                } 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;
    }
 }

2.2.2 deep idle

Under idle, idle mode is set by service instance to enter idle:

 void stepIdleStateLocked(String reason) {
    switch (mState) {
case STATE_IDLE_MAINTENANCE:
                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:
                // 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;
    }
 }

2.2.3 DIC-State Change Factor

(1) screen status
(2) charging state
(3) The state monitored by AnyMonitionDetetor, whose range of action is from entering STATE_SENSING to leaving STATE_LOCATING.
(4) Significant Motion Sensor monitors the status, and its range of action is from entering STATE_IDLE_PENDING to re-entering ACTIVE or INACTIVE.
(5) External module calls exitIdle directly
(6) force-idle using dumpsys
(7) The main switch controlling IDLE function: config.xml: config_enableAutoPowerModes, default to false
(8) When the voice-search event is detected, idle mode will be withdrawn. In fact, the exitIdle method of DIC will be invoked.

III. The Impact of Doze Model

3.1 DIC-Wakelock limitation

3.1 DIC-Network Limitation

3.1 DIC-alarm limitation

3.1 DIC-job service limitation

IV. NOTES

1. Whitelist settings:

2. Application development verification:

Testing APP at Doze

1 .System version greater than or equal to 6.0
2 . Connect USB,Operation is measured app,keep app In active state
3 . Close the device screen
4 . Through the following adb Command Enforcement System Entry Doze Pattern
$ adb shell dumpsys battery unplug
$ adb shell dumpsys deviceidle step
5. observation app Are there areas where performance needs to be optimized and improved?

Testing App Standby mode

1. Run the following adb Commands force applications to enter App Standby Pattern:
$ adb shell dumpsys battery unplug
$ adb shell am set-inactive <packageName> true
2. Simulate the wake-up of your application using the following commands:
$ adb shell am set-inactive <packageName> false
$ adb shell am get-inactive <packageName>
3. Observe your App,Ensure that the application returns to normal from standby mode. App Notification and back movements can achieve the desired results.

Application development needs to verify whether doze mode or exit doze mode behaves normally:

3. The difference between Doze and App Standby

Doze mode requires screen closure (usually at night or for a long time before the screen closes), while App Standby does not need screen closure, and App's access to the background for a period of time will be limited by connecting to the network and so on.
Trigger any of the following conditions to exit the App Standby state:
1. Users actively start the App;
2. The App currently has a front-end process (either containing an active front-end service or being used by another activity or front-end service);
3. App generates a Notification that users can see on the lock screen or notification tray. When the user device is plugged into the power supply, the system releases App's standby state, allowing them to freely connect to the network and perform unfinished work and synchronization. If the device is idle for a long time, the system will allow the idle App to access the network once a day.

5. Reference Blog

Detailed description of the new Android M feature Doze and App Standby mode

App Standby Learning Summary

Analysis of Dreamwing-Blog Android N Idle Model

(Original) Android 6.0 System Doze Mode (DeviceIdle) Implementation and Control Logic

Posted by Tedglen2 on Mon, 07 Jan 2019 09:12:10 -0800