Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 627dfa1d authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Be smarter about determining when we can stop idle maintenance.

The device idle service now knows when the system is actively
doing significant things (syncs, jobs, alarms, downloads).  It
uses this, when in an idle maintenance window, to determine when
it can end that window early -- when such work is no longer
happening.

For now this just allows us to shorten the windows.  In the future
we should use this to allow us to expand the windows to a longer
potential time, adjusting future windows to shorter durations if
earlier ones use more time.  This will allow us to batch occasional
long operations (such as downloads) into one window, making up
for that with much shorter later windows.

Change-Id: Ie482abd50bc43be9a8917a769a5175851eee4ec4
parent f20bfb67
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -35,4 +35,6 @@ interface IDeviceIdleController {
    long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
    long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
    void exitIdle(String reason);
    void downloadServiceActive(IBinder token);
    void downloadServiceInactive();
}
+14 −4
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ class AlarmManagerService extends SystemService {
    final LocalLog mLog = new LocalLog(TAG);

    AppOpsManager mAppOps;
    DeviceIdleController.LocalService mLocalDeviceIdleController;

    final Object mLock = new Object();

@@ -897,6 +898,8 @@ class AlarmManagerService extends SystemService {
        if (phase == PHASE_SYSTEM_SERVICES_READY) {
            mConstants.start(getContext().getContentResolver());
            mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
            mLocalDeviceIdleController
                    = LocalServices.getService(DeviceIdleController.LocalService.class);
        }
    }

@@ -2468,10 +2471,9 @@ class AlarmManagerService extends SystemService {

    private class AlarmHandler extends Handler {
        public static final int ALARM_EVENT = 1;
        public static final int MINUTE_CHANGE_EVENT = 2;
        public static final int DATE_CHANGE_EVENT = 3;
        public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 4;
        public static final int LISTENER_TIMEOUT = 5;
        public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 2;
        public static final int LISTENER_TIMEOUT = 3;
        public static final int REPORT_ALARMS_ACTIVE = 4;
        
        public AlarmHandler() {
        }
@@ -2511,6 +2513,12 @@ class AlarmManagerService extends SystemService {
                    mDeliveryTracker.alarmTimedOut((IBinder) msg.obj);
                    break;

                case REPORT_ALARMS_ACTIVE:
                    if (mLocalDeviceIdleController != null) {
                        mLocalDeviceIdleController.setAlarmsActive(msg.arg1 != 0);
                    }
                    break;

                default:
                    // nope, just ignore it
                    break;
@@ -2740,6 +2748,7 @@ class AlarmManagerService extends SystemService {
            }
            mBroadcastRefCount--;
            if (mBroadcastRefCount == 0) {
                mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 0).sendToTarget();
                mWakeLock.release();
                if (mInFlight.size() > 0) {
                    mLog.w("Finished all dispatches with " + mInFlight.size()
@@ -2873,6 +2882,7 @@ class AlarmManagerService extends SystemService {
                        alarm.type, alarm.statsTag, (alarm.operation == null) ? alarm.uid : -1,
                        true);
                mWakeLock.acquire();
                mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 1).sendToTarget();
            }
            final InFlight inflight = new InFlight(AlarmManagerService.this,
                    alarm.operation, alarm.listener, alarm.workSource, alarm.uid,
+160 −21
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.IDeviceIdleController;
import android.os.Looper;
import android.os.Message;
@@ -196,6 +197,12 @@ public class DeviceIdleController extends SystemService
    private long mNextIdleDelay;
    private long mNextLightAlarmTime;

    private int mActiveIdleOpCount;
    private IBinder mDownloadServiceActive;
    private boolean mSyncActive;
    private boolean mJobsActive;
    private boolean mAlarmsActive;

    public final AtomicFile mConfigFile;

    /**
@@ -282,13 +289,19 @@ public class DeviceIdleController extends SystemService
                }
            } else if (ACTION_STEP_LIGHT_IDLE_STATE.equals(intent.getAction())) {
                synchronized (DeviceIdleController.this) {
                    stepLightIdleStateLocked();
                    stepLightIdleStateLocked("s:alarm");
                }
            } else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
                synchronized (DeviceIdleController.this) {
                    stepIdleStateLocked();
                    stepIdleStateLocked("s:alarm");
                }
            }
        }
    };

    private final BroadcastReceiver mIdleStartedDoneReceiver = new BroadcastReceiver() {
        @Override public void onReceive(Context context, Intent intent) {
            decActiveIdleOps();
        }
    };

@@ -733,7 +746,7 @@ public class DeviceIdleController extends SystemService
                // If we are currently sensing, it is time to move to locating.
                synchronized (this) {
                    mNotMoving = true;
                    stepIdleStateLocked();
                    stepIdleStateLocked("s:stationary");
                }
            } else if (mState == STATE_LOCATING) {
                // If we are currently locating, note that we are not moving and step
@@ -741,7 +754,7 @@ public class DeviceIdleController extends SystemService
                synchronized (this) {
                    mNotMoving = true;
                    if (mLocated) {
                        stepIdleStateLocked();
                        stepIdleStateLocked("s:stationary");
                    }
                }
            }
@@ -804,11 +817,18 @@ public class DeviceIdleController extends SystemService
                    } catch (RemoteException e) {
                    }
                    if (fullChanged) {
                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
                        incActiveIdleOps();
                        getContext().sendOrderedBroadcastAsUser(mIdleIntent, UserHandle.ALL,
                                null, mIdleStartedDoneReceiver, null, 0, null, null);
                    }
                    if (lightChanged) {
                        getContext().sendBroadcastAsUser(mLightIdleIntent, UserHandle.ALL);
                        incActiveIdleOps();
                        getContext().sendOrderedBroadcastAsUser(mLightIdleIntent, UserHandle.ALL,
                                null, mIdleStartedDoneReceiver, null, 0, null, null);
                    }
                    // Always start with one active op for the message being sent here.
                    // Now we we done!
                    decActiveIdleOps();
                    EventLogTags.writeDeviceIdleOffComplete();
                } break;
                case MSG_REPORT_ACTIVE: {
@@ -913,11 +933,23 @@ public class DeviceIdleController extends SystemService
        }

        @Override public void exitIdle(String reason) {
            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
            getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,
                    null);
            exitIdleInternal(reason);
        }

        @Override public void downloadServiceActive(IBinder token) {
            getContext().enforceCallingOrSelfPermission(
                    "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS", null);
            DeviceIdleController.this.downloadServiceActive(token);
        }

        @Override public void downloadServiceInactive() {
            getContext().enforceCallingOrSelfPermission(
                    "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS", null);
            DeviceIdleController.this.downloadServiceInactive();
        }

        @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            DeviceIdleController.this.dump(fd, pw, args);
        }
@@ -937,6 +969,19 @@ public class DeviceIdleController extends SystemService
        public void setNetworkPolicyTempWhitelistCallback(Runnable callback) {
            setNetworkPolicyTempWhitelistCallbackInternal(callback);
        }

        public void setSyncActive(boolean active) {
            DeviceIdleController.this.setSyncActive(active);
        }

        public void setJobsActive(boolean active) {
            DeviceIdleController.this.setJobsActive(active);
        }

        // Up-call from alarm manager.
        public void setAlarmsActive(boolean active) {
            DeviceIdleController.this.setAlarmsActive(active);
        }
    }

    public DeviceIdleController(Context context) {
@@ -1439,7 +1484,7 @@ public class DeviceIdleController extends SystemService
        }
    }

    void stepLightIdleStateLocked() {
    void stepLightIdleStateLocked(String reason) {
        if (mLightState == LIGHT_STATE_OVERRIDE) {
            // If we are already in full device idle mode, then
            // there is nothing left to do for light mode.
@@ -1455,22 +1500,23 @@ public class DeviceIdleController extends SystemService
                scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_TIMEOUT);
                if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
                mLightState = LIGHT_STATE_IDLE;
                EventLogTags.writeDeviceIdleLight(mLightState, "step");
                EventLogTags.writeDeviceIdleLight(mLightState, reason);
                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
                break;
            case LIGHT_STATE_IDLE:
                // We have been idling long enough, now it is time to do some work.
                mActiveIdleOpCount = 1;
                scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_PENDING_TIMEOUT);
                if (DEBUG) Slog.d(TAG,
                        "Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
                mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
                EventLogTags.writeDeviceIdleLight(mLightState, "step");
                EventLogTags.writeDeviceIdleLight(mLightState, reason);
                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
                break;
        }
    }

    void stepIdleStateLocked() {
    void stepIdleStateLocked(String reason) {
        if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
        EventLogTags.writeDeviceIdleStep();

@@ -1494,12 +1540,12 @@ public class DeviceIdleController extends SystemService
                mNextIdleDelay = mConstants.IDLE_TIMEOUT;
                mState = STATE_IDLE_PENDING;
                if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");
                EventLogTags.writeDeviceIdle(mState, "step");
                EventLogTags.writeDeviceIdle(mState, reason);
                break;
            case STATE_IDLE_PENDING:
                mState = STATE_SENSING;
                if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING.");
                EventLogTags.writeDeviceIdle(mState, "step");
                EventLogTags.writeDeviceIdle(mState, reason);
                scheduleAlarmLocked(mConstants.SENSING_TIMEOUT, false);
                cancelLocatingLocked();
                mAnyMotionDetector.checkForAnyMotion();
@@ -1511,7 +1557,7 @@ public class DeviceIdleController extends SystemService
            case STATE_SENSING:
                mState = STATE_LOCATING;
                if (DEBUG) Slog.d(TAG, "Moved from STATE_SENSING to STATE_LOCATING.");
                EventLogTags.writeDeviceIdle(mState, "step");
                EventLogTags.writeDeviceIdle(mState, reason);
                scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT, false);
                if (mLocationManager != null
                        && mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
@@ -1553,23 +1599,101 @@ public class DeviceIdleController extends SystemService
                    mLightState = LIGHT_STATE_OVERRIDE;
                    cancelLightAlarmLocked();
                }
                EventLogTags.writeDeviceIdle(mState, "step");
                EventLogTags.writeDeviceIdle(mState, reason);
                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;
                scheduleAlarmLocked(mNextIdlePendingDelay, false);
                if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
                        "Next alarm in " + mNextIdlePendingDelay + " ms.");
                mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,
                        (long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
                mState = STATE_IDLE_MAINTENANCE;
                EventLogTags.writeDeviceIdle(mState, "step");
                EventLogTags.writeDeviceIdle(mState, reason);
                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
                break;
        }
    }

    void incActiveIdleOps() {
        synchronized (this) {
            mActiveIdleOpCount++;
        }
    }

    void decActiveIdleOps() {
        synchronized (this) {
            mActiveIdleOpCount--;
            if (mActiveIdleOpCount <= 0) {
                exitMaintenanceEarlyIfNeededLocked();
            }
        }
    }

    void downloadServiceActive(IBinder token) {
        synchronized (this) {
            mDownloadServiceActive = token;
            try {
                token.linkToDeath(new IBinder.DeathRecipient() {
                    @Override public void binderDied() {
                        downloadServiceInactive();
                    }
                }, 0);
            } catch (RemoteException e) {
                mDownloadServiceActive = null;
            }
        }
    }

    void downloadServiceInactive() {
        synchronized (this) {
            mDownloadServiceActive = null;
            exitMaintenanceEarlyIfNeededLocked();
        }
    }

    void setSyncActive(boolean active) {
        synchronized (this) {
            mSyncActive = active;
            if (!active) {
                exitMaintenanceEarlyIfNeededLocked();
            }
        }
    }

    void setJobsActive(boolean active) {
        synchronized (this) {
            mJobsActive = active;
            if (!active) {
                exitMaintenanceEarlyIfNeededLocked();
            }
        }
    }

    void setAlarmsActive(boolean active) {
        synchronized (this) {
            mAlarmsActive = active;
            if (!active) {
                exitMaintenanceEarlyIfNeededLocked();
            }
        }
    }

    void exitMaintenanceEarlyIfNeededLocked() {
        if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE) {
            if (mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
                    && !mSyncActive && !mJobsActive && !mAlarmsActive) {
                if (mState == STATE_IDLE_MAINTENANCE) {
                    stepIdleStateLocked("s:early");
                } else {
                    stepLightIdleStateLocked("s:early");
                }
            }
        }
    }

    void motionLocked() {
        if (DEBUG) Slog.d(TAG, "motionLocked()");
        // The motion sensor will have been disabled at this point
@@ -1612,7 +1736,7 @@ public class DeviceIdleController extends SystemService
        }
        mLocated = true;
        if (mNotMoving) {
            stepIdleStateLocked();
            stepIdleStateLocked("s:location");
        }
    }

@@ -1628,7 +1752,7 @@ public class DeviceIdleController extends SystemService
        }
        mLocated = true;
        if (mNotMoving) {
            stepIdleStateLocked();
            stepIdleStateLocked("s:gps");
        }
    }

@@ -1933,7 +2057,7 @@ public class DeviceIdleController extends SystemService
                long token = Binder.clearCallingIdentity();
                try {
                    exitForceIdleLocked();
                    stepIdleStateLocked();
                    stepIdleStateLocked("s:shell");
                    pw.print("Stepped to: ");
                    pw.println(stateToString(mState));
                } finally {
@@ -1947,7 +2071,7 @@ public class DeviceIdleController extends SystemService
                long token = Binder.clearCallingIdentity();
                try {
                    exitForceIdleLocked();
                    stepLightIdleStateLocked();
                    stepLightIdleStateLocked("s:shell");
                    pw.print("Stepped to: "); pw.println(lightStateToString(mLightState));
                } finally {
                    Binder.restoreCallingIdentity(token);
@@ -1967,7 +2091,7 @@ public class DeviceIdleController extends SystemService
                    becomeInactiveIfAppropriateLocked();
                    int curState = mState;
                    while (curState != STATE_IDLE) {
                        stepIdleStateLocked();
                        stepIdleStateLocked("s:shell");
                        if (curState == mState) {
                            pw.print("Unable to go idle; stopped at ");
                            pw.println(stateToString(mState));
@@ -2226,6 +2350,9 @@ public class DeviceIdleController extends SystemService
            pw.println(lightStateToString(mLightState));
            pw.print("  mInactiveTimeout="); TimeUtils.formatDuration(mInactiveTimeout, pw);
            pw.println();
            if (mActiveIdleOpCount != 0) {
                pw.print("  mActiveIdleOpCount="); pw.println(mActiveIdleOpCount);
            }
            if (mNextAlarmTime != 0) {
                pw.print("  mNextAlarmTime=");
                TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw);
@@ -2246,6 +2373,18 @@ public class DeviceIdleController extends SystemService
                TimeUtils.formatDuration(mNextLightAlarmTime, SystemClock.elapsedRealtime(), pw);
                pw.println();
            }
            if (mSyncActive) {
                pw.print("  mSyncActive="); pw.println(mSyncActive);
            }
            if (mJobsActive) {
                pw.print("  mJobsActive="); pw.println(mJobsActive);
            }
            if (mAlarmsActive) {
                pw.print("  mAlarmsActive="); pw.println(mAlarmsActive);
            }
            if (mDownloadServiceActive != null) {
                pw.print("  mDownloadServiceActive="); pw.println(mDownloadServiceActive);
            }
        }
    }
}
+31 −0
Original line number Diff line number Diff line
@@ -84,6 +84,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.accounts.AccountManagerService;
import com.android.server.content.SyncStorageEngine.AuthorityInfo;
import com.android.server.content.SyncStorageEngine.EndPoint;
@@ -207,6 +209,7 @@ public class SyncManager {
    volatile private boolean mDataConnectionIsConnected = false;
    volatile private boolean mStorageIsLow = false;
    volatile private boolean mDeviceIsIdle = false;
    volatile private boolean mReportedSyncActive = false;

    private final NotificationManager mNotificationMgr;
    private AlarmManager mAlarmService = null;
@@ -267,6 +270,12 @@ public class SyncManager {
                        SyncStorageEngine.EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
                        null /* any sync */);
            } else {
                if (mLocalDeviceIdleController != null) {
                    if (!mReportedSyncActive) {
                        mReportedSyncActive = true;
                        mLocalDeviceIdleController.setSyncActive(true);
                    }
                }
                sendCheckAlarmsMessage();
            }
        }
@@ -292,6 +301,7 @@ public class SyncManager {
    };

    private final PowerManager mPowerManager;
    DeviceIdleController.LocalService mLocalDeviceIdleController;

    // Use this as a random offset to seed all periodic syncs.
    private int mSyncRandomOffsetMillis;
@@ -1470,6 +1480,7 @@ public class SyncManager {
        }
        pw.print("memory low: "); pw.println(mStorageIsLow);
        pw.print("device idle: "); pw.println(mDeviceIsIdle);
        pw.print("reported active: "); pw.println(mReportedSyncActive);

        final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();

@@ -2544,6 +2555,7 @@ public class SyncManager {
                if (isLoggable) {
                    Log.v(TAG, "maybeStartNextSync: no data connection, skipping");
                }
                setSyncActive(false);
                return Long.MAX_VALUE;
            }

@@ -2551,6 +2563,7 @@ public class SyncManager {
                if (isLoggable) {
                    Log.v(TAG, "maybeStartNextSync: memory low, skipping");
                }
                setSyncActive(false);
                return Long.MAX_VALUE;
            }

@@ -2558,6 +2571,7 @@ public class SyncManager {
                if (isLoggable) {
                    Log.v(TAG, "maybeStartNextSync: device idle, skipping");
                }
                setSyncActive(false);
                return Long.MAX_VALUE;
            }

@@ -2567,6 +2581,7 @@ public class SyncManager {
                if (isLoggable) {
                    Log.v(TAG, "maybeStartNextSync: accounts not known, skipping");
                }
                setSyncActive(false);
                return Long.MAX_VALUE;
            }

@@ -2772,9 +2787,25 @@ public class SyncManager {
                dispatchSyncOperation(candidate);
            }

            setSyncActive(mActiveSyncContexts.size() > 0);

            return nextReadyToRunTime;
        }

        void setSyncActive(boolean active) {
            if (mLocalDeviceIdleController == null) {
                mLocalDeviceIdleController
                        = LocalServices.getService(DeviceIdleController.LocalService.class);
            }
            if (mLocalDeviceIdleController != null) {
                if (mReportedSyncActive != active) {
                    mReportedSyncActive = active;
                    mLocalDeviceIdleController.setSyncActive(active);
                }
            }

        }

        private boolean isSyncNotUsingNetworkH(ActiveSyncContext activeSyncContext) {
            final long bytesTransferredCurrent =
                    getTotalBytesTransferredByUid(activeSyncContext.mSyncAdapterUid);
+42 −0
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.app.IBatteryStats;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.job.controllers.AppIdleController;
import com.android.server.job.controllers.BatteryController;
import com.android.server.job.controllers.ConnectivityController;
@@ -127,6 +129,7 @@ public class JobSchedulerService extends com.android.server.SystemService

    IBatteryStats mBatteryStats;
    PowerManager mPowerManager;
    DeviceIdleController.LocalService mLocalDeviceIdleController;

    /**
     * Set to true once we are allowed to run third party apps.
@@ -138,6 +141,11 @@ public class JobSchedulerService extends com.android.server.SystemService
     */
    boolean mDeviceIdleMode;

    /**
     * What we last reported to DeviceIdleController about wheter we are active.
     */
    boolean mReportedActive;

    /**
     * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
     * still clean up. On reinstall the package will have a new uid.
@@ -268,6 +276,7 @@ public class JobSchedulerService extends com.android.server.SystemService
            mPendingJobs.remove(cancelled);
            // Cancel if running.
            stopJobOnServiceContextLocked(cancelled);
            reportActive();
        }
    }

@@ -299,12 +308,39 @@ public class JobSchedulerService extends com.android.server.SystemService
                    }
                } else {
                    // When coming out of idle, allow thing to start back up.
                    if (rocking) {
                        if (mLocalDeviceIdleController != null) {
                            if (!mReportedActive) {
                                mReportedActive = true;
                                mLocalDeviceIdleController.setJobsActive(true);
                            }
                        }
                    }
                    mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
                }
            }
        }
    }

    void reportActive() {
        boolean active = false;
        if (mPendingJobs.size() <= 0) {
            for (int i=0; i<mActiveServices.size(); i++) {
                JobServiceContext jsc = mActiveServices.get(i);
                if (!jsc.isAvailable()) {
                    active = true;
                    break;
                }
            }
        }
        if (mLocalDeviceIdleController != null) {
            if (mReportedActive != active) {
                mReportedActive = active;
                mLocalDeviceIdleController.setJobsActive(active);
            }
        }
    }

    /**
     * Initializes the system service.
     * <p>
@@ -354,6 +390,8 @@ public class JobSchedulerService extends com.android.server.SystemService
                mReadyToRock = true;
                mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
                        BatteryStats.SERVICE_NAME));
                mLocalDeviceIdleController
                        = LocalServices.getService(DeviceIdleController.LocalService.class);
                // Create the "runners".
                for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
                    mActiveServices.add(
@@ -623,6 +661,7 @@ public class JobSchedulerService extends com.android.server.SystemService
                    stopJobOnServiceContextLocked(job);
                }
            }
            reportActive();
            if (DEBUG) {
                final int queuedJobs = mPendingJobs.size();
                if (queuedJobs == 0) {
@@ -685,6 +724,7 @@ public class JobSchedulerService extends com.android.server.SystemService
                    Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Not running anything.");
                }
            }
            reportActive();
            if (DEBUG) {
                Slog.d(TAG, "idle=" + idleCount + " connectivity=" +
                connectivityCount + " charging=" + chargingCount + " tot=" +
@@ -766,6 +806,7 @@ public class JobSchedulerService extends com.android.server.SystemService
                        it.remove();
                    }
                }
                reportActive();
            }
        }
    }
@@ -948,6 +989,7 @@ public class JobSchedulerService extends com.android.server.SystemService
            pw.println();
            pw.print("mReadyToRock="); pw.println(mReadyToRock);
            pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode);
            pw.print("mReportedActive="); pw.println(mReportedActive);
        }
        pw.println();
    }