1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.Manifest;
20import android.app.ActivityManager;
21import android.app.ActivityManagerInternal;
22import android.app.AlarmManager;
23import android.content.BroadcastReceiver;
24import android.content.ContentResolver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.ApplicationInfo;
29import android.content.pm.PackageManager;
30import android.content.pm.PackageManager.NameNotFoundException;
31import android.database.ContentObserver;
32import android.hardware.Sensor;
33import android.hardware.SensorManager;
34import android.hardware.SensorEvent;
35import android.hardware.SensorEventListener;
36import android.hardware.TriggerEvent;
37import android.hardware.TriggerEventListener;
38import android.location.LocationRequest;
39import android.location.Location;
40import android.location.LocationListener;
41import android.location.LocationManager;
42import android.net.ConnectivityManager;
43import android.net.INetworkPolicyManager;
44import android.net.NetworkInfo;
45import android.net.Uri;
46import android.os.BatteryStats;
47import android.os.Binder;
48import android.os.Bundle;
49import android.os.Environment;
50import android.os.FileUtils;
51import android.os.Handler;
52import android.os.IDeviceIdleController;
53import android.os.IMaintenanceActivityListener;
54import android.os.Looper;
55import android.os.Message;
56import android.os.PowerManager;
57import android.os.PowerManagerInternal;
58import android.os.Process;
59import android.os.RemoteCallbackList;
60import android.os.RemoteException;
61import android.os.ResultReceiver;
62import android.os.ServiceManager;
63import android.os.ShellCallback;
64import android.os.ShellCommand;
65import android.os.SystemClock;
66import android.os.UserHandle;
67import android.provider.Settings;
68import android.util.ArrayMap;
69import android.util.ArraySet;
70import android.util.KeyValueListParser;
71import android.util.MutableLong;
72import android.util.Pair;
73import android.util.Slog;
74import android.util.SparseArray;
75import android.util.SparseBooleanArray;
76import android.util.TimeUtils;
77import android.util.Xml;
78
79import com.android.internal.annotations.GuardedBy;
80import com.android.internal.app.IBatteryStats;
81import com.android.internal.os.AtomicFile;
82import com.android.internal.os.BackgroundThread;
83import com.android.internal.util.DumpUtils;
84import com.android.internal.util.FastXmlSerializer;
85import com.android.internal.util.Preconditions;
86import com.android.internal.util.XmlUtils;
87import com.android.server.am.BatteryStatsService;
88import com.android.server.net.NetworkPolicyManagerInternal;
89
90import org.xmlpull.v1.XmlPullParser;
91import org.xmlpull.v1.XmlPullParserException;
92import org.xmlpull.v1.XmlSerializer;
93
94import java.io.ByteArrayOutputStream;
95import java.io.File;
96import java.io.FileDescriptor;
97import java.io.FileInputStream;
98import java.io.FileNotFoundException;
99import java.io.FileOutputStream;
100import java.io.IOException;
101import java.io.PrintWriter;
102import java.nio.charset.StandardCharsets;
103import java.util.Arrays;
104
105/**
106 * Keeps track of device idleness and drives low power mode based on that.
107 */
108public class DeviceIdleController extends SystemService
109        implements AnyMotionDetector.DeviceIdleCallback {
110    private static final String TAG = "DeviceIdleController";
111
112    private static final boolean DEBUG = false;
113
114    private static final boolean COMPRESS_TIME = false;
115
116    private static final int EVENT_BUFFER_SIZE = 100;
117
118    private AlarmManager mAlarmManager;
119    private IBatteryStats mBatteryStats;
120    private ActivityManagerInternal mLocalActivityManager;
121    private PowerManagerInternal mLocalPowerManager;
122    private PowerManager mPowerManager;
123    private ConnectivityService mConnectivityService;
124    private INetworkPolicyManager mNetworkPolicyManager;
125    private SensorManager mSensorManager;
126    private Sensor mMotionSensor;
127    private LocationManager mLocationManager;
128    private LocationRequest mLocationRequest;
129    private Intent mIdleIntent;
130    private Intent mLightIdleIntent;
131    private AnyMotionDetector mAnyMotionDetector;
132    private final AppStateTracker mAppStateTracker;
133    private boolean mLightEnabled;
134    private boolean mDeepEnabled;
135    private boolean mForceIdle;
136    private boolean mNetworkConnected;
137    private boolean mScreenOn;
138    private boolean mCharging;
139    private boolean mNotMoving;
140    private boolean mLocating;
141    private boolean mLocated;
142    private boolean mHasGps;
143    private boolean mHasNetworkLocation;
144    private Location mLastGenericLocation;
145    private Location mLastGpsLocation;
146    // Current locked state of the screen
147    private boolean mScreenLocked;
148
149    /** Device is currently active. */
150    private static final int STATE_ACTIVE = 0;
151    /** Device is inactive (screen off, no motion) and we are waiting to for idle. */
152    private static final int STATE_INACTIVE = 1;
153    /** Device is past the initial inactive period, and waiting for the next idle period. */
154    private static final int STATE_IDLE_PENDING = 2;
155    /** Device is currently sensing motion. */
156    private static final int STATE_SENSING = 3;
157    /** Device is currently finding location (and may still be sensing). */
158    private static final int STATE_LOCATING = 4;
159    /** Device is in the idle state, trying to stay asleep as much as possible. */
160    private static final int STATE_IDLE = 5;
161    /** Device is in the idle state, but temporarily out of idle to do regular maintenance. */
162    private static final int STATE_IDLE_MAINTENANCE = 6;
163
164    private static String stateToString(int state) {
165        switch (state) {
166            case STATE_ACTIVE: return "ACTIVE";
167            case STATE_INACTIVE: return "INACTIVE";
168            case STATE_IDLE_PENDING: return "IDLE_PENDING";
169            case STATE_SENSING: return "SENSING";
170            case STATE_LOCATING: return "LOCATING";
171            case STATE_IDLE: return "IDLE";
172            case STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
173            default: return Integer.toString(state);
174        }
175    }
176
177    /** Device is currently active. */
178    private static final int LIGHT_STATE_ACTIVE = 0;
179    /** Device is inactive (screen off) and we are waiting to for the first light idle. */
180    private static final int LIGHT_STATE_INACTIVE = 1;
181    /** Device is about to go idle for the first time, wait for current work to complete. */
182    private static final int LIGHT_STATE_PRE_IDLE = 3;
183    /** Device is in the light idle state, trying to stay asleep as much as possible. */
184    private static final int LIGHT_STATE_IDLE = 4;
185    /** Device is in the light idle state, we want to go in to idle maintenance but are
186     * waiting for network connectivity before doing so. */
187    private static final int LIGHT_STATE_WAITING_FOR_NETWORK = 5;
188    /** Device is in the light idle state, but temporarily out of idle to do regular maintenance. */
189    private static final int LIGHT_STATE_IDLE_MAINTENANCE = 6;
190    /** Device light idle state is overriden, now applying deep doze state. */
191    private static final int LIGHT_STATE_OVERRIDE = 7;
192    private static String lightStateToString(int state) {
193        switch (state) {
194            case LIGHT_STATE_ACTIVE: return "ACTIVE";
195            case LIGHT_STATE_INACTIVE: return "INACTIVE";
196            case LIGHT_STATE_PRE_IDLE: return "PRE_IDLE";
197            case LIGHT_STATE_IDLE: return "IDLE";
198            case LIGHT_STATE_WAITING_FOR_NETWORK: return "WAITING_FOR_NETWORK";
199            case LIGHT_STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
200            case LIGHT_STATE_OVERRIDE: return "OVERRIDE";
201            default: return Integer.toString(state);
202        }
203    }
204
205    private int mState;
206    private int mLightState;
207
208    private long mInactiveTimeout;
209    private long mNextAlarmTime;
210    private long mNextIdlePendingDelay;
211    private long mNextIdleDelay;
212    private long mNextLightIdleDelay;
213    private long mNextLightAlarmTime;
214    private long mNextSensingTimeoutAlarmTime;
215    private long mCurIdleBudget;
216    private long mMaintenanceStartTime;
217
218    private int mActiveIdleOpCount;
219    private PowerManager.WakeLock mActiveIdleWakeLock; // held when there are operations in progress
220    private PowerManager.WakeLock mGoingIdleWakeLock;  // held when we are going idle so hardware
221                                                       // (especially NetworkPolicyManager) can shut
222                                                       // down.
223    private boolean mJobsActive;
224    private boolean mAlarmsActive;
225    private boolean mReportedMaintenanceActivity;
226
227    public final AtomicFile mConfigFile;
228
229    private final RemoteCallbackList<IMaintenanceActivityListener> mMaintenanceActivityListeners =
230            new RemoteCallbackList<IMaintenanceActivityListener>();
231
232    /**
233     * Package names the system has white-listed to opt out of power save restrictions,
234     * except for device idle mode.
235     */
236    private final ArrayMap<String, Integer> mPowerSaveWhitelistAppsExceptIdle = new ArrayMap<>();
237
238    /**
239     * Package names the user has white-listed using commandline option to opt out of
240     * power save restrictions, except for device idle mode.
241     */
242    private final ArraySet<String> mPowerSaveWhitelistUserAppsExceptIdle = new ArraySet<>();
243
244    /**
245     * Package names the system has white-listed to opt out of power save restrictions for
246     * all modes.
247     */
248    private final ArrayMap<String, Integer> mPowerSaveWhitelistApps = new ArrayMap<>();
249
250    /**
251     * Package names the user has white-listed to opt out of power save restrictions.
252     */
253    private final ArrayMap<String, Integer> mPowerSaveWhitelistUserApps = new ArrayMap<>();
254
255    /**
256     * App IDs of built-in system apps that have been white-listed except for idle modes.
257     */
258    private final SparseBooleanArray mPowerSaveWhitelistSystemAppIdsExceptIdle
259            = new SparseBooleanArray();
260
261    /**
262     * App IDs of built-in system apps that have been white-listed.
263     */
264    private final SparseBooleanArray mPowerSaveWhitelistSystemAppIds = new SparseBooleanArray();
265
266    /**
267     * App IDs that have been white-listed to opt out of power save restrictions, except
268     * for device idle modes.
269     */
270    private final SparseBooleanArray mPowerSaveWhitelistExceptIdleAppIds = new SparseBooleanArray();
271
272    /**
273     * Current app IDs that are in the complete power save white list, but shouldn't be
274     * excluded from idle modes.  This array can be shared with others because it will not be
275     * modified once set.
276     */
277    private int[] mPowerSaveWhitelistExceptIdleAppIdArray = new int[0];
278
279    /**
280     * App IDs that have been white-listed to opt out of power save restrictions.
281     */
282    private final SparseBooleanArray mPowerSaveWhitelistAllAppIds = new SparseBooleanArray();
283
284    /**
285     * Current app IDs that are in the complete power save white list.  This array can
286     * be shared with others because it will not be modified once set.
287     */
288    private int[] mPowerSaveWhitelistAllAppIdArray = new int[0];
289
290    /**
291     * App IDs that have been white-listed by the user to opt out of power save restrictions.
292     */
293    private final SparseBooleanArray mPowerSaveWhitelistUserAppIds = new SparseBooleanArray();
294
295    /**
296     * Current app IDs that are in the user power save white list.  This array can
297     * be shared with others because it will not be modified once set.
298     */
299    private int[] mPowerSaveWhitelistUserAppIdArray = new int[0];
300
301    /**
302     * List of end times for UIDs that are temporarily marked as being allowed to access
303     * the network and acquire wakelocks. Times are in milliseconds.
304     */
305    private final SparseArray<Pair<MutableLong, String>> mTempWhitelistAppIdEndTimes
306            = new SparseArray<>();
307
308    private NetworkPolicyManagerInternal mNetworkPolicyManagerInternal;
309
310    /**
311     * Current app IDs of temporarily whitelist apps for high-priority messages.
312     */
313    private int[] mTempWhitelistAppIdArray = new int[0];
314
315    /**
316     * Apps in the system whitelist that have been taken out (probably because the user wanted to).
317     * They can be restored back by calling restoreAppToSystemWhitelist(String).
318     */
319    private ArrayMap<String, Integer> mRemovedFromSystemWhitelistApps = new ArrayMap<>();
320
321    private static final int EVENT_NULL = 0;
322    private static final int EVENT_NORMAL = 1;
323    private static final int EVENT_LIGHT_IDLE = 2;
324    private static final int EVENT_LIGHT_MAINTENANCE = 3;
325    private static final int EVENT_DEEP_IDLE = 4;
326    private static final int EVENT_DEEP_MAINTENANCE = 5;
327
328    private final int[] mEventCmds = new int[EVENT_BUFFER_SIZE];
329    private final long[] mEventTimes = new long[EVENT_BUFFER_SIZE];
330    private final String[] mEventReasons = new String[EVENT_BUFFER_SIZE];
331
332    private void addEvent(int cmd, String reason) {
333        if (mEventCmds[0] != cmd) {
334            System.arraycopy(mEventCmds, 0, mEventCmds, 1, EVENT_BUFFER_SIZE - 1);
335            System.arraycopy(mEventTimes, 0, mEventTimes, 1, EVENT_BUFFER_SIZE - 1);
336            System.arraycopy(mEventReasons, 0, mEventReasons, 1, EVENT_BUFFER_SIZE - 1);
337            mEventCmds[0] = cmd;
338            mEventTimes[0] = SystemClock.elapsedRealtime();
339            mEventReasons[0] = reason;
340        }
341    }
342
343    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
344        @Override public void onReceive(Context context, Intent intent) {
345            switch (intent.getAction()) {
346                case ConnectivityManager.CONNECTIVITY_ACTION: {
347                    updateConnectivityState(intent);
348                } break;
349                case Intent.ACTION_BATTERY_CHANGED: {
350                    synchronized (DeviceIdleController.this) {
351                        int plugged = intent.getIntExtra("plugged", 0);
352                        updateChargingLocked(plugged != 0);
353                    }
354                } break;
355                case Intent.ACTION_PACKAGE_REMOVED: {
356                    if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
357                        Uri data = intent.getData();
358                        String ssp;
359                        if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
360                            removePowerSaveWhitelistAppInternal(ssp);
361                        }
362                    }
363                } break;
364            }
365        }
366    };
367
368    private final AlarmManager.OnAlarmListener mLightAlarmListener
369            = new AlarmManager.OnAlarmListener() {
370        @Override
371        public void onAlarm() {
372            synchronized (DeviceIdleController.this) {
373                stepLightIdleStateLocked("s:alarm");
374            }
375        }
376    };
377
378    private final AlarmManager.OnAlarmListener mSensingTimeoutAlarmListener
379            = new AlarmManager.OnAlarmListener() {
380        @Override
381        public void onAlarm() {
382            if (mState == STATE_SENSING) {
383                synchronized (DeviceIdleController.this) {
384                    becomeInactiveIfAppropriateLocked();
385                }
386            }
387        }
388    };
389
390    private final AlarmManager.OnAlarmListener mDeepAlarmListener
391            = new AlarmManager.OnAlarmListener() {
392        @Override
393        public void onAlarm() {
394            synchronized (DeviceIdleController.this) {
395                stepIdleStateLocked("s:alarm");
396            }
397        }
398    };
399
400    private final BroadcastReceiver mIdleStartedDoneReceiver = new BroadcastReceiver() {
401        @Override public void onReceive(Context context, Intent intent) {
402            // When coming out of a deep idle, we will add in some delay before we allow
403            // the system to settle down and finish the maintenance window.  This is
404            // to give a chance for any pending work to be scheduled.
405            if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
406                mHandler.sendEmptyMessageDelayed(MSG_FINISH_IDLE_OP,
407                        mConstants.MIN_DEEP_MAINTENANCE_TIME);
408            } else {
409                mHandler.sendEmptyMessageDelayed(MSG_FINISH_IDLE_OP,
410                        mConstants.MIN_LIGHT_MAINTENANCE_TIME);
411            }
412        }
413    };
414
415    private final BroadcastReceiver mInteractivityReceiver = new BroadcastReceiver() {
416        @Override
417        public void onReceive(Context context, Intent intent) {
418            synchronized (DeviceIdleController.this) {
419                updateInteractivityLocked();
420            }
421        }
422    };
423
424    private final class MotionListener extends TriggerEventListener
425            implements SensorEventListener {
426
427        boolean active = false;
428
429        @Override
430        public void onTrigger(TriggerEvent event) {
431            synchronized (DeviceIdleController.this) {
432                active = false;
433                motionLocked();
434            }
435        }
436
437        @Override
438        public void onSensorChanged(SensorEvent event) {
439            synchronized (DeviceIdleController.this) {
440                mSensorManager.unregisterListener(this, mMotionSensor);
441                active = false;
442                motionLocked();
443            }
444        }
445
446        @Override
447        public void onAccuracyChanged(Sensor sensor, int accuracy) {}
448
449        public boolean registerLocked() {
450            boolean success;
451            if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
452                success = mSensorManager.requestTriggerSensor(mMotionListener, mMotionSensor);
453            } else {
454                success = mSensorManager.registerListener(
455                        mMotionListener, mMotionSensor, SensorManager.SENSOR_DELAY_NORMAL);
456            }
457            if (success) {
458                active = true;
459            } else {
460                Slog.e(TAG, "Unable to register for " + mMotionSensor);
461            }
462            return success;
463        }
464
465        public void unregisterLocked() {
466            if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
467                mSensorManager.cancelTriggerSensor(mMotionListener, mMotionSensor);
468            } else {
469                mSensorManager.unregisterListener(mMotionListener);
470            }
471            active = false;
472        }
473    }
474    private final MotionListener mMotionListener = new MotionListener();
475
476    private final LocationListener mGenericLocationListener = new LocationListener() {
477        @Override
478        public void onLocationChanged(Location location) {
479            synchronized (DeviceIdleController.this) {
480                receivedGenericLocationLocked(location);
481            }
482        }
483
484        @Override
485        public void onStatusChanged(String provider, int status, Bundle extras) {
486        }
487
488        @Override
489        public void onProviderEnabled(String provider) {
490        }
491
492        @Override
493        public void onProviderDisabled(String provider) {
494        }
495    };
496
497    private final LocationListener mGpsLocationListener = new LocationListener() {
498        @Override
499        public void onLocationChanged(Location location) {
500            synchronized (DeviceIdleController.this) {
501                receivedGpsLocationLocked(location);
502            }
503        }
504
505        @Override
506        public void onStatusChanged(String provider, int status, Bundle extras) {
507        }
508
509        @Override
510        public void onProviderEnabled(String provider) {
511        }
512
513        @Override
514        public void onProviderDisabled(String provider) {
515        }
516    };
517
518    /**
519     * All times are in milliseconds. These constants are kept synchronized with the system
520     * global Settings. Any access to this class or its fields should be done while
521     * holding the DeviceIdleController lock.
522     */
523    private final class Constants extends ContentObserver {
524        // Key names stored in the settings value.
525        private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
526                = "light_after_inactive_to";
527        private static final String KEY_LIGHT_PRE_IDLE_TIMEOUT = "light_pre_idle_to";
528        private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to";
529        private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
530        private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
531        private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET
532                = "light_idle_maintenance_min_budget";
533        private static final String KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET
534                = "light_idle_maintenance_max_budget";
535        private static final String KEY_MIN_LIGHT_MAINTENANCE_TIME = "min_light_maintenance_time";
536        private static final String KEY_MIN_DEEP_MAINTENANCE_TIME = "min_deep_maintenance_time";
537        private static final String KEY_INACTIVE_TIMEOUT = "inactive_to";
538        private static final String KEY_SENSING_TIMEOUT = "sensing_to";
539        private static final String KEY_LOCATING_TIMEOUT = "locating_to";
540        private static final String KEY_LOCATION_ACCURACY = "location_accuracy";
541        private static final String KEY_MOTION_INACTIVE_TIMEOUT = "motion_inactive_to";
542        private static final String KEY_IDLE_AFTER_INACTIVE_TIMEOUT = "idle_after_inactive_to";
543        private static final String KEY_IDLE_PENDING_TIMEOUT = "idle_pending_to";
544        private static final String KEY_MAX_IDLE_PENDING_TIMEOUT = "max_idle_pending_to";
545        private static final String KEY_IDLE_PENDING_FACTOR = "idle_pending_factor";
546        private static final String KEY_IDLE_TIMEOUT = "idle_to";
547        private static final String KEY_MAX_IDLE_TIMEOUT = "max_idle_to";
548        private static final String KEY_IDLE_FACTOR = "idle_factor";
549        private static final String KEY_MIN_TIME_TO_ALARM = "min_time_to_alarm";
550        private static final String KEY_MAX_TEMP_APP_WHITELIST_DURATION =
551                "max_temp_app_whitelist_duration";
552        private static final String KEY_MMS_TEMP_APP_WHITELIST_DURATION =
553                "mms_temp_app_whitelist_duration";
554        private static final String KEY_SMS_TEMP_APP_WHITELIST_DURATION =
555                "sms_temp_app_whitelist_duration";
556        private static final String KEY_NOTIFICATION_WHITELIST_DURATION =
557                "notification_whitelist_duration";
558        /**
559         * Whether to wait for the user to unlock the device before causing screen-on to
560         * exit doze. Default = true
561         */
562        private static final String KEY_WAIT_FOR_UNLOCK = "wait_for_unlock";
563
564        /**
565         * This is the time, after becoming inactive, that we go in to the first
566         * light-weight idle mode.
567         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
568         * @see #KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
569         */
570        public long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
571
572        /**
573         * This is amount of time we will wait from the point where we decide we would
574         * like to go idle until we actually do, while waiting for jobs and other current
575         * activity to finish.
576         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
577         * @see #KEY_LIGHT_PRE_IDLE_TIMEOUT
578         */
579        public long LIGHT_PRE_IDLE_TIMEOUT;
580
581        /**
582         * This is the initial time that we will run in idle maintenance mode.
583         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
584         * @see #KEY_LIGHT_IDLE_TIMEOUT
585         */
586        public long LIGHT_IDLE_TIMEOUT;
587
588        /**
589         * Scaling factor to apply to the light idle mode time each time we complete a cycle.
590         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
591         * @see #KEY_LIGHT_IDLE_FACTOR
592         */
593        public float LIGHT_IDLE_FACTOR;
594
595        /**
596         * This is the maximum time we will run in idle maintenence mode.
597         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
598         * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT
599         */
600        public long LIGHT_MAX_IDLE_TIMEOUT;
601
602        /**
603         * This is the minimum amount of time we want to make available for maintenance mode
604         * when lightly idling.  That is, we will always have at least this amount of time
605         * available maintenance before timing out and cutting off maintenance mode.
606         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
607         * @see #KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET
608         */
609        public long LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
610
611        /**
612         * This is the maximum amount of time we want to make available for maintenance mode
613         * when lightly idling.  That is, if the system isn't using up its minimum maintenance
614         * budget and this time is being added to the budget reserve, this is the maximum
615         * reserve size we will allow to grow and thus the maximum amount of time we will
616         * allow for the maintenance window.
617         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
618         * @see #KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET
619         */
620        public long LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
621
622        /**
623         * This is the minimum amount of time that we will stay in maintenance mode after
624         * a light doze.  We have this minimum to allow various things to respond to switching
625         * in to maintenance mode and scheduling their work -- otherwise we may
626         * see there is nothing to do (no jobs pending) and go out of maintenance
627         * mode immediately.
628         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
629         * @see #KEY_MIN_LIGHT_MAINTENANCE_TIME
630         */
631        public long MIN_LIGHT_MAINTENANCE_TIME;
632
633        /**
634         * This is the minimum amount of time that we will stay in maintenance mode after
635         * a full doze.  We have this minimum to allow various things to respond to switching
636         * in to maintenance mode and scheduling their work -- otherwise we may
637         * see there is nothing to do (no jobs pending) and go out of maintenance
638         * mode immediately.
639         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
640         * @see #KEY_MIN_DEEP_MAINTENANCE_TIME
641         */
642        public long MIN_DEEP_MAINTENANCE_TIME;
643
644        /**
645         * This is the time, after becoming inactive, at which we start looking at the
646         * motion sensor to determine if the device is being left alone.  We don't do this
647         * immediately after going inactive just because we don't want to be continually running
648         * the motion sensor whenever the screen is off.
649         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
650         * @see #KEY_INACTIVE_TIMEOUT
651         */
652        public long INACTIVE_TIMEOUT;
653
654        /**
655         * If we don't receive a callback from AnyMotion in this amount of time +
656         * {@link #LOCATING_TIMEOUT}, we will change from
657         * STATE_SENSING to STATE_INACTIVE, and any AnyMotion callbacks while not in STATE_SENSING
658         * will be ignored.
659         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
660         * @see #KEY_SENSING_TIMEOUT
661         */
662        public long SENSING_TIMEOUT;
663
664        /**
665         * This is how long we will wait to try to get a good location fix before going in to
666         * idle mode.
667         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
668         * @see #KEY_LOCATING_TIMEOUT
669         */
670        public long LOCATING_TIMEOUT;
671
672        /**
673         * The desired maximum accuracy (in meters) we consider the location to be good enough to go
674         * on to idle.  We will be trying to get an accuracy fix at least this good or until
675         * {@link #LOCATING_TIMEOUT} expires.
676         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
677         * @see #KEY_LOCATION_ACCURACY
678         */
679        public float LOCATION_ACCURACY;
680
681        /**
682         * This is the time, after seeing motion, that we wait after becoming inactive from
683         * that until we start looking for motion again.
684         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
685         * @see #KEY_MOTION_INACTIVE_TIMEOUT
686         */
687        public long MOTION_INACTIVE_TIMEOUT;
688
689        /**
690         * This is the time, after the inactive timeout elapses, that we will wait looking
691         * for motion until we truly consider the device to be idle.
692         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
693         * @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT
694         */
695        public long IDLE_AFTER_INACTIVE_TIMEOUT;
696
697        /**
698         * This is the initial time, after being idle, that we will allow ourself to be back
699         * in the IDLE_MAINTENANCE state allowing the system to run normally until we return to
700         * idle.
701         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
702         * @see #KEY_IDLE_PENDING_TIMEOUT
703         */
704        public long IDLE_PENDING_TIMEOUT;
705
706        /**
707         * Maximum pending idle timeout (time spent running) we will be allowed to use.
708         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
709         * @see #KEY_MAX_IDLE_PENDING_TIMEOUT
710         */
711        public long MAX_IDLE_PENDING_TIMEOUT;
712
713        /**
714         * Scaling factor to apply to current pending idle timeout each time we cycle through
715         * that state.
716         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
717         * @see #KEY_IDLE_PENDING_FACTOR
718         */
719        public float IDLE_PENDING_FACTOR;
720
721        /**
722         * This is the initial time that we want to sit in the idle state before waking up
723         * again to return to pending idle and allowing normal work to run.
724         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
725         * @see #KEY_IDLE_TIMEOUT
726         */
727        public long IDLE_TIMEOUT;
728
729        /**
730         * Maximum idle duration we will be allowed to use.
731         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
732         * @see #KEY_MAX_IDLE_TIMEOUT
733         */
734        public long MAX_IDLE_TIMEOUT;
735
736        /**
737         * Scaling factor to apply to current idle timeout each time we cycle through that state.
738          * @see Settings.Global#DEVICE_IDLE_CONSTANTS
739         * @see #KEY_IDLE_FACTOR
740         */
741        public float IDLE_FACTOR;
742
743        /**
744         * This is the minimum time we will allow until the next upcoming alarm for us to
745         * actually go in to idle mode.
746         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
747         * @see #KEY_MIN_TIME_TO_ALARM
748         */
749        public long MIN_TIME_TO_ALARM;
750
751        /**
752         * Max amount of time to temporarily whitelist an app when it receives a high priority
753         * tickle.
754         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
755         * @see #KEY_MAX_TEMP_APP_WHITELIST_DURATION
756         */
757        public long MAX_TEMP_APP_WHITELIST_DURATION;
758
759        /**
760         * Amount of time we would like to whitelist an app that is receiving an MMS.
761         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
762         * @see #KEY_MMS_TEMP_APP_WHITELIST_DURATION
763         */
764        public long MMS_TEMP_APP_WHITELIST_DURATION;
765
766        /**
767         * Amount of time we would like to whitelist an app that is receiving an SMS.
768         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
769         * @see #KEY_SMS_TEMP_APP_WHITELIST_DURATION
770         */
771        public long SMS_TEMP_APP_WHITELIST_DURATION;
772
773        /**
774         * Amount of time we would like to whitelist an app that is handling a
775         * {@link android.app.PendingIntent} triggered by a {@link android.app.Notification}.
776         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
777         * @see #KEY_NOTIFICATION_WHITELIST_DURATION
778         */
779        public long NOTIFICATION_WHITELIST_DURATION;
780
781        public boolean WAIT_FOR_UNLOCK;
782
783        private final ContentResolver mResolver;
784        private final boolean mSmallBatteryDevice;
785        private final KeyValueListParser mParser = new KeyValueListParser(',');
786
787        public Constants(Handler handler, ContentResolver resolver) {
788            super(handler);
789            mResolver = resolver;
790            mSmallBatteryDevice = ActivityManager.isSmallBatteryDevice();
791            mResolver.registerContentObserver(
792                    Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS),
793                    false, this);
794            updateConstants();
795        }
796
797        @Override
798        public void onChange(boolean selfChange, Uri uri) {
799            updateConstants();
800        }
801
802        private void updateConstants() {
803            synchronized (DeviceIdleController.this) {
804                try {
805                    mParser.setString(Settings.Global.getString(mResolver,
806                            Settings.Global.DEVICE_IDLE_CONSTANTS));
807                } catch (IllegalArgumentException e) {
808                    // Failed to parse the settings string, log this and move on
809                    // with defaults.
810                    Slog.e(TAG, "Bad device idle settings", e);
811                }
812
813                LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getDurationMillis(
814                        KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
815                        !COMPRESS_TIME ? 3 * 60 * 1000L : 15 * 1000L);
816                LIGHT_PRE_IDLE_TIMEOUT = mParser.getDurationMillis(KEY_LIGHT_PRE_IDLE_TIMEOUT,
817                        !COMPRESS_TIME ? 3 * 60 * 1000L : 30 * 1000L);
818                LIGHT_IDLE_TIMEOUT = mParser.getDurationMillis(KEY_LIGHT_IDLE_TIMEOUT,
819                        !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);
820                LIGHT_IDLE_FACTOR = mParser.getFloat(KEY_LIGHT_IDLE_FACTOR,
821                        2f);
822                LIGHT_MAX_IDLE_TIMEOUT = mParser.getDurationMillis(KEY_LIGHT_MAX_IDLE_TIMEOUT,
823                        !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L);
824                LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mParser.getDurationMillis(
825                        KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET,
826                        !COMPRESS_TIME ? 1 * 60 * 1000L : 15 * 1000L);
827                LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mParser.getDurationMillis(
828                        KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET,
829                        !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);
830                MIN_LIGHT_MAINTENANCE_TIME = mParser.getDurationMillis(
831                        KEY_MIN_LIGHT_MAINTENANCE_TIME,
832                        !COMPRESS_TIME ? 5 * 1000L : 1 * 1000L);
833                MIN_DEEP_MAINTENANCE_TIME = mParser.getDurationMillis(
834                        KEY_MIN_DEEP_MAINTENANCE_TIME,
835                        !COMPRESS_TIME ? 30 * 1000L : 5 * 1000L);
836                long inactiveTimeoutDefault = (mSmallBatteryDevice ? 15 : 30) * 60 * 1000L;
837                INACTIVE_TIMEOUT = mParser.getDurationMillis(KEY_INACTIVE_TIMEOUT,
838                        !COMPRESS_TIME ? inactiveTimeoutDefault : (inactiveTimeoutDefault / 10));
839                SENSING_TIMEOUT = mParser.getDurationMillis(KEY_SENSING_TIMEOUT,
840                        !DEBUG ? 4 * 60 * 1000L : 60 * 1000L);
841                LOCATING_TIMEOUT = mParser.getDurationMillis(KEY_LOCATING_TIMEOUT,
842                        !DEBUG ? 30 * 1000L : 15 * 1000L);
843                LOCATION_ACCURACY = mParser.getFloat(KEY_LOCATION_ACCURACY, 20);
844                MOTION_INACTIVE_TIMEOUT = mParser.getDurationMillis(KEY_MOTION_INACTIVE_TIMEOUT,
845                        !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
846                long idleAfterInactiveTimeout = (mSmallBatteryDevice ? 15 : 30) * 60 * 1000L;
847                IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getDurationMillis(
848                        KEY_IDLE_AFTER_INACTIVE_TIMEOUT,
849                        !COMPRESS_TIME ? idleAfterInactiveTimeout
850                                       : (idleAfterInactiveTimeout / 10));
851                IDLE_PENDING_TIMEOUT = mParser.getDurationMillis(KEY_IDLE_PENDING_TIMEOUT,
852                        !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);
853                MAX_IDLE_PENDING_TIMEOUT = mParser.getDurationMillis(KEY_MAX_IDLE_PENDING_TIMEOUT,
854                        !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
855                IDLE_PENDING_FACTOR = mParser.getFloat(KEY_IDLE_PENDING_FACTOR,
856                        2f);
857                IDLE_TIMEOUT = mParser.getDurationMillis(KEY_IDLE_TIMEOUT,
858                        !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
859                MAX_IDLE_TIMEOUT = mParser.getDurationMillis(KEY_MAX_IDLE_TIMEOUT,
860                        !COMPRESS_TIME ? 6 * 60 * 60 * 1000L : 30 * 60 * 1000L);
861                IDLE_FACTOR = mParser.getFloat(KEY_IDLE_FACTOR,
862                        2f);
863                MIN_TIME_TO_ALARM = mParser.getDurationMillis(KEY_MIN_TIME_TO_ALARM,
864                        !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
865                MAX_TEMP_APP_WHITELIST_DURATION = mParser.getDurationMillis(
866                        KEY_MAX_TEMP_APP_WHITELIST_DURATION, 5 * 60 * 1000L);
867                MMS_TEMP_APP_WHITELIST_DURATION = mParser.getDurationMillis(
868                        KEY_MMS_TEMP_APP_WHITELIST_DURATION, 60 * 1000L);
869                SMS_TEMP_APP_WHITELIST_DURATION = mParser.getDurationMillis(
870                        KEY_SMS_TEMP_APP_WHITELIST_DURATION, 20 * 1000L);
871                NOTIFICATION_WHITELIST_DURATION = mParser.getDurationMillis(
872                        KEY_NOTIFICATION_WHITELIST_DURATION, 30 * 1000L);
873                WAIT_FOR_UNLOCK = mParser.getBoolean(KEY_WAIT_FOR_UNLOCK, false);
874            }
875        }
876
877        void dump(PrintWriter pw) {
878            pw.println("  Settings:");
879
880            pw.print("    "); pw.print(KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT); pw.print("=");
881            TimeUtils.formatDuration(LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT, pw);
882            pw.println();
883
884            pw.print("    "); pw.print(KEY_LIGHT_PRE_IDLE_TIMEOUT); pw.print("=");
885            TimeUtils.formatDuration(LIGHT_PRE_IDLE_TIMEOUT, pw);
886            pw.println();
887
888            pw.print("    "); pw.print(KEY_LIGHT_IDLE_TIMEOUT); pw.print("=");
889            TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw);
890            pw.println();
891
892            pw.print("    "); pw.print(KEY_LIGHT_IDLE_FACTOR); pw.print("=");
893            pw.print(LIGHT_IDLE_FACTOR);
894            pw.println();
895
896            pw.print("    "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT); pw.print("=");
897            TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT, pw);
898            pw.println();
899
900            pw.print("    "); pw.print(KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET); pw.print("=");
901            TimeUtils.formatDuration(LIGHT_IDLE_MAINTENANCE_MIN_BUDGET, pw);
902            pw.println();
903
904            pw.print("    "); pw.print(KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET); pw.print("=");
905            TimeUtils.formatDuration(LIGHT_IDLE_MAINTENANCE_MAX_BUDGET, pw);
906            pw.println();
907
908            pw.print("    "); pw.print(KEY_MIN_LIGHT_MAINTENANCE_TIME); pw.print("=");
909            TimeUtils.formatDuration(MIN_LIGHT_MAINTENANCE_TIME, pw);
910            pw.println();
911
912            pw.print("    "); pw.print(KEY_MIN_DEEP_MAINTENANCE_TIME); pw.print("=");
913            TimeUtils.formatDuration(MIN_DEEP_MAINTENANCE_TIME, pw);
914            pw.println();
915
916            pw.print("    "); pw.print(KEY_INACTIVE_TIMEOUT); pw.print("=");
917            TimeUtils.formatDuration(INACTIVE_TIMEOUT, pw);
918            pw.println();
919
920            pw.print("    "); pw.print(KEY_SENSING_TIMEOUT); pw.print("=");
921            TimeUtils.formatDuration(SENSING_TIMEOUT, pw);
922            pw.println();
923
924            pw.print("    "); pw.print(KEY_LOCATING_TIMEOUT); pw.print("=");
925            TimeUtils.formatDuration(LOCATING_TIMEOUT, pw);
926            pw.println();
927
928            pw.print("    "); pw.print(KEY_LOCATION_ACCURACY); pw.print("=");
929            pw.print(LOCATION_ACCURACY); pw.print("m");
930            pw.println();
931
932            pw.print("    "); pw.print(KEY_MOTION_INACTIVE_TIMEOUT); pw.print("=");
933            TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT, pw);
934            pw.println();
935
936            pw.print("    "); pw.print(KEY_IDLE_AFTER_INACTIVE_TIMEOUT); pw.print("=");
937            TimeUtils.formatDuration(IDLE_AFTER_INACTIVE_TIMEOUT, pw);
938            pw.println();
939
940            pw.print("    "); pw.print(KEY_IDLE_PENDING_TIMEOUT); pw.print("=");
941            TimeUtils.formatDuration(IDLE_PENDING_TIMEOUT, pw);
942            pw.println();
943
944            pw.print("    "); pw.print(KEY_MAX_IDLE_PENDING_TIMEOUT); pw.print("=");
945            TimeUtils.formatDuration(MAX_IDLE_PENDING_TIMEOUT, pw);
946            pw.println();
947
948            pw.print("    "); pw.print(KEY_IDLE_PENDING_FACTOR); pw.print("=");
949            pw.println(IDLE_PENDING_FACTOR);
950
951            pw.print("    "); pw.print(KEY_IDLE_TIMEOUT); pw.print("=");
952            TimeUtils.formatDuration(IDLE_TIMEOUT, pw);
953            pw.println();
954
955            pw.print("    "); pw.print(KEY_MAX_IDLE_TIMEOUT); pw.print("=");
956            TimeUtils.formatDuration(MAX_IDLE_TIMEOUT, pw);
957            pw.println();
958
959            pw.print("    "); pw.print(KEY_IDLE_FACTOR); pw.print("=");
960            pw.println(IDLE_FACTOR);
961
962            pw.print("    "); pw.print(KEY_MIN_TIME_TO_ALARM); pw.print("=");
963            TimeUtils.formatDuration(MIN_TIME_TO_ALARM, pw);
964            pw.println();
965
966            pw.print("    "); pw.print(KEY_MAX_TEMP_APP_WHITELIST_DURATION); pw.print("=");
967            TimeUtils.formatDuration(MAX_TEMP_APP_WHITELIST_DURATION, pw);
968            pw.println();
969
970            pw.print("    "); pw.print(KEY_MMS_TEMP_APP_WHITELIST_DURATION); pw.print("=");
971            TimeUtils.formatDuration(MMS_TEMP_APP_WHITELIST_DURATION, pw);
972            pw.println();
973
974            pw.print("    "); pw.print(KEY_SMS_TEMP_APP_WHITELIST_DURATION); pw.print("=");
975            TimeUtils.formatDuration(SMS_TEMP_APP_WHITELIST_DURATION, pw);
976            pw.println();
977
978            pw.print("    "); pw.print(KEY_NOTIFICATION_WHITELIST_DURATION); pw.print("=");
979            TimeUtils.formatDuration(NOTIFICATION_WHITELIST_DURATION, pw);
980            pw.println();
981
982            pw.print("    "); pw.print(KEY_WAIT_FOR_UNLOCK); pw.print("=");
983            pw.println(WAIT_FOR_UNLOCK);
984        }
985    }
986
987    private Constants mConstants;
988
989    @Override
990    public void onAnyMotionResult(int result) {
991        if (DEBUG) Slog.d(TAG, "onAnyMotionResult(" + result + ")");
992        if (result != AnyMotionDetector.RESULT_UNKNOWN) {
993            synchronized (this) {
994                cancelSensingTimeoutAlarmLocked();
995            }
996        }
997        if ((result == AnyMotionDetector.RESULT_MOVED) ||
998            (result == AnyMotionDetector.RESULT_UNKNOWN)) {
999            synchronized (this) {
1000                handleMotionDetectedLocked(mConstants.INACTIVE_TIMEOUT, "non_stationary");
1001            }
1002        } else if (result == AnyMotionDetector.RESULT_STATIONARY) {
1003            if (mState == STATE_SENSING) {
1004                // If we are currently sensing, it is time to move to locating.
1005                synchronized (this) {
1006                    mNotMoving = true;
1007                    stepIdleStateLocked("s:stationary");
1008                }
1009            } else if (mState == STATE_LOCATING) {
1010                // If we are currently locating, note that we are not moving and step
1011                // if we have located the position.
1012                synchronized (this) {
1013                    mNotMoving = true;
1014                    if (mLocated) {
1015                        stepIdleStateLocked("s:stationary");
1016                    }
1017                }
1018            }
1019        }
1020    }
1021
1022    private static final int MSG_WRITE_CONFIG = 1;
1023    private static final int MSG_REPORT_IDLE_ON = 2;
1024    private static final int MSG_REPORT_IDLE_ON_LIGHT = 3;
1025    private static final int MSG_REPORT_IDLE_OFF = 4;
1026    private static final int MSG_REPORT_ACTIVE = 5;
1027    private static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 6;
1028    private static final int MSG_REPORT_MAINTENANCE_ACTIVITY = 7;
1029    private static final int MSG_FINISH_IDLE_OP = 8;
1030    private static final int MSG_REPORT_TEMP_APP_WHITELIST_CHANGED = 9;
1031
1032    final class MyHandler extends Handler {
1033        MyHandler(Looper looper) {
1034            super(looper);
1035        }
1036
1037        @Override public void handleMessage(Message msg) {
1038            if (DEBUG) Slog.d(TAG, "handleMessage(" + msg.what + ")");
1039            switch (msg.what) {
1040                case MSG_WRITE_CONFIG: {
1041                    // Does not hold a wakelock. Just let this happen whenever.
1042                    handleWriteConfigFile();
1043                } break;
1044                case MSG_REPORT_IDLE_ON:
1045                case MSG_REPORT_IDLE_ON_LIGHT: {
1046                    // mGoingIdleWakeLock is held at this point
1047                    EventLogTags.writeDeviceIdleOnStart();
1048                    final boolean deepChanged;
1049                    final boolean lightChanged;
1050                    if (msg.what == MSG_REPORT_IDLE_ON) {
1051                        deepChanged = mLocalPowerManager.setDeviceIdleMode(true);
1052                        lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
1053                    } else {
1054                        deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
1055                        lightChanged = mLocalPowerManager.setLightDeviceIdleMode(true);
1056                    }
1057                    try {
1058                        mNetworkPolicyManager.setDeviceIdleMode(true);
1059                        mBatteryStats.noteDeviceIdleMode(msg.what == MSG_REPORT_IDLE_ON
1060                                ? BatteryStats.DEVICE_IDLE_MODE_DEEP
1061                                : BatteryStats.DEVICE_IDLE_MODE_LIGHT, null, Process.myUid());
1062                    } catch (RemoteException e) {
1063                    }
1064                    if (deepChanged) {
1065                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
1066                    }
1067                    if (lightChanged) {
1068                        getContext().sendBroadcastAsUser(mLightIdleIntent, UserHandle.ALL);
1069                    }
1070                    EventLogTags.writeDeviceIdleOnComplete();
1071                    mGoingIdleWakeLock.release();
1072                } break;
1073                case MSG_REPORT_IDLE_OFF: {
1074                    // mActiveIdleWakeLock is held at this point
1075                    EventLogTags.writeDeviceIdleOffStart("unknown");
1076                    final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
1077                    final boolean lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
1078                    try {
1079                        mNetworkPolicyManager.setDeviceIdleMode(false);
1080                        mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_OFF,
1081                                null, Process.myUid());
1082                    } catch (RemoteException e) {
1083                    }
1084                    if (deepChanged) {
1085                        incActiveIdleOps();
1086                        getContext().sendOrderedBroadcastAsUser(mIdleIntent, UserHandle.ALL,
1087                                null, mIdleStartedDoneReceiver, null, 0, null, null);
1088                    }
1089                    if (lightChanged) {
1090                        incActiveIdleOps();
1091                        getContext().sendOrderedBroadcastAsUser(mLightIdleIntent, UserHandle.ALL,
1092                                null, mIdleStartedDoneReceiver, null, 0, null, null);
1093                    }
1094                    // Always start with one active op for the message being sent here.
1095                    // Now we are done!
1096                    decActiveIdleOps();
1097                    EventLogTags.writeDeviceIdleOffComplete();
1098                } break;
1099                case MSG_REPORT_ACTIVE: {
1100                    // The device is awake at this point, so no wakelock necessary.
1101                    String activeReason = (String)msg.obj;
1102                    int activeUid = msg.arg1;
1103                    EventLogTags.writeDeviceIdleOffStart(
1104                            activeReason != null ? activeReason : "unknown");
1105                    final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
1106                    final boolean lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
1107                    try {
1108                        mNetworkPolicyManager.setDeviceIdleMode(false);
1109                        mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_OFF,
1110                                activeReason, activeUid);
1111                    } catch (RemoteException e) {
1112                    }
1113                    if (deepChanged) {
1114                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
1115                    }
1116                    if (lightChanged) {
1117                        getContext().sendBroadcastAsUser(mLightIdleIntent, UserHandle.ALL);
1118                    }
1119                    EventLogTags.writeDeviceIdleOffComplete();
1120                } break;
1121                case MSG_TEMP_APP_WHITELIST_TIMEOUT: {
1122                    // TODO: What is keeping the device awake at this point? Does it need to be?
1123                    int uid = msg.arg1;
1124                    checkTempAppWhitelistTimeout(uid);
1125                } break;
1126                case MSG_REPORT_MAINTENANCE_ACTIVITY: {
1127                    // TODO: What is keeping the device awake at this point? Does it need to be?
1128                    boolean active = (msg.arg1 == 1);
1129                    final int size = mMaintenanceActivityListeners.beginBroadcast();
1130                    try {
1131                        for (int i = 0; i < size; i++) {
1132                            try {
1133                                mMaintenanceActivityListeners.getBroadcastItem(i)
1134                                        .onMaintenanceActivityChanged(active);
1135                            } catch (RemoteException ignored) {
1136                            }
1137                        }
1138                    } finally {
1139                        mMaintenanceActivityListeners.finishBroadcast();
1140                    }
1141                } break;
1142                case MSG_FINISH_IDLE_OP: {
1143                    // mActiveIdleWakeLock is held at this point
1144                    decActiveIdleOps();
1145                } break;
1146                case MSG_REPORT_TEMP_APP_WHITELIST_CHANGED: {
1147                    final int appId = msg.arg1;
1148                    final boolean added = (msg.arg2 == 1);
1149                    mNetworkPolicyManagerInternal.onTempPowerSaveWhitelistChange(appId, added);
1150                } break;
1151            }
1152        }
1153    }
1154
1155    final MyHandler mHandler;
1156
1157    BinderService mBinderService;
1158
1159    private final class BinderService extends IDeviceIdleController.Stub {
1160        @Override public void addPowerSaveWhitelistApp(String name) {
1161            if (DEBUG) {
1162                Slog.i(TAG, "addPowerSaveWhitelistApp(name = " + name + ")");
1163            }
1164            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
1165                    null);
1166            long ident = Binder.clearCallingIdentity();
1167            try {
1168                addPowerSaveWhitelistAppInternal(name);
1169            } finally {
1170                Binder.restoreCallingIdentity(ident);
1171            }
1172        }
1173
1174        @Override public void removePowerSaveWhitelistApp(String name) {
1175            if (DEBUG) {
1176                Slog.i(TAG, "removePowerSaveWhitelistApp(name = " + name + ")");
1177            }
1178            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
1179                    null);
1180            long ident = Binder.clearCallingIdentity();
1181            try {
1182                removePowerSaveWhitelistAppInternal(name);
1183            } finally {
1184                Binder.restoreCallingIdentity(ident);
1185            }
1186        }
1187
1188        @Override public void removeSystemPowerWhitelistApp(String name) {
1189            if (DEBUG) {
1190                Slog.d(TAG, "removeAppFromSystemWhitelist(name = " + name + ")");
1191            }
1192            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
1193                    null);
1194            long ident = Binder.clearCallingIdentity();
1195            try {
1196                removeSystemPowerWhitelistAppInternal(name);
1197            } finally {
1198                Binder.restoreCallingIdentity(ident);
1199            }
1200        }
1201
1202        @Override public void restoreSystemPowerWhitelistApp(String name) {
1203            if (DEBUG) {
1204                Slog.d(TAG, "restoreAppToSystemWhitelist(name = " + name + ")");
1205            }
1206            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
1207                    null);
1208            long ident = Binder.clearCallingIdentity();
1209            try {
1210                restoreSystemPowerWhitelistAppInternal(name);
1211            } finally {
1212                Binder.restoreCallingIdentity(ident);
1213            }
1214        }
1215
1216        public String[] getRemovedSystemPowerWhitelistApps() {
1217            return getRemovedSystemPowerWhitelistAppsInternal();
1218        }
1219
1220        @Override public String[] getSystemPowerWhitelistExceptIdle() {
1221            return getSystemPowerWhitelistExceptIdleInternal();
1222        }
1223
1224        @Override public String[] getSystemPowerWhitelist() {
1225            return getSystemPowerWhitelistInternal();
1226        }
1227
1228        @Override public String[] getUserPowerWhitelist() {
1229            return getUserPowerWhitelistInternal();
1230        }
1231
1232        @Override public String[] getFullPowerWhitelistExceptIdle() {
1233            return getFullPowerWhitelistExceptIdleInternal();
1234        }
1235
1236        @Override public String[] getFullPowerWhitelist() {
1237            return getFullPowerWhitelistInternal();
1238        }
1239
1240        @Override public int[] getAppIdWhitelistExceptIdle() {
1241            return getAppIdWhitelistExceptIdleInternal();
1242        }
1243
1244        @Override public int[] getAppIdWhitelist() {
1245            return getAppIdWhitelistInternal();
1246        }
1247
1248        @Override public int[] getAppIdUserWhitelist() {
1249            return getAppIdUserWhitelistInternal();
1250        }
1251
1252        @Override public int[] getAppIdTempWhitelist() {
1253            return getAppIdTempWhitelistInternal();
1254        }
1255
1256        @Override public boolean isPowerSaveWhitelistExceptIdleApp(String name) {
1257            return isPowerSaveWhitelistExceptIdleAppInternal(name);
1258        }
1259
1260        @Override public boolean isPowerSaveWhitelistApp(String name) {
1261            return isPowerSaveWhitelistAppInternal(name);
1262        }
1263
1264        @Override public void addPowerSaveTempWhitelistApp(String packageName, long duration,
1265                int userId, String reason) throws RemoteException {
1266            addPowerSaveTempWhitelistAppChecked(packageName, duration, userId, reason);
1267        }
1268
1269        @Override public long addPowerSaveTempWhitelistAppForMms(String packageName,
1270                int userId, String reason) throws RemoteException {
1271            long duration = mConstants.MMS_TEMP_APP_WHITELIST_DURATION;
1272            addPowerSaveTempWhitelistAppChecked(packageName, duration, userId, reason);
1273            return duration;
1274        }
1275
1276        @Override public long addPowerSaveTempWhitelistAppForSms(String packageName,
1277                int userId, String reason) throws RemoteException {
1278            long duration = mConstants.SMS_TEMP_APP_WHITELIST_DURATION;
1279            addPowerSaveTempWhitelistAppChecked(packageName, duration, userId, reason);
1280            return duration;
1281        }
1282
1283        @Override public void exitIdle(String reason) {
1284            getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,
1285                    null);
1286            long ident = Binder.clearCallingIdentity();
1287            try {
1288                exitIdleInternal(reason);
1289            } finally {
1290                Binder.restoreCallingIdentity(ident);
1291            }
1292        }
1293
1294        @Override public boolean registerMaintenanceActivityListener(
1295                IMaintenanceActivityListener listener) {
1296            return DeviceIdleController.this.registerMaintenanceActivityListener(listener);
1297        }
1298
1299        @Override public void unregisterMaintenanceActivityListener(
1300                IMaintenanceActivityListener listener) {
1301            DeviceIdleController.this.unregisterMaintenanceActivityListener(listener);
1302        }
1303
1304        @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1305            DeviceIdleController.this.dump(fd, pw, args);
1306        }
1307
1308        @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
1309                FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
1310            (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
1311        }
1312    }
1313
1314    public class LocalService {
1315        // duration in milliseconds
1316        public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
1317                long duration, int userId, boolean sync, String reason) {
1318            addPowerSaveTempWhitelistAppInternal(callingUid, packageName, duration,
1319                    userId, sync, reason);
1320        }
1321
1322        // duration in milliseconds
1323        public void addPowerSaveTempWhitelistAppDirect(int appId, long duration, boolean sync,
1324                String reason) {
1325            addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration, sync, reason);
1326        }
1327
1328        // duration in milliseconds
1329        public long getNotificationWhitelistDuration() {
1330            return mConstants.NOTIFICATION_WHITELIST_DURATION;
1331        }
1332
1333        public void setJobsActive(boolean active) {
1334            DeviceIdleController.this.setJobsActive(active);
1335        }
1336
1337        // Up-call from alarm manager.
1338        public void setAlarmsActive(boolean active) {
1339            DeviceIdleController.this.setAlarmsActive(active);
1340        }
1341
1342        /** Is the app on any of the power save whitelists, whether system or user? */
1343        public boolean isAppOnWhitelist(int appid) {
1344            return DeviceIdleController.this.isAppOnWhitelistInternal(appid);
1345        }
1346
1347        /**
1348         * Returns the array of app ids whitelisted by user. Take care not to
1349         * modify this, as it is a reference to the original copy. But the reference
1350         * can change when the list changes, so it needs to be re-acquired when
1351         * {@link PowerManager#ACTION_POWER_SAVE_WHITELIST_CHANGED} is sent.
1352         */
1353        public int[] getPowerSaveWhitelistUserAppIds() {
1354            return DeviceIdleController.this.getPowerSaveWhitelistUserAppIds();
1355        }
1356
1357        public int[] getPowerSaveTempWhitelistAppIds() {
1358            return DeviceIdleController.this.getAppIdTempWhitelistInternal();
1359        }
1360    }
1361
1362    private ActivityManagerInternal.ScreenObserver mScreenObserver =
1363            new ActivityManagerInternal.ScreenObserver() {
1364                @Override
1365                public void onAwakeStateChanged(boolean isAwake) { }
1366
1367                @Override
1368                public void onKeyguardStateChanged(boolean isShowing) {
1369                    synchronized (DeviceIdleController.this) {
1370                        DeviceIdleController.this.keyguardShowingLocked(isShowing);
1371                    }
1372                }
1373            };
1374
1375    public DeviceIdleController(Context context) {
1376        super(context);
1377        mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
1378        mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
1379        mAppStateTracker = new AppStateTracker(context, FgThread.get().getLooper());
1380        LocalServices.addService(AppStateTracker.class, mAppStateTracker);
1381    }
1382
1383    boolean isAppOnWhitelistInternal(int appid) {
1384        synchronized (this) {
1385            return Arrays.binarySearch(mPowerSaveWhitelistAllAppIdArray, appid) >= 0;
1386        }
1387    }
1388
1389    int[] getPowerSaveWhitelistUserAppIds() {
1390        synchronized (this) {
1391            return mPowerSaveWhitelistUserAppIdArray;
1392        }
1393    }
1394
1395    private static File getSystemDir() {
1396        return new File(Environment.getDataDirectory(), "system");
1397    }
1398
1399    @Override
1400    public void onStart() {
1401        final PackageManager pm = getContext().getPackageManager();
1402
1403        synchronized (this) {
1404            mLightEnabled = mDeepEnabled = getContext().getResources().getBoolean(
1405                    com.android.internal.R.bool.config_enableAutoPowerModes);
1406            SystemConfig sysConfig = SystemConfig.getInstance();
1407            ArraySet<String> allowPowerExceptIdle = sysConfig.getAllowInPowerSaveExceptIdle();
1408            for (int i=0; i<allowPowerExceptIdle.size(); i++) {
1409                String pkg = allowPowerExceptIdle.valueAt(i);
1410                try {
1411                    ApplicationInfo ai = pm.getApplicationInfo(pkg,
1412                            PackageManager.MATCH_SYSTEM_ONLY);
1413                    int appid = UserHandle.getAppId(ai.uid);
1414                    mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
1415                    mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
1416                } catch (PackageManager.NameNotFoundException e) {
1417                }
1418            }
1419            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
1420            for (int i=0; i<allowPower.size(); i++) {
1421                String pkg = allowPower.valueAt(i);
1422                try {
1423                    ApplicationInfo ai = pm.getApplicationInfo(pkg,
1424                            PackageManager.MATCH_SYSTEM_ONLY);
1425                    int appid = UserHandle.getAppId(ai.uid);
1426                    // These apps are on both the whitelist-except-idle as well
1427                    // as the full whitelist, so they apply in all cases.
1428                    mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
1429                    mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
1430                    mPowerSaveWhitelistApps.put(ai.packageName, appid);
1431                    mPowerSaveWhitelistSystemAppIds.put(appid, true);
1432                } catch (PackageManager.NameNotFoundException e) {
1433                }
1434            }
1435
1436            mConstants = new Constants(mHandler, getContext().getContentResolver());
1437
1438            readConfigFileLocked();
1439            updateWhitelistAppIdsLocked();
1440
1441            mNetworkConnected = true;
1442            mScreenOn = true;
1443            mScreenLocked = false;
1444            // Start out assuming we are charging.  If we aren't, we will at least get
1445            // a battery update the next time the level drops.
1446            mCharging = true;
1447            mState = STATE_ACTIVE;
1448            mLightState = LIGHT_STATE_ACTIVE;
1449            mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
1450        }
1451
1452        mBinderService = new BinderService();
1453        publishBinderService(Context.DEVICE_IDLE_CONTROLLER, mBinderService);
1454        publishLocalService(LocalService.class, new LocalService());
1455    }
1456
1457    @Override
1458    public void onBootPhase(int phase) {
1459        if (phase == PHASE_SYSTEM_SERVICES_READY) {
1460            synchronized (this) {
1461                mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1462                mBatteryStats = BatteryStatsService.getService();
1463                mLocalActivityManager = getLocalService(ActivityManagerInternal.class);
1464                mLocalPowerManager = getLocalService(PowerManagerInternal.class);
1465                mPowerManager = getContext().getSystemService(PowerManager.class);
1466                mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
1467                        "deviceidle_maint");
1468                mActiveIdleWakeLock.setReferenceCounted(false);
1469                mGoingIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
1470                        "deviceidle_going_idle");
1471                mGoingIdleWakeLock.setReferenceCounted(true);
1472                mConnectivityService = (ConnectivityService)ServiceManager.getService(
1473                        Context.CONNECTIVITY_SERVICE);
1474                mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
1475                        ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
1476                mNetworkPolicyManagerInternal = getLocalService(NetworkPolicyManagerInternal.class);
1477                mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
1478                int sigMotionSensorId = getContext().getResources().getInteger(
1479                        com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);
1480                if (sigMotionSensorId > 0) {
1481                    mMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
1482                }
1483                if (mMotionSensor == null && getContext().getResources().getBoolean(
1484                        com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) {
1485                    mMotionSensor = mSensorManager.getDefaultSensor(
1486                            Sensor.TYPE_WRIST_TILT_GESTURE, true);
1487                }
1488                if (mMotionSensor == null) {
1489                    // As a last ditch, fall back to SMD.
1490                    mMotionSensor = mSensorManager.getDefaultSensor(
1491                            Sensor.TYPE_SIGNIFICANT_MOTION, true);
1492                }
1493
1494                if (getContext().getResources().getBoolean(
1495                        com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
1496                    mLocationManager = (LocationManager) getContext().getSystemService(
1497                            Context.LOCATION_SERVICE);
1498                    mLocationRequest = new LocationRequest()
1499                        .setQuality(LocationRequest.ACCURACY_FINE)
1500                        .setInterval(0)
1501                        .setFastestInterval(0)
1502                        .setNumUpdates(1);
1503                }
1504
1505                float angleThreshold = getContext().getResources().getInteger(
1506                        com.android.internal.R.integer.config_autoPowerModeThresholdAngle) / 100f;
1507                mAnyMotionDetector = new AnyMotionDetector(
1508                        (PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
1509                        mHandler, mSensorManager, this, angleThreshold);
1510
1511                mAppStateTracker.onSystemServicesReady();
1512
1513                mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
1514                mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
1515                        | Intent.FLAG_RECEIVER_FOREGROUND);
1516                mLightIdleIntent = new Intent(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
1517                mLightIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
1518                        | Intent.FLAG_RECEIVER_FOREGROUND);
1519
1520                IntentFilter filter = new IntentFilter();
1521                filter.addAction(Intent.ACTION_BATTERY_CHANGED);
1522                getContext().registerReceiver(mReceiver, filter);
1523
1524                filter = new IntentFilter();
1525                filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1526                filter.addDataScheme("package");
1527                getContext().registerReceiver(mReceiver, filter);
1528
1529                filter = new IntentFilter();
1530                filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
1531                getContext().registerReceiver(mReceiver, filter);
1532
1533                filter = new IntentFilter();
1534                filter.addAction(Intent.ACTION_SCREEN_OFF);
1535                filter.addAction(Intent.ACTION_SCREEN_ON);
1536                getContext().registerReceiver(mInteractivityReceiver, filter);
1537
1538                mLocalActivityManager.setDeviceIdleWhitelist(
1539                        mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
1540                mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
1541
1542                mLocalActivityManager.registerScreenObserver(mScreenObserver);
1543
1544                passWhiteListsToForceAppStandbyTrackerLocked();
1545                updateInteractivityLocked();
1546            }
1547            updateConnectivityState(null);
1548        }
1549    }
1550
1551    public boolean addPowerSaveWhitelistAppInternal(String name) {
1552        synchronized (this) {
1553            try {
1554                ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name,
1555                        PackageManager.MATCH_ANY_USER);
1556                if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid)) == null) {
1557                    reportPowerSaveWhitelistChangedLocked();
1558                    updateWhitelistAppIdsLocked();
1559                    writeConfigFileLocked();
1560                }
1561                return true;
1562            } catch (PackageManager.NameNotFoundException e) {
1563                return false;
1564            }
1565        }
1566    }
1567
1568    public boolean removePowerSaveWhitelistAppInternal(String name) {
1569        synchronized (this) {
1570            if (mPowerSaveWhitelistUserApps.remove(name) != null) {
1571                reportPowerSaveWhitelistChangedLocked();
1572                updateWhitelistAppIdsLocked();
1573                writeConfigFileLocked();
1574                return true;
1575            }
1576        }
1577        return false;
1578    }
1579
1580    public boolean getPowerSaveWhitelistAppInternal(String name) {
1581        synchronized (this) {
1582            return mPowerSaveWhitelistUserApps.containsKey(name);
1583        }
1584    }
1585
1586    void resetSystemPowerWhitelistInternal() {
1587        synchronized (this) {
1588            mPowerSaveWhitelistApps.putAll(mRemovedFromSystemWhitelistApps);
1589            mRemovedFromSystemWhitelistApps.clear();
1590            reportPowerSaveWhitelistChangedLocked();
1591            updateWhitelistAppIdsLocked();
1592            writeConfigFileLocked();
1593        }
1594    }
1595
1596    public boolean restoreSystemPowerWhitelistAppInternal(String name) {
1597        synchronized (this) {
1598            if (!mRemovedFromSystemWhitelistApps.containsKey(name)) {
1599                return false;
1600            }
1601            mPowerSaveWhitelistApps.put(name, mRemovedFromSystemWhitelistApps.remove(name));
1602            reportPowerSaveWhitelistChangedLocked();
1603            updateWhitelistAppIdsLocked();
1604            writeConfigFileLocked();
1605            return true;
1606        }
1607    }
1608
1609    public boolean removeSystemPowerWhitelistAppInternal(String name) {
1610        synchronized (this) {
1611            if (!mPowerSaveWhitelistApps.containsKey(name)) {
1612                return false;
1613            }
1614            mRemovedFromSystemWhitelistApps.put(name, mPowerSaveWhitelistApps.remove(name));
1615            reportPowerSaveWhitelistChangedLocked();
1616            updateWhitelistAppIdsLocked();
1617            writeConfigFileLocked();
1618            return true;
1619        }
1620    }
1621
1622    public boolean addPowerSaveWhitelistExceptIdleInternal(String name) {
1623        synchronized (this) {
1624            try {
1625                final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name,
1626                        PackageManager.MATCH_ANY_USER);
1627                if (mPowerSaveWhitelistAppsExceptIdle.put(name, UserHandle.getAppId(ai.uid))
1628                        == null) {
1629                    mPowerSaveWhitelistUserAppsExceptIdle.add(name);
1630                    reportPowerSaveWhitelistChangedLocked();
1631                    mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray(
1632                            mPowerSaveWhitelistAppsExceptIdle, mPowerSaveWhitelistUserApps,
1633                            mPowerSaveWhitelistExceptIdleAppIds);
1634
1635                    passWhiteListsToForceAppStandbyTrackerLocked();
1636                }
1637                return true;
1638            } catch (PackageManager.NameNotFoundException e) {
1639                return false;
1640            }
1641        }
1642    }
1643
1644    public void resetPowerSaveWhitelistExceptIdleInternal() {
1645        synchronized (this) {
1646            if (mPowerSaveWhitelistAppsExceptIdle.removeAll(
1647                    mPowerSaveWhitelistUserAppsExceptIdle)) {
1648                reportPowerSaveWhitelistChangedLocked();
1649                mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray(
1650                        mPowerSaveWhitelistAppsExceptIdle, mPowerSaveWhitelistUserApps,
1651                        mPowerSaveWhitelistExceptIdleAppIds);
1652                mPowerSaveWhitelistUserAppsExceptIdle.clear();
1653
1654                passWhiteListsToForceAppStandbyTrackerLocked();
1655            }
1656        }
1657    }
1658
1659    public boolean getPowerSaveWhitelistExceptIdleInternal(String name) {
1660        synchronized (this) {
1661            return mPowerSaveWhitelistAppsExceptIdle.containsKey(name);
1662        }
1663    }
1664
1665    public String[] getSystemPowerWhitelistExceptIdleInternal() {
1666        synchronized (this) {
1667            int size = mPowerSaveWhitelistAppsExceptIdle.size();
1668            String[] apps = new String[size];
1669            for (int i = 0; i < size; i++) {
1670                apps[i] = mPowerSaveWhitelistAppsExceptIdle.keyAt(i);
1671            }
1672            return apps;
1673        }
1674    }
1675
1676    public String[] getSystemPowerWhitelistInternal() {
1677        synchronized (this) {
1678            int size = mPowerSaveWhitelistApps.size();
1679            String[] apps = new String[size];
1680            for (int i = 0; i < size; i++) {
1681                apps[i] = mPowerSaveWhitelistApps.keyAt(i);
1682            }
1683            return apps;
1684        }
1685    }
1686
1687    public String[] getRemovedSystemPowerWhitelistAppsInternal() {
1688        synchronized (this) {
1689            int size = mRemovedFromSystemWhitelistApps.size();
1690            final String[] apps = new String[size];
1691            for (int i = 0; i < size; i++) {
1692                apps[i] = mRemovedFromSystemWhitelistApps.keyAt(i);
1693            }
1694            return apps;
1695        }
1696    }
1697
1698    public String[] getUserPowerWhitelistInternal() {
1699        synchronized (this) {
1700            int size = mPowerSaveWhitelistUserApps.size();
1701            String[] apps = new String[size];
1702            for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
1703                apps[i] = mPowerSaveWhitelistUserApps.keyAt(i);
1704            }
1705            return apps;
1706        }
1707    }
1708
1709    public String[] getFullPowerWhitelistExceptIdleInternal() {
1710        synchronized (this) {
1711            int size = mPowerSaveWhitelistAppsExceptIdle.size() + mPowerSaveWhitelistUserApps.size();
1712            String[] apps = new String[size];
1713            int cur = 0;
1714            for (int i = 0; i < mPowerSaveWhitelistAppsExceptIdle.size(); i++) {
1715                apps[cur] = mPowerSaveWhitelistAppsExceptIdle.keyAt(i);
1716                cur++;
1717            }
1718            for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
1719                apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i);
1720                cur++;
1721            }
1722            return apps;
1723        }
1724    }
1725
1726    public String[] getFullPowerWhitelistInternal() {
1727        synchronized (this) {
1728            int size = mPowerSaveWhitelistApps.size() + mPowerSaveWhitelistUserApps.size();
1729            String[] apps = new String[size];
1730            int cur = 0;
1731            for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) {
1732                apps[cur] = mPowerSaveWhitelistApps.keyAt(i);
1733                cur++;
1734            }
1735            for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
1736                apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i);
1737                cur++;
1738            }
1739            return apps;
1740        }
1741    }
1742
1743    public boolean isPowerSaveWhitelistExceptIdleAppInternal(String packageName) {
1744        synchronized (this) {
1745            return mPowerSaveWhitelistAppsExceptIdle.containsKey(packageName)
1746                    || mPowerSaveWhitelistUserApps.containsKey(packageName);
1747        }
1748    }
1749
1750    public boolean isPowerSaveWhitelistAppInternal(String packageName) {
1751        synchronized (this) {
1752            return mPowerSaveWhitelistApps.containsKey(packageName)
1753                    || mPowerSaveWhitelistUserApps.containsKey(packageName);
1754        }
1755    }
1756
1757    public int[] getAppIdWhitelistExceptIdleInternal() {
1758        synchronized (this) {
1759            return mPowerSaveWhitelistExceptIdleAppIdArray;
1760        }
1761    }
1762
1763    public int[] getAppIdWhitelistInternal() {
1764        synchronized (this) {
1765            return mPowerSaveWhitelistAllAppIdArray;
1766        }
1767    }
1768
1769    public int[] getAppIdUserWhitelistInternal() {
1770        synchronized (this) {
1771            return mPowerSaveWhitelistUserAppIdArray;
1772        }
1773    }
1774
1775    public int[] getAppIdTempWhitelistInternal() {
1776        synchronized (this) {
1777            return mTempWhitelistAppIdArray;
1778        }
1779    }
1780
1781    void addPowerSaveTempWhitelistAppChecked(String packageName, long duration,
1782            int userId, String reason) throws RemoteException {
1783        getContext().enforceCallingPermission(
1784                Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
1785                "No permission to change device idle whitelist");
1786        final int callingUid = Binder.getCallingUid();
1787        userId = ActivityManager.getService().handleIncomingUser(
1788                Binder.getCallingPid(),
1789                callingUid,
1790                userId,
1791                /*allowAll=*/ false,
1792                /*requireFull=*/ false,
1793                "addPowerSaveTempWhitelistApp", null);
1794        final long token = Binder.clearCallingIdentity();
1795        try {
1796            addPowerSaveTempWhitelistAppInternal(callingUid,
1797                    packageName, duration, userId, true, reason);
1798        } finally {
1799            Binder.restoreCallingIdentity(token);
1800        }
1801    }
1802
1803    void removePowerSaveTempWhitelistAppChecked(String packageName, int userId)
1804            throws RemoteException {
1805        getContext().enforceCallingPermission(
1806                Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
1807                "No permission to change device idle whitelist");
1808        final int callingUid = Binder.getCallingUid();
1809        userId = ActivityManager.getService().handleIncomingUser(
1810                Binder.getCallingPid(),
1811                callingUid,
1812                userId,
1813                /*allowAll=*/ false,
1814                /*requireFull=*/ false,
1815                "removePowerSaveTempWhitelistApp", null);
1816        final long token = Binder.clearCallingIdentity();
1817        try {
1818            removePowerSaveTempWhitelistAppInternal(packageName, userId);
1819        } finally {
1820            Binder.restoreCallingIdentity(token);
1821        }
1822    }
1823
1824    /**
1825     * Adds an app to the temporary whitelist and resets the endTime for granting the
1826     * app an exemption to access network and acquire wakelocks.
1827     */
1828    void addPowerSaveTempWhitelistAppInternal(int callingUid, String packageName,
1829            long duration, int userId, boolean sync, String reason) {
1830        try {
1831            int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId);
1832            int appId = UserHandle.getAppId(uid);
1833            addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration, sync, reason);
1834        } catch (NameNotFoundException e) {
1835        }
1836    }
1837
1838    /**
1839     * Adds an app to the temporary whitelist and resets the endTime for granting the
1840     * app an exemption to access network and acquire wakelocks.
1841     */
1842    void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int appId,
1843            long duration, boolean sync, String reason) {
1844        final long timeNow = SystemClock.elapsedRealtime();
1845        boolean informWhitelistChanged = false;
1846        synchronized (this) {
1847            int callingAppId = UserHandle.getAppId(callingUid);
1848            if (callingAppId >= Process.FIRST_APPLICATION_UID) {
1849                if (!mPowerSaveWhitelistSystemAppIds.get(callingAppId)) {
1850                    throw new SecurityException("Calling app " + UserHandle.formatUid(callingUid)
1851                            + " is not on whitelist");
1852                }
1853            }
1854            duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION);
1855            Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(appId);
1856            final boolean newEntry = entry == null;
1857            // Set the new end time
1858            if (newEntry) {
1859                entry = new Pair<>(new MutableLong(0), reason);
1860                mTempWhitelistAppIdEndTimes.put(appId, entry);
1861            }
1862            entry.first.value = timeNow + duration;
1863            if (DEBUG) {
1864                Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist. New entry: " + newEntry);
1865            }
1866            if (newEntry) {
1867                // No pending timeout for the app id, post a delayed message
1868                try {
1869                    mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_START,
1870                            reason, appId);
1871                } catch (RemoteException e) {
1872                }
1873                postTempActiveTimeoutMessage(appId, duration);
1874                updateTempWhitelistAppIdsLocked(appId, true);
1875                if (sync) {
1876                    informWhitelistChanged = true;
1877                } else {
1878                    mHandler.obtainMessage(MSG_REPORT_TEMP_APP_WHITELIST_CHANGED, appId, 1)
1879                            .sendToTarget();
1880                }
1881                reportTempWhitelistChangedLocked();
1882            }
1883        }
1884        if (informWhitelistChanged) {
1885            mNetworkPolicyManagerInternal.onTempPowerSaveWhitelistChange(appId, true);
1886        }
1887    }
1888
1889    /**
1890     * Removes an app from the temporary whitelist and notifies the observers.
1891     */
1892    private void removePowerSaveTempWhitelistAppInternal(String packageName, int userId) {
1893        try {
1894            final int uid = getContext().getPackageManager().getPackageUidAsUser(
1895                    packageName, userId);
1896            final int appId = UserHandle.getAppId(uid);
1897            removePowerSaveTempWhitelistAppDirectInternal(appId);
1898        } catch (NameNotFoundException e) {
1899        }
1900    }
1901
1902    private void removePowerSaveTempWhitelistAppDirectInternal(int appId) {
1903        synchronized (this) {
1904            final int idx = mTempWhitelistAppIdEndTimes.indexOfKey(appId);
1905            if (idx < 0) {
1906                // Nothing else to do
1907                return;
1908            }
1909            final String reason = mTempWhitelistAppIdEndTimes.valueAt(idx).second;
1910            mTempWhitelistAppIdEndTimes.removeAt(idx);
1911            onAppRemovedFromTempWhitelistLocked(appId, reason);
1912        }
1913    }
1914
1915    private void postTempActiveTimeoutMessage(int uid, long delay) {
1916        if (DEBUG) {
1917            Slog.d(TAG, "postTempActiveTimeoutMessage: uid=" + uid + ", delay=" + delay);
1918        }
1919        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, uid, 0),
1920                delay);
1921    }
1922
1923    void checkTempAppWhitelistTimeout(int uid) {
1924        final long timeNow = SystemClock.elapsedRealtime();
1925        if (DEBUG) {
1926            Slog.d(TAG, "checkTempAppWhitelistTimeout: uid=" + uid + ", timeNow=" + timeNow);
1927        }
1928        synchronized (this) {
1929            Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(uid);
1930            if (entry == null) {
1931                // Nothing to do
1932                return;
1933            }
1934            if (timeNow >= entry.first.value) {
1935                mTempWhitelistAppIdEndTimes.delete(uid);
1936                onAppRemovedFromTempWhitelistLocked(uid, entry.second);
1937            } else {
1938                // Need more time
1939                if (DEBUG) {
1940                    Slog.d(TAG, "Time to remove UID " + uid + ": " + entry.first.value);
1941                }
1942                postTempActiveTimeoutMessage(uid, entry.first.value - timeNow);
1943            }
1944        }
1945    }
1946
1947    @GuardedBy("this")
1948    private void onAppRemovedFromTempWhitelistLocked(int appId, String reason) {
1949        if (DEBUG) {
1950            Slog.d(TAG, "Removing appId " + appId + " from temp whitelist");
1951        }
1952        updateTempWhitelistAppIdsLocked(appId, false);
1953        mHandler.obtainMessage(MSG_REPORT_TEMP_APP_WHITELIST_CHANGED, appId, 0)
1954                .sendToTarget();
1955        reportTempWhitelistChangedLocked();
1956        try {
1957            mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_FINISH,
1958                    reason, appId);
1959        } catch (RemoteException e) {
1960        }
1961    }
1962
1963    public void exitIdleInternal(String reason) {
1964        synchronized (this) {
1965            becomeActiveLocked(reason, Binder.getCallingUid());
1966        }
1967    }
1968
1969    void updateConnectivityState(Intent connIntent) {
1970        ConnectivityService cm;
1971        synchronized (this) {
1972            cm = mConnectivityService;
1973        }
1974        if (cm == null) {
1975            return;
1976        }
1977        // Note: can't call out to ConnectivityService with our lock held.
1978        NetworkInfo ni = cm.getActiveNetworkInfo();
1979        synchronized (this) {
1980            boolean conn;
1981            if (ni == null) {
1982                conn = false;
1983            } else {
1984                if (connIntent == null) {
1985                    conn = ni.isConnected();
1986                } else {
1987                    final int networkType =
1988                            connIntent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
1989                                    ConnectivityManager.TYPE_NONE);
1990                    if (ni.getType() != networkType) {
1991                        return;
1992                    }
1993                    conn = !connIntent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
1994                            false);
1995                }
1996            }
1997            if (conn != mNetworkConnected) {
1998                mNetworkConnected = conn;
1999                if (conn && mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
2000                    stepLightIdleStateLocked("network");
2001                }
2002            }
2003        }
2004    }
2005
2006    void updateInteractivityLocked() {
2007        // The interactivity state from the power manager tells us whether the display is
2008        // in a state that we need to keep things running so they will update at a normal
2009        // frequency.
2010        boolean screenOn = mPowerManager.isInteractive();
2011        if (DEBUG) Slog.d(TAG, "updateInteractivityLocked: screenOn=" + screenOn);
2012        if (!screenOn && mScreenOn) {
2013            mScreenOn = false;
2014            if (!mForceIdle) {
2015                becomeInactiveIfAppropriateLocked();
2016            }
2017        } else if (screenOn) {
2018            mScreenOn = true;
2019            if (!mForceIdle && (!mScreenLocked || !mConstants.WAIT_FOR_UNLOCK)) {
2020                becomeActiveLocked("screen", Process.myUid());
2021            }
2022        }
2023    }
2024
2025    void updateChargingLocked(boolean charging) {
2026        if (DEBUG) Slog.i(TAG, "updateChargingLocked: charging=" + charging);
2027        if (!charging && mCharging) {
2028            mCharging = false;
2029            if (!mForceIdle) {
2030                becomeInactiveIfAppropriateLocked();
2031            }
2032        } else if (charging) {
2033            mCharging = charging;
2034            if (!mForceIdle) {
2035                becomeActiveLocked("charging", Process.myUid());
2036            }
2037        }
2038    }
2039
2040    void keyguardShowingLocked(boolean showing) {
2041        if (DEBUG) Slog.i(TAG, "keyguardShowing=" + showing);
2042        if (mScreenLocked != showing) {
2043            mScreenLocked = showing;
2044            if (mScreenOn && !mForceIdle && !mScreenLocked) {
2045                becomeActiveLocked("unlocked", Process.myUid());
2046            }
2047        }
2048    }
2049
2050    void scheduleReportActiveLocked(String activeReason, int activeUid) {
2051        Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, activeUid, 0, activeReason);
2052        mHandler.sendMessage(msg);
2053    }
2054
2055    void becomeActiveLocked(String activeReason, int activeUid) {
2056        if (DEBUG) Slog.i(TAG, "becomeActiveLocked, reason = " + activeReason);
2057        if (mState != STATE_ACTIVE || mLightState != STATE_ACTIVE) {
2058            EventLogTags.writeDeviceIdle(STATE_ACTIVE, activeReason);
2059            EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason);
2060            scheduleReportActiveLocked(activeReason, activeUid);
2061            mState = STATE_ACTIVE;
2062            mLightState = LIGHT_STATE_ACTIVE;
2063            mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
2064            mCurIdleBudget = 0;
2065            mMaintenanceStartTime = 0;
2066            resetIdleManagementLocked();
2067            resetLightIdleManagementLocked();
2068            addEvent(EVENT_NORMAL, activeReason);
2069        }
2070    }
2071
2072    void becomeInactiveIfAppropriateLocked() {
2073        if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
2074        if ((!mScreenOn && !mCharging) || mForceIdle) {
2075            // Screen has turned off; we are now going to become inactive and start
2076            // waiting to see if we will ultimately go idle.
2077            if (mState == STATE_ACTIVE && mDeepEnabled) {
2078                mState = STATE_INACTIVE;
2079                if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
2080                resetIdleManagementLocked();
2081                scheduleAlarmLocked(mInactiveTimeout, false);
2082                EventLogTags.writeDeviceIdle(mState, "no activity");
2083            }
2084            if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
2085                mLightState = LIGHT_STATE_INACTIVE;
2086                if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
2087                resetLightIdleManagementLocked();
2088                scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
2089                EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
2090            }
2091        }
2092    }
2093
2094    void resetIdleManagementLocked() {
2095        mNextIdlePendingDelay = 0;
2096        mNextIdleDelay = 0;
2097        mNextLightIdleDelay = 0;
2098        cancelAlarmLocked();
2099        cancelSensingTimeoutAlarmLocked();
2100        cancelLocatingLocked();
2101        stopMonitoringMotionLocked();
2102        mAnyMotionDetector.stop();
2103    }
2104
2105    void resetLightIdleManagementLocked() {
2106        cancelLightAlarmLocked();
2107    }
2108
2109    void exitForceIdleLocked() {
2110        if (mForceIdle) {
2111            mForceIdle = false;
2112            if (mScreenOn || mCharging) {
2113                becomeActiveLocked("exit-force", Process.myUid());
2114            }
2115        }
2116    }
2117
2118    void stepLightIdleStateLocked(String reason) {
2119        if (mLightState == LIGHT_STATE_OVERRIDE) {
2120            // If we are already in deep device idle mode, then
2121            // there is nothing left to do for light mode.
2122            return;
2123        }
2124
2125        if (DEBUG) Slog.d(TAG, "stepLightIdleStateLocked: mLightState=" + mLightState);
2126        EventLogTags.writeDeviceIdleLightStep();
2127
2128        switch (mLightState) {
2129            case LIGHT_STATE_INACTIVE:
2130                mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
2131                // Reset the upcoming idle delays.
2132                mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
2133                mMaintenanceStartTime = 0;
2134                if (!isOpsInactiveLocked()) {
2135                    // We have some active ops going on...  give them a chance to finish
2136                    // before going in to our first idle.
2137                    mLightState = LIGHT_STATE_PRE_IDLE;
2138                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
2139                    scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT);
2140                    break;
2141                }
2142                // Nothing active, fall through to immediately idle.
2143            case LIGHT_STATE_PRE_IDLE:
2144            case LIGHT_STATE_IDLE_MAINTENANCE:
2145                if (mMaintenanceStartTime != 0) {
2146                    long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;
2147                    if (duration < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
2148                        // We didn't use up all of our minimum budget; add this to the reserve.
2149                        mCurIdleBudget += (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET-duration);
2150                    } else {
2151                        // We used more than our minimum budget; this comes out of the reserve.
2152                        mCurIdleBudget -= (duration-mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
2153                    }
2154                }
2155                mMaintenanceStartTime = 0;
2156                scheduleLightAlarmLocked(mNextLightIdleDelay);
2157                mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
2158                        (long)(mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
2159                if (mNextLightIdleDelay < mConstants.LIGHT_IDLE_TIMEOUT) {
2160                    mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
2161                }
2162                if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
2163                mLightState = LIGHT_STATE_IDLE;
2164                EventLogTags.writeDeviceIdleLight(mLightState, reason);
2165                addEvent(EVENT_LIGHT_IDLE, null);
2166                mGoingIdleWakeLock.acquire();
2167                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
2168                break;
2169            case LIGHT_STATE_IDLE:
2170            case LIGHT_STATE_WAITING_FOR_NETWORK:
2171                if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
2172                    // We have been idling long enough, now it is time to do some work.
2173                    mActiveIdleOpCount = 1;
2174                    mActiveIdleWakeLock.acquire();
2175                    mMaintenanceStartTime = SystemClock.elapsedRealtime();
2176                    if (mCurIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
2177                        mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
2178                    } else if (mCurIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
2179                        mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
2180                    }
2181                    scheduleLightAlarmLocked(mCurIdleBudget);
2182                    if (DEBUG) Slog.d(TAG,
2183                            "Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
2184                    mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
2185                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
2186                    addEvent(EVENT_LIGHT_MAINTENANCE, null);
2187                    mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
2188                } else {
2189                    // We'd like to do maintenance, but currently don't have network
2190                    // connectivity...  let's try to wait until the network comes back.
2191                    // We'll only wait for another full idle period, however, and then give up.
2192                    scheduleLightAlarmLocked(mNextLightIdleDelay);
2193                    if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK.");
2194                    mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;
2195                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
2196                }
2197                break;
2198        }
2199    }
2200
2201    void stepIdleStateLocked(String reason) {
2202        if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
2203        EventLogTags.writeDeviceIdleStep();
2204
2205        final long now = SystemClock.elapsedRealtime();
2206        if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
2207            // Whoops, there is an upcoming alarm.  We don't actually want to go idle.
2208            if (mState != STATE_ACTIVE) {
2209                becomeActiveLocked("alarm", Process.myUid());
2210                becomeInactiveIfAppropriateLocked();
2211            }
2212            return;
2213        }
2214
2215        switch (mState) {
2216            case STATE_INACTIVE:
2217                // We have now been inactive long enough, it is time to start looking
2218                // for motion and sleep some more while doing so.
2219                startMonitoringMotionLocked();
2220                scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
2221                // Reset the upcoming idle delays.
2222                mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
2223                mNextIdleDelay = mConstants.IDLE_TIMEOUT;
2224                mState = STATE_IDLE_PENDING;
2225                if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");
2226                EventLogTags.writeDeviceIdle(mState, reason);
2227                break;
2228            case STATE_IDLE_PENDING:
2229                mState = STATE_SENSING;
2230                if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING.");
2231                EventLogTags.writeDeviceIdle(mState, reason);
2232                scheduleSensingTimeoutAlarmLocked(mConstants.SENSING_TIMEOUT);
2233                cancelLocatingLocked();
2234                mNotMoving = false;
2235                mLocated = false;
2236                mLastGenericLocation = null;
2237                mLastGpsLocation = null;
2238                mAnyMotionDetector.checkForAnyMotion();
2239                break;
2240            case STATE_SENSING:
2241                cancelSensingTimeoutAlarmLocked();
2242                mState = STATE_LOCATING;
2243                if (DEBUG) Slog.d(TAG, "Moved from STATE_SENSING to STATE_LOCATING.");
2244                EventLogTags.writeDeviceIdle(mState, reason);
2245                scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT, false);
2246                if (mLocationManager != null
2247                        && mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
2248                    mLocationManager.requestLocationUpdates(mLocationRequest,
2249                            mGenericLocationListener, mHandler.getLooper());
2250                    mLocating = true;
2251                } else {
2252                    mHasNetworkLocation = false;
2253                }
2254                if (mLocationManager != null
2255                        && mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
2256                    mHasGps = true;
2257                    mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
2258                            mGpsLocationListener, mHandler.getLooper());
2259                    mLocating = true;
2260                } else {
2261                    mHasGps = false;
2262                }
2263                // If we have a location provider, we're all set, the listeners will move state
2264                // forward.
2265                if (mLocating) {
2266                    break;
2267                }
2268
2269                // Otherwise, we have to move from locating into idle maintenance.
2270            case STATE_LOCATING:
2271                cancelAlarmLocked();
2272                cancelLocatingLocked();
2273                mAnyMotionDetector.stop();
2274
2275            case STATE_IDLE_MAINTENANCE:
2276                scheduleAlarmLocked(mNextIdleDelay, true);
2277                if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
2278                        " ms.");
2279                mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
2280                if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);
2281                mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);
2282                if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {
2283                    mNextIdleDelay = mConstants.IDLE_TIMEOUT;
2284                }
2285                mState = STATE_IDLE;
2286                if (mLightState != LIGHT_STATE_OVERRIDE) {
2287                    mLightState = LIGHT_STATE_OVERRIDE;
2288                    cancelLightAlarmLocked();
2289                }
2290                EventLogTags.writeDeviceIdle(mState, reason);
2291                addEvent(EVENT_DEEP_IDLE, null);
2292                mGoingIdleWakeLock.acquire();
2293                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
2294                break;
2295            case STATE_IDLE:
2296                // We have been idling long enough, now it is time to do some work.
2297                mActiveIdleOpCount = 1;
2298                mActiveIdleWakeLock.acquire();
2299                scheduleAlarmLocked(mNextIdlePendingDelay, false);
2300                if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
2301                        "Next alarm in " + mNextIdlePendingDelay + " ms.");
2302                mMaintenanceStartTime = SystemClock.elapsedRealtime();
2303                mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,
2304                        (long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
2305                if (mNextIdlePendingDelay < mConstants.IDLE_PENDING_TIMEOUT) {
2306                    mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
2307                }
2308                mState = STATE_IDLE_MAINTENANCE;
2309                EventLogTags.writeDeviceIdle(mState, reason);
2310                addEvent(EVENT_DEEP_MAINTENANCE, null);
2311                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
2312                break;
2313        }
2314    }
2315
2316    void incActiveIdleOps() {
2317        synchronized (this) {
2318            mActiveIdleOpCount++;
2319        }
2320    }
2321
2322    void decActiveIdleOps() {
2323        synchronized (this) {
2324            mActiveIdleOpCount--;
2325            if (mActiveIdleOpCount <= 0) {
2326                exitMaintenanceEarlyIfNeededLocked();
2327                mActiveIdleWakeLock.release();
2328            }
2329        }
2330    }
2331
2332    void setJobsActive(boolean active) {
2333        synchronized (this) {
2334            mJobsActive = active;
2335            reportMaintenanceActivityIfNeededLocked();
2336            if (!active) {
2337                exitMaintenanceEarlyIfNeededLocked();
2338            }
2339        }
2340    }
2341
2342    void setAlarmsActive(boolean active) {
2343        synchronized (this) {
2344            mAlarmsActive = active;
2345            if (!active) {
2346                exitMaintenanceEarlyIfNeededLocked();
2347            }
2348        }
2349    }
2350
2351    boolean registerMaintenanceActivityListener(IMaintenanceActivityListener listener) {
2352        synchronized (this) {
2353            mMaintenanceActivityListeners.register(listener);
2354            return mReportedMaintenanceActivity;
2355        }
2356    }
2357
2358    void unregisterMaintenanceActivityListener(IMaintenanceActivityListener listener) {
2359        synchronized (this) {
2360            mMaintenanceActivityListeners.unregister(listener);
2361        }
2362    }
2363
2364    void reportMaintenanceActivityIfNeededLocked() {
2365        boolean active = mJobsActive;
2366        if (active == mReportedMaintenanceActivity) {
2367            return;
2368        }
2369        mReportedMaintenanceActivity = active;
2370        Message msg = mHandler.obtainMessage(MSG_REPORT_MAINTENANCE_ACTIVITY,
2371                mReportedMaintenanceActivity ? 1 : 0, 0);
2372        mHandler.sendMessage(msg);
2373    }
2374
2375    boolean isOpsInactiveLocked() {
2376        return mActiveIdleOpCount <= 0 && !mJobsActive && !mAlarmsActive;
2377    }
2378
2379    void exitMaintenanceEarlyIfNeededLocked() {
2380        if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE
2381                || mLightState == LIGHT_STATE_PRE_IDLE) {
2382            if (isOpsInactiveLocked()) {
2383                final long now = SystemClock.elapsedRealtime();
2384                if (DEBUG) {
2385                    StringBuilder sb = new StringBuilder();
2386                    sb.append("Exit: start=");
2387                    TimeUtils.formatDuration(mMaintenanceStartTime, sb);
2388                    sb.append(" now=");
2389                    TimeUtils.formatDuration(now, sb);
2390                    Slog.d(TAG, sb.toString());
2391                }
2392                if (mState == STATE_IDLE_MAINTENANCE) {
2393                    stepIdleStateLocked("s:early");
2394                } else if (mLightState == LIGHT_STATE_PRE_IDLE) {
2395                    stepLightIdleStateLocked("s:predone");
2396                } else {
2397                    stepLightIdleStateLocked("s:early");
2398                }
2399            }
2400        }
2401    }
2402
2403    void motionLocked() {
2404        if (DEBUG) Slog.d(TAG, "motionLocked()");
2405        // The motion sensor will have been disabled at this point
2406        handleMotionDetectedLocked(mConstants.MOTION_INACTIVE_TIMEOUT, "motion");
2407    }
2408
2409    void handleMotionDetectedLocked(long timeout, String type) {
2410        // The device is not yet active, so we want to go back to the pending idle
2411        // state to wait again for no motion.  Note that we only monitor for motion
2412        // after moving out of the inactive state, so no need to worry about that.
2413        boolean becomeInactive = false;
2414        if (mState != STATE_ACTIVE) {
2415            // Motion shouldn't affect light state, if it's already in doze-light or maintenance
2416            boolean lightIdle = mLightState == LIGHT_STATE_IDLE
2417                    || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK
2418                    || mLightState == LIGHT_STATE_IDLE_MAINTENANCE;
2419            if (!lightIdle) {
2420                // Only switch to active state if we're not in either idle state
2421                scheduleReportActiveLocked(type, Process.myUid());
2422                addEvent(EVENT_NORMAL, type);
2423            }
2424            mState = STATE_ACTIVE;
2425            mInactiveTimeout = timeout;
2426            mCurIdleBudget = 0;
2427            mMaintenanceStartTime = 0;
2428            EventLogTags.writeDeviceIdle(mState, type);
2429            becomeInactive = true;
2430        }
2431        if (mLightState == LIGHT_STATE_OVERRIDE) {
2432            // We went out of light idle mode because we had started deep idle mode...  let's
2433            // now go back and reset things so we resume light idling if appropriate.
2434            mLightState = LIGHT_STATE_ACTIVE;
2435            EventLogTags.writeDeviceIdleLight(mLightState, type);
2436            becomeInactive = true;
2437        }
2438        if (becomeInactive) {
2439            becomeInactiveIfAppropriateLocked();
2440        }
2441    }
2442
2443    void receivedGenericLocationLocked(Location location) {
2444        if (mState != STATE_LOCATING) {
2445            cancelLocatingLocked();
2446            return;
2447        }
2448        if (DEBUG) Slog.d(TAG, "Generic location: " + location);
2449        mLastGenericLocation = new Location(location);
2450        if (location.getAccuracy() > mConstants.LOCATION_ACCURACY && mHasGps) {
2451            return;
2452        }
2453        mLocated = true;
2454        if (mNotMoving) {
2455            stepIdleStateLocked("s:location");
2456        }
2457    }
2458
2459    void receivedGpsLocationLocked(Location location) {
2460        if (mState != STATE_LOCATING) {
2461            cancelLocatingLocked();
2462            return;
2463        }
2464        if (DEBUG) Slog.d(TAG, "GPS location: " + location);
2465        mLastGpsLocation = new Location(location);
2466        if (location.getAccuracy() > mConstants.LOCATION_ACCURACY) {
2467            return;
2468        }
2469        mLocated = true;
2470        if (mNotMoving) {
2471            stepIdleStateLocked("s:gps");
2472        }
2473    }
2474
2475    void startMonitoringMotionLocked() {
2476        if (DEBUG) Slog.d(TAG, "startMonitoringMotionLocked()");
2477        if (mMotionSensor != null && !mMotionListener.active) {
2478            mMotionListener.registerLocked();
2479        }
2480    }
2481
2482    void stopMonitoringMotionLocked() {
2483        if (DEBUG) Slog.d(TAG, "stopMonitoringMotionLocked()");
2484        if (mMotionSensor != null && mMotionListener.active) {
2485            mMotionListener.unregisterLocked();
2486        }
2487    }
2488
2489    void cancelAlarmLocked() {
2490        if (mNextAlarmTime != 0) {
2491            mNextAlarmTime = 0;
2492            mAlarmManager.cancel(mDeepAlarmListener);
2493        }
2494    }
2495
2496    void cancelLightAlarmLocked() {
2497        if (mNextLightAlarmTime != 0) {
2498            mNextLightAlarmTime = 0;
2499            mAlarmManager.cancel(mLightAlarmListener);
2500        }
2501    }
2502
2503    void cancelLocatingLocked() {
2504        if (mLocating) {
2505            mLocationManager.removeUpdates(mGenericLocationListener);
2506            mLocationManager.removeUpdates(mGpsLocationListener);
2507            mLocating = false;
2508        }
2509    }
2510
2511    void cancelSensingTimeoutAlarmLocked() {
2512        if (mNextSensingTimeoutAlarmTime != 0) {
2513            mNextSensingTimeoutAlarmTime = 0;
2514            mAlarmManager.cancel(mSensingTimeoutAlarmListener);
2515        }
2516    }
2517
2518    void scheduleAlarmLocked(long delay, boolean idleUntil) {
2519        if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
2520        if (mMotionSensor == null) {
2521            // If there is no motion sensor on this device, then we won't schedule
2522            // alarms, because we can't determine if the device is not moving.  This effectively
2523            // turns off normal execution of device idling, although it is still possible to
2524            // manually poke it by pretending like the alarm is going off.
2525            return;
2526        }
2527        mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
2528        if (idleUntil) {
2529            mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
2530                    mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
2531        } else {
2532            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
2533                    mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
2534        }
2535    }
2536
2537    void scheduleLightAlarmLocked(long delay) {
2538        if (DEBUG) Slog.d(TAG, "scheduleLightAlarmLocked(" + delay + ")");
2539        mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay;
2540        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
2541                mNextLightAlarmTime, "DeviceIdleController.light", mLightAlarmListener, mHandler);
2542    }
2543
2544    void scheduleSensingTimeoutAlarmLocked(long delay) {
2545        if (DEBUG) Slog.d(TAG, "scheduleSensingAlarmLocked(" + delay + ")");
2546        mNextSensingTimeoutAlarmTime = SystemClock.elapsedRealtime() + delay;
2547        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextSensingTimeoutAlarmTime,
2548            "DeviceIdleController.sensing", mSensingTimeoutAlarmListener, mHandler);
2549    }
2550
2551    private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps,
2552            ArrayMap<String, Integer> userApps, SparseBooleanArray outAppIds) {
2553        outAppIds.clear();
2554        if (systemApps != null) {
2555            for (int i = 0; i < systemApps.size(); i++) {
2556                outAppIds.put(systemApps.valueAt(i), true);
2557            }
2558        }
2559        if (userApps != null) {
2560            for (int i = 0; i < userApps.size(); i++) {
2561                outAppIds.put(userApps.valueAt(i), true);
2562            }
2563        }
2564        int size = outAppIds.size();
2565        int[] appids = new int[size];
2566        for (int i = 0; i < size; i++) {
2567            appids[i] = outAppIds.keyAt(i);
2568        }
2569        return appids;
2570    }
2571
2572    private void updateWhitelistAppIdsLocked() {
2573        mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray(mPowerSaveWhitelistAppsExceptIdle,
2574                mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds);
2575        mPowerSaveWhitelistAllAppIdArray = buildAppIdArray(mPowerSaveWhitelistApps,
2576                mPowerSaveWhitelistUserApps, mPowerSaveWhitelistAllAppIds);
2577        mPowerSaveWhitelistUserAppIdArray = buildAppIdArray(null,
2578                mPowerSaveWhitelistUserApps, mPowerSaveWhitelistUserAppIds);
2579        if (mLocalActivityManager != null) {
2580            mLocalActivityManager.setDeviceIdleWhitelist(
2581                    mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
2582        }
2583        if (mLocalPowerManager != null) {
2584            if (DEBUG) {
2585                Slog.d(TAG, "Setting wakelock whitelist to "
2586                        + Arrays.toString(mPowerSaveWhitelistAllAppIdArray));
2587            }
2588            mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
2589        }
2590        passWhiteListsToForceAppStandbyTrackerLocked();
2591    }
2592
2593    private void updateTempWhitelistAppIdsLocked(int appId, boolean adding) {
2594        final int size = mTempWhitelistAppIdEndTimes.size();
2595        if (mTempWhitelistAppIdArray.length != size) {
2596            mTempWhitelistAppIdArray = new int[size];
2597        }
2598        for (int i = 0; i < size; i++) {
2599            mTempWhitelistAppIdArray[i] = mTempWhitelistAppIdEndTimes.keyAt(i);
2600        }
2601        if (mLocalActivityManager != null) {
2602            if (DEBUG) {
2603                Slog.d(TAG, "Setting activity manager temp whitelist to "
2604                        + Arrays.toString(mTempWhitelistAppIdArray));
2605            }
2606            mLocalActivityManager.updateDeviceIdleTempWhitelist(mTempWhitelistAppIdArray, appId,
2607                    adding);
2608        }
2609        if (mLocalPowerManager != null) {
2610            if (DEBUG) {
2611                Slog.d(TAG, "Setting wakelock temp whitelist to "
2612                        + Arrays.toString(mTempWhitelistAppIdArray));
2613            }
2614            mLocalPowerManager.setDeviceIdleTempWhitelist(mTempWhitelistAppIdArray);
2615        }
2616        passWhiteListsToForceAppStandbyTrackerLocked();
2617    }
2618
2619    private void reportPowerSaveWhitelistChangedLocked() {
2620        Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
2621        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
2622        getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
2623    }
2624
2625    private void reportTempWhitelistChangedLocked() {
2626        Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
2627        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
2628        getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
2629    }
2630
2631    private void passWhiteListsToForceAppStandbyTrackerLocked() {
2632        mAppStateTracker.setPowerSaveWhitelistAppIds(
2633                mPowerSaveWhitelistExceptIdleAppIdArray,
2634                mPowerSaveWhitelistUserAppIdArray,
2635                mTempWhitelistAppIdArray);
2636    }
2637
2638    void readConfigFileLocked() {
2639        if (DEBUG) Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile());
2640        mPowerSaveWhitelistUserApps.clear();
2641        FileInputStream stream;
2642        try {
2643            stream = mConfigFile.openRead();
2644        } catch (FileNotFoundException e) {
2645            return;
2646        }
2647        try {
2648            XmlPullParser parser = Xml.newPullParser();
2649            parser.setInput(stream, StandardCharsets.UTF_8.name());
2650            readConfigFileLocked(parser);
2651        } catch (XmlPullParserException e) {
2652        } finally {
2653            try {
2654                stream.close();
2655            } catch (IOException e) {
2656            }
2657        }
2658    }
2659
2660    private void readConfigFileLocked(XmlPullParser parser) {
2661        final PackageManager pm = getContext().getPackageManager();
2662
2663        try {
2664            int type;
2665            while ((type = parser.next()) != XmlPullParser.START_TAG
2666                    && type != XmlPullParser.END_DOCUMENT) {
2667                ;
2668            }
2669
2670            if (type != XmlPullParser.START_TAG) {
2671                throw new IllegalStateException("no start tag found");
2672            }
2673
2674            int outerDepth = parser.getDepth();
2675            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2676                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2677                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2678                    continue;
2679                }
2680
2681                String tagName = parser.getName();
2682                switch (tagName) {
2683                    case "wl":
2684                        String name = parser.getAttributeValue(null, "n");
2685                        if (name != null) {
2686                            try {
2687                                ApplicationInfo ai = pm.getApplicationInfo(name,
2688                                        PackageManager.MATCH_ANY_USER);
2689                                mPowerSaveWhitelistUserApps.put(ai.packageName,
2690                                        UserHandle.getAppId(ai.uid));
2691                            } catch (PackageManager.NameNotFoundException e) {
2692                            }
2693                        }
2694                        break;
2695                    case "un-wl":
2696                        final String packageName = parser.getAttributeValue(null, "n");
2697                        if (mPowerSaveWhitelistApps.containsKey(packageName)) {
2698                            mRemovedFromSystemWhitelistApps.put(packageName,
2699                                    mPowerSaveWhitelistApps.remove(packageName));
2700                        }
2701                        break;
2702                    default:
2703                        Slog.w(TAG, "Unknown element under <config>: "
2704                                + parser.getName());
2705                        XmlUtils.skipCurrentTag(parser);
2706                        break;
2707                }
2708            }
2709
2710        } catch (IllegalStateException e) {
2711            Slog.w(TAG, "Failed parsing config " + e);
2712        } catch (NullPointerException e) {
2713            Slog.w(TAG, "Failed parsing config " + e);
2714        } catch (NumberFormatException e) {
2715            Slog.w(TAG, "Failed parsing config " + e);
2716        } catch (XmlPullParserException e) {
2717            Slog.w(TAG, "Failed parsing config " + e);
2718        } catch (IOException e) {
2719            Slog.w(TAG, "Failed parsing config " + e);
2720        } catch (IndexOutOfBoundsException e) {
2721            Slog.w(TAG, "Failed parsing config " + e);
2722        }
2723    }
2724
2725    void writeConfigFileLocked() {
2726        mHandler.removeMessages(MSG_WRITE_CONFIG);
2727        mHandler.sendEmptyMessageDelayed(MSG_WRITE_CONFIG, 5000);
2728    }
2729
2730    void handleWriteConfigFile() {
2731        final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
2732
2733        try {
2734            synchronized (this) {
2735                XmlSerializer out = new FastXmlSerializer();
2736                out.setOutput(memStream, StandardCharsets.UTF_8.name());
2737                writeConfigFileLocked(out);
2738            }
2739        } catch (IOException e) {
2740        }
2741
2742        synchronized (mConfigFile) {
2743            FileOutputStream stream = null;
2744            try {
2745                stream = mConfigFile.startWrite();
2746                memStream.writeTo(stream);
2747                stream.flush();
2748                FileUtils.sync(stream);
2749                stream.close();
2750                mConfigFile.finishWrite(stream);
2751            } catch (IOException e) {
2752                Slog.w(TAG, "Error writing config file", e);
2753                mConfigFile.failWrite(stream);
2754            }
2755        }
2756    }
2757
2758    void writeConfigFileLocked(XmlSerializer out) throws IOException {
2759        out.startDocument(null, true);
2760        out.startTag(null, "config");
2761        for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) {
2762            String name = mPowerSaveWhitelistUserApps.keyAt(i);
2763            out.startTag(null, "wl");
2764            out.attribute(null, "n", name);
2765            out.endTag(null, "wl");
2766        }
2767        for (int i = 0; i < mRemovedFromSystemWhitelistApps.size(); i++) {
2768            out.startTag(null, "un-wl");
2769            out.attribute(null, "n", mRemovedFromSystemWhitelistApps.keyAt(i));
2770            out.endTag(null, "un-wl");
2771        }
2772        out.endTag(null, "config");
2773        out.endDocument();
2774    }
2775
2776    static void dumpHelp(PrintWriter pw) {
2777        pw.println("Device idle controller (deviceidle) commands:");
2778        pw.println("  help");
2779        pw.println("    Print this help text.");
2780        pw.println("  step [light|deep]");
2781        pw.println("    Immediately step to next state, without waiting for alarm.");
2782        pw.println("  force-idle [light|deep]");
2783        pw.println("    Force directly into idle mode, regardless of other device state.");
2784        pw.println("  force-inactive");
2785        pw.println("    Force to be inactive, ready to freely step idle states.");
2786        pw.println("  unforce");
2787        pw.println("    Resume normal functioning after force-idle or force-inactive.");
2788        pw.println("  get [light|deep|force|screen|charging|network]");
2789        pw.println("    Retrieve the current given state.");
2790        pw.println("  disable [light|deep|all]");
2791        pw.println("    Completely disable device idle mode.");
2792        pw.println("  enable [light|deep|all]");
2793        pw.println("    Re-enable device idle mode after it had previously been disabled.");
2794        pw.println("  enabled [light|deep|all]");
2795        pw.println("    Print 1 if device idle mode is currently enabled, else 0.");
2796        pw.println("  whitelist");
2797        pw.println("    Print currently whitelisted apps.");
2798        pw.println("  whitelist [package ...]");
2799        pw.println("    Add (prefix with +) or remove (prefix with -) packages.");
2800        pw.println("  sys-whitelist [package ...|reset]");
2801        pw.println("    Prefix the package with '-' to remove it from the system whitelist or '+'"
2802                + " to put it back in the system whitelist.");
2803        pw.println("    Note that only packages that were"
2804                + " earlier removed from the system whitelist can be added back.");
2805        pw.println("    reset will reset the whitelist to the original state");
2806        pw.println("    Prints the system whitelist if no arguments are specified");
2807        pw.println("  except-idle-whitelist [package ...|reset]");
2808        pw.println("    Prefix the package with '+' to add it to whitelist or "
2809                + "'=' to check if it is already whitelisted");
2810        pw.println("    [reset] will reset the whitelist to it's original state");
2811        pw.println("    Note that unlike <whitelist> cmd, "
2812                + "changes made using this won't be persisted across boots");
2813        pw.println("  tempwhitelist");
2814        pw.println("    Print packages that are temporarily whitelisted.");
2815        pw.println("  tempwhitelist [-u USER] [-d DURATION] [-r] [package]");
2816        pw.println("    Temporarily place package in whitelist for DURATION milliseconds.");
2817        pw.println("    If no DURATION is specified, 10 seconds is used");
2818        pw.println("    If [-r] option is used, then the package is removed from temp whitelist "
2819                + "and any [-d] is ignored");
2820        pw.println("  motion");
2821        pw.println("    Simulate a motion event to bring the device out of deep doze");
2822    }
2823
2824    class Shell extends ShellCommand {
2825        int userId = UserHandle.USER_SYSTEM;
2826
2827        @Override
2828        public int onCommand(String cmd) {
2829            return onShellCommand(this, cmd);
2830        }
2831
2832        @Override
2833        public void onHelp() {
2834            PrintWriter pw = getOutPrintWriter();
2835            dumpHelp(pw);
2836        }
2837    }
2838
2839    int onShellCommand(Shell shell, String cmd) {
2840        PrintWriter pw = shell.getOutPrintWriter();
2841        if ("step".equals(cmd)) {
2842            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
2843                    null);
2844            synchronized (this) {
2845                long token = Binder.clearCallingIdentity();
2846                String arg = shell.getNextArg();
2847                try {
2848                    if (arg == null || "deep".equals(arg)) {
2849                        stepIdleStateLocked("s:shell");
2850                        pw.print("Stepped to deep: ");
2851                        pw.println(stateToString(mState));
2852                    } else if ("light".equals(arg)) {
2853                        stepLightIdleStateLocked("s:shell");
2854                        pw.print("Stepped to light: "); pw.println(lightStateToString(mLightState));
2855                    } else {
2856                        pw.println("Unknown idle mode: " + arg);
2857                    }
2858                } finally {
2859                    Binder.restoreCallingIdentity(token);
2860                }
2861            }
2862        } else if ("force-idle".equals(cmd)) {
2863            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
2864                    null);
2865            synchronized (this) {
2866                long token = Binder.clearCallingIdentity();
2867                String arg = shell.getNextArg();
2868                try {
2869                    if (arg == null || "deep".equals(arg)) {
2870                        if (!mDeepEnabled) {
2871                            pw.println("Unable to go deep idle; not enabled");
2872                            return -1;
2873                        }
2874                        mForceIdle = true;
2875                        becomeInactiveIfAppropriateLocked();
2876                        int curState = mState;
2877                        while (curState != STATE_IDLE) {
2878                            stepIdleStateLocked("s:shell");
2879                            if (curState == mState) {
2880                                pw.print("Unable to go deep idle; stopped at ");
2881                                pw.println(stateToString(mState));
2882                                exitForceIdleLocked();
2883                                return -1;
2884                            }
2885                            curState = mState;
2886                        }
2887                        pw.println("Now forced in to deep idle mode");
2888                    } else if ("light".equals(arg)) {
2889                        mForceIdle = true;
2890                        becomeInactiveIfAppropriateLocked();
2891                        int curLightState = mLightState;
2892                        while (curLightState != LIGHT_STATE_IDLE) {
2893                            stepLightIdleStateLocked("s:shell");
2894                            if (curLightState == mLightState) {
2895                                pw.print("Unable to go light idle; stopped at ");
2896                                pw.println(lightStateToString(mLightState));
2897                                exitForceIdleLocked();
2898                                return -1;
2899                            }
2900                            curLightState = mLightState;
2901                        }
2902                        pw.println("Now forced in to light idle mode");
2903                    } else {
2904                        pw.println("Unknown idle mode: " + arg);
2905                    }
2906                } finally {
2907                    Binder.restoreCallingIdentity(token);
2908                }
2909            }
2910        } else if ("force-inactive".equals(cmd)) {
2911            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
2912                    null);
2913            synchronized (this) {
2914                long token = Binder.clearCallingIdentity();
2915                try {
2916                    mForceIdle = true;
2917                    becomeInactiveIfAppropriateLocked();
2918                    pw.print("Light state: ");
2919                    pw.print(lightStateToString(mLightState));
2920                    pw.print(", deep state: ");
2921                    pw.println(stateToString(mState));
2922                } finally {
2923                    Binder.restoreCallingIdentity(token);
2924                }
2925            }
2926        } else if ("unforce".equals(cmd)) {
2927            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
2928                    null);
2929            synchronized (this) {
2930                long token = Binder.clearCallingIdentity();
2931                try {
2932                    exitForceIdleLocked();
2933                    pw.print("Light state: ");
2934                    pw.print(lightStateToString(mLightState));
2935                    pw.print(", deep state: ");
2936                    pw.println(stateToString(mState));
2937                } finally {
2938                    Binder.restoreCallingIdentity(token);
2939                }
2940            }
2941        } else if ("get".equals(cmd)) {
2942            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
2943                    null);
2944            synchronized (this) {
2945                String arg = shell.getNextArg();
2946                if (arg != null) {
2947                    long token = Binder.clearCallingIdentity();
2948                    try {
2949                        switch (arg) {
2950                            case "light": pw.println(lightStateToString(mLightState)); break;
2951                            case "deep": pw.println(stateToString(mState)); break;
2952                            case "force": pw.println(mForceIdle); break;
2953                            case "screen": pw.println(mScreenOn); break;
2954                            case "charging": pw.println(mCharging); break;
2955                            case "network": pw.println(mNetworkConnected); break;
2956                            default: pw.println("Unknown get option: " + arg); break;
2957                        }
2958                    } finally {
2959                        Binder.restoreCallingIdentity(token);
2960                    }
2961                } else {
2962                    pw.println("Argument required");
2963                }
2964            }
2965        } else if ("disable".equals(cmd)) {
2966            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
2967                    null);
2968            synchronized (this) {
2969                long token = Binder.clearCallingIdentity();
2970                String arg = shell.getNextArg();
2971                try {
2972                    boolean becomeActive = false;
2973                    boolean valid = false;
2974                    if (arg == null || "deep".equals(arg) || "all".equals(arg)) {
2975                        valid = true;
2976                        if (mDeepEnabled) {
2977                            mDeepEnabled = false;
2978                            becomeActive = true;
2979                            pw.println("Deep idle mode disabled");
2980                        }
2981                    }
2982                    if (arg == null || "light".equals(arg) || "all".equals(arg)) {
2983                        valid = true;
2984                        if (mLightEnabled) {
2985                            mLightEnabled = false;
2986                            becomeActive = true;
2987                            pw.println("Light idle mode disabled");
2988                        }
2989                    }
2990                    if (becomeActive) {
2991                        becomeActiveLocked((arg == null ? "all" : arg) + "-disabled",
2992                                Process.myUid());
2993                    }
2994                    if (!valid) {
2995                        pw.println("Unknown idle mode: " + arg);
2996                    }
2997                } finally {
2998                    Binder.restoreCallingIdentity(token);
2999                }
3000            }
3001        } else if ("enable".equals(cmd)) {
3002            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
3003                    null);
3004            synchronized (this) {
3005                long token = Binder.clearCallingIdentity();
3006                String arg = shell.getNextArg();
3007                try {
3008                    boolean becomeInactive = false;
3009                    boolean valid = false;
3010                    if (arg == null || "deep".equals(arg) || "all".equals(arg)) {
3011                        valid = true;
3012                        if (!mDeepEnabled) {
3013                            mDeepEnabled = true;
3014                            becomeInactive = true;
3015                            pw.println("Deep idle mode enabled");
3016                        }
3017                    }
3018                    if (arg == null || "light".equals(arg) || "all".equals(arg)) {
3019                        valid = true;
3020                        if (!mLightEnabled) {
3021                            mLightEnabled = true;
3022                            becomeInactive = true;
3023                            pw.println("Light idle mode enable");
3024                        }
3025                    }
3026                    if (becomeInactive) {
3027                        becomeInactiveIfAppropriateLocked();
3028                    }
3029                    if (!valid) {
3030                        pw.println("Unknown idle mode: " + arg);
3031                    }
3032                } finally {
3033                    Binder.restoreCallingIdentity(token);
3034                }
3035            }
3036        } else if ("enabled".equals(cmd)) {
3037            synchronized (this) {
3038                String arg = shell.getNextArg();
3039                if (arg == null || "all".equals(arg)) {
3040                    pw.println(mDeepEnabled && mLightEnabled ? "1" : 0);
3041                } else if ("deep".equals(arg)) {
3042                    pw.println(mDeepEnabled ? "1" : 0);
3043                } else if ("light".equals(arg)) {
3044                    pw.println(mLightEnabled ? "1" : 0);
3045                } else {
3046                    pw.println("Unknown idle mode: " + arg);
3047                }
3048            }
3049        } else if ("whitelist".equals(cmd)) {
3050            String arg = shell.getNextArg();
3051            if (arg != null) {
3052                getContext().enforceCallingOrSelfPermission(
3053                        android.Manifest.permission.DEVICE_POWER, null);
3054                long token = Binder.clearCallingIdentity();
3055                try {
3056                    do {
3057                        if (arg.length() < 1 || (arg.charAt(0) != '-'
3058                                && arg.charAt(0) != '+' && arg.charAt(0) != '=')) {
3059                            pw.println("Package must be prefixed with +, -, or =: " + arg);
3060                            return -1;
3061                        }
3062                        char op = arg.charAt(0);
3063                        String pkg = arg.substring(1);
3064                        if (op == '+') {
3065                            if (addPowerSaveWhitelistAppInternal(pkg)) {
3066                                pw.println("Added: " + pkg);
3067                            } else {
3068                                pw.println("Unknown package: " + pkg);
3069                            }
3070                        } else if (op == '-') {
3071                            if (removePowerSaveWhitelistAppInternal(pkg)) {
3072                                pw.println("Removed: " + pkg);
3073                            }
3074                        } else {
3075                            pw.println(getPowerSaveWhitelistAppInternal(pkg));
3076                        }
3077                    } while ((arg=shell.getNextArg()) != null);
3078                } finally {
3079                    Binder.restoreCallingIdentity(token);
3080                }
3081            } else {
3082                synchronized (this) {
3083                    for (int j=0; j<mPowerSaveWhitelistAppsExceptIdle.size(); j++) {
3084                        pw.print("system-excidle,");
3085                        pw.print(mPowerSaveWhitelistAppsExceptIdle.keyAt(j));
3086                        pw.print(",");
3087                        pw.println(mPowerSaveWhitelistAppsExceptIdle.valueAt(j));
3088                    }
3089                    for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) {
3090                        pw.print("system,");
3091                        pw.print(mPowerSaveWhitelistApps.keyAt(j));
3092                        pw.print(",");
3093                        pw.println(mPowerSaveWhitelistApps.valueAt(j));
3094                    }
3095                    for (int j=0; j<mPowerSaveWhitelistUserApps.size(); j++) {
3096                        pw.print("user,");
3097                        pw.print(mPowerSaveWhitelistUserApps.keyAt(j));
3098                        pw.print(",");
3099                        pw.println(mPowerSaveWhitelistUserApps.valueAt(j));
3100                    }
3101                }
3102            }
3103        } else if ("tempwhitelist".equals(cmd)) {
3104            long duration = 10000;
3105            boolean removePkg = false;
3106            String opt;
3107            while ((opt=shell.getNextOption()) != null) {
3108                if ("-u".equals(opt)) {
3109                    opt = shell.getNextArg();
3110                    if (opt == null) {
3111                        pw.println("-u requires a user number");
3112                        return -1;
3113                    }
3114                    shell.userId = Integer.parseInt(opt);
3115                } else if ("-d".equals(opt)) {
3116                    opt = shell.getNextArg();
3117                    if (opt == null) {
3118                        pw.println("-d requires a duration");
3119                        return -1;
3120                    }
3121                    duration = Long.parseLong(opt);
3122                } else if ("-r".equals(opt)) {
3123                    removePkg = true;
3124                }
3125            }
3126            String arg = shell.getNextArg();
3127            if (arg != null) {
3128                try {
3129                    if (removePkg) {
3130                        removePowerSaveTempWhitelistAppChecked(arg, shell.userId);
3131                    } else {
3132                        addPowerSaveTempWhitelistAppChecked(arg, duration, shell.userId, "shell");
3133                    }
3134                } catch (Exception e) {
3135                    pw.println("Failed: " + e);
3136                    return -1;
3137                }
3138            } else if (removePkg) {
3139                pw.println("[-r] requires a package name");
3140                return -1;
3141            } else {
3142                dumpTempWhitelistSchedule(pw, false);
3143            }
3144        } else if ("except-idle-whitelist".equals(cmd)) {
3145            getContext().enforceCallingOrSelfPermission(
3146                    android.Manifest.permission.DEVICE_POWER, null);
3147            final long token = Binder.clearCallingIdentity();
3148            try {
3149                String arg = shell.getNextArg();
3150                if (arg == null) {
3151                    pw.println("No arguments given");
3152                    return -1;
3153                } else if ("reset".equals(arg)) {
3154                    resetPowerSaveWhitelistExceptIdleInternal();
3155                } else {
3156                    do {
3157                        if (arg.length() < 1 || (arg.charAt(0) != '-'
3158                                && arg.charAt(0) != '+' && arg.charAt(0) != '=')) {
3159                            pw.println("Package must be prefixed with +, -, or =: " + arg);
3160                            return -1;
3161                        }
3162                        char op = arg.charAt(0);
3163                        String pkg = arg.substring(1);
3164                        if (op == '+') {
3165                            if (addPowerSaveWhitelistExceptIdleInternal(pkg)) {
3166                                pw.println("Added: " + pkg);
3167                            } else {
3168                                pw.println("Unknown package: " + pkg);
3169                            }
3170                        } else if (op == '=') {
3171                            pw.println(getPowerSaveWhitelistExceptIdleInternal(pkg));
3172                        } else {
3173                            pw.println("Unknown argument: " + arg);
3174                            return -1;
3175                        }
3176                    } while ((arg = shell.getNextArg()) != null);
3177                }
3178            } finally {
3179                Binder.restoreCallingIdentity(token);
3180            }
3181        } else if ("sys-whitelist".equals(cmd)) {
3182            String arg = shell.getNextArg();
3183            if (arg != null) {
3184                getContext().enforceCallingOrSelfPermission(
3185                        android.Manifest.permission.DEVICE_POWER, null);
3186                final long token = Binder.clearCallingIdentity();
3187                try {
3188                    if ("reset".equals(arg)) {
3189                        resetSystemPowerWhitelistInternal();
3190                    } else {
3191                        do {
3192                            if (arg.length() < 1
3193                                    || (arg.charAt(0) != '-' && arg.charAt(0) != '+')) {
3194                                pw.println("Package must be prefixed with + or - " + arg);
3195                                return -1;
3196                            }
3197                            final char op = arg.charAt(0);
3198                            final String pkg = arg.substring(1);
3199                            switch (op) {
3200                                case '+':
3201                                    if (restoreSystemPowerWhitelistAppInternal(pkg)) {
3202                                        pw.println("Restored " + pkg);
3203                                    }
3204                                    break;
3205                                case '-':
3206                                    if (removeSystemPowerWhitelistAppInternal(pkg)) {
3207                                        pw.println("Removed " + pkg);
3208                                    }
3209                                    break;
3210                            }
3211                        } while ((arg = shell.getNextArg()) != null);
3212                    }
3213                } finally {
3214                    Binder.restoreCallingIdentity(token);
3215                }
3216            } else {
3217                synchronized (this) {
3218                    for (int j = 0; j < mPowerSaveWhitelistApps.size(); j++) {
3219                        pw.print(mPowerSaveWhitelistApps.keyAt(j));
3220                        pw.print(",");
3221                        pw.println(mPowerSaveWhitelistApps.valueAt(j));
3222                    }
3223                }
3224            }
3225        } else if ("motion".equals(cmd)) {
3226            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
3227                    null);
3228            synchronized (this) {
3229                long token = Binder.clearCallingIdentity();
3230                try {
3231                    motionLocked();
3232                    pw.print("Light state: ");
3233                    pw.print(lightStateToString(mLightState));
3234                    pw.print(", deep state: ");
3235                    pw.println(stateToString(mState));
3236                } finally {
3237                    Binder.restoreCallingIdentity(token);
3238                }
3239            }
3240        } else {
3241            return shell.handleDefaultCommands(cmd);
3242        }
3243        return 0;
3244    }
3245
3246    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3247        if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
3248
3249        if (args != null) {
3250            int userId = UserHandle.USER_SYSTEM;
3251            for (int i=0; i<args.length; i++) {
3252                String arg = args[i];
3253                if ("-h".equals(arg)) {
3254                    dumpHelp(pw);
3255                    return;
3256                } else if ("-u".equals(arg)) {
3257                    i++;
3258                    if (i < args.length) {
3259                        arg = args[i];
3260                        userId = Integer.parseInt(arg);
3261                    }
3262                } else if ("-a".equals(arg)) {
3263                    // Ignore, we always dump all.
3264                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
3265                    pw.println("Unknown option: " + arg);
3266                    return;
3267                } else {
3268                    Shell shell = new Shell();
3269                    shell.userId = userId;
3270                    String[] newArgs = new String[args.length-i];
3271                    System.arraycopy(args, i, newArgs, 0, args.length-i);
3272                    shell.exec(mBinderService, null, fd, null, newArgs, null,
3273                            new ResultReceiver(null));
3274                    return;
3275                }
3276            }
3277        }
3278
3279        synchronized (this) {
3280            mConstants.dump(pw);
3281
3282            if (mEventCmds[0] != EVENT_NULL) {
3283                pw.println("  Idling history:");
3284                long now = SystemClock.elapsedRealtime();
3285                for (int i=EVENT_BUFFER_SIZE-1; i>=0; i--) {
3286                    int cmd = mEventCmds[i];
3287                    if (cmd == EVENT_NULL) {
3288                        continue;
3289                    }
3290                    String label;
3291                    switch (mEventCmds[i]) {
3292                        case EVENT_NORMAL:              label = "     normal"; break;
3293                        case EVENT_LIGHT_IDLE:          label = " light-idle"; break;
3294                        case EVENT_LIGHT_MAINTENANCE:   label = "light-maint"; break;
3295                        case EVENT_DEEP_IDLE:           label = "  deep-idle"; break;
3296                        case EVENT_DEEP_MAINTENANCE:    label = " deep-maint"; break;
3297                        default:                        label = "         ??"; break;
3298                    }
3299                    pw.print("    ");
3300                    pw.print(label);
3301                    pw.print(": ");
3302                    TimeUtils.formatDuration(mEventTimes[i], now, pw);
3303                    if (mEventReasons[i] != null) {
3304                        pw.print(" (");
3305                        pw.print(mEventReasons[i]);
3306                        pw.print(")");
3307                    }
3308                    pw.println();
3309
3310                }
3311            }
3312
3313            int size = mPowerSaveWhitelistAppsExceptIdle.size();
3314            if (size > 0) {
3315                pw.println("  Whitelist (except idle) system apps:");
3316                for (int i = 0; i < size; i++) {
3317                    pw.print("    ");
3318                    pw.println(mPowerSaveWhitelistAppsExceptIdle.keyAt(i));
3319                }
3320            }
3321            size = mPowerSaveWhitelistApps.size();
3322            if (size > 0) {
3323                pw.println("  Whitelist system apps:");
3324                for (int i = 0; i < size; i++) {
3325                    pw.print("    ");
3326                    pw.println(mPowerSaveWhitelistApps.keyAt(i));
3327                }
3328            }
3329            size = mRemovedFromSystemWhitelistApps.size();
3330            if (size > 0) {
3331                pw.println("  Removed from whitelist system apps:");
3332                for (int i = 0; i < size; i++) {
3333                    pw.print("    ");
3334                    pw.println(mRemovedFromSystemWhitelistApps.keyAt(i));
3335                }
3336            }
3337            size = mPowerSaveWhitelistUserApps.size();
3338            if (size > 0) {
3339                pw.println("  Whitelist user apps:");
3340                for (int i = 0; i < size; i++) {
3341                    pw.print("    ");
3342                    pw.println(mPowerSaveWhitelistUserApps.keyAt(i));
3343                }
3344            }
3345            size = mPowerSaveWhitelistExceptIdleAppIds.size();
3346            if (size > 0) {
3347                pw.println("  Whitelist (except idle) all app ids:");
3348                for (int i = 0; i < size; i++) {
3349                    pw.print("    ");
3350                    pw.print(mPowerSaveWhitelistExceptIdleAppIds.keyAt(i));
3351                    pw.println();
3352                }
3353            }
3354            size = mPowerSaveWhitelistUserAppIds.size();
3355            if (size > 0) {
3356                pw.println("  Whitelist user app ids:");
3357                for (int i = 0; i < size; i++) {
3358                    pw.print("    ");
3359                    pw.print(mPowerSaveWhitelistUserAppIds.keyAt(i));
3360                    pw.println();
3361                }
3362            }
3363            size = mPowerSaveWhitelistAllAppIds.size();
3364            if (size > 0) {
3365                pw.println("  Whitelist all app ids:");
3366                for (int i = 0; i < size; i++) {
3367                    pw.print("    ");
3368                    pw.print(mPowerSaveWhitelistAllAppIds.keyAt(i));
3369                    pw.println();
3370                }
3371            }
3372            dumpTempWhitelistSchedule(pw, true);
3373
3374            size = mTempWhitelistAppIdArray != null ? mTempWhitelistAppIdArray.length : 0;
3375            if (size > 0) {
3376                pw.println("  Temp whitelist app ids:");
3377                for (int i = 0; i < size; i++) {
3378                    pw.print("    ");
3379                    pw.print(mTempWhitelistAppIdArray[i]);
3380                    pw.println();
3381                }
3382            }
3383
3384            pw.print("  mLightEnabled="); pw.print(mLightEnabled);
3385            pw.print("  mDeepEnabled="); pw.println(mDeepEnabled);
3386            pw.print("  mForceIdle="); pw.println(mForceIdle);
3387            pw.print("  mMotionSensor="); pw.println(mMotionSensor);
3388            pw.print("  mScreenOn="); pw.println(mScreenOn);
3389            pw.print("  mScreenLocked="); pw.println(mScreenLocked);
3390            pw.print("  mNetworkConnected="); pw.println(mNetworkConnected);
3391            pw.print("  mCharging="); pw.println(mCharging);
3392            pw.print("  mMotionActive="); pw.println(mMotionListener.active);
3393            pw.print("  mNotMoving="); pw.println(mNotMoving);
3394            pw.print("  mLocating="); pw.print(mLocating); pw.print(" mHasGps=");
3395                    pw.print(mHasGps); pw.print(" mHasNetwork=");
3396                    pw.print(mHasNetworkLocation); pw.print(" mLocated="); pw.println(mLocated);
3397            if (mLastGenericLocation != null) {
3398                pw.print("  mLastGenericLocation="); pw.println(mLastGenericLocation);
3399            }
3400            if (mLastGpsLocation != null) {
3401                pw.print("  mLastGpsLocation="); pw.println(mLastGpsLocation);
3402            }
3403            pw.print("  mState="); pw.print(stateToString(mState));
3404            pw.print(" mLightState=");
3405            pw.println(lightStateToString(mLightState));
3406            pw.print("  mInactiveTimeout="); TimeUtils.formatDuration(mInactiveTimeout, pw);
3407            pw.println();
3408            if (mActiveIdleOpCount != 0) {
3409                pw.print("  mActiveIdleOpCount="); pw.println(mActiveIdleOpCount);
3410            }
3411            if (mNextAlarmTime != 0) {
3412                pw.print("  mNextAlarmTime=");
3413                TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw);
3414                pw.println();
3415            }
3416            if (mNextIdlePendingDelay != 0) {
3417                pw.print("  mNextIdlePendingDelay=");
3418                TimeUtils.formatDuration(mNextIdlePendingDelay, pw);
3419                pw.println();
3420            }
3421            if (mNextIdleDelay != 0) {
3422                pw.print("  mNextIdleDelay=");
3423                TimeUtils.formatDuration(mNextIdleDelay, pw);
3424                pw.println();
3425            }
3426            if (mNextLightIdleDelay != 0) {
3427                pw.print("  mNextIdleDelay=");
3428                TimeUtils.formatDuration(mNextLightIdleDelay, pw);
3429                pw.println();
3430            }
3431            if (mNextLightAlarmTime != 0) {
3432                pw.print("  mNextLightAlarmTime=");
3433                TimeUtils.formatDuration(mNextLightAlarmTime, SystemClock.elapsedRealtime(), pw);
3434                pw.println();
3435            }
3436            if (mCurIdleBudget != 0) {
3437                pw.print("  mCurIdleBudget=");
3438                TimeUtils.formatDuration(mCurIdleBudget, pw);
3439                pw.println();
3440            }
3441            if (mMaintenanceStartTime != 0) {
3442                pw.print("  mMaintenanceStartTime=");
3443                TimeUtils.formatDuration(mMaintenanceStartTime, SystemClock.elapsedRealtime(), pw);
3444                pw.println();
3445            }
3446            if (mJobsActive) {
3447                pw.print("  mJobsActive="); pw.println(mJobsActive);
3448            }
3449            if (mAlarmsActive) {
3450                pw.print("  mAlarmsActive="); pw.println(mAlarmsActive);
3451            }
3452        }
3453    }
3454
3455    void dumpTempWhitelistSchedule(PrintWriter pw, boolean printTitle) {
3456        final int size = mTempWhitelistAppIdEndTimes.size();
3457        if (size > 0) {
3458            String prefix = "";
3459            if (printTitle) {
3460                pw.println("  Temp whitelist schedule:");
3461                prefix = "    ";
3462            }
3463            final long timeNow = SystemClock.elapsedRealtime();
3464            for (int i = 0; i < size; i++) {
3465                pw.print(prefix);
3466                pw.print("UID=");
3467                pw.print(mTempWhitelistAppIdEndTimes.keyAt(i));
3468                pw.print(": ");
3469                Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.valueAt(i);
3470                TimeUtils.formatDuration(entry.first.value, timeNow, pw);
3471                pw.print(" - ");
3472                pw.println(entry.second);
3473            }
3474        }
3475    }
3476 }
3477