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