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