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