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