blob: ad34b370e846a8db5e464867ed696586ce151678 [file] [log] [blame]
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001/*
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
Amith Yamasaniaf575b92015-05-29 15:35:26 -070019import android.Manifest;
20import android.app.ActivityManagerNative;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070021import android.app.AlarmManager;
Amith Yamasaniaf575b92015-05-29 15:35:26 -070022import android.app.AppGlobals;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070023import android.app.PendingIntent;
24import android.content.BroadcastReceiver;
Adam Lesinski31c05d12015-06-09 17:34:04 -070025import android.content.ContentResolver;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070026import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.pm.ApplicationInfo;
Amith Yamasaniaf575b92015-05-29 15:35:26 -070030import android.content.pm.PackageInfo;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070031import android.content.pm.PackageManager;
Amith Yamasaniaf575b92015-05-29 15:35:26 -070032import android.content.pm.PackageManager.NameNotFoundException;
Adam Lesinski31c05d12015-06-09 17:34:04 -070033import android.database.ContentObserver;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070034import android.hardware.Sensor;
35import android.hardware.SensorManager;
36import android.hardware.TriggerEvent;
37import android.hardware.TriggerEventListener;
38import android.hardware.display.DisplayManager;
39import android.net.INetworkPolicyManager;
Adam Lesinski31c05d12015-06-09 17:34:04 -070040import android.net.Uri;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070041import android.os.Binder;
42import android.os.Environment;
43import android.os.FileUtils;
44import android.os.Handler;
45import android.os.IDeviceIdleController;
46import android.os.Looper;
47import android.os.Message;
48import android.os.PowerManager;
49import android.os.PowerManagerInternal;
50import android.os.RemoteException;
51import android.os.ServiceManager;
52import android.os.SystemClock;
53import android.os.UserHandle;
Adam Lesinski31c05d12015-06-09 17:34:04 -070054import android.provider.Settings;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070055import android.util.ArrayMap;
56import android.util.ArraySet;
Adam Lesinski31c05d12015-06-09 17:34:04 -070057import android.util.KeyValueListParser;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070058import android.util.Slog;
59import android.util.SparseBooleanArray;
Amith Yamasaniaf575b92015-05-29 15:35:26 -070060import android.util.SparseLongArray;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070061import android.util.TimeUtils;
62import android.util.Xml;
63import android.view.Display;
Amith Yamasani520d8f22015-05-08 16:36:21 -070064
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070065import com.android.internal.app.IBatteryStats;
66import com.android.internal.os.AtomicFile;
67import com.android.internal.os.BackgroundThread;
68import com.android.internal.util.FastXmlSerializer;
69import com.android.internal.util.XmlUtils;
70import com.android.server.am.BatteryStatsService;
Amith Yamasani520d8f22015-05-08 16:36:21 -070071
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070072import org.xmlpull.v1.XmlPullParser;
73import org.xmlpull.v1.XmlPullParserException;
74import org.xmlpull.v1.XmlSerializer;
75
76import java.io.ByteArrayOutputStream;
77import java.io.File;
78import java.io.FileDescriptor;
79import java.io.FileInputStream;
80import java.io.FileNotFoundException;
81import java.io.FileOutputStream;
82import java.io.IOException;
83import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +010084import java.nio.charset.StandardCharsets;
Amith Yamasaniaf575b92015-05-29 15:35:26 -070085import java.util.Arrays;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070086
87/**
88 * Keeps track of device idleness and drives low power mode based on that.
89 */
Kevin Gabayan89ecf822015-05-18 12:10:07 -070090public class DeviceIdleController extends SystemService
91 implements AnyMotionDetector.DeviceIdleCallback {
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070092 private static final String TAG = "DeviceIdleController";
93
Amith Yamasaniaf575b92015-05-29 15:35:26 -070094 private static final boolean DEBUG = false;
Kevin Gabayan89ecf822015-05-18 12:10:07 -070095
Amith Yamasaniaf575b92015-05-29 15:35:26 -070096 private static final boolean COMPRESS_TIME = false;
Amith Yamasani520d8f22015-05-08 16:36:21 -070097
Dianne Hackborn0b4daca2015-04-27 09:47:32 -070098 public static final String SERVICE_NAME = "deviceidle";
99
100 private static final String ACTION_STEP_IDLE_STATE =
101 "com.android.server.device_idle.STEP_IDLE_STATE";
102
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700103 private static final String ACTION_ENTER_INACTIVE_STATE =
104 "com.android.server.device_idle.ENTER_INACTIVE_STATE";
105
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700106 // TODO: These need to be moved to system settings.
107
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700108
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700109
110 private AlarmManager mAlarmManager;
111 private IBatteryStats mBatteryStats;
112 private PowerManagerInternal mLocalPowerManager;
113 private INetworkPolicyManager mNetworkPolicyManager;
114 private DisplayManager mDisplayManager;
115 private SensorManager mSensorManager;
116 private Sensor mSigMotionSensor;
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700117 private PendingIntent mSensingAlarmIntent;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700118 private PendingIntent mAlarmIntent;
119 private Intent mIdleIntent;
120 private Display mCurDisplay;
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700121 private AnyMotionDetector mAnyMotionDetector;
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -0700122 private boolean mIdleDisabled;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700123 private boolean mScreenOn;
124 private boolean mCharging;
125 private boolean mSigMotionActive;
126
127 /** Device is currently active. */
128 private static final int STATE_ACTIVE = 0;
129 /** Device is inactve (screen off, no motion) and we are waiting to for idle. */
130 private static final int STATE_INACTIVE = 1;
131 /** Device is past the initial inactive period, and waiting for the next idle period. */
132 private static final int STATE_IDLE_PENDING = 2;
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700133 /** Device is currently sensing motion. */
134 private static final int STATE_SENSING = 3;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700135 /** Device is in the idle state, trying to stay asleep as much as possible. */
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700136 private static final int STATE_IDLE = 4;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700137 /** Device is in the idle state, but temporarily out of idle to do regular maintenance. */
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700138 private static final int STATE_IDLE_MAINTENANCE = 5;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700139 private static String stateToString(int state) {
140 switch (state) {
141 case STATE_ACTIVE: return "ACTIVE";
142 case STATE_INACTIVE: return "INACTIVE";
143 case STATE_IDLE_PENDING: return "IDLE_PENDING";
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700144 case STATE_SENSING: return "SENSING";
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700145 case STATE_IDLE: return "IDLE";
146 case STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
147 default: return Integer.toString(state);
148 }
149 }
150
151 private int mState;
152
153 private long mInactiveTimeout;
154 private long mNextAlarmTime;
155 private long mNextIdlePendingDelay;
156 private long mNextIdleDelay;
157
158 public final AtomicFile mConfigFile;
159
160 /**
161 * Package names the system has white-listed to opt out of power save restrictions.
162 */
163 private final ArrayMap<String, Integer> mPowerSaveWhitelistApps = new ArrayMap<>();
164
165 /**
166 * Package names the user has white-listed to opt out of power save restrictions.
167 */
168 private final ArrayMap<String, Integer> mPowerSaveWhitelistUserApps = new ArrayMap<>();
169
170 /**
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -0700171 * App IDs that have been white-listed to opt out of power save restrictions.
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700172 */
173 private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
174
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -0700175 /**
176 * Current app IDs that are in the complete power save white list. This array can
177 * be shared with others because it will not be modified once set.
178 */
179 private int[] mPowerSaveWhitelistAppIdArray = new int[0];
180
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700181 /**
182 * List of end times for UIDs that are temporarily marked as being allowed to access
183 * the network and acquire wakelocks. Times are in milliseconds.
184 */
185 private SparseLongArray mTempWhitelistAppIdEndTimes = new SparseLongArray();
186
187 /**
188 * Current app IDs of temporarily whitelist apps for high-priority messages.
189 */
190 private int[] mTempWhitelistAppIdArray = new int[0];
191
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700192 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
193 @Override public void onReceive(Context context, Intent intent) {
194 if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
195 int plugged = intent.getIntExtra("plugged", 0);
196 updateChargingLocked(plugged != 0);
197 } else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
198 synchronized (DeviceIdleController.this) {
199 stepIdleStateLocked();
200 }
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700201 } else if (ACTION_ENTER_INACTIVE_STATE.equals(intent.getAction())) {
202 synchronized (DeviceIdleController.this) {
203 enterInactiveStateLocked();
204 }
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700205 }
206 }
207 };
208
209 private final DisplayManager.DisplayListener mDisplayListener
210 = new DisplayManager.DisplayListener() {
211 @Override public void onDisplayAdded(int displayId) {
212 }
213
214 @Override public void onDisplayRemoved(int displayId) {
215 }
216
217 @Override public void onDisplayChanged(int displayId) {
218 if (displayId == Display.DEFAULT_DISPLAY) {
219 synchronized (DeviceIdleController.this) {
220 updateDisplayLocked();
221 }
222 }
223 }
224 };
225
226 private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
227 @Override public void onTrigger(TriggerEvent event) {
228 synchronized (DeviceIdleController.this) {
229 significantMotionLocked();
230 }
231 }
232 };
233
Adam Lesinski31c05d12015-06-09 17:34:04 -0700234 /**
235 * All times are in milliseconds. These constants are kept synchronized with the system
236 * global Settings. Any access to this class or its fields should be done while
237 * holding the DeviceIdleController lock.
238 */
239 private class Constants extends ContentObserver {
240 // Key names stored in the settings value.
241 private static final String KEY_INACTIVE_TIMEOUT = "inactive_to";
242 private static final String KEY_SENSING_TIMEOUT = "sensing_to";
243 private static final String KEY_MOTION_INACTIVE_TIMEOUT = "motion_inactive_to";
244 private static final String KEY_IDLE_AFTER_INACTIVE_TIMEOUT = "idle_after_inactive_to";
245 private static final String KEY_IDLE_PENDING_TIMEOUT = "idle_pending_to";
246 private static final String KEY_MAX_IDLE_PENDING_TIMEOUT = "max_idle_pending_to";
247 private static final String KEY_IDLE_PENDING_FACTOR = "idle_pending_factor";
248 private static final String KEY_IDLE_TIMEOUT = "idle_to";
249 private static final String KEY_MAX_IDLE_TIMEOUT = "max_idle_to";
250 private static final String KEY_IDLE_FACTOR = "idle_factor";
251 private static final String KEY_MIN_TIME_TO_ALARM = "min_time_to_alarm";
252 private static final String KEY_MAX_TEMP_APP_WHITELIST_DURATION =
253 "max_temp_app_whitelist_duration";
254
255 /**
256 * This is the time, after becoming inactive, at which we start looking at the
257 * motion sensor to determine if the device is being left alone. We don't do this
258 * immediately after going inactive just because we don't want to be continually running
259 * the significant motion sensor whenever the screen is off.
260 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
261 * @see #KEY_INACTIVE_TIMEOUT
262 */
263 public long INACTIVE_TIMEOUT;
264
265 /**
266 * If we don't receive a callback from AnyMotion in this amount of time, we will change from
267 * STATE_SENSING to STATE_INACTIVE, and any AnyMotion callbacks while not in STATE_SENSING
268 * will be ignored.
269 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
270 * @see #KEY_SENSING_TIMEOUT
271 */
272 public long SENSING_TIMEOUT;
273
274 /**
275 * This is the time, after seeing motion, that we wait after becoming inactive from
276 * that until we start looking for motion again.
277 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
278 * @see #KEY_MOTION_INACTIVE_TIMEOUT
279 */
280 public long MOTION_INACTIVE_TIMEOUT;
281
282 /**
283 * This is the time, after the inactive timeout elapses, that we will wait looking
284 * for significant motion until we truly consider the device to be idle.
285 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
286 * @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT
287 */
288 public long IDLE_AFTER_INACTIVE_TIMEOUT;
289
290 /**
291 * This is the initial time, after being idle, that we will allow ourself to be back
292 * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
293 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
294 * @see #KEY_IDLE_PENDING_TIMEOUT
295 */
296 public long IDLE_PENDING_TIMEOUT;
297
298 /**
299 * Maximum pending idle timeout (time spent running) we will be allowed to use.
300 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
301 * @see #KEY_MAX_IDLE_PENDING_TIMEOUT
302 */
303 public long MAX_IDLE_PENDING_TIMEOUT;
304
305 /**
306 * Scaling factor to apply to current pending idle timeout each time we cycle through
307 * that state.
308 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
309 * @see #KEY_IDLE_PENDING_FACTOR
310 */
311 public float IDLE_PENDING_FACTOR;
312
313 /**
314 * This is the initial time that we want to sit in the idle state before waking up
315 * again to return to pending idle and allowing normal work to run.
316 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
317 * @see #KEY_IDLE_TIMEOUT
318 */
319 public long IDLE_TIMEOUT;
320
321 /**
322 * Maximum idle duration we will be allowed to use.
323 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
324 * @see #KEY_MAX_IDLE_TIMEOUT
325 */
326 public long MAX_IDLE_TIMEOUT;
327
328 /**
329 * Scaling factor to apply to current idle timeout each time we cycle through that state.
330 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
331 * @see #KEY_IDLE_FACTOR
332 */
333 public float IDLE_FACTOR;
334
335 /**
336 * This is the minimum time we will allow until the next upcoming alarm for us to
337 * actually go in to idle mode.
338 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
339 * @see #KEY_MIN_TIME_TO_ALARM
340 */
341 public long MIN_TIME_TO_ALARM;
342
343 /**
344 * Max amount of time to temporarily whitelist an app when it receives a high priority
345 * tickle.
346 * @see Settings.Global#DEVICE_IDLE_CONSTANTS
347 * @see #KEY_MAX_TEMP_APP_WHITELIST_DURATION
348 */
349 public long MAX_TEMP_APP_WHITELIST_DURATION;
350
351 private final ContentResolver mResolver;
352 private final KeyValueListParser mParser = new KeyValueListParser(',');
353
354 public Constants(Handler handler, ContentResolver resolver) {
355 super(handler);
356 mResolver = resolver;
357 mResolver.registerContentObserver(
358 Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS), false, this);
359 updateConstants();
360 }
361
362 @Override
363 public void onChange(boolean selfChange, Uri uri) {
364 updateConstants();
365 }
366
367 private void updateConstants() {
368 synchronized (DeviceIdleController.this) {
369 try {
370 mParser.setString(Settings.Global.getString(mResolver,
371 Settings.Global.DEVICE_IDLE_CONSTANTS));
372 } catch (IllegalArgumentException e) {
373 // Failed to parse the settings string, log this and move on
374 // with defaults.
375 Slog.e(TAG, "Bad device idle settings", e);
376 }
377
378 INACTIVE_TIMEOUT = mParser.getLong(KEY_INACTIVE_TIMEOUT,
379 !COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
380 SENSING_TIMEOUT = mParser.getLong(KEY_SENSING_TIMEOUT,
381 !DEBUG ? 5 * 60 * 1000L : 60 * 1000L);
382 MOTION_INACTIVE_TIMEOUT = mParser.getLong(KEY_MOTION_INACTIVE_TIMEOUT,
383 !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
384 IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(KEY_IDLE_AFTER_INACTIVE_TIMEOUT,
385 !COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
386 IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_IDLE_PENDING_TIMEOUT,
387 !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);
388 MAX_IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_PENDING_TIMEOUT,
389 !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
390 IDLE_PENDING_FACTOR = mParser.getFloat(KEY_IDLE_PENDING_FACTOR,
391 2f);
392 IDLE_TIMEOUT = mParser.getLong(KEY_IDLE_TIMEOUT,
393 !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
394 MAX_IDLE_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_TIMEOUT,
395 !COMPRESS_TIME ? 6 * 60 * 60 * 1000L : 30 * 60 * 1000L);
396 IDLE_FACTOR = mParser.getFloat(KEY_IDLE_FACTOR,
397 2f);
398 MIN_TIME_TO_ALARM = mParser.getLong(KEY_MIN_TIME_TO_ALARM,
399 !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
400 MAX_TEMP_APP_WHITELIST_DURATION = mParser.getLong(KEY_MAX_TEMP_APP_WHITELIST_DURATION,
401 5 * 60 * 1000L);
402 }
403 }
404
405 void dump(PrintWriter pw) {
406 pw.println(" Settings:");
407
408 pw.print(" DOZE_INACTIVE_TIMEOUT=");
409 TimeUtils.formatDuration(INACTIVE_TIMEOUT, pw);
410 pw.println();
411
412 pw.print(" DOZE_SENSING_TIMEOUT=");
413 TimeUtils.formatDuration(SENSING_TIMEOUT, pw);
414 pw.println();
415
416 pw.print(" DOZE_MOTION_INACTIVE_TIMEOUT=");
417 TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT, pw);
418 pw.println();
419
420 pw.print(" DOZE_IDLE_AFTER_INACTIVE_TIMEOUT=");
421 TimeUtils.formatDuration(IDLE_AFTER_INACTIVE_TIMEOUT, pw);
422 pw.println();
423
424 pw.print(" DOZE_IDLE_PENDING_TIMEOUT=");
425 TimeUtils.formatDuration(IDLE_PENDING_TIMEOUT, pw);
426 pw.println();
427
428 pw.print(" DOZE_MAX_IDLE_PENDING_TIMEOUT=");
429 TimeUtils.formatDuration(MAX_IDLE_PENDING_TIMEOUT, pw);
430 pw.println();
431
432 pw.print(" DOZE_IDLE_PENDING_FACTOR=");
433 pw.println(IDLE_PENDING_FACTOR);
434
435 pw.print(" DOZE_IDLE_TIMEOUT=");
436 TimeUtils.formatDuration(IDLE_TIMEOUT, pw);
437 pw.println();
438
439 pw.print(" DOZE_MAX_IDLE_TIMEOUT=");
440 TimeUtils.formatDuration(MAX_IDLE_TIMEOUT, pw);
441 pw.println();
442
443 pw.print(" DOZE_IDLE_FACTOR=");
444 pw.println(IDLE_FACTOR);
445
446 pw.print(" DOZE_MIN_TIME_TO_ALARM=");
447 TimeUtils.formatDuration(MIN_TIME_TO_ALARM, pw);
448 pw.println();
449
450 pw.print(" DOZE_MAX_TEMP_APP_WHITELIST_DURATION=");
451 TimeUtils.formatDuration(MAX_TEMP_APP_WHITELIST_DURATION, pw);
452 pw.println();
453 }
454 }
455
456 private Constants mConstants;
457
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700458 @Override
459 public void onAnyMotionResult(int result) {
460 if (DEBUG) Slog.d(TAG, "onAnyMotionResult(" + result + ")");
461 if (mState == STATE_SENSING) {
462 if (result == AnyMotionDetector.RESULT_STATIONARY) {
463 if (DEBUG) Slog.d(TAG, "RESULT_STATIONARY received.");
464 synchronized (this) {
465 stepIdleStateLocked();
466 }
467 } else if (result == AnyMotionDetector.RESULT_MOVED) {
468 if (DEBUG) Slog.d(TAG, "RESULT_MOVED received.");
469 synchronized (this) {
470 enterInactiveStateLocked();
471 }
472 }
473 }
474 }
475
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700476 static final int MSG_WRITE_CONFIG = 1;
477 static final int MSG_REPORT_IDLE_ON = 2;
478 static final int MSG_REPORT_IDLE_OFF = 3;
479 static final int MSG_REPORT_ACTIVE = 4;
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700480 static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 5;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700481
482 final class MyHandler extends Handler {
483 MyHandler(Looper looper) {
484 super(looper);
485 }
486
487 @Override public void handleMessage(Message msg) {
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700488 if (DEBUG) Slog.d(TAG, "handleMessage(" + msg.what + ")");
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700489 switch (msg.what) {
490 case MSG_WRITE_CONFIG: {
491 handleWriteConfigFile();
492 } break;
493 case MSG_REPORT_IDLE_ON: {
494 mLocalPowerManager.setDeviceIdleMode(true);
495 try {
496 mNetworkPolicyManager.setDeviceIdleMode(true);
497 mBatteryStats.noteDeviceIdleMode(true, false, false);
498 } catch (RemoteException e) {
499 }
500 getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
501 } break;
502 case MSG_REPORT_IDLE_OFF: {
503 mLocalPowerManager.setDeviceIdleMode(false);
504 try {
505 mNetworkPolicyManager.setDeviceIdleMode(false);
506 mBatteryStats.noteDeviceIdleMode(false, false, false);
507 } catch (RemoteException e) {
508 }
509 getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
510 } break;
511 case MSG_REPORT_ACTIVE: {
512 boolean fromMotion = msg.arg1 != 0;
513 boolean needBroadcast = msg.arg2 != 0;
514 mLocalPowerManager.setDeviceIdleMode(false);
515 try {
516 mNetworkPolicyManager.setDeviceIdleMode(false);
517 mBatteryStats.noteDeviceIdleMode(false, !fromMotion, fromMotion);
518 } catch (RemoteException e) {
519 }
520 if (needBroadcast) {
521 getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
522 }
523 } break;
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700524 case MSG_TEMP_APP_WHITELIST_TIMEOUT: {
525 int uid = msg.arg1;
526 checkTempAppWhitelistTimeout(uid);
527 } break;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700528 }
529 }
530 }
531
532 final MyHandler mHandler;
533
534 private final class BinderService extends IDeviceIdleController.Stub {
535 @Override public void addPowerSaveWhitelistApp(String name) {
536 getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
537 null);
538 addPowerSaveWhitelistAppInternal(name);
539 }
540
541 @Override public void removePowerSaveWhitelistApp(String name) {
542 getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
543 null);
544 removePowerSaveWhitelistAppInternal(name);
545 }
546
547 @Override public String[] getSystemPowerWhitelist() {
548 return getSystemPowerWhitelistInternal();
549 }
550
551 @Override public String[] getFullPowerWhitelist() {
552 return getFullPowerWhitelistInternal();
553 }
554
555 @Override public int[] getAppIdWhitelist() {
556 return getAppIdWhitelistInternal();
557 }
558
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700559 @Override public int[] getAppIdTempWhitelist() {
560 return getAppIdTempWhitelistInternal();
561 }
562
Amith Yamasani06bf8242015-05-08 16:36:21 -0700563 @Override public boolean isPowerSaveWhitelistApp(String name) {
564 return isPowerSaveWhitelistAppInternal(name);
565 }
566
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700567 @Override public void addPowerSaveTempWhitelistApp(String packageName, long duration,
568 int userId) throws RemoteException {
569 getContext().enforceCallingPermission(
570 Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
571 "No permission to change device idle whitelist");
572 userId = ActivityManagerNative.getDefault().handleIncomingUser(
573 Binder.getCallingPid(),
574 Binder.getCallingUid(),
575 userId,
576 /*allowAll=*/ false,
577 /*requireFull=*/ false,
578 "addAppBrieflyToWhitelist", null);
579 final long token = Binder.clearCallingIdentity();
580 try {
581 PackageInfo pi = AppGlobals.getPackageManager()
582 .getPackageInfo(packageName, 0, userId);
583 if (pi == null) return;
584 DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(packageName,
585 duration, userId);
586 } catch (RemoteException re) {
587 } finally {
588 Binder.restoreCallingIdentity(token);
589 }
590 }
591
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700592 @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
593 DeviceIdleController.this.dump(fd, pw, args);
594 }
595 }
596
597 public DeviceIdleController(Context context) {
598 super(context);
599 mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
600 mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
601 }
602
603 private static File getSystemDir() {
604 return new File(Environment.getDataDirectory(), "system");
605 }
606
607 @Override
608 public void onStart() {
609 final PackageManager pm = getContext().getPackageManager();
610
611 synchronized (this) {
612 SystemConfig sysConfig = SystemConfig.getInstance();
613 ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
614 for (int i=0; i<allowPower.size(); i++) {
615 String pkg = allowPower.valueAt(i);
616 try {
617 ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
618 if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
619 mPowerSaveWhitelistApps.put(ai.packageName,
620 UserHandle.getAppId(ai.uid));
621 }
622 } catch (PackageManager.NameNotFoundException e) {
623 }
624 }
625
Adam Lesinski31c05d12015-06-09 17:34:04 -0700626 mConstants = new Constants(mHandler, getContext().getContentResolver());
627
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700628 readConfigFileLocked();
629 updateWhitelistAppIdsLocked();
630
631 mScreenOn = true;
632 // Start out assuming we are charging. If we aren't, we will at least get
633 // a battery update the next time the level drops.
634 mCharging = true;
635 mState = STATE_ACTIVE;
Adam Lesinski31c05d12015-06-09 17:34:04 -0700636 mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700637 }
638
639 publishBinderService(SERVICE_NAME, new BinderService());
640 }
641
642 @Override
643 public void onBootPhase(int phase) {
644 if (phase == PHASE_SYSTEM_SERVICES_READY) {
645 synchronized (this) {
646 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
647 mBatteryStats = BatteryStatsService.getService();
648 mLocalPowerManager = getLocalService(PowerManagerInternal.class);
649 mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
650 ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
651 mDisplayManager = (DisplayManager) getContext().getSystemService(
652 Context.DISPLAY_SERVICE);
653 mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
654 mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700655 mAnyMotionDetector = new AnyMotionDetector(
656 mAlarmManager,
657 (PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
658 mHandler, mSensorManager, this);
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700659
660 Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
661 .setPackage("android")
662 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
663 mAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
664
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700665 Intent intentSensing = new Intent(ACTION_STEP_IDLE_STATE)
666 .setPackage("android")
667 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
668 mSensingAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intentSensing, 0);
669
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700670 mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
671 mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
672
673 IntentFilter filter = new IntentFilter();
674 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
675 filter.addAction(ACTION_STEP_IDLE_STATE);
676 getContext().registerReceiver(mReceiver, filter);
677
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -0700678 mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray);
679
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700680 mDisplayManager.registerDisplayListener(mDisplayListener, null);
681 updateDisplayLocked();
682 }
683 }
684 }
685
686 public boolean addPowerSaveWhitelistAppInternal(String name) {
687 synchronized (this) {
688 try {
689 ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name, 0);
690 if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid)) == null) {
691 reportPowerSaveWhitelistChangedLocked();
692 updateWhitelistAppIdsLocked();
693 writeConfigFileLocked();
694 }
695 return true;
696 } catch (PackageManager.NameNotFoundException e) {
697 return false;
698 }
699 }
700 }
701
702 public boolean removePowerSaveWhitelistAppInternal(String name) {
703 synchronized (this) {
704 if (mPowerSaveWhitelistUserApps.remove(name) != null) {
705 reportPowerSaveWhitelistChangedLocked();
706 updateWhitelistAppIdsLocked();
707 writeConfigFileLocked();
708 return true;
709 }
710 }
711 return false;
712 }
713
714 public String[] getSystemPowerWhitelistInternal() {
715 synchronized (this) {
716 int size = mPowerSaveWhitelistApps.size();
717 String[] apps = new String[size];
718 for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) {
719 apps[i] = mPowerSaveWhitelistApps.keyAt(i);
720 }
721 return apps;
722 }
723 }
724
725 public String[] getFullPowerWhitelistInternal() {
726 synchronized (this) {
727 int size = mPowerSaveWhitelistApps.size() + mPowerSaveWhitelistUserApps.size();
728 String[] apps = new String[size];
729 int cur = 0;
730 for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) {
731 apps[cur] = mPowerSaveWhitelistApps.keyAt(i);
732 cur++;
733 }
734 for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
735 apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i);
736 cur++;
737 }
738 return apps;
739 }
740 }
741
Amith Yamasani06bf8242015-05-08 16:36:21 -0700742 public boolean isPowerSaveWhitelistAppInternal(String packageName) {
743 synchronized (this) {
744 return mPowerSaveWhitelistApps.containsKey(packageName)
745 || mPowerSaveWhitelistUserApps.containsKey(packageName);
746 }
747 }
748
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700749 public int[] getAppIdWhitelistInternal() {
750 synchronized (this) {
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -0700751 return mPowerSaveWhitelistAppIdArray;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700752 }
753 }
754
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700755 public int[] getAppIdTempWhitelistInternal() {
756 synchronized (this) {
757 return mTempWhitelistAppIdArray;
758 }
759 }
760
761 /**
762 * Adds an app to the temporary whitelist and resets the endTime for granting the
763 * app an exemption to access network and acquire wakelocks.
764 */
765 public void addPowerSaveTempWhitelistAppInternal(String packageName, long duration,
766 int userId) {
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700767 try {
768 int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
769 int appId = UserHandle.getAppId(uid);
770 final long timeNow = System.currentTimeMillis();
771 synchronized (this) {
Adam Lesinski31c05d12015-06-09 17:34:04 -0700772 duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION);
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700773 long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId);
774 // Set the new end time
775 mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration);
776 if (DEBUG) {
777 Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist");
778 }
779 if (currentEndTime == 0) {
780 // No pending timeout for the app id, post a delayed message
781 postTempActiveTimeoutMessage(appId, duration);
782 updateTempWhitelistAppIdsLocked();
783 reportTempWhitelistChangedLocked();
784 }
785 }
786 } catch (NameNotFoundException e) {
787 }
788 }
789
790 private void postTempActiveTimeoutMessage(int uid, long delay) {
791 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, uid, 0),
792 delay);
793 }
794
795 void checkTempAppWhitelistTimeout(int uid) {
796 final long timeNow = System.currentTimeMillis();
797 synchronized (this) {
798 long endTime = mTempWhitelistAppIdEndTimes.get(uid);
799 if (endTime == 0) {
800 // Nothing to do
801 return;
802 }
803 if (timeNow >= endTime) {
804 mTempWhitelistAppIdEndTimes.delete(uid);
805 if (DEBUG) {
806 Slog.d(TAG, "Removing UID " + uid + " from temp whitelist");
807 }
808 updateTempWhitelistAppIdsLocked();
809 reportTempWhitelistChangedLocked();
810 } else {
811 // Need more time
812 postTempActiveTimeoutMessage(uid, endTime - timeNow);
813 }
814 }
815 }
816
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700817 void updateDisplayLocked() {
818 mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
819 // We consider any situation where the display is showing something to be it on,
820 // because if there is anything shown we are going to be updating it at some
821 // frequency so can't be allowed to go into deep sleeps.
822 boolean screenOn = mCurDisplay.getState() != Display.STATE_OFF;;
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700823 if (DEBUG) Slog.d(TAG, "updateDisplayLocked: screenOn=" + screenOn);
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700824 if (!screenOn && mScreenOn) {
825 mScreenOn = false;
826 becomeInactiveIfAppropriateLocked();
827 } else if (screenOn) {
828 mScreenOn = true;
829 becomeActiveLocked("screen");
830 }
831 }
832
833 void updateChargingLocked(boolean charging) {
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700834 if (DEBUG) Slog.i(TAG, "updateChargingLocked: charging=" + charging);
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700835 if (!charging && mCharging) {
836 mCharging = false;
837 becomeInactiveIfAppropriateLocked();
838 } else if (charging) {
839 mCharging = charging;
840 becomeActiveLocked("charging");
841 }
842 }
843
844 void scheduleReportActiveLocked(boolean fromMotion) {
845 Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, fromMotion ? 1 : 0,
846 mState == STATE_IDLE ? 1 : 0);
847 mHandler.sendMessage(msg);
848 }
849
850 void becomeActiveLocked(String reason) {
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700851 if (DEBUG) Slog.i(TAG, "becomeActiveLocked, reason = " + reason);
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700852 if (mState != STATE_ACTIVE) {
853 EventLogTags.writeDeviceIdle(STATE_ACTIVE, reason);
854 scheduleReportActiveLocked(false);
855 mState = STATE_ACTIVE;
Adam Lesinski31c05d12015-06-09 17:34:04 -0700856 mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700857 mNextIdlePendingDelay = 0;
858 mNextIdleDelay = 0;
859 cancelAlarmLocked();
860 stopMonitoringSignificantMotion();
861 }
862 }
863
864 void becomeInactiveIfAppropriateLocked() {
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700865 if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -0700866 if (!mScreenOn && !mCharging && !mIdleDisabled && mState == STATE_ACTIVE) {
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700867 // Screen has turned off; we are now going to become inactive and start
868 // waiting to see if we will ultimately go idle.
869 mState = STATE_INACTIVE;
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700870 if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700871 mNextIdlePendingDelay = 0;
872 mNextIdleDelay = 0;
873 scheduleAlarmLocked(mInactiveTimeout, false);
874 EventLogTags.writeDeviceIdle(mState, "no activity");
875 }
876 }
877
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700878 /**
879 * This is called when we've failed to receive a callback from AnyMotionDetector
880 * within the DEFAULT_SENSING_TIMEOUT, to return to STATE_INACTIVE.
881 */
882 void enterInactiveStateLocked() {
Adam Lesinski31c05d12015-06-09 17:34:04 -0700883 mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700884 becomeInactiveIfAppropriateLocked();
885 }
886
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700887 void stepIdleStateLocked() {
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700888 if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700889 EventLogTags.writeDeviceIdleStep();
890
891 final long now = SystemClock.elapsedRealtime();
Adam Lesinski31c05d12015-06-09 17:34:04 -0700892 if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700893 // Whoops, there is an upcoming alarm. We don't actually want to go idle.
894 if (mState != STATE_ACTIVE) {
895 becomeActiveLocked("alarm");
896 }
897 return;
898 }
899
900 switch (mState) {
901 case STATE_INACTIVE:
902 // We have now been inactive long enough, it is time to start looking
903 // for significant motion and sleep some more while doing so.
904 startMonitoringSignificantMotion();
Adam Lesinski31c05d12015-06-09 17:34:04 -0700905 scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700906 // Reset the upcoming idle delays.
Adam Lesinski31c05d12015-06-09 17:34:04 -0700907 mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
908 mNextIdleDelay = mConstants.IDLE_TIMEOUT;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700909 mState = STATE_IDLE_PENDING;
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700910 if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700911 EventLogTags.writeDeviceIdle(mState, "step");
912 break;
913 case STATE_IDLE_PENDING:
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700914 mState = STATE_SENSING;
915 if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING.");
Adam Lesinski31c05d12015-06-09 17:34:04 -0700916 scheduleSensingAlarmLocked(mConstants.SENSING_TIMEOUT);
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700917 mAnyMotionDetector.checkForAnyMotion();
918 break;
919 case STATE_SENSING:
920 cancelSensingAlarmLocked();
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700921 case STATE_IDLE_MAINTENANCE:
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700922 scheduleAlarmLocked(mNextIdleDelay, true);
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700923 if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
924 " ms.");
Adam Lesinski31c05d12015-06-09 17:34:04 -0700925 mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700926 if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);
Adam Lesinski31c05d12015-06-09 17:34:04 -0700927 mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700928 mState = STATE_IDLE;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700929 mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
930 break;
931 case STATE_IDLE:
932 // We have been idling long enough, now it is time to do some work.
933 scheduleAlarmLocked(mNextIdlePendingDelay, false);
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700934 if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
935 "Next alarm in " + mNextIdlePendingDelay + " ms.");
Adam Lesinski31c05d12015-06-09 17:34:04 -0700936 mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,
937 (long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700938 mState = STATE_IDLE_MAINTENANCE;
939 EventLogTags.writeDeviceIdle(mState, "step");
940 mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
941 break;
942 }
943 }
944
945 void significantMotionLocked() {
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700946 if (DEBUG) Slog.d(TAG, "significantMotionLocked()");
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700947 // When the sensor goes off, its trigger is automatically removed.
948 mSigMotionActive = false;
949 // The device is not yet active, so we want to go back to the pending idle
950 // state to wait again for no motion. Note that we only monitor for significant
951 // motion after moving out of the inactive state, so no need to worry about that.
952 if (mState != STATE_ACTIVE) {
953 scheduleReportActiveLocked(true);
954 mState = STATE_ACTIVE;
Adam Lesinski31c05d12015-06-09 17:34:04 -0700955 mInactiveTimeout = mConstants.MOTION_INACTIVE_TIMEOUT;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700956 EventLogTags.writeDeviceIdle(mState, "motion");
957 becomeInactiveIfAppropriateLocked();
958 }
959 }
960
961 void startMonitoringSignificantMotion() {
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700962 if (DEBUG) Slog.d(TAG, "startMonitoringSignificantMotion()");
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700963 if (mSigMotionSensor != null && !mSigMotionActive) {
964 mSensorManager.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
965 mSigMotionActive = true;
966 }
967 }
968
969 void stopMonitoringSignificantMotion() {
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700970 if (DEBUG) Slog.d(TAG, "stopMonitoringSignificantMotion()");
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700971 if (mSigMotionActive) {
972 mSensorManager.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
973 mSigMotionActive = false;
974 }
975 }
976
977 void cancelAlarmLocked() {
978 if (mNextAlarmTime != 0) {
979 mNextAlarmTime = 0;
980 mAlarmManager.cancel(mAlarmIntent);
981 }
982 }
983
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700984 void cancelSensingAlarmLocked() {
985 if (DEBUG) Slog.d(TAG, "cancelSensingAlarmLocked()");
986 mAlarmManager.cancel(mSensingAlarmIntent);
987 }
988
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700989 void scheduleAlarmLocked(long delay, boolean idleUntil) {
Kevin Gabayan89ecf822015-05-18 12:10:07 -0700990 if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700991 if (mSigMotionSensor == null) {
992 // If there is no significant motion sensor on this device, then we won't schedule
993 // alarms, because we can't determine if the device is not moving. This effectively
994 // turns off normal exeuction of device idling, although it is still possible to
995 // manually poke it by pretending like the alarm is going off.
996 return;
997 }
998 mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
999 if (idleUntil) {
1000 mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1001 mNextAlarmTime, mAlarmIntent);
1002 } else {
1003 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1004 mNextAlarmTime, mAlarmIntent);
1005 }
1006 }
1007
Kevin Gabayan89ecf822015-05-18 12:10:07 -07001008 void scheduleSensingAlarmLocked(long delay) {
1009 if (DEBUG) Slog.d(TAG, "scheduleSensingAlarmLocked(" + delay + ")");
1010 mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
1011 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1012 mNextAlarmTime, mSensingAlarmIntent);
1013 }
1014
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001015 private void updateWhitelistAppIdsLocked() {
1016 mPowerSaveWhitelistAppIds.clear();
1017 for (int i=0; i<mPowerSaveWhitelistApps.size(); i++) {
1018 mPowerSaveWhitelistAppIds.put(mPowerSaveWhitelistApps.valueAt(i), true);
1019 }
1020 for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) {
1021 mPowerSaveWhitelistAppIds.put(mPowerSaveWhitelistUserApps.valueAt(i), true);
1022 }
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -07001023 int size = mPowerSaveWhitelistAppIds.size();
1024 int[] appids = new int[size];
1025 for (int i = 0; i < size; i++) {
1026 appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
1027 }
1028 mPowerSaveWhitelistAppIdArray = appids;
1029 if (mLocalPowerManager != null) {
Amith Yamasaniaf575b92015-05-29 15:35:26 -07001030 if (DEBUG) {
1031 Slog.d(TAG, "Setting wakelock whitelist to "
1032 + Arrays.toString(mPowerSaveWhitelistAppIdArray));
1033 }
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -07001034 mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray);
1035 }
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001036 }
1037
Amith Yamasaniaf575b92015-05-29 15:35:26 -07001038 private void updateTempWhitelistAppIdsLocked() {
1039 final int size = mTempWhitelistAppIdEndTimes.size();
1040 if (mTempWhitelistAppIdArray.length != size) {
1041 mTempWhitelistAppIdArray = new int[size];
1042 }
1043 for (int i = 0; i < size; i++) {
1044 mTempWhitelistAppIdArray[i] = mTempWhitelistAppIdEndTimes.keyAt(i);
1045 }
1046 if (mLocalPowerManager != null) {
1047 if (DEBUG) {
1048 Slog.d(TAG, "Setting wakelock temp whitelist to "
1049 + Arrays.toString(mTempWhitelistAppIdArray));
1050 }
1051 mLocalPowerManager.setDeviceIdleTempWhitelist(mTempWhitelistAppIdArray);
1052 }
1053 }
1054
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001055 private void reportPowerSaveWhitelistChangedLocked() {
1056 Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
1057 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Amith Yamasaniaf575b92015-05-29 15:35:26 -07001058 getContext().sendBroadcastAsUser(intent, UserHandle.OWNER);
1059 }
1060
1061 private void reportTempWhitelistChangedLocked() {
1062 Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
1063 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
1064 getContext().sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001065 }
1066
1067 void readConfigFileLocked() {
1068 Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile());
1069 mPowerSaveWhitelistUserApps.clear();
1070 FileInputStream stream;
1071 try {
1072 stream = mConfigFile.openRead();
1073 } catch (FileNotFoundException e) {
1074 return;
1075 }
1076 try {
1077 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001078 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001079 readConfigFileLocked(parser);
1080 } catch (XmlPullParserException e) {
1081 } finally {
1082 try {
1083 stream.close();
1084 } catch (IOException e) {
1085 }
1086 }
1087
1088 }
1089
1090 private void readConfigFileLocked(XmlPullParser parser) {
1091 final PackageManager pm = getContext().getPackageManager();
1092
1093 try {
1094 int type;
1095 while ((type = parser.next()) != XmlPullParser.START_TAG
1096 && type != XmlPullParser.END_DOCUMENT) {
1097 ;
1098 }
1099
1100 if (type != XmlPullParser.START_TAG) {
1101 throw new IllegalStateException("no start tag found");
1102 }
1103
1104 int outerDepth = parser.getDepth();
1105 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1106 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1107 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1108 continue;
1109 }
1110
1111 String tagName = parser.getName();
1112 if (tagName.equals("wl")) {
1113 String name = parser.getAttributeValue(null, "n");
1114 if (name != null) {
1115 try {
1116 ApplicationInfo ai = pm.getApplicationInfo(name, 0);
1117 mPowerSaveWhitelistUserApps.put(ai.packageName,
1118 UserHandle.getAppId(ai.uid));
1119 } catch (PackageManager.NameNotFoundException e) {
1120 }
1121 }
1122 } else {
1123 Slog.w(TAG, "Unknown element under <config>: "
1124 + parser.getName());
1125 XmlUtils.skipCurrentTag(parser);
1126 }
1127 }
1128
1129 } catch (IllegalStateException e) {
1130 Slog.w(TAG, "Failed parsing config " + e);
1131 } catch (NullPointerException e) {
1132 Slog.w(TAG, "Failed parsing config " + e);
1133 } catch (NumberFormatException e) {
1134 Slog.w(TAG, "Failed parsing config " + e);
1135 } catch (XmlPullParserException e) {
1136 Slog.w(TAG, "Failed parsing config " + e);
1137 } catch (IOException e) {
1138 Slog.w(TAG, "Failed parsing config " + e);
1139 } catch (IndexOutOfBoundsException e) {
1140 Slog.w(TAG, "Failed parsing config " + e);
1141 }
1142 }
1143
1144 void writeConfigFileLocked() {
1145 mHandler.removeMessages(MSG_WRITE_CONFIG);
1146 mHandler.sendEmptyMessageDelayed(MSG_WRITE_CONFIG, 5000);
1147 }
1148
1149 void handleWriteConfigFile() {
1150 final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
1151
1152 try {
1153 synchronized (this) {
1154 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001155 out.setOutput(memStream, StandardCharsets.UTF_8.name());
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001156 writeConfigFileLocked(out);
1157 }
1158 } catch (IOException e) {
1159 }
1160
1161 synchronized (mConfigFile) {
1162 FileOutputStream stream = null;
1163 try {
1164 stream = mConfigFile.startWrite();
1165 memStream.writeTo(stream);
1166 stream.flush();
1167 FileUtils.sync(stream);
1168 stream.close();
1169 mConfigFile.finishWrite(stream);
1170 } catch (IOException e) {
1171 Slog.w(TAG, "Error writing config file", e);
1172 mConfigFile.failWrite(stream);
1173 }
1174 }
1175 }
1176
1177 void writeConfigFileLocked(XmlSerializer out) throws IOException {
1178 out.startDocument(null, true);
1179 out.startTag(null, "config");
1180 for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) {
1181 String name = mPowerSaveWhitelistUserApps.keyAt(i);
1182 out.startTag(null, "wl");
1183 out.attribute(null, "n", name);
1184 out.endTag(null, "wl");
1185 }
1186 out.endTag(null, "config");
1187 out.endDocument();
1188 }
1189
1190 private void dumpHelp(PrintWriter pw) {
1191 pw.println("Device idle controller (deviceidle) dump options:");
1192 pw.println(" [-h] [CMD]");
1193 pw.println(" -h: print this help text.");
1194 pw.println("Commands:");
1195 pw.println(" step");
1196 pw.println(" Immediately step to next state, without waiting for alarm.");
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -07001197 pw.println(" disable");
1198 pw.println(" Completely disable device idle mode.");
1199 pw.println(" enable");
1200 pw.println(" Re-enable device idle mode after it had previously been disabled.");
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001201 pw.println(" whitelist");
1202 pw.println(" Add (prefix with +) or remove (prefix with -) packages.");
1203 }
1204
1205 void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1206 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1207 != PackageManager.PERMISSION_GRANTED) {
1208 pw.println("Permission Denial: can't dump DeviceIdleController from from pid="
1209 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
1210 + " without permission " + android.Manifest.permission.DUMP);
1211 return;
1212 }
1213
1214 if (args != null) {
Amith Yamasaniaf575b92015-05-29 15:35:26 -07001215 int userId = UserHandle.USER_OWNER;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001216 for (int i=0; i<args.length; i++) {
1217 String arg = args[i];
1218 if ("-h".equals(arg)) {
1219 dumpHelp(pw);
1220 return;
Amith Yamasaniaf575b92015-05-29 15:35:26 -07001221 } else if ("-u".equals(arg)) {
1222 i++;
1223 if (i < args.length) {
1224 arg = args[i];
1225 userId = Integer.parseInt(arg);
1226 }
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -07001227 } else if ("-a".equals(arg)) {
1228 // Ignore, we always dump all.
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001229 } else if ("step".equals(arg)) {
1230 synchronized (this) {
1231 stepIdleStateLocked();
1232 pw.print("Stepped to: "); pw.println(stateToString(mState));
1233 }
1234 return;
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -07001235 } else if ("disable".equals(arg)) {
1236 synchronized (this) {
1237 if (!mIdleDisabled) {
1238 mIdleDisabled = true;
1239 becomeActiveLocked("disabled");
1240 pw.println("Idle mode disabled");
1241 }
1242 }
1243 return;
1244 } else if ("enable".equals(arg)) {
1245 synchronized (this) {
1246 if (mIdleDisabled) {
1247 mIdleDisabled = false;
1248 becomeInactiveIfAppropriateLocked();
1249 pw.println("Idle mode enabled");
1250 }
1251 }
1252 return;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001253 } else if ("whitelist".equals(arg)) {
1254 i++;
1255 while (i < args.length) {
1256 arg = args[i];
1257 i++;
1258 if (arg.length() < 1 || (arg.charAt(0) != '-'
1259 && arg.charAt(0) != '+')) {
1260 pw.println("Package must be prefixed with + or -: " + arg);
1261 return;
1262 }
1263 char op = arg.charAt(0);
1264 String pkg = arg.substring(1);
1265 if (op == '+') {
1266 if (addPowerSaveWhitelistAppInternal(pkg)) {
1267 pw.println("Added: " + pkg);
1268 } else {
1269 pw.println("Unknown package: " + pkg);
1270 }
1271 } else {
1272 if (removePowerSaveWhitelistAppInternal(pkg)) {
1273 pw.println("Removed: " + pkg);
1274 }
1275 }
1276 }
1277 return;
Amith Yamasaniaf575b92015-05-29 15:35:26 -07001278 } else if ("tempwhitelist".equals(arg)) {
1279 i++;
1280 if (i >= args.length) {
1281 pw.println("At least one package name must be specified");
1282 return;
1283 }
1284 while (i < args.length) {
1285 arg = args[i];
1286 i++;
1287 addPowerSaveTempWhitelistAppInternal(arg, 10000L, userId);
1288 }
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001289 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
1290 pw.println("Unknown option: " + arg);
1291 return;
1292 } else {
1293 pw.println("Unknown command: " + arg);
1294 return;
1295 }
1296 }
1297 }
1298
1299 synchronized (this) {
1300 int size = mPowerSaveWhitelistApps.size();
1301 if (size > 0) {
1302 pw.println(" Whitelist system apps:");
1303 for (int i = 0; i < size; i++) {
1304 pw.print(" ");
1305 pw.println(mPowerSaveWhitelistApps.keyAt(i));
1306 }
1307 }
1308 size = mPowerSaveWhitelistUserApps.size();
1309 if (size > 0) {
1310 pw.println(" Whitelist user apps:");
1311 for (int i = 0; i < size; i++) {
1312 pw.print(" ");
1313 pw.println(mPowerSaveWhitelistUserApps.keyAt(i));
1314 }
1315 }
1316 size = mPowerSaveWhitelistAppIds.size();
1317 if (size > 0) {
1318 pw.println(" Whitelist app uids:");
1319 for (int i = 0; i < size; i++) {
1320 pw.print(" UID=");
1321 pw.print(mPowerSaveWhitelistAppIds.keyAt(i));
1322 pw.print(": ");
1323 pw.print(mPowerSaveWhitelistAppIds.valueAt(i));
1324 pw.println();
1325 }
1326 }
Adam Lesinski31c05d12015-06-09 17:34:04 -07001327
1328 mConstants.dump(pw);
1329
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001330 pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor);
1331 pw.print(" mCurDisplay="); pw.println(mCurDisplay);
Dianne Hackborn8d66b3f2015-05-08 17:21:48 -07001332 pw.print(" mIdleDisabled="); pw.println(mIdleDisabled);
Dianne Hackborn0b4daca2015-04-27 09:47:32 -07001333 pw.print(" mScreenOn="); pw.println(mScreenOn);
1334 pw.print(" mCharging="); pw.println(mCharging);
1335 pw.print(" mSigMotionActive="); pw.println(mSigMotionActive);
1336 pw.print(" mState="); pw.println(stateToString(mState));
1337 pw.print(" mInactiveTimeout="); TimeUtils.formatDuration(mInactiveTimeout, pw);
1338 pw.println();
1339 if (mNextAlarmTime != 0) {
1340 pw.print(" mNextAlarmTime=");
1341 TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw);
1342 pw.println();
1343 }
1344 if (mNextIdlePendingDelay != 0) {
1345 pw.print(" mNextIdlePendingDelay=");
1346 TimeUtils.formatDuration(mNextIdlePendingDelay, pw);
1347 pw.println();
1348 }
1349 if (mNextIdleDelay != 0) {
1350 pw.print(" mNextIdleDelay=");
1351 TimeUtils.formatDuration(mNextIdleDelay, pw);
1352 pw.println();
1353 }
1354 }
1355 }
1356}