1b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav/* 2b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * Copyright (C) 2013 The Android Open Source Project 3b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * 4b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * Licensed under the Apache License, Version 2.0 (the "License"); 5b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * you may not use this file except in compliance with the License. 6b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * You may obtain a copy of the License at 7b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * 8b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * http://www.apache.org/licenses/LICENSE-2.0 9b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * 10b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * Unless required by applicable law or agreed to in writing, software 11b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * distributed under the License is distributed on an "AS IS" BASIS, 12b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * See the License for the specific language governing permissions and 14b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * limitations under the License. 15b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav */ 16b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 17b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavpackage com.android.server; 18b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 19b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.app.Activity; 2035f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackbornimport android.app.ActivityManagerNative; 216a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslavimport android.app.AlarmManager; 226a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslavimport android.app.PendingIntent; 23b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.content.BroadcastReceiver; 24b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.content.Context; 25b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.content.Intent; 26b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.content.IntentFilter; 27b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.Handler; 28b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.PowerManager; 29b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.PowerManager.WakeLock; 3035f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackbornimport android.os.RemoteException; 31b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.SystemClock; 32b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.UserHandle; 33b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.util.Log; 3435f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackbornimport android.util.Slog; 35b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 36b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav/** 37b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * This service observes the device state and when applicable sends 38b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * broadcasts at the beginning and at the end of a period during which 39b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * observers can perform idle maintenance tasks. Typical use of the 40b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * idle maintenance is to perform somehow expensive tasks that can be 41b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * postponed to a moment when they will not degrade user experience. 42b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * 43b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * The current implementation is very simple. The start of a maintenance 44b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * window is announced if: the screen is off or showing a dream AND the 45b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * battery level is more than twenty percent AND at least one hour passed 46b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * activity). 47b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * 48b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * The end of a maintenance window is announced only if: a start was 49b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * announced AND the screen turned on or a dream was stopped. 50b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav */ 51b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavpublic class IdleMaintenanceService extends BroadcastReceiver { 52b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 536a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final boolean DEBUG = false; 54b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 55b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private static final String LOG_TAG = IdleMaintenanceService.class.getSimpleName(); 56b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 57b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1; 58b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 596a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final long MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS = 24 * 60 * 60 * 1000; // 1 day 60f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav 61f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING = 30; // percent 62f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav 63f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING = 80; // percent 64b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 656a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING = 20; // percent 66f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav 676a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final long MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START = 71 * 60 * 1000; // 71 min 68b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 696a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final long MAX_IDLE_MAINTENANCE_DURATION = 71 * 60 * 1000; // 71 min 70b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 716a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE = 726a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav "com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE"; 736a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 7435f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn private static final String ACTION_FORCE_IDLE_MAINTENANCE = 7535f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE"; 7635f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn 776a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final Intent sIdleMaintenanceStartIntent; 786a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav static { 796a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav sIdleMaintenanceStartIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_START); 806a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav sIdleMaintenanceStartIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 816a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav }; 826a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 836a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final Intent sIdleMaintenanceEndIntent; 846a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav static { 856a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav sIdleMaintenanceEndIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_END); 866a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav sIdleMaintenanceEndIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 876a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 886a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 896a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private final AlarmManager mAlarmService; 906a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 916a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private final BatteryService mBatteryService; 926a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 936a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private final PendingIntent mUpdateIdleMaintenanceStatePendingIntent; 94b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 95b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private final Context mContext; 96b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 97b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private final WakeLock mWakeLock; 98b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 99b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private final Handler mHandler; 100b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 1016a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private long mLastIdleMaintenanceStartTimeMillis; 102b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 103b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID; 104b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 105b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private boolean mIdleMaintenanceStarted; 106b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 1076a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav public IdleMaintenanceService(Context context, BatteryService batteryService) { 108b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mContext = context; 1096a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mBatteryService = batteryService; 1106a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 1116a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mAlarmService = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 112b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 113b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 114b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); 115b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 116b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mHandler = new Handler(mContext.getMainLooper()); 117b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 1186a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav Intent intent = new Intent(ACTION_UPDATE_IDLE_MAINTENANCE_STATE); 1196a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 1206a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0, 1216a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav intent, PendingIntent.FLAG_UPDATE_CURRENT); 1226a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 12335f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn register(mHandler); 124b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 125b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 12635f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn public void register(Handler handler) { 127b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav IntentFilter intentFilter = new IntentFilter(); 128b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 1296a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Alarm actions. 1306a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav intentFilter.addAction(ACTION_UPDATE_IDLE_MAINTENANCE_STATE); 1316a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 132b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav // Battery actions. 133b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 134b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 135b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav // Screen actions. 136b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter.addAction(Intent.ACTION_SCREEN_ON); 137b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 138b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 139b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav // Dream actions. 140b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter.addAction(Intent.ACTION_DREAMING_STARTED); 141b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED); 142b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 143b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mContext.registerReceiverAsUser(this, UserHandle.ALL, 14435f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn intentFilter, null, mHandler); 14535f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn 14635f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn intentFilter = new IntentFilter(); 14735f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn intentFilter.addAction(ACTION_FORCE_IDLE_MAINTENANCE); 14835f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn mContext.registerReceiverAsUser(this, UserHandle.ALL, 14935f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn intentFilter, android.Manifest.permission.SET_ACTIVITY_WATCHER, mHandler); 150b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 151b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 1526a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private void scheduleUpdateIdleMaintenanceState(long delayMillis) { 1536a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav final long triggetRealTimeMillis = SystemClock.elapsedRealtime() + delayMillis; 1546a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggetRealTimeMillis, 1556a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mUpdateIdleMaintenanceStatePendingIntent); 1566a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 1576a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 1586a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private void unscheduleUpdateIdleMaintenanceState() { 1596a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent); 1606a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 1616a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 16235f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn private void updateIdleMaintenanceState(boolean noisy) { 163b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav if (mIdleMaintenanceStarted) { 1646a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Idle maintenance can be interrupted by user activity, or duration 1656a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // time out, or low battery. 1666a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav if (!lastUserActivityPermitsIdleMaintenanceRunning() 1676a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav || !batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) { 1686a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav unscheduleUpdateIdleMaintenanceState(); 169b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mIdleMaintenanceStarted = false; 170f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(), 1716a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(), 1726a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav isBatteryCharging() ? 1 : 0); 173b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav sendIdleMaintenanceEndIntent(); 1746a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // We stopped since we don't have enough battery or timed out but the 1756a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // user is not using the device, so we should be able to run maintenance 1766a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // in the next maintenance window since the battery may be charged 1776a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // without interaction and the min interval between maintenances passed. 1786a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav if (!batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) { 1796a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav scheduleUpdateIdleMaintenanceState( 1806a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav getNextIdleMaintenanceIntervalStartFromNow()); 1816a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 182b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 18335f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn } else if (deviceStatePermitsIdleMaintenanceStart(noisy) 18435f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn && lastUserActivityPermitsIdleMaintenanceStart(noisy) 18535f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn && lastRunPermitsIdleMaintenanceStart(noisy)) { 1866a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Now that we started idle maintenance, we should schedule another 1876a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // update for the moment when the idle maintenance times out. 1886a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION); 189b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mIdleMaintenanceStarted = true; 190f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav EventLogTags.writeIdleMaintenanceWindowStart(SystemClock.elapsedRealtime(), 1916a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(), 1926a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav isBatteryCharging() ? 1 : 0); 193f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime(); 194b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav sendIdleMaintenanceStartIntent(); 19535f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn } else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) { 19635f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn if (lastRunPermitsIdleMaintenanceStart(noisy)) { 1976a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // The user does not use the device and we did not run maintenance in more 1986a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // than the min interval between runs, so schedule an update - maybe the 1996a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // battery will be charged latter. 2006a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); 2016a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } else { 2026a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // The user does not use the device but we have run maintenance in the min 2036a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // interval between runs, so schedule an update after the min interval ends. 2046a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav scheduleUpdateIdleMaintenanceState( 2056a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav getNextIdleMaintenanceIntervalStartFromNow()); 2066a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 207b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 208b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 209b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 2106a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private long getNextIdleMaintenanceIntervalStartFromNow() { 2116a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav return mLastIdleMaintenanceStartTimeMillis + MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS 2126a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav - SystemClock.elapsedRealtime(); 2136a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 2146a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 215b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private void sendIdleMaintenanceStartIntent() { 216b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mWakeLock.acquire(); 21735f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn try { 21835f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn ActivityManagerNative.getDefault().performIdleMaintenance(); 21935f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn } catch (RemoteException e) { 22035f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn } 2216a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceStartIntent, UserHandle.ALL, 222b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav null, this, mHandler, Activity.RESULT_OK, null, null); 223b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 224b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 225b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private void sendIdleMaintenanceEndIntent() { 226b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mWakeLock.acquire(); 2276a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceEndIntent, UserHandle.ALL, 228b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav null, this, mHandler, Activity.RESULT_OK, null, null); 229b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 230b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 23135f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) { 2326a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav final int minBatteryLevel = isBatteryCharging() 233f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav ? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING 234f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav : MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING; 23535f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID 2366a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav && mBatteryService.getBatteryLevel() > minBatteryLevel); 23735f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn if (!allowed && noisy) { 23835f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn Slog.i("IdleMaintenance", "Idle maintenance not allowed due to power"); 23935f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn } 24035f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn return allowed; 241f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav } 242f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav 24335f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn private boolean lastUserActivityPermitsIdleMaintenanceStart(boolean noisy) { 2446a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // The last time the user poked the device is above the threshold. 24535f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID 2466a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav && SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis 2476a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav > MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); 24835f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn if (!allowed && noisy) { 24935f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn Slog.i("IdleMaintenance", "Idle maintenance not allowed due to last user activity"); 25035f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn } 25135f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn return allowed; 252b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 253b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 25435f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn private boolean lastRunPermitsIdleMaintenanceStart(boolean noisy) { 2556a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Enough time passed since the last maintenance run. 25635f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn boolean allowed = SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis 2576a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav > MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS; 25835f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn if (!allowed && noisy) { 25935f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn Slog.i("IdleMaintenance", "Idle maintenance not allowed due time since last"); 26035f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn } 26135f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn return allowed; 262b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 263b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 2646a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private boolean lastUserActivityPermitsIdleMaintenanceRunning() { 2656a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // The user is not using the device. 2666a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID); 2676a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 2686a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 2696a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private boolean batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning() { 2706a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Battery not too low and the maintenance duration did not timeout. 2716a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav return (mBatteryService.getBatteryLevel() > MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING 2726a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav && mLastIdleMaintenanceStartTimeMillis + MAX_IDLE_MAINTENANCE_DURATION 2736a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav > SystemClock.elapsedRealtime()); 2746a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 2756a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 2766a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private boolean isBatteryCharging() { 2776a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav return mBatteryService.getPlugType() > 0 2786a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav && mBatteryService.getInvalidCharger() == 0; 279b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 280b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 281b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav @Override 282b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav public void onReceive(Context context, Intent intent) { 283b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav if (DEBUG) { 284b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav Log.i(LOG_TAG, intent.getAction()); 285b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 286b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav String action = intent.getAction(); 287b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { 2886a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // We care about battery only if maintenance is in progress so we can 2896a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // stop it if battery is too low. Note that here we assume that the 2906a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // maintenance clients are properly holding a wake lock. We will 2916a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // refactor the maintenance to use services instead of intents for the 2926a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // next release. The only client for this for now is internal an holds 2936a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // a wake lock correctly. 2946a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav if (mIdleMaintenanceStarted) { 29535f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn updateIdleMaintenanceState(false); 2966a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 297b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } else if (Intent.ACTION_SCREEN_ON.equals(action) 298b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav || Intent.ACTION_DREAMING_STOPPED.equals(action)) { 299b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID; 3006a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Unschedule any future updates since we already know that maintenance 3016a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // cannot be performed since the user is back. 3026a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav unscheduleUpdateIdleMaintenanceState(); 3036a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // If the screen went on/stopped dreaming, we know the user is using the 3046a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // device which means that idle maintenance should be stopped if running. 30535f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn updateIdleMaintenanceState(false); 306b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } else if (Intent.ACTION_SCREEN_OFF.equals(action) 307b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav || Intent.ACTION_DREAMING_STARTED.equals(action)) { 308b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime(); 3096a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // If screen went off/started dreaming, we may be able to start idle maintenance 3106a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // after the minimal user inactivity elapses. We schedule an alarm for when 3116a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // this timeout elapses since the device may go to sleep by then. 3126a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); 3136a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) { 31435f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn updateIdleMaintenanceState(false); 31535f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn } else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) { 31635f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn long now = SystemClock.elapsedRealtime() - 1; 31735f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START; 31835f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS; 31935f72be50b8a2d11bce591dcdac5dc3fa336dac0Dianne Hackborn updateIdleMaintenanceState(true); 320b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action) 321b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav || Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) { 3226a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // We were holding a wake lock while broadcasting the idle maintenance 3236a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // intents but now that we finished the broadcast release the wake lock. 324b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mWakeLock.release(); 325b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 326b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 327b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav} 328