blob: f1bfa0411978ea9af738c2876106b5fe1f1c6714 [file] [log] [blame]
Amith Yamasani7e528f32017-10-05 16:06:16 -07001/**
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
17package com.android.server.usage;
18
Amith Yamasani119be9a2018-02-18 22:23:00 -080019import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
Kweku Adamsc182d5e2020-01-08 18:37:26 -080020import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
21import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
Amith Yamasani119be9a2018-02-18 22:23:00 -080022import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK;
23import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
24import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
25import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
Kweku Adamsc6a9b342020-01-08 18:37:26 -080026import static android.app.usage.UsageStatsManager.REASON_SUB_MASK;
Amith Yamasani3154dcf2018-03-27 18:24:04 -070027import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
Amith Yamasani119be9a2018-02-18 22:23:00 -080028import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
Makoto Onukid5f25d22018-05-22 16:02:17 -070029import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
30import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
Makoto Onuki75ad2492018-03-28 14:42:42 -070031import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START;
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -070032import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
Amith Yamasani119be9a2018-02-18 22:23:00 -080033import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
34import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
35import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
Kweku Adams1e8947c2018-11-05 18:06:13 -080036import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
37import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
Amith Yamasani119be9a2018-02-18 22:23:00 -080038import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
39import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
40import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
Michael Wachenschwanzc3295202019-02-20 17:19:52 -080041import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED;
Amith Yamasani119be9a2018-02-18 22:23:00 -080042import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080043import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
Amith Yamasani5a8cc722017-12-06 10:26:10 -080044import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080045import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
Amith Yamasani93885192017-12-13 11:52:10 -080046import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080047import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
Kweku Adamsc6a9b342020-01-08 18:37:26 -080048import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080049import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
Kweku Adams1e8947c2018-11-05 18:06:13 -080050
Amith Yamasani7e528f32017-10-05 16:06:16 -070051import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
Amith Yamasani7e528f32017-10-05 16:06:16 -070052
Kweku Adamsc4ee9982020-01-08 11:14:39 -080053import android.annotation.NonNull;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -080054import android.annotation.UserIdInt;
Amith Yamasani7e528f32017-10-05 16:06:16 -070055import android.app.ActivityManager;
56import android.app.AppGlobals;
Suprabh Shukla868bde22018-02-20 20:59:52 -080057import android.app.usage.AppStandbyInfo;
Amith Yamasani7e528f32017-10-05 16:06:16 -070058import android.app.usage.UsageEvents;
Jason Monk1918ef72018-03-14 09:20:39 -040059import android.app.usage.UsageStatsManager.StandbyBuckets;
Amith Yamasani7e528f32017-10-05 16:06:16 -070060import android.appwidget.AppWidgetManager;
61import android.content.BroadcastReceiver;
62import android.content.ContentResolver;
63import android.content.Context;
64import android.content.Intent;
65import android.content.IntentFilter;
66import android.content.pm.ApplicationInfo;
67import android.content.pm.PackageInfo;
68import android.content.pm.PackageManager;
69import android.content.pm.PackageManagerInternal;
70import android.content.pm.ParceledListSlice;
71import android.database.ContentObserver;
72import android.hardware.display.DisplayManager;
Michael Wachenschwanz113a0fa2018-03-30 12:45:18 -070073import android.net.ConnectivityManager;
74import android.net.Network;
Michael Wachenschwanz113a0fa2018-03-30 12:45:18 -070075import android.net.NetworkRequest;
Amith Yamasani7e528f32017-10-05 16:06:16 -070076import android.net.NetworkScoreManager;
Amith Yamasani7e528f32017-10-05 16:06:16 -070077import android.os.BatteryStats;
Kweku Adamsc6a9b342020-01-08 18:37:26 -080078import android.os.Build;
Amith Yamasani17fffee2017-09-29 13:17:43 -070079import android.os.Environment;
Amith Yamasani7e528f32017-10-05 16:06:16 -070080import android.os.Handler;
81import android.os.IDeviceIdleController;
82import android.os.Looper;
83import android.os.Message;
84import android.os.PowerManager;
85import android.os.Process;
86import android.os.RemoteException;
87import android.os.ServiceManager;
88import android.os.SystemClock;
89import android.os.UserHandle;
Lei Yu4b976ad2018-04-19 10:38:58 -070090import android.provider.Settings.Global;
Amith Yamasani7e528f32017-10-05 16:06:16 -070091import android.telephony.TelephonyManager;
Sudheer Shanka101c3532018-01-08 16:28:42 -080092import android.util.ArraySet;
Amith Yamasani7e528f32017-10-05 16:06:16 -070093import android.util.KeyValueListParser;
94import android.util.Slog;
Sudheer Shanka101c3532018-01-08 16:28:42 -080095import android.util.SparseArray;
Amith Yamasani7e528f32017-10-05 16:06:16 -070096import android.util.SparseIntArray;
97import android.util.TimeUtils;
98import android.view.Display;
Kweku Adamsc6a9b342020-01-08 18:37:26 -080099import android.widget.Toast;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700100
Kweku Adamsc6a9b342020-01-08 18:37:26 -0800101import com.android.internal.R;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700102import com.android.internal.annotations.GuardedBy;
Sudheer Shanka101c3532018-01-08 16:28:42 -0800103import com.android.internal.annotations.VisibleForTesting;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700104import com.android.internal.app.IBatteryStats;
105import com.android.internal.os.SomeArgs;
106import com.android.internal.util.ArrayUtils;
Sudheer Shankac53c47f2018-01-16 12:01:00 -0800107import com.android.internal.util.ConcurrentUtils;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700108import com.android.internal.util.IndentingPrintWriter;
109import com.android.server.LocalServices;
Christopher Tated117b292018-01-05 17:32:36 -0800110import com.android.server.usage.AppIdleHistory.AppUsageHistory;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700111
Amith Yamasani17fffee2017-09-29 13:17:43 -0700112import java.io.File;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700113import java.io.PrintWriter;
Amith Yamasani761d3ff2017-12-14 17:50:03 -0800114import java.time.Duration;
115import java.time.format.DateTimeParseException;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700116import java.util.ArrayList;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700117import java.util.Arrays;
Kweku Adamsc4ee9982020-01-08 11:14:39 -0800118import java.util.Collections;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700119import java.util.List;
Sudheer Shanka101c3532018-01-08 16:28:42 -0800120import java.util.Set;
Sudheer Shankac53c47f2018-01-16 12:01:00 -0800121import java.util.concurrent.CountDownLatch;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700122
123/**
124 * Manages the standby state of an app, listening to various events.
Makoto Onukia0058b42018-05-22 16:32:23 -0700125 *
126 * Unit test:
Makoto Onukia72e04f2019-10-03 11:10:45 -0700127 atest com.android.server.usage.AppStandbyControllerTests
Amith Yamasani7e528f32017-10-05 16:06:16 -0700128 */
Makoto Onukia72e04f2019-10-03 11:10:45 -0700129public class AppStandbyController implements AppStandbyInternal {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700130
131 private static final String TAG = "AppStandbyController";
Kweku Adamsc6a9b342020-01-08 18:37:26 -0800132 static final boolean DEBUG = true;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700133
134 static final boolean COMPRESS_TIME = false;
135 private static final long ONE_MINUTE = 60 * 1000;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700136 private static final long ONE_HOUR = ONE_MINUTE * 60;
137 private static final long ONE_DAY = ONE_HOUR * 24;
138
Kweku Adams4297b5d2020-02-06 15:56:12 -0800139 /**
140 * The minimum amount of time the screen must have been on before an app can time out from its
141 * current bucket to the next bucket.
142 */
143 private static final long[] SCREEN_TIME_THRESHOLDS = {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700144 0,
145 0,
Kweku Adams4297b5d2020-02-06 15:56:12 -0800146 COMPRESS_TIME ? 2 * ONE_MINUTE : 1 * ONE_HOUR,
147 COMPRESS_TIME ? 4 * ONE_MINUTE : 2 * ONE_HOUR,
148 COMPRESS_TIME ? 8 * ONE_MINUTE : 6 * ONE_HOUR
Amith Yamasani17fffee2017-09-29 13:17:43 -0700149 };
150
Kweku Adams4297b5d2020-02-06 15:56:12 -0800151 /** The minimum allowed values for each index in {@link #SCREEN_TIME_THRESHOLDS}. */
152 private static final long[] MINIMUM_SCREEN_TIME_THRESHOLDS = COMPRESS_TIME
153 ? new long[SCREEN_TIME_THRESHOLDS.length]
154 : new long[]{
155 0,
156 0,
157 0,
158 30 * ONE_MINUTE,
159 ONE_HOUR
160 };
161
162 /**
163 * The minimum amount of elapsed time that must have passed before an app can time out from its
164 * current bucket to the next bucket.
165 */
166 private static final long[] ELAPSED_TIME_THRESHOLDS = {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700167 0,
168 COMPRESS_TIME ? 1 * ONE_MINUTE : 12 * ONE_HOUR,
Amith Yamasani301e94a2017-11-17 16:35:44 -0800169 COMPRESS_TIME ? 4 * ONE_MINUTE : 24 * ONE_HOUR,
Kweku Adams4297b5d2020-02-06 15:56:12 -0800170 COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR,
171 // TODO(149050681): increase timeout to 30+ days
172 COMPRESS_TIME ? 32 * ONE_MINUTE : 4 * ONE_DAY
Amith Yamasani17fffee2017-09-29 13:17:43 -0700173 };
174
Kweku Adams4297b5d2020-02-06 15:56:12 -0800175 /** The minimum allowed values for each index in {@link #ELAPSED_TIME_THRESHOLDS}. */
176 private static final long[] MINIMUM_ELAPSED_TIME_THRESHOLDS = COMPRESS_TIME
177 ? new long[ELAPSED_TIME_THRESHOLDS.length]
178 : new long[]{
179 0,
180 ONE_HOUR,
181 ONE_HOUR,
182 2 * ONE_HOUR,
183 4 * ONE_DAY
184 };
185
186 private static final int[] THRESHOLD_BUCKETS = {
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800187 STANDBY_BUCKET_ACTIVE,
188 STANDBY_BUCKET_WORKING_SET,
189 STANDBY_BUCKET_FREQUENT,
Kweku Adams4297b5d2020-02-06 15:56:12 -0800190 STANDBY_BUCKET_RARE,
191 STANDBY_BUCKET_RESTRICTED
Amith Yamasani17fffee2017-09-29 13:17:43 -0700192 };
Amith Yamasani7e528f32017-10-05 16:06:16 -0700193
Amith Yamasani119be9a2018-02-18 22:23:00 -0800194 /** Default expiration time for bucket prediction. After this, use thresholds to downgrade. */
195 private static final long DEFAULT_PREDICTION_TIMEOUT = 12 * ONE_HOUR;
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800196
Sudheer Shankac53c47f2018-01-16 12:01:00 -0800197 /**
198 * Indicates the maximum wait time for admin data to be available;
199 */
200 private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
201
Amith Yamasani7e528f32017-10-05 16:06:16 -0700202 // To name the lock for stack traces
203 static class Lock {}
204
205 /** Lock to protect the app's standby state. Required for calls into AppIdleHistory */
206 private final Object mAppIdleLock = new Lock();
207
208 /** Keeps the history and state for each app. */
209 @GuardedBy("mAppIdleLock")
210 private AppIdleHistory mAppIdleHistory;
211
Amith Yamasani93885192017-12-13 11:52:10 -0800212 @GuardedBy("mPackageAccessListeners")
Amith Yamasani17fffee2017-09-29 13:17:43 -0700213 private ArrayList<AppIdleStateChangeListener>
Amith Yamasani7e528f32017-10-05 16:06:16 -0700214 mPackageAccessListeners = new ArrayList<>();
215
216 /** Whether we've queried the list of carrier privileged apps. */
217 @GuardedBy("mAppIdleLock")
218 private boolean mHaveCarrierPrivilegedApps;
219
220 /** List of carrier-privileged apps that should be excluded from standby */
221 @GuardedBy("mAppIdleLock")
222 private List<String> mCarrierPrivilegedApps;
223
Sudheer Shanka101c3532018-01-08 16:28:42 -0800224 @GuardedBy("mActiveAdminApps")
225 private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
226
Sudheer Shankac53c47f2018-01-16 12:01:00 -0800227 private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
228
Amith Yamasani7e528f32017-10-05 16:06:16 -0700229 // Messages for the handler
230 static final int MSG_INFORM_LISTENERS = 3;
231 static final int MSG_FORCE_IDLE_STATE = 4;
232 static final int MSG_CHECK_IDLE_STATES = 5;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700233 static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700234 static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800235 /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
236 static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800237 static final int MSG_REPORT_SYNC_SCHEDULED = 12;
Makoto Onukid5f25d22018-05-22 16:02:17 -0700238 static final int MSG_REPORT_EXEMPTED_SYNC_START = 13;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700239
Amith Yamasani7e528f32017-10-05 16:06:16 -0700240 long mCheckIdleIntervalMillis;
Kweku Adams4297b5d2020-02-06 15:56:12 -0800241 /**
242 * The minimum amount of time the screen must have been on before an app can time out from its
243 * current bucket to the next bucket.
244 */
Amith Yamasani17fffee2017-09-29 13:17:43 -0700245 long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS;
Kweku Adams4297b5d2020-02-06 15:56:12 -0800246 /**
247 * The minimum amount of elapsed time that must have passed before an app can time out from its
248 * current bucket to the next bucket.
249 */
Amith Yamasani17fffee2017-09-29 13:17:43 -0700250 long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS;
Amith Yamasani7ec89412018-02-07 08:48:49 -0800251 /** Minimum time a strong usage event should keep the bucket elevated. */
252 long mStrongUsageTimeoutMillis;
253 /** Minimum time a notification seen event should keep the bucket elevated. */
254 long mNotificationSeenTimeoutMillis;
255 /** Minimum time a system update event should keep the buckets elevated. */
256 long mSystemUpdateUsageTimeoutMillis;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800257 /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */
258 long mPredictionTimeoutMillis;
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700259 /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */
260 long mSyncAdapterTimeoutMillis;
Makoto Onukid5f25d22018-05-22 16:02:17 -0700261 /**
262 * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
263 * non-doze
264 */
265 long mExemptedSyncScheduledNonDozeTimeoutMillis;
266 /**
267 * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
268 * doze
269 */
270 long mExemptedSyncScheduledDozeTimeoutMillis;
271 /**
272 * Maximum time an exempted sync should keep the buckets elevated, when sync is started.
273 */
274 long mExemptedSyncStartTimeoutMillis;
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800275 /**
276 * Maximum time an unexempted sync should keep the buckets elevated, when sync is scheduled
277 */
278 long mUnexemptedSyncScheduledTimeoutMillis;
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700279 /** Maximum time a system interaction should keep the buckets elevated. */
280 long mSystemInteractionTimeoutMillis;
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -0700281 /**
282 * Maximum time a foreground service start should keep the buckets elevated if the service
283 * start is the first usage of the app
284 */
285 long mInitialForegroundServiceStartTimeoutMillis;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700286
Makoto Onukia72e04f2019-10-03 11:10:45 -0700287 private volatile boolean mAppIdleEnabled;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700288 private boolean mSystemServicesReady = false;
Amith Yamasani777b1532018-01-28 23:20:07 +0000289 // There was a system update, defaults need to be initialized after services are ready
290 private boolean mPendingInitializeDefaults;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700291
292 private volatile boolean mPendingOneTimeCheckIdleStates;
293
Christopher Tatea732f012017-10-26 17:26:53 -0700294 private final AppStandbyHandler mHandler;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700295 private final Context mContext;
296
Amith Yamasani17fffee2017-09-29 13:17:43 -0700297 // TODO: Provide a mechanism to set an external bucketing service
Amith Yamasani17fffee2017-09-29 13:17:43 -0700298
Amith Yamasani7e528f32017-10-05 16:06:16 -0700299 private AppWidgetManager mAppWidgetManager;
Michael Wachenschwanz113a0fa2018-03-30 12:45:18 -0700300 private ConnectivityManager mConnectivityManager;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700301 private PackageManager mPackageManager;
Amith Yamasani172612c2017-12-15 10:51:53 -0800302 Injector mInjector;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700303
Christopher Tated117b292018-01-05 17:32:36 -0800304 static final ArrayList<StandbyUpdateRecord> sStandbyUpdatePool = new ArrayList<>(4);
305
306 public static class StandbyUpdateRecord {
307 // Identity of the app whose standby state has changed
308 String packageName;
309 int userId;
310
311 // What the standby bucket the app is now in
312 int bucket;
313
314 // Whether the bucket change is because the user has started interacting with the app
315 boolean isUserInteraction;
316
Amith Yamasani119be9a2018-02-18 22:23:00 -0800317 // Reason for bucket change
318 int reason;
319
320 StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason,
321 boolean isInteraction) {
Christopher Tated117b292018-01-05 17:32:36 -0800322 this.packageName = pkgName;
323 this.userId = userId;
324 this.bucket = bucket;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800325 this.reason = reason;
Christopher Tated117b292018-01-05 17:32:36 -0800326 this.isUserInteraction = isInteraction;
327 }
328
329 public static StandbyUpdateRecord obtain(String pkgName, int userId,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800330 int bucket, int reason, boolean isInteraction) {
Christopher Tated117b292018-01-05 17:32:36 -0800331 synchronized (sStandbyUpdatePool) {
332 final int size = sStandbyUpdatePool.size();
333 if (size < 1) {
Amith Yamasani119be9a2018-02-18 22:23:00 -0800334 return new StandbyUpdateRecord(pkgName, userId, bucket, reason, isInteraction);
Christopher Tated117b292018-01-05 17:32:36 -0800335 }
336 StandbyUpdateRecord r = sStandbyUpdatePool.remove(size - 1);
337 r.packageName = pkgName;
338 r.userId = userId;
339 r.bucket = bucket;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800340 r.reason = reason;
Christopher Tated117b292018-01-05 17:32:36 -0800341 r.isUserInteraction = isInteraction;
342 return r;
343 }
344 }
345
346 public void recycle() {
347 synchronized (sStandbyUpdatePool) {
348 sStandbyUpdatePool.add(this);
349 }
350 }
351 }
Amith Yamasani7e528f32017-10-05 16:06:16 -0700352
Makoto Onukia72e04f2019-10-03 11:10:45 -0700353 public AppStandbyController(Context context, Looper looper) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700354 this(new Injector(context, looper));
355 }
356
357 AppStandbyController(Injector injector) {
358 mInjector = injector;
359 mContext = mInjector.getContext();
360 mHandler = new AppStandbyHandler(mInjector.getLooper());
Amith Yamasani7e528f32017-10-05 16:06:16 -0700361 mPackageManager = mContext.getPackageManager();
Amith Yamasani172612c2017-12-15 10:51:53 -0800362
Amith Yamasani7e528f32017-10-05 16:06:16 -0700363 synchronized (mAppIdleLock) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700364 mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(),
365 mInjector.elapsedRealtime());
Amith Yamasani7e528f32017-10-05 16:06:16 -0700366 }
367
368 IntentFilter packageFilter = new IntentFilter();
369 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
370 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
371 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
372 packageFilter.addDataScheme("package");
373
374 mContext.registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter,
375 null, mHandler);
376 }
377
Makoto Onukia72e04f2019-10-03 11:10:45 -0700378 @VisibleForTesting
Amith Yamasani172612c2017-12-15 10:51:53 -0800379 void setAppIdleEnabled(boolean enabled) {
Kweku Adamsdf33ae12019-10-08 11:51:41 -0700380 mAppIdleEnabled = enabled;
Amith Yamasani172612c2017-12-15 10:51:53 -0800381 }
382
Makoto Onukia72e04f2019-10-03 11:10:45 -0700383 @Override
384 public boolean isAppIdleEnabled() {
385 return mAppIdleEnabled;
386 }
387
388 @Override
Amith Yamasani7e528f32017-10-05 16:06:16 -0700389 public void onBootPhase(int phase) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700390 mInjector.onBootPhase(phase);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700391 if (phase == PHASE_SYSTEM_SERVICES_READY) {
Amith Yamasani777b1532018-01-28 23:20:07 +0000392 Slog.d(TAG, "Setting app idle enabled state");
Amith Yamasani7e528f32017-10-05 16:06:16 -0700393 // Observe changes to the threshold
394 SettingsObserver settingsObserver = new SettingsObserver(mHandler);
395 settingsObserver.registerObserver();
396 settingsObserver.updateSettings();
397
398 mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class);
Michael Wachenschwanz113a0fa2018-03-30 12:45:18 -0700399 mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700400
Amith Yamasani17fffee2017-09-29 13:17:43 -0700401 mInjector.registerDisplayListener(mDisplayListener, mHandler);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700402 synchronized (mAppIdleLock) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700403 mAppIdleHistory.updateDisplay(isDisplayOn(), mInjector.elapsedRealtime());
Amith Yamasani7e528f32017-10-05 16:06:16 -0700404 }
405
Amith Yamasani777b1532018-01-28 23:20:07 +0000406 mSystemServicesReady = true;
407
Michael Wachenschwanzd1d8aa62019-02-28 16:38:37 -0800408 boolean userFileExists;
409 synchronized (mAppIdleLock) {
410 userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM);
411 }
412
413 if (mPendingInitializeDefaults || !userFileExists) {
Amith Yamasani777b1532018-01-28 23:20:07 +0000414 initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM);
415 }
416
Amith Yamasani7e528f32017-10-05 16:06:16 -0700417 if (mPendingOneTimeCheckIdleStates) {
418 postOneTimeCheckIdleStates();
419 }
Amith Yamasani7e528f32017-10-05 16:06:16 -0700420 }
421 }
422
Makoto Onukia72e04f2019-10-03 11:10:45 -0700423 private void reportContentProviderUsage(String authority, String providerPkgName, int userId) {
Amith Yamasani172612c2017-12-15 10:51:53 -0800424 if (!mAppIdleEnabled) return;
425
Amith Yamasani7e528f32017-10-05 16:06:16 -0700426 // Get sync adapters for the authority
427 String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
428 authority, userId);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800429 final long elapsedRealtime = mInjector.elapsedRealtime();
Amith Yamasani7e528f32017-10-05 16:06:16 -0700430 for (String packageName: packages) {
431 // Only force the sync adapters to active if the provider is not in the same package and
432 // the sync adapter is a system package.
433 try {
434 PackageInfo pi = mPackageManager.getPackageInfoAsUser(
435 packageName, PackageManager.MATCH_SYSTEM_ONLY, userId);
436 if (pi == null || pi.applicationInfo == null) {
437 continue;
438 }
439 if (!packageName.equals(providerPkgName)) {
Amith Yamasani803eab692017-11-09 17:47:04 -0800440 synchronized (mAppIdleLock) {
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800441 reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_ACTIVE,
442 REASON_SUB_USAGE_SYNC_ADAPTER, elapsedRealtime,
443 mSyncAdapterTimeoutMillis);
Amith Yamasani803eab692017-11-09 17:47:04 -0800444 }
Amith Yamasani7e528f32017-10-05 16:06:16 -0700445 }
446 } catch (PackageManager.NameNotFoundException e) {
447 // Shouldn't happen
448 }
449 }
450 }
451
Makoto Onukia72e04f2019-10-03 11:10:45 -0700452 private void reportExemptedSyncScheduled(String packageName, int userId) {
Makoto Onukid5f25d22018-05-22 16:02:17 -0700453 if (!mAppIdleEnabled) return;
454
455 final int bucketToPromote;
456 final int usageReason;
457 final long durationMillis;
458
459 if (!mInjector.isDeviceIdleMode()) {
460 // Not dozing.
461 bucketToPromote = STANDBY_BUCKET_ACTIVE;
462 usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
463 durationMillis = mExemptedSyncScheduledNonDozeTimeoutMillis;
464 } else {
465 // Dozing.
466 bucketToPromote = STANDBY_BUCKET_WORKING_SET;
467 usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
468 durationMillis = mExemptedSyncScheduledDozeTimeoutMillis;
469 }
470
471 final long elapsedRealtime = mInjector.elapsedRealtime();
472
473 synchronized (mAppIdleLock) {
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800474 reportNoninteractiveUsageLocked(packageName, userId, bucketToPromote,
475 usageReason, elapsedRealtime, durationMillis);
Makoto Onukid5f25d22018-05-22 16:02:17 -0700476 }
477 }
478
Makoto Onukia72e04f2019-10-03 11:10:45 -0700479 private void reportUnexemptedSyncScheduled(String packageName, int userId) {
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800480 if (!mAppIdleEnabled) return;
481
482 final long elapsedRealtime = mInjector.elapsedRealtime();
483 synchronized (mAppIdleLock) {
484 final int currentBucket =
485 mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
486 if (currentBucket == STANDBY_BUCKET_NEVER) {
487 // Bring the app out of the never bucket
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800488 reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_WORKING_SET,
489 REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED, elapsedRealtime,
490 mUnexemptedSyncScheduledTimeoutMillis);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800491 }
492 }
493 }
494
Makoto Onukia72e04f2019-10-03 11:10:45 -0700495 private void reportExemptedSyncStart(String packageName, int userId) {
Makoto Onuki75ad2492018-03-28 14:42:42 -0700496 if (!mAppIdleEnabled) return;
497
498 final long elapsedRealtime = mInjector.elapsedRealtime();
499
500 synchronized (mAppIdleLock) {
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800501 reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_ACTIVE,
502 REASON_SUB_USAGE_EXEMPTED_SYNC_START, elapsedRealtime,
503 mExemptedSyncStartTimeoutMillis);
Makoto Onuki75ad2492018-03-28 14:42:42 -0700504 }
505 }
506
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800507 private void reportNoninteractiveUsageLocked(String packageName, int userId, int bucket,
508 int subReason, long elapsedRealtime, long nextCheckDelay) {
509 final AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, bucket,
510 subReason, 0, elapsedRealtime + nextCheckDelay);
511 mHandler.sendMessageDelayed(
512 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, packageName),
513 nextCheckDelay);
514 maybeInformListeners(packageName, userId, elapsedRealtime, appUsage.currentBucket,
515 appUsage.bucketingReason, false);
516 }
517
Makoto Onukia72e04f2019-10-03 11:10:45 -0700518 @Override
519 public void postCheckIdleStates(int userId) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700520 mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
521 }
522
Makoto Onukia72e04f2019-10-03 11:10:45 -0700523 @Override
524 public void postOneTimeCheckIdleStates() {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700525 if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700526 // Not booted yet; wait for it!
527 mPendingOneTimeCheckIdleStates = true;
528 } else {
529 mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
530 mPendingOneTimeCheckIdleStates = false;
531 }
532 }
533
Makoto Onukia72e04f2019-10-03 11:10:45 -0700534 @VisibleForTesting
Amith Yamasani7e528f32017-10-05 16:06:16 -0700535 boolean checkIdleStates(int checkUserId) {
536 if (!mAppIdleEnabled) {
537 return false;
538 }
539
540 final int[] runningUserIds;
541 try {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700542 runningUserIds = mInjector.getRunningUserIds();
Amith Yamasani7e528f32017-10-05 16:06:16 -0700543 if (checkUserId != UserHandle.USER_ALL
544 && !ArrayUtils.contains(runningUserIds, checkUserId)) {
545 return false;
546 }
547 } catch (RemoteException re) {
548 throw re.rethrowFromSystemServer();
549 }
550
Amith Yamasani17fffee2017-09-29 13:17:43 -0700551 final long elapsedRealtime = mInjector.elapsedRealtime();
Amith Yamasani7e528f32017-10-05 16:06:16 -0700552 for (int i = 0; i < runningUserIds.length; i++) {
553 final int userId = runningUserIds[i];
554 if (checkUserId != UserHandle.USER_ALL && checkUserId != userId) {
555 continue;
556 }
557 if (DEBUG) {
558 Slog.d(TAG, "Checking idle state for user " + userId);
559 }
560 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
561 PackageManager.MATCH_DISABLED_COMPONENTS,
562 userId);
563 final int packageCount = packages.size();
564 for (int p = 0; p < packageCount; p++) {
565 final PackageInfo pi = packages.get(p);
566 final String packageName = pi.packageName;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800567 checkAndUpdateStandbyState(packageName, userId, pi.applicationInfo.uid,
568 elapsedRealtime);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700569 }
570 }
571 if (DEBUG) {
572 Slog.d(TAG, "checkIdleStates took "
Amith Yamasani17fffee2017-09-29 13:17:43 -0700573 + (mInjector.elapsedRealtime() - elapsedRealtime));
Amith Yamasani7e528f32017-10-05 16:06:16 -0700574 }
575 return true;
576 }
577
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800578 /** Check if we need to update the standby state of a specific app. */
579 private void checkAndUpdateStandbyState(String packageName, @UserIdInt int userId,
580 int uid, long elapsedRealtime) {
581 if (uid <= 0) {
582 try {
583 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
584 } catch (PackageManager.NameNotFoundException e) {
585 // Not a valid package for this user, nothing to do
586 // TODO: Remove any history of removed packages
587 return;
588 }
589 }
590 final boolean isSpecial = isAppSpecial(packageName,
591 UserHandle.getAppId(uid),
592 userId);
593 if (DEBUG) {
594 Slog.d(TAG, " Checking idle state for " + packageName + " special=" +
595 isSpecial);
596 }
597 if (isSpecial) {
598 synchronized (mAppIdleLock) {
599 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800600 STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800601 }
602 maybeInformListeners(packageName, userId, elapsedRealtime,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800603 STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT, false);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800604 } else {
605 synchronized (mAppIdleLock) {
606 final AppIdleHistory.AppUsageHistory app =
607 mAppIdleHistory.getAppUsageHistory(packageName,
608 userId, elapsedRealtime);
Amith Yamasani119be9a2018-02-18 22:23:00 -0800609 int reason = app.bucketingReason;
610 final int oldMainReason = reason & REASON_MAIN_MASK;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800611
612 // If the bucket was forced by the user/developer, leave it alone.
613 // A usage event will be the only way to bring it out of this forced state
Kweku Adamsc182d5e2020-01-08 18:37:26 -0800614 if (oldMainReason == REASON_MAIN_FORCED_BY_USER) {
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800615 return;
616 }
617 final int oldBucket = app.currentBucket;
618 int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700619 boolean predictionLate = predictionTimedOut(app, elapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800620 // Compute age-based bucket
Amith Yamasani119be9a2018-02-18 22:23:00 -0800621 if (oldMainReason == REASON_MAIN_DEFAULT
622 || oldMainReason == REASON_MAIN_USAGE
623 || oldMainReason == REASON_MAIN_TIMEOUT
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700624 || predictionLate) {
625
626 if (!predictionLate && app.lastPredictedBucket >= STANDBY_BUCKET_ACTIVE
627 && app.lastPredictedBucket <= STANDBY_BUCKET_RARE) {
628 newBucket = app.lastPredictedBucket;
629 reason = REASON_MAIN_PREDICTED | REASON_SUB_PREDICTED_RESTORED;
630 if (DEBUG) {
631 Slog.d(TAG, "Restored predicted newBucket = " + newBucket);
632 }
633 } else {
634 newBucket = getBucketForLocked(packageName, userId,
635 elapsedRealtime);
636 if (DEBUG) {
637 Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket);
638 }
639 reason = REASON_MAIN_TIMEOUT;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800640 }
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800641 }
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700642
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800643 // Check if the app is within one of the timeouts for forced bucket elevation
644 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
645 if (newBucket >= STANDBY_BUCKET_ACTIVE
646 && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
647 newBucket = STANDBY_BUCKET_ACTIVE;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800648 reason = app.bucketingReason;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800649 if (DEBUG) {
650 Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
651 }
652 } else if (newBucket >= STANDBY_BUCKET_WORKING_SET
653 && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
654 newBucket = STANDBY_BUCKET_WORKING_SET;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800655 // If it was already there, keep the reason, else assume timeout to WS
656 reason = (newBucket == oldBucket)
657 ? app.bucketingReason
658 : REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800659 if (DEBUG) {
660 Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
661 }
662 }
Kweku Adamsc6a9b342020-01-08 18:37:26 -0800663
664 if (app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime
665 && elapsedTimeAdjusted - app.lastUsedByUserElapsedTime
Kweku Adams109cd9c2020-02-11 11:10:52 -0800666 >= mInjector.getAutoRestrictedBucketDelayMs()) {
Kweku Adamsc6a9b342020-01-08 18:37:26 -0800667 newBucket = STANDBY_BUCKET_RESTRICTED;
668 reason = app.lastRestrictReason;
669 if (DEBUG) {
670 Slog.d(TAG, "Bringing down to RESTRICTED due to timeout");
671 }
672 }
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800673 if (DEBUG) {
674 Slog.d(TAG, " Old bucket=" + oldBucket
675 + ", newBucket=" + newBucket);
676 }
677 if (oldBucket < newBucket || predictionLate) {
678 mAppIdleHistory.setAppStandbyBucket(packageName, userId,
679 elapsedRealtime, newBucket, reason);
680 maybeInformListeners(packageName, userId, elapsedRealtime,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800681 newBucket, reason, false);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800682 }
683 }
684 }
685 }
686
Amith Yamasani119be9a2018-02-18 22:23:00 -0800687 /** Returns true if there hasn't been a prediction for the app in a while. */
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800688 private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700689 return app.lastPredictedTime > 0
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800690 && mAppIdleHistory.getElapsedTime(elapsedRealtime)
Amith Yamasani119be9a2018-02-18 22:23:00 -0800691 - app.lastPredictedTime > mPredictionTimeoutMillis;
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800692 }
693
Amith Yamasani119be9a2018-02-18 22:23:00 -0800694 /** Inform listeners if the bucket has changed since it was last reported to listeners */
Amith Yamasani17fffee2017-09-29 13:17:43 -0700695 private void maybeInformListeners(String packageName, int userId,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800696 long elapsedRealtime, int bucket, int reason, boolean userStartedInteracting) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700697 synchronized (mAppIdleLock) {
698 if (mAppIdleHistory.shouldInformListeners(packageName, userId,
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800699 elapsedRealtime, bucket)) {
Amith Yamasani119be9a2018-02-18 22:23:00 -0800700 final StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId,
701 bucket, reason, userStartedInteracting);
Amith Yamasani777b1532018-01-28 23:20:07 +0000702 if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket);
Amith Yamasani119be9a2018-02-18 22:23:00 -0800703 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, r));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700704 }
705 }
706 }
707
Amith Yamasani119be9a2018-02-18 22:23:00 -0800708 /**
709 * Evaluates next bucket based on time since last used and the bucketing thresholds.
710 * @param packageName the app
711 * @param userId the user
712 * @param elapsedRealtime as the name suggests, current elapsed time
713 * @return the bucket for the app, based on time since last used
714 */
Andreas Gampebbab23f2018-02-07 15:34:27 -0800715 @GuardedBy("mAppIdleLock")
Makoto Onukia72e04f2019-10-03 11:10:45 -0700716 @StandbyBuckets
717 private int getBucketForLocked(String packageName, int userId,
Amith Yamasani17fffee2017-09-29 13:17:43 -0700718 long elapsedRealtime) {
719 int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId,
720 elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds);
721 return THRESHOLD_BUCKETS[bucketIndex];
722 }
723
Amith Yamasani7e528f32017-10-05 16:06:16 -0700724 private void notifyBatteryStats(String packageName, int userId, boolean idle) {
725 try {
726 final int uid = mPackageManager.getPackageUidAsUser(packageName,
727 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
728 if (idle) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700729 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
Amith Yamasani7e528f32017-10-05 16:06:16 -0700730 packageName, uid);
731 } else {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700732 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
Amith Yamasani7e528f32017-10-05 16:06:16 -0700733 packageName, uid);
734 }
735 } catch (PackageManager.NameNotFoundException | RemoteException e) {
736 }
737 }
738
Makoto Onukia72e04f2019-10-03 11:10:45 -0700739 @Override
740 public void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) {
Amith Yamasani172612c2017-12-15 10:51:53 -0800741 if (!mAppIdleEnabled) return;
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800742 final int eventType = event.getEventType();
743 if ((eventType == UsageEvents.Event.ACTIVITY_RESUMED
744 || eventType == UsageEvents.Event.ACTIVITY_PAUSED
745 || eventType == UsageEvents.Event.SYSTEM_INTERACTION
746 || eventType == UsageEvents.Event.USER_INTERACTION
747 || eventType == UsageEvents.Event.NOTIFICATION_SEEN
748 || eventType == UsageEvents.Event.SLICE_PINNED
749 || eventType == UsageEvents.Event.SLICE_PINNED_PRIV
750 || eventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) {
751 synchronized (mAppIdleLock) {
752 reportEventLocked(event.getPackageName(), eventType, elapsedRealtime, userId);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700753 }
754 }
Amith Yamasani7e528f32017-10-05 16:06:16 -0700755 }
756
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800757 private void reportEventLocked(String pkg, int eventType, long elapsedRealtime, int userId) {
758 // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
759 // about apps that are on some kind of whitelist anyway.
760 final boolean previouslyIdle = mAppIdleHistory.isIdle(
761 pkg, userId, elapsedRealtime);
762
763 final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory(
764 pkg, userId, elapsedRealtime);
765 final int prevBucket = appHistory.currentBucket;
766 final int prevBucketReason = appHistory.bucketingReason;
767 final long nextCheckDelay;
768 final int subReason = usageEventToSubReason(eventType);
769 final int reason = REASON_MAIN_USAGE | subReason;
770 if (eventType == UsageEvents.Event.NOTIFICATION_SEEN
771 || eventType == UsageEvents.Event.SLICE_PINNED) {
772 // Mild usage elevates to WORKING_SET but doesn't change usage time.
773 mAppIdleHistory.reportUsage(appHistory, pkg,
774 STANDBY_BUCKET_WORKING_SET, subReason,
775 0, elapsedRealtime + mNotificationSeenTimeoutMillis);
776 nextCheckDelay = mNotificationSeenTimeoutMillis;
777 } else if (eventType == UsageEvents.Event.SYSTEM_INTERACTION) {
778 mAppIdleHistory.reportUsage(appHistory, pkg,
779 STANDBY_BUCKET_ACTIVE, subReason,
780 0, elapsedRealtime + mSystemInteractionTimeoutMillis);
781 nextCheckDelay = mSystemInteractionTimeoutMillis;
782 } else if (eventType == UsageEvents.Event.FOREGROUND_SERVICE_START) {
783 // Only elevate bucket if this is the first usage of the app
784 if (prevBucket != STANDBY_BUCKET_NEVER) return;
785 mAppIdleHistory.reportUsage(appHistory, pkg,
786 STANDBY_BUCKET_ACTIVE, subReason,
787 0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis);
788 nextCheckDelay = mInitialForegroundServiceStartTimeoutMillis;
789 } else {
790 mAppIdleHistory.reportUsage(appHistory, pkg,
791 STANDBY_BUCKET_ACTIVE, subReason,
792 elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
793 nextCheckDelay = mStrongUsageTimeoutMillis;
794 }
795 if (appHistory.currentBucket != prevBucket) {
796 mHandler.sendMessageDelayed(
797 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkg),
798 nextCheckDelay);
799 final boolean userStartedInteracting =
800 appHistory.currentBucket == STANDBY_BUCKET_ACTIVE
801 && (prevBucketReason & REASON_MAIN_MASK) != REASON_MAIN_USAGE;
802 maybeInformListeners(pkg, userId, elapsedRealtime,
803 appHistory.currentBucket, reason, userStartedInteracting);
804 }
805
806 if (previouslyIdle) {
807 notifyBatteryStats(pkg, userId, false);
808 }
809 }
810
Amith Yamasani119be9a2018-02-18 22:23:00 -0800811 private int usageEventToSubReason(int eventType) {
812 switch (eventType) {
Hui Yu03d12402018-12-06 18:00:37 -0800813 case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
814 case UsageEvents.Event.ACTIVITY_PAUSED: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800815 case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION;
816 case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION;
817 case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN;
Amith Yamasani80c4be82018-03-26 10:54:04 -0700818 case UsageEvents.Event.SLICE_PINNED: return REASON_SUB_USAGE_SLICE_PINNED;
819 case UsageEvents.Event.SLICE_PINNED_PRIV: return REASON_SUB_USAGE_SLICE_PINNED_PRIV;
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -0700820 case UsageEvents.Event.FOREGROUND_SERVICE_START:
821 return REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800822 default: return 0;
823 }
824 }
825
Makoto Onukia72e04f2019-10-03 11:10:45 -0700826 @VisibleForTesting
Amith Yamasani7e528f32017-10-05 16:06:16 -0700827 void forceIdleState(String packageName, int userId, boolean idle) {
Amith Yamasani172612c2017-12-15 10:51:53 -0800828 if (!mAppIdleEnabled) return;
829
Amith Yamasani7e528f32017-10-05 16:06:16 -0700830 final int appId = getAppId(packageName);
831 if (appId < 0) return;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700832 final long elapsedRealtime = mInjector.elapsedRealtime();
Amith Yamasani7e528f32017-10-05 16:06:16 -0700833
834 final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
835 userId, elapsedRealtime);
Christopher Tatea732f012017-10-26 17:26:53 -0700836 final int standbyBucket;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700837 synchronized (mAppIdleLock) {
Christopher Tatea732f012017-10-26 17:26:53 -0700838 standbyBucket = mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700839 }
840 final boolean stillIdle = isAppIdleFiltered(packageName, appId,
841 userId, elapsedRealtime);
842 // Inform listeners if necessary
843 if (previouslyIdle != stillIdle) {
Amith Yamasani119be9a2018-02-18 22:23:00 -0800844 maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket,
Kweku Adamsc182d5e2020-01-08 18:37:26 -0800845 REASON_MAIN_FORCED_BY_USER, false);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700846 if (!stillIdle) {
847 notifyBatteryStats(packageName, userId, idle);
848 }
849 }
850 }
851
Makoto Onukia72e04f2019-10-03 11:10:45 -0700852 @Override
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800853 public void setLastJobRunTime(String packageName, int userId, long elapsedRealtime) {
854 synchronized (mAppIdleLock) {
855 mAppIdleHistory.setLastJobRunTime(packageName, userId, elapsedRealtime);
856 }
857 }
858
Makoto Onukia72e04f2019-10-03 11:10:45 -0700859 @Override
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800860 public long getTimeSinceLastJobRun(String packageName, int userId) {
861 final long elapsedRealtime = mInjector.elapsedRealtime();
862 synchronized (mAppIdleLock) {
863 return mAppIdleHistory.getTimeSinceLastJobRun(packageName, userId, elapsedRealtime);
864 }
865 }
866
Makoto Onukia72e04f2019-10-03 11:10:45 -0700867 @Override
Amith Yamasani7e528f32017-10-05 16:06:16 -0700868 public void onUserRemoved(int userId) {
869 synchronized (mAppIdleLock) {
870 mAppIdleHistory.onUserRemoved(userId);
Sudheer Shanka101c3532018-01-08 16:28:42 -0800871 synchronized (mActiveAdminApps) {
872 mActiveAdminApps.remove(userId);
873 }
Amith Yamasani7e528f32017-10-05 16:06:16 -0700874 }
875 }
876
877 private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
878 synchronized (mAppIdleLock) {
879 return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
880 }
881 }
882
Makoto Onukia72e04f2019-10-03 11:10:45 -0700883 @Override
884 public void addListener(AppIdleStateChangeListener listener) {
Amith Yamasani93885192017-12-13 11:52:10 -0800885 synchronized (mPackageAccessListeners) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700886 if (!mPackageAccessListeners.contains(listener)) {
887 mPackageAccessListeners.add(listener);
888 }
889 }
890 }
891
Makoto Onukia72e04f2019-10-03 11:10:45 -0700892 @Override
893 public void removeListener(AppIdleStateChangeListener listener) {
Amith Yamasani93885192017-12-13 11:52:10 -0800894 synchronized (mPackageAccessListeners) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700895 mPackageAccessListeners.remove(listener);
896 }
897 }
898
Makoto Onukia72e04f2019-10-03 11:10:45 -0700899 @Override
900 public int getAppId(String packageName) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700901 try {
902 ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName,
903 PackageManager.MATCH_ANY_USER
904 | PackageManager.MATCH_DISABLED_COMPONENTS);
905 return ai.uid;
906 } catch (PackageManager.NameNotFoundException re) {
907 return -1;
908 }
909 }
910
Makoto Onukia72e04f2019-10-03 11:10:45 -0700911 @Override
Kweku Adamsdf33ae12019-10-08 11:51:41 -0700912 public boolean isAppIdleFiltered(String packageName, int userId, long elapsedRealtime,
Amith Yamasani7e528f32017-10-05 16:06:16 -0700913 boolean shouldObfuscateInstantApps) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700914 if (shouldObfuscateInstantApps &&
Amith Yamasani17fffee2017-09-29 13:17:43 -0700915 mInjector.isPackageEphemeral(userId, packageName)) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700916 return false;
917 }
918 return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
919 }
920
Makoto Onukia72e04f2019-10-03 11:10:45 -0700921 private boolean isAppSpecial(String packageName, int appId, int userId) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700922 if (packageName == null) return false;
923 // If not enabled at all, of course nobody is ever idle.
924 if (!mAppIdleEnabled) {
925 return true;
926 }
927 if (appId < Process.FIRST_APPLICATION_UID) {
928 // System uids never go idle.
929 return true;
930 }
931 if (packageName.equals("android")) {
932 // Nor does the framework (which should be redundant with the above, but for MR1 we will
933 // retain this for safety).
934 return true;
935 }
936 if (mSystemServicesReady) {
937 try {
938 // We allow all whitelisted apps, including those that don't want to be whitelisted
939 // for idle mode, because app idle (aka app standby) is really not as big an issue
940 // for controlling who participates vs. doze mode.
941 if (mInjector.isPowerSaveWhitelistExceptIdleApp(packageName)) {
942 return true;
943 }
944 } catch (RemoteException re) {
945 throw re.rethrowFromSystemServer();
946 }
947
948 if (isActiveDeviceAdmin(packageName, userId)) {
949 return true;
950 }
951
952 if (isActiveNetworkScorer(packageName)) {
953 return true;
954 }
955
956 if (mAppWidgetManager != null
957 && mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) {
958 return true;
959 }
960
961 if (isDeviceProvisioningPackage(packageName)) {
962 return true;
963 }
964 }
965
966 // Check this last, as it can be the most expensive check
967 if (isCarrierApp(packageName)) {
968 return true;
969 }
970
971 return false;
972 }
973
Makoto Onukia72e04f2019-10-03 11:10:45 -0700974 @Override
975 public boolean isAppIdleFiltered(String packageName, int appId, int userId,
Amith Yamasani7e528f32017-10-05 16:06:16 -0700976 long elapsedRealtime) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700977 if (isAppSpecial(packageName, appId, userId)) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700978 return false;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700979 } else {
980 return isAppIdleUnfiltered(packageName, userId, elapsedRealtime);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700981 }
Amith Yamasani7e528f32017-10-05 16:06:16 -0700982 }
983
Kweku Adamsc6a9b342020-01-08 18:37:26 -0800984 static boolean isUserUsage(int reason) {
985 if ((reason & REASON_MAIN_MASK) == REASON_MAIN_USAGE) {
986 final int subReason = reason & REASON_SUB_MASK;
987 return subReason == REASON_SUB_USAGE_USER_INTERACTION
988 || subReason == REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
989 }
990 return false;
991 }
992
Makoto Onukia72e04f2019-10-03 11:10:45 -0700993 @Override
994 public int[] getIdleUidsForUser(int userId) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700995 if (!mAppIdleEnabled) {
996 return new int[0];
997 }
998
Amith Yamasani17fffee2017-09-29 13:17:43 -0700999 final long elapsedRealtime = mInjector.elapsedRealtime();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001000
1001 List<ApplicationInfo> apps;
1002 try {
1003 ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager()
1004 .getInstalledApplications(/* flags= */ 0, userId);
1005 if (slice == null) {
1006 return new int[0];
1007 }
1008 apps = slice.getList();
1009 } catch (RemoteException e) {
1010 throw e.rethrowFromSystemServer();
1011 }
1012
1013 // State of each uid. Key is the uid. Value lower 16 bits is the number of apps
1014 // associated with that uid, upper 16 bits is the number of those apps that is idle.
1015 SparseIntArray uidStates = new SparseIntArray();
1016
1017 // Now resolve all app state. Iterating over all apps, keeping track of how many
1018 // we find for each uid and how many of those are idle.
1019 for (int i = apps.size() - 1; i >= 0; i--) {
1020 ApplicationInfo ai = apps.get(i);
1021
1022 // Check whether this app is idle.
1023 boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid),
1024 userId, elapsedRealtime);
1025
1026 int index = uidStates.indexOfKey(ai.uid);
1027 if (index < 0) {
1028 uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0));
1029 } else {
1030 int value = uidStates.valueAt(index);
1031 uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0));
1032 }
1033 }
1034 if (DEBUG) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001035 Slog.d(TAG, "getIdleUids took " + (mInjector.elapsedRealtime() - elapsedRealtime));
Amith Yamasani7e528f32017-10-05 16:06:16 -07001036 }
1037 int numIdle = 0;
1038 for (int i = uidStates.size() - 1; i >= 0; i--) {
1039 int value = uidStates.valueAt(i);
1040 if ((value&0x7fff) == (value>>16)) {
1041 numIdle++;
1042 }
1043 }
1044
1045 int[] res = new int[numIdle];
1046 numIdle = 0;
1047 for (int i = uidStates.size() - 1; i >= 0; i--) {
1048 int value = uidStates.valueAt(i);
1049 if ((value&0x7fff) == (value>>16)) {
1050 res[numIdle] = uidStates.keyAt(i);
1051 numIdle++;
1052 }
1053 }
1054
1055 return res;
1056 }
1057
Makoto Onukia72e04f2019-10-03 11:10:45 -07001058 @Override
1059 public void setAppIdleAsync(String packageName, boolean idle, int userId) {
Amith Yamasani172612c2017-12-15 10:51:53 -08001060 if (packageName == null || !mAppIdleEnabled) return;
Amith Yamasani7e528f32017-10-05 16:06:16 -07001061
1062 mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
1063 .sendToTarget();
1064 }
1065
Makoto Onukia72e04f2019-10-03 11:10:45 -07001066 @Override
Christopher Tatea732f012017-10-26 17:26:53 -07001067 @StandbyBuckets public int getAppStandbyBucket(String packageName, int userId,
Amith Yamasani17fffee2017-09-29 13:17:43 -07001068 long elapsedRealtime, boolean shouldObfuscateInstantApps) {
Amith Yamasani172612c2017-12-15 10:51:53 -08001069 if (!mAppIdleEnabled || (shouldObfuscateInstantApps
1070 && mInjector.isPackageEphemeral(userId, packageName))) {
Amith Yamasaniafbccb72017-11-27 10:44:24 -08001071 return STANDBY_BUCKET_ACTIVE;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001072 }
1073
Amith Yamasanie8789312017-12-10 14:34:26 -08001074 synchronized (mAppIdleLock) {
1075 return mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
1076 }
1077 }
1078
Makoto Onukia72e04f2019-10-03 11:10:45 -07001079 @Override
Suprabh Shukla868bde22018-02-20 20:59:52 -08001080 public List<AppStandbyInfo> getAppStandbyBuckets(int userId) {
Amith Yamasanie8789312017-12-10 14:34:26 -08001081 synchronized (mAppIdleLock) {
Suprabh Shukla868bde22018-02-20 20:59:52 -08001082 return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled);
Amith Yamasanie8789312017-12-10 14:34:26 -08001083 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07001084 }
1085
Kweku Adamsc4ee9982020-01-08 11:14:39 -08001086 @Override
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001087 public void restrictApp(@NonNull String packageName, int userId, int restrictReason) {
1088 // If the package is not installed, don't allow the bucket to be set.
1089 if (!mInjector.isPackageInstalled(packageName, 0, userId)) {
1090 Slog.e(TAG, "Tried to restrict uninstalled app: " + packageName);
1091 return;
1092 }
1093
1094 final int reason = REASON_MAIN_FORCED_BY_SYSTEM | (REASON_SUB_MASK & restrictReason);
1095 final long nowElapsed = mInjector.elapsedRealtime();
1096 setAppStandbyBucket(packageName, userId, STANDBY_BUCKET_RESTRICTED, reason,
1097 nowElapsed, false);
1098 }
1099
1100 @Override
Kweku Adamsc4ee9982020-01-08 11:14:39 -08001101 public void setAppStandbyBucket(@NonNull String packageName, int bucket, int userId,
1102 int callingUid, int callingPid) {
1103 setAppStandbyBuckets(
1104 Collections.singletonList(new AppStandbyInfo(packageName, bucket)),
1105 userId, callingUid, callingPid);
Makoto Onukia0058b42018-05-22 16:32:23 -07001106 }
1107
Makoto Onukia72e04f2019-10-03 11:10:45 -07001108 @Override
Kweku Adamsc4ee9982020-01-08 11:14:39 -08001109 public void setAppStandbyBuckets(@NonNull List<AppStandbyInfo> appBuckets, int userId,
1110 int callingUid, int callingPid) {
1111 userId = ActivityManager.handleIncomingUser(
1112 callingPid, callingUid, userId, false, true, "setAppStandbyBucket", null);
1113 final boolean shellCaller = callingUid == Process.ROOT_UID
1114 || callingUid == Process.SHELL_UID;
Kweku Adamsc182d5e2020-01-08 18:37:26 -08001115 final int reason;
1116 // The Settings app runs in the system UID but in a separate process. Assume
1117 // things coming from other processes are due to the user.
1118 if ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && callingPid != Process.myPid())
1119 || shellCaller) {
1120 reason = REASON_MAIN_FORCED_BY_USER;
1121 } else if (UserHandle.isCore(callingUid)) {
1122 reason = REASON_MAIN_FORCED_BY_SYSTEM;
1123 } else {
1124 reason = REASON_MAIN_PREDICTED;
1125 }
Kweku Adamsc4ee9982020-01-08 11:14:39 -08001126 final int packageFlags = PackageManager.MATCH_ANY_USER
1127 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
1128 | PackageManager.MATCH_DIRECT_BOOT_AWARE;
1129 final int numApps = appBuckets.size();
1130 final long elapsedRealtime = mInjector.elapsedRealtime();
1131 for (int i = 0; i < numApps; ++i) {
1132 final AppStandbyInfo bucketInfo = appBuckets.get(i);
1133 final String packageName = bucketInfo.mPackageName;
1134 final int bucket = bucketInfo.mStandbyBucket;
1135 if (bucket < STANDBY_BUCKET_ACTIVE || bucket > STANDBY_BUCKET_NEVER) {
1136 throw new IllegalArgumentException("Cannot set the standby bucket to " + bucket);
1137 }
1138 final int packageUid = mInjector.getPackageManagerInternal()
1139 .getPackageUid(packageName, packageFlags, userId);
1140 // Caller cannot set their own standby state
1141 if (packageUid == callingUid) {
1142 throw new IllegalArgumentException("Cannot set your own standby bucket");
1143 }
1144 if (packageUid < 0) {
1145 throw new IllegalArgumentException(
1146 "Cannot set standby bucket for non existent package (" + packageName + ")");
1147 }
1148 setAppStandbyBucket(packageName, userId, bucket, reason, elapsedRealtime, shellCaller);
1149 }
1150 }
1151
1152 @VisibleForTesting
1153 void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
1154 int reason) {
1155 setAppStandbyBucket(
1156 packageName, userId, newBucket, reason, mInjector.elapsedRealtime(), false);
1157 }
1158
1159 private void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
Makoto Onukia0058b42018-05-22 16:32:23 -07001160 int reason, long elapsedRealtime, boolean resetTimeout) {
Amith Yamasanie8789312017-12-10 14:34:26 -08001161 synchronized (mAppIdleLock) {
Varun Shah7609b752018-10-15 15:07:47 -07001162 // If the package is not installed, don't allow the bucket to be set.
1163 if (!mInjector.isPackageInstalled(packageName, 0, userId)) {
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001164 Slog.e(TAG, "Tried to set bucket of uninstalled app: " + packageName);
Varun Shah7609b752018-10-15 15:07:47 -07001165 return;
1166 }
Amith Yamasani93885192017-12-13 11:52:10 -08001167 AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
1168 userId, elapsedRealtime);
Amith Yamasani119be9a2018-02-18 22:23:00 -08001169 boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED;
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001170
Amith Yamasani93885192017-12-13 11:52:10 -08001171 // Don't allow changing bucket if higher than ACTIVE
1172 if (app.currentBucket < STANDBY_BUCKET_ACTIVE) return;
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001173
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001174 // Don't allow prediction to change from/to NEVER or from RESTRICTED.
Amith Yamasani93885192017-12-13 11:52:10 -08001175 if ((app.currentBucket == STANDBY_BUCKET_NEVER
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001176 || app.currentBucket == STANDBY_BUCKET_RESTRICTED
Amith Yamasani93885192017-12-13 11:52:10 -08001177 || newBucket == STANDBY_BUCKET_NEVER)
1178 && predicted) {
1179 return;
1180 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001181
Amith Yamasani93885192017-12-13 11:52:10 -08001182 // If the bucket was forced, don't allow prediction to override
Kweku Adamsc182d5e2020-01-08 18:37:26 -08001183 if (predicted
1184 && ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER
1185 || (app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM)) {
1186 return;
1187 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001188
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001189 final boolean isForcedByUser =
1190 (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER;
1191
Kweku Adams4297b5d2020-02-06 15:56:12 -08001192 // If the current bucket is RESTRICTED, only user force or usage should bring it out,
1193 // unless the app was put into the bucket due to timing out.
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001194 if (app.currentBucket == STANDBY_BUCKET_RESTRICTED && !isUserUsage(reason)
Kweku Adams4297b5d2020-02-06 15:56:12 -08001195 && !isForcedByUser
1196 && (app.bucketingReason & REASON_MAIN_MASK) != REASON_MAIN_TIMEOUT) {
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001197 return;
1198 }
1199
1200 if (newBucket == STANDBY_BUCKET_RESTRICTED) {
1201 mAppIdleHistory
1202 .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason);
1203
1204 if (isForcedByUser) {
1205 // Only user force can bypass the delay restriction. If the user forced the
1206 // app into the RESTRICTED bucket, then a toast confirming the action
1207 // shouldn't be surprising.
1208 if (Build.IS_DEBUGGABLE) {
1209 Toast.makeText(mContext,
1210 // Since AppStandbyController sits low in the lock hierarchy,
1211 // make sure not to call out with the lock held.
1212 mHandler.getLooper(),
1213 mContext.getResources().getString(
1214 R.string.as_app_forced_to_restricted_bucket, packageName),
1215 Toast.LENGTH_SHORT)
1216 .show();
1217 } else {
1218 Slog.i(TAG, packageName + " restricted by user");
1219 }
1220 } else {
1221 final long timeUntilRestrictPossibleMs = app.lastUsedByUserElapsedTime
Kweku Adams109cd9c2020-02-11 11:10:52 -08001222 + mInjector.getAutoRestrictedBucketDelayMs() - elapsedRealtime;
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001223 if (timeUntilRestrictPossibleMs > 0) {
1224 Slog.w(TAG, "Tried to restrict recently used app: " + packageName
1225 + " due to " + reason);
1226 mHandler.sendMessageDelayed(
1227 mHandler.obtainMessage(
1228 MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, packageName),
1229 timeUntilRestrictPossibleMs);
1230 return;
1231 }
1232 }
1233 }
1234
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001235 // If the bucket is required to stay in a higher state for a specified duration, don't
1236 // override unless the duration has passed
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08001237 if (predicted) {
1238 // Check if the app is within one of the timeouts for forced bucket elevation
1239 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
Amith Yamasani3154dcf2018-03-27 18:24:04 -07001240 // In case of not using the prediction, just keep track of it for applying after
1241 // ACTIVE or WORKING_SET timeout.
1242 mAppIdleHistory.updateLastPrediction(app, elapsedTimeAdjusted, newBucket);
1243
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08001244 if (newBucket > STANDBY_BUCKET_ACTIVE
1245 && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
1246 newBucket = STANDBY_BUCKET_ACTIVE;
Amith Yamasani119be9a2018-02-18 22:23:00 -08001247 reason = app.bucketingReason;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08001248 if (DEBUG) {
1249 Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
1250 }
1251 } else if (newBucket > STANDBY_BUCKET_WORKING_SET
1252 && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
1253 newBucket = STANDBY_BUCKET_WORKING_SET;
Amith Yamasani119be9a2018-02-18 22:23:00 -08001254 if (app.currentBucket != newBucket) {
1255 reason = REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT;
1256 } else {
1257 reason = app.bucketingReason;
1258 }
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08001259 if (DEBUG) {
1260 Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
1261 }
1262 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001263 }
1264
Amith Yamasanie8789312017-12-10 14:34:26 -08001265 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
Makoto Onukia0058b42018-05-22 16:32:23 -07001266 reason, resetTimeout);
Amith Yamasanie8789312017-12-10 14:34:26 -08001267 }
Amith Yamasani119be9a2018-02-18 22:23:00 -08001268 maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false);
Amith Yamasani17fffee2017-09-29 13:17:43 -07001269 }
1270
Sudheer Shanka101c3532018-01-08 16:28:42 -08001271 @VisibleForTesting
1272 boolean isActiveDeviceAdmin(String packageName, int userId) {
1273 synchronized (mActiveAdminApps) {
1274 final Set<String> adminPkgs = mActiveAdminApps.get(userId);
1275 return adminPkgs != null && adminPkgs.contains(packageName);
1276 }
1277 }
1278
Makoto Onukia72e04f2019-10-03 11:10:45 -07001279 @Override
Sudheer Shanka101c3532018-01-08 16:28:42 -08001280 public void addActiveDeviceAdmin(String adminPkg, int userId) {
1281 synchronized (mActiveAdminApps) {
1282 Set<String> adminPkgs = mActiveAdminApps.get(userId);
1283 if (adminPkgs == null) {
1284 adminPkgs = new ArraySet<>();
1285 mActiveAdminApps.put(userId, adminPkgs);
1286 }
1287 adminPkgs.add(adminPkg);
1288 }
1289 }
1290
Makoto Onukia72e04f2019-10-03 11:10:45 -07001291 @Override
Sudheer Shanka101c3532018-01-08 16:28:42 -08001292 public void setActiveAdminApps(Set<String> adminPkgs, int userId) {
1293 synchronized (mActiveAdminApps) {
1294 if (adminPkgs == null) {
1295 mActiveAdminApps.remove(userId);
1296 } else {
1297 mActiveAdminApps.put(userId, adminPkgs);
1298 }
1299 }
1300 }
1301
Makoto Onukia72e04f2019-10-03 11:10:45 -07001302 @Override
Sudheer Shankac53c47f2018-01-16 12:01:00 -08001303 public void onAdminDataAvailable() {
1304 mAdminDataAvailableLatch.countDown();
1305 }
1306
1307 /**
1308 * This will only ever be called once - during device boot.
1309 */
1310 private void waitForAdminData() {
1311 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
1312 ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch,
1313 WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data");
1314 }
1315 }
1316
Makoto Onukia72e04f2019-10-03 11:10:45 -07001317 @VisibleForTesting
Sudheer Shanka101c3532018-01-08 16:28:42 -08001318 Set<String> getActiveAdminAppsForTest(int userId) {
1319 synchronized (mActiveAdminApps) {
1320 return mActiveAdminApps.get(userId);
1321 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07001322 }
1323
1324 /**
1325 * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
1326 * returns {@code false}.
1327 */
1328 private boolean isDeviceProvisioningPackage(String packageName) {
1329 String deviceProvisioningPackage = mContext.getResources().getString(
1330 com.android.internal.R.string.config_deviceProvisioningPackage);
1331 return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
1332 }
1333
1334 private boolean isCarrierApp(String packageName) {
1335 synchronized (mAppIdleLock) {
1336 if (!mHaveCarrierPrivilegedApps) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001337 fetchCarrierPrivilegedAppsLocked();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001338 }
1339 if (mCarrierPrivilegedApps != null) {
1340 return mCarrierPrivilegedApps.contains(packageName);
1341 }
1342 return false;
1343 }
1344 }
1345
Makoto Onukia72e04f2019-10-03 11:10:45 -07001346 @Override
1347 public void clearCarrierPrivilegedApps() {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001348 if (DEBUG) {
1349 Slog.i(TAG, "Clearing carrier privileged apps list");
1350 }
1351 synchronized (mAppIdleLock) {
1352 mHaveCarrierPrivilegedApps = false;
1353 mCarrierPrivilegedApps = null; // Need to be refetched.
1354 }
1355 }
1356
1357 @GuardedBy("mAppIdleLock")
Amith Yamasani17fffee2017-09-29 13:17:43 -07001358 private void fetchCarrierPrivilegedAppsLocked() {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001359 TelephonyManager telephonyManager =
1360 mContext.getSystemService(TelephonyManager.class);
Shuo Qian6f27c572019-12-03 23:52:13 +00001361 mCarrierPrivilegedApps =
1362 telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001363 mHaveCarrierPrivilegedApps = true;
1364 if (DEBUG) {
1365 Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
1366 }
1367 }
1368
1369 private boolean isActiveNetworkScorer(String packageName) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001370 String activeScorer = mInjector.getActiveNetworkScorer();
1371 return packageName != null && packageName.equals(activeScorer);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001372 }
1373
Makoto Onukia72e04f2019-10-03 11:10:45 -07001374 private void informListeners(String packageName, int userId, int bucket, int reason,
Amith Yamasani119be9a2018-02-18 22:23:00 -08001375 boolean userInteraction) {
Amith Yamasaniafbccb72017-11-27 10:44:24 -08001376 final boolean idle = bucket >= STANDBY_BUCKET_RARE;
Amith Yamasani93885192017-12-13 11:52:10 -08001377 synchronized (mPackageAccessListeners) {
1378 for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
Amith Yamasani119be9a2018-02-18 22:23:00 -08001379 listener.onAppIdleStateChanged(packageName, userId, idle, bucket, reason);
Christopher Tated117b292018-01-05 17:32:36 -08001380 if (userInteraction) {
1381 listener.onUserInteractionStarted(packageName, userId);
1382 }
Amith Yamasani93885192017-12-13 11:52:10 -08001383 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07001384 }
1385 }
1386
Makoto Onukia72e04f2019-10-03 11:10:45 -07001387 @Override
1388 public void flushToDisk(int userId) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001389 synchronized (mAppIdleLock) {
1390 mAppIdleHistory.writeAppIdleTimes(userId);
1391 }
1392 }
1393
Makoto Onukia72e04f2019-10-03 11:10:45 -07001394 @Override
1395 public void flushDurationsToDisk() {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001396 // Persist elapsed and screen on time. If this fails for whatever reason, the apps will be
1397 // considered not-idle, which is the safest outcome in such an event.
1398 synchronized (mAppIdleLock) {
1399 mAppIdleHistory.writeAppIdleDurations();
1400 }
1401 }
1402
Makoto Onukia72e04f2019-10-03 11:10:45 -07001403 private boolean isDisplayOn() {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001404 return mInjector.isDefaultDisplayOn();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001405 }
1406
Makoto Onukia72e04f2019-10-03 11:10:45 -07001407 @VisibleForTesting
Amith Yamasani7e528f32017-10-05 16:06:16 -07001408 void clearAppIdleForPackage(String packageName, int userId) {
1409 synchronized (mAppIdleLock) {
1410 mAppIdleHistory.clearUsage(packageName, userId);
1411 }
1412 }
1413
1414 private class PackageReceiver extends BroadcastReceiver {
1415 @Override
1416 public void onReceive(Context context, Intent intent) {
1417 final String action = intent.getAction();
1418 if (Intent.ACTION_PACKAGE_ADDED.equals(action)
1419 || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
1420 clearCarrierPrivilegedApps();
1421 }
1422 if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
1423 Intent.ACTION_PACKAGE_ADDED.equals(action))
1424 && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1425 clearAppIdleForPackage(intent.getData().getSchemeSpecificPart(),
1426 getSendingUserId());
1427 }
1428 }
1429 }
1430
Makoto Onukia72e04f2019-10-03 11:10:45 -07001431 @Override
1432 public void initializeDefaultsForSystemApps(int userId) {
Amith Yamasani777b1532018-01-28 23:20:07 +00001433 if (!mSystemServicesReady) {
1434 // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled
1435 mPendingInitializeDefaults = true;
1436 return;
1437 }
1438 Slog.d(TAG, "Initializing defaults for system apps on user " + userId + ", "
1439 + "appIdleEnabled=" + mAppIdleEnabled);
Amith Yamasani17fffee2017-09-29 13:17:43 -07001440 final long elapsedRealtime = mInjector.elapsedRealtime();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001441 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
1442 PackageManager.MATCH_DISABLED_COMPONENTS,
1443 userId);
1444 final int packageCount = packages.size();
1445 synchronized (mAppIdleLock) {
1446 for (int i = 0; i < packageCount; i++) {
1447 final PackageInfo pi = packages.get(i);
1448 String packageName = pi.packageName;
1449 if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08001450 // Mark app as used for 2 hours. After that it can timeout to whatever the
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001451 // past usage pattern was.
Amith Yamasani119be9a2018-02-18 22:23:00 -08001452 mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE,
1453 REASON_SUB_USAGE_SYSTEM_UPDATE, 0,
Amith Yamasani7ec89412018-02-07 08:48:49 -08001454 elapsedRealtime + mSystemUpdateUsageTimeoutMillis);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001455 }
1456 }
Michael Wachenschwanzd1d8aa62019-02-28 16:38:37 -08001457 // Immediately persist defaults to disk
1458 mAppIdleHistory.writeAppIdleTimes(userId);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001459 }
1460 }
1461
Makoto Onukia72e04f2019-10-03 11:10:45 -07001462 @Override
1463 public void postReportContentProviderUsage(String name, String packageName, int userId) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001464 SomeArgs args = SomeArgs.obtain();
1465 args.arg1 = name;
1466 args.arg2 = packageName;
1467 args.arg3 = userId;
1468 mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, args)
1469 .sendToTarget();
1470 }
1471
Makoto Onukia72e04f2019-10-03 11:10:45 -07001472 @Override
1473 public void postReportSyncScheduled(String packageName, int userId, boolean exempted) {
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001474 mHandler.obtainMessage(MSG_REPORT_SYNC_SCHEDULED, userId, exempted ? 1 : 0, packageName)
Makoto Onukid5f25d22018-05-22 16:02:17 -07001475 .sendToTarget();
1476 }
1477
Makoto Onukia72e04f2019-10-03 11:10:45 -07001478 @Override
1479 public void postReportExemptedSyncStart(String packageName, int userId) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001480 mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName)
1481 .sendToTarget();
1482 }
1483
Makoto Onukia72e04f2019-10-03 11:10:45 -07001484 @Override
1485 public void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001486 synchronized (mAppIdleLock) {
Dianne Hackbornc81983a2017-10-20 16:16:32 -07001487 mAppIdleHistory.dump(idpw, userId, pkg);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001488 }
1489 }
1490
Makoto Onukia72e04f2019-10-03 11:10:45 -07001491 @Override
1492 public void dumpState(String[] args, PrintWriter pw) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001493 synchronized (mAppIdleLock) {
1494 pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
1495 + "): " + mCarrierPrivilegedApps);
1496 }
1497
Amith Yamasani8b7725b2018-08-27 13:44:31 -07001498 final long now = System.currentTimeMillis();
1499
Amith Yamasani7e528f32017-10-05 16:06:16 -07001500 pw.println();
1501 pw.println("Settings:");
1502
Amith Yamasani7e528f32017-10-05 16:06:16 -07001503 pw.print(" mCheckIdleIntervalMillis=");
1504 TimeUtils.formatDuration(mCheckIdleIntervalMillis, pw);
1505 pw.println();
1506
Esteban Talavera5b79bfa2018-07-05 15:15:22 +01001507 pw.print(" mStrongUsageTimeoutMillis=");
1508 TimeUtils.formatDuration(mStrongUsageTimeoutMillis, pw);
1509 pw.println();
1510 pw.print(" mNotificationSeenTimeoutMillis=");
1511 TimeUtils.formatDuration(mNotificationSeenTimeoutMillis, pw);
1512 pw.println();
1513 pw.print(" mSyncAdapterTimeoutMillis=");
1514 TimeUtils.formatDuration(mSyncAdapterTimeoutMillis, pw);
1515 pw.println();
1516 pw.print(" mSystemInteractionTimeoutMillis=");
1517 TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw);
1518 pw.println();
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -07001519 pw.print(" mInitialForegroundServiceStartTimeoutMillis=");
1520 TimeUtils.formatDuration(mInitialForegroundServiceStartTimeoutMillis, pw);
1521 pw.println();
Esteban Talavera5b79bfa2018-07-05 15:15:22 +01001522
1523 pw.print(" mPredictionTimeoutMillis=");
1524 TimeUtils.formatDuration(mPredictionTimeoutMillis, pw);
1525 pw.println();
1526
Makoto Onukid5f25d22018-05-22 16:02:17 -07001527 pw.print(" mExemptedSyncScheduledNonDozeTimeoutMillis=");
1528 TimeUtils.formatDuration(mExemptedSyncScheduledNonDozeTimeoutMillis, pw);
1529 pw.println();
1530 pw.print(" mExemptedSyncScheduledDozeTimeoutMillis=");
1531 TimeUtils.formatDuration(mExemptedSyncScheduledDozeTimeoutMillis, pw);
1532 pw.println();
1533 pw.print(" mExemptedSyncStartTimeoutMillis=");
1534 TimeUtils.formatDuration(mExemptedSyncStartTimeoutMillis, pw);
1535 pw.println();
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001536 pw.print(" mUnexemptedSyncScheduledTimeoutMillis=");
1537 TimeUtils.formatDuration(mUnexemptedSyncScheduledTimeoutMillis, pw);
1538 pw.println();
Makoto Onukid5f25d22018-05-22 16:02:17 -07001539
Esteban Talavera5b79bfa2018-07-05 15:15:22 +01001540 pw.print(" mSystemUpdateUsageTimeoutMillis=");
1541 TimeUtils.formatDuration(mSystemUpdateUsageTimeoutMillis, pw);
1542 pw.println();
1543
Amith Yamasani7e528f32017-10-05 16:06:16 -07001544 pw.println();
1545 pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001546 pw.println();
Amith Yamasani17fffee2017-09-29 13:17:43 -07001547 pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds));
1548 pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds));
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -07001549 pw.println();
Amith Yamasani17fffee2017-09-29 13:17:43 -07001550 }
1551
1552 /**
1553 * Injector for interaction with external code. Override methods to provide a mock
1554 * implementation for tests.
1555 * onBootPhase() must be called with at least the PHASE_SYSTEM_SERVICES_READY
1556 */
1557 static class Injector {
1558
1559 private final Context mContext;
1560 private final Looper mLooper;
1561 private IDeviceIdleController mDeviceIdleController;
1562 private IBatteryStats mBatteryStats;
1563 private PackageManagerInternal mPackageManagerInternal;
1564 private DisplayManager mDisplayManager;
Makoto Onukid5f25d22018-05-22 16:02:17 -07001565 private PowerManager mPowerManager;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001566 int mBootPhase;
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001567 /**
1568 * The minimum amount of time required since the last user interaction before an app can be
Kweku Adams109cd9c2020-02-11 11:10:52 -08001569 * automatically placed in the RESTRICTED bucket.
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001570 */
Kweku Adams109cd9c2020-02-11 11:10:52 -08001571 long mAutoRestrictedBucketDelayMs = ONE_DAY;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001572
1573 Injector(Context context, Looper looper) {
1574 mContext = context;
1575 mLooper = looper;
1576 }
1577
1578 Context getContext() {
1579 return mContext;
1580 }
1581
1582 Looper getLooper() {
1583 return mLooper;
1584 }
1585
1586 void onBootPhase(int phase) {
1587 if (phase == PHASE_SYSTEM_SERVICES_READY) {
1588 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1589 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
1590 mBatteryStats = IBatteryStats.Stub.asInterface(
1591 ServiceManager.getService(BatteryStats.SERVICE_NAME));
1592 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
1593 mDisplayManager = (DisplayManager) mContext.getSystemService(
1594 Context.DISPLAY_SERVICE);
Makoto Onukid5f25d22018-05-22 16:02:17 -07001595 mPowerManager = mContext.getSystemService(PowerManager.class);
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001596
1597 final ActivityManager activityManager =
1598 (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
1599 if (activityManager.isLowRamDevice() || ActivityManager.isSmallBatteryDevice()) {
Kweku Adams109cd9c2020-02-11 11:10:52 -08001600 mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR;
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001601 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07001602 }
1603 mBootPhase = phase;
1604 }
1605
1606 int getBootPhase() {
1607 return mBootPhase;
1608 }
1609
1610 /**
1611 * Returns the elapsed realtime since the device started. Override this
1612 * to control the clock.
1613 * @return elapsed realtime
1614 */
1615 long elapsedRealtime() {
1616 return SystemClock.elapsedRealtime();
1617 }
1618
1619 long currentTimeMillis() {
1620 return System.currentTimeMillis();
1621 }
1622
1623 boolean isAppIdleEnabled() {
Amith Yamasani172612c2017-12-15 10:51:53 -08001624 final boolean buildFlag = mContext.getResources().getBoolean(
Amith Yamasani17fffee2017-09-29 13:17:43 -07001625 com.android.internal.R.bool.config_enableAutoPowerModes);
Lei Yu4b976ad2018-04-19 10:38:58 -07001626 final boolean runtimeFlag = Global.getInt(mContext.getContentResolver(),
1627 Global.APP_STANDBY_ENABLED, 1) == 1
1628 && Global.getInt(mContext.getContentResolver(),
1629 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1) == 1;
Amith Yamasani172612c2017-12-15 10:51:53 -08001630 return buildFlag && runtimeFlag;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001631 }
1632
Amith Yamasani17fffee2017-09-29 13:17:43 -07001633 boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
1634 return mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName);
1635 }
1636
1637 File getDataSystemDirectory() {
1638 return Environment.getDataSystemDirectory();
1639 }
1640
Kweku Adams109cd9c2020-02-11 11:10:52 -08001641 /**
1642 * Return the minimum amount of time that must have passed since the last user usage before
1643 * an app can be automatically put into the
1644 * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket.
1645 */
1646 long getAutoRestrictedBucketDelayMs() {
1647 return mAutoRestrictedBucketDelayMs;
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001648 }
1649
Amith Yamasani17fffee2017-09-29 13:17:43 -07001650 void noteEvent(int event, String packageName, int uid) throws RemoteException {
1651 mBatteryStats.noteEvent(event, packageName, uid);
1652 }
1653
Kweku Adamsc4ee9982020-01-08 11:14:39 -08001654 PackageManagerInternal getPackageManagerInternal() {
1655 return mPackageManagerInternal;
1656 }
1657
Amith Yamasani17fffee2017-09-29 13:17:43 -07001658 boolean isPackageEphemeral(int userId, String packageName) {
1659 return mPackageManagerInternal.isPackageEphemeral(userId, packageName);
1660 }
1661
Varun Shah7609b752018-10-15 15:07:47 -07001662 boolean isPackageInstalled(String packageName, int flags, int userId) {
1663 return mPackageManagerInternal.getPackageUid(packageName, flags, userId) >= 0;
1664 }
1665
Amith Yamasani17fffee2017-09-29 13:17:43 -07001666 int[] getRunningUserIds() throws RemoteException {
1667 return ActivityManager.getService().getRunningUserIds();
1668 }
1669
1670 boolean isDefaultDisplayOn() {
1671 return mDisplayManager
1672 .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON;
1673 }
1674
1675 void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) {
1676 mDisplayManager.registerDisplayListener(listener, handler);
1677 }
1678
1679 String getActiveNetworkScorer() {
1680 NetworkScoreManager nsm = (NetworkScoreManager) mContext.getSystemService(
1681 Context.NETWORK_SCORE_SERVICE);
1682 return nsm.getActiveScorerPackage();
1683 }
1684
1685 public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName,
1686 int userId) {
1687 return appWidgetManager.isBoundWidgetPackage(packageName, userId);
1688 }
Amith Yamasani301e94a2017-11-17 16:35:44 -08001689
1690 String getAppIdleSettings() {
Lei Yu4b976ad2018-04-19 10:38:58 -07001691 return Global.getString(mContext.getContentResolver(),
1692 Global.APP_IDLE_CONSTANTS);
Amith Yamasani301e94a2017-11-17 16:35:44 -08001693 }
Makoto Onukid5f25d22018-05-22 16:02:17 -07001694
1695 /** Whether the device is in doze or not. */
1696 public boolean isDeviceIdleMode() {
1697 return mPowerManager.isDeviceIdleMode();
1698 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07001699 }
1700
1701 class AppStandbyHandler extends Handler {
1702
1703 AppStandbyHandler(Looper looper) {
1704 super(looper);
1705 }
1706
1707 @Override
1708 public void handleMessage(Message msg) {
1709 switch (msg.what) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001710 case MSG_INFORM_LISTENERS:
Christopher Tated117b292018-01-05 17:32:36 -08001711 StandbyUpdateRecord r = (StandbyUpdateRecord) msg.obj;
Amith Yamasani119be9a2018-02-18 22:23:00 -08001712 informListeners(r.packageName, r.userId, r.bucket, r.reason,
1713 r.isUserInteraction);
Christopher Tated117b292018-01-05 17:32:36 -08001714 r.recycle();
Amith Yamasani17fffee2017-09-29 13:17:43 -07001715 break;
1716
Amith Yamasani7e528f32017-10-05 16:06:16 -07001717 case MSG_FORCE_IDLE_STATE:
1718 forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1);
1719 break;
1720
1721 case MSG_CHECK_IDLE_STATES:
Amith Yamasani172612c2017-12-15 10:51:53 -08001722 if (checkIdleStates(msg.arg1) && mAppIdleEnabled) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001723 mHandler.sendMessageDelayed(mHandler.obtainMessage(
1724 MSG_CHECK_IDLE_STATES, msg.arg1, 0),
1725 mCheckIdleIntervalMillis);
1726 }
1727 break;
1728
1729 case MSG_ONE_TIME_CHECK_IDLE_STATES:
1730 mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
Sudheer Shankac53c47f2018-01-16 12:01:00 -08001731 waitForAdminData();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001732 checkIdleStates(UserHandle.USER_ALL);
1733 break;
1734
Amith Yamasani7e528f32017-10-05 16:06:16 -07001735 case MSG_REPORT_CONTENT_PROVIDER_USAGE:
1736 SomeArgs args = (SomeArgs) msg.obj;
1737 reportContentProviderUsage((String) args.arg1, // authority name
1738 (String) args.arg2, // package name
1739 (int) args.arg3); // userId
1740 args.recycle();
1741 break;
1742
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08001743 case MSG_CHECK_PACKAGE_IDLE_STATE:
1744 checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
1745 mInjector.elapsedRealtime());
1746 break;
Makoto Onuki75ad2492018-03-28 14:42:42 -07001747
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001748 case MSG_REPORT_SYNC_SCHEDULED:
1749 final boolean exempted = msg.arg1 > 0 ? true : false;
1750 if (exempted) {
1751 reportExemptedSyncScheduled((String) msg.obj, msg.arg1);
1752 } else {
1753 reportUnexemptedSyncScheduled((String) msg.obj, msg.arg1);
1754 }
Makoto Onukid5f25d22018-05-22 16:02:17 -07001755 break;
1756
Makoto Onuki75ad2492018-03-28 14:42:42 -07001757 case MSG_REPORT_EXEMPTED_SYNC_START:
1758 reportExemptedSyncStart((String) msg.obj, msg.arg1);
1759 break;
1760
Amith Yamasani7e528f32017-10-05 16:06:16 -07001761 default:
1762 super.handleMessage(msg);
1763 break;
1764
1765 }
1766 }
1767 };
1768
Michael Wachenschwanz113a0fa2018-03-30 12:45:18 -07001769 private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder().build();
1770
1771 private final ConnectivityManager.NetworkCallback mNetworkCallback
1772 = new ConnectivityManager.NetworkCallback() {
1773 @Override
1774 public void onAvailable(Network network) {
1775 mConnectivityManager.unregisterNetworkCallback(this);
Michael Wachenschwanz113a0fa2018-03-30 12:45:18 -07001776 }
1777 };
1778
Amith Yamasani7e528f32017-10-05 16:06:16 -07001779 private final DisplayManager.DisplayListener mDisplayListener
1780 = new DisplayManager.DisplayListener() {
1781
1782 @Override public void onDisplayAdded(int displayId) {
1783 }
1784
1785 @Override public void onDisplayRemoved(int displayId) {
1786 }
1787
1788 @Override public void onDisplayChanged(int displayId) {
1789 if (displayId == Display.DEFAULT_DISPLAY) {
1790 final boolean displayOn = isDisplayOn();
1791 synchronized (mAppIdleLock) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001792 mAppIdleHistory.updateDisplay(displayOn, mInjector.elapsedRealtime());
Amith Yamasani7e528f32017-10-05 16:06:16 -07001793 }
1794 }
1795 }
1796 };
1797
1798 /**
Lei Yu4b976ad2018-04-19 10:38:58 -07001799 * Observe settings changes for {@link Global#APP_IDLE_CONSTANTS}.
Amith Yamasani7e528f32017-10-05 16:06:16 -07001800 */
1801 private class SettingsObserver extends ContentObserver {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001802 private static final String KEY_SCREEN_TIME_THRESHOLDS = "screen_thresholds";
1803 private static final String KEY_ELAPSED_TIME_THRESHOLDS = "elapsed_thresholds";
Amith Yamasani7ec89412018-02-07 08:48:49 -08001804 private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration";
1805 private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION =
1806 "notification_seen_duration";
1807 private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION =
1808 "system_update_usage_duration";
Amith Yamasani119be9a2018-02-18 22:23:00 -08001809 private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout";
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07001810 private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration";
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001811 private static final String KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION =
1812 "exempted_sync_scheduled_nd_duration";
1813 private static final String KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION =
1814 "exempted_sync_scheduled_d_duration";
1815 private static final String KEY_EXEMPTED_SYNC_START_HOLD_DURATION =
1816 "exempted_sync_start_duration";
1817 private static final String KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION =
1818 "unexempted_sync_scheduled_duration";
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07001819 private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
1820 "system_interaction_duration";
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -07001821 private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION =
1822 "initial_foreground_service_start_duration";
Kweku Adams109cd9c2020-02-11 11:10:52 -08001823 private static final String KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS =
1824 "auto_restricted_bucket_delay_ms";
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07001825 public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
1826 public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR;
1827 public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
1828 public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
1829 public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
Makoto Onukid5f25d22018-05-22 16:02:17 -07001830 public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = 10 * ONE_MINUTE;
1831 public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 4 * ONE_HOUR;
1832 public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE;
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001833 public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE;
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -07001834 public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE;
Kweku Adams109cd9c2020-02-11 11:10:52 -08001835 public static final long DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS = ONE_DAY;
Amith Yamasani7e528f32017-10-05 16:06:16 -07001836
1837 private final KeyValueListParser mParser = new KeyValueListParser(',');
1838
1839 SettingsObserver(Handler handler) {
1840 super(handler);
1841 }
1842
1843 void registerObserver() {
Lei Yu4b976ad2018-04-19 10:38:58 -07001844 final ContentResolver cr = mContext.getContentResolver();
1845 cr.registerContentObserver(Global.getUriFor(Global.APP_IDLE_CONSTANTS), false, this);
1846 cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this);
1847 cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED),
1848 false, this);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001849 }
1850
1851 @Override
1852 public void onChange(boolean selfChange) {
1853 updateSettings();
1854 postOneTimeCheckIdleStates();
1855 }
1856
1857 void updateSettings() {
Amith Yamasani172612c2017-12-15 10:51:53 -08001858 if (DEBUG) {
1859 Slog.d(TAG,
Lei Yu4b976ad2018-04-19 10:38:58 -07001860 "appidle=" + Global.getString(mContext.getContentResolver(),
1861 Global.APP_STANDBY_ENABLED));
1862 Slog.d(TAG,
1863 "adaptivebat=" + Global.getString(mContext.getContentResolver(),
1864 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED));
1865 Slog.d(TAG, "appidleconstants=" + Global.getString(
Amith Yamasani172612c2017-12-15 10:51:53 -08001866 mContext.getContentResolver(),
Lei Yu4b976ad2018-04-19 10:38:58 -07001867 Global.APP_IDLE_CONSTANTS));
Amith Yamasani172612c2017-12-15 10:51:53 -08001868 }
Amith Yamasani172612c2017-12-15 10:51:53 -08001869
1870 // Look at global settings for this.
1871 // TODO: Maybe apply different thresholds for different users.
1872 try {
1873 mParser.setString(mInjector.getAppIdleSettings());
1874 } catch (IllegalArgumentException e) {
1875 Slog.e(TAG, "Bad value for app idle settings: " + e.getMessage());
1876 // fallthrough, mParser is empty and all defaults will be returned.
1877 }
1878
Amith Yamasani7e528f32017-10-05 16:06:16 -07001879 synchronized (mAppIdleLock) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001880
Amith Yamasani17fffee2017-09-29 13:17:43 -07001881 String screenThresholdsValue = mParser.getString(KEY_SCREEN_TIME_THRESHOLDS, null);
1882 mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue,
Kweku Adams4297b5d2020-02-06 15:56:12 -08001883 SCREEN_TIME_THRESHOLDS, MINIMUM_SCREEN_TIME_THRESHOLDS);
Amith Yamasani17fffee2017-09-29 13:17:43 -07001884
Amith Yamasani84cd7b72017-11-07 13:59:37 -08001885 String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS,
1886 null);
Amith Yamasani17fffee2017-09-29 13:17:43 -07001887 mAppStandbyElapsedThresholds = parseLongArray(elapsedThresholdsValue,
Kweku Adams4297b5d2020-02-06 15:56:12 -08001888 ELAPSED_TIME_THRESHOLDS, MINIMUM_ELAPSED_TIME_THRESHOLDS);
Amith Yamasania0ef1ca2017-11-20 09:43:56 -08001889 mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4,
1890 COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001891 mStrongUsageTimeoutMillis = mParser.getDurationMillis(
1892 KEY_STRONG_USAGE_HOLD_DURATION,
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07001893 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STRONG_USAGE_TIMEOUT);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001894 mNotificationSeenTimeoutMillis = mParser.getDurationMillis(
1895 KEY_NOTIFICATION_SEEN_HOLD_DURATION,
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07001896 COMPRESS_TIME ? 12 * ONE_MINUTE : DEFAULT_NOTIFICATION_TIMEOUT);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001897 mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis(
1898 KEY_SYSTEM_UPDATE_HOLD_DURATION,
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07001899 COMPRESS_TIME ? 2 * ONE_MINUTE : DEFAULT_SYSTEM_UPDATE_TIMEOUT);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001900 mPredictionTimeoutMillis = mParser.getDurationMillis(
1901 KEY_PREDICTION_TIMEOUT,
Amith Yamasani119be9a2018-02-18 22:23:00 -08001902 COMPRESS_TIME ? 10 * ONE_MINUTE : DEFAULT_PREDICTION_TIMEOUT);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001903 mSyncAdapterTimeoutMillis = mParser.getDurationMillis(
1904 KEY_SYNC_ADAPTER_HOLD_DURATION,
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07001905 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT);
Makoto Onukid5f25d22018-05-22 16:02:17 -07001906
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001907 mExemptedSyncScheduledNonDozeTimeoutMillis = mParser.getDurationMillis(
1908 KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION,
Makoto Onukid5f25d22018-05-22 16:02:17 -07001909 COMPRESS_TIME ? (ONE_MINUTE / 2)
1910 : DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT);
1911
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001912 mExemptedSyncScheduledDozeTimeoutMillis = mParser.getDurationMillis(
1913 KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION,
Makoto Onukid5f25d22018-05-22 16:02:17 -07001914 COMPRESS_TIME ? ONE_MINUTE
1915 : DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT);
1916
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001917 mExemptedSyncStartTimeoutMillis = mParser.getDurationMillis(
1918 KEY_EXEMPTED_SYNC_START_HOLD_DURATION,
Makoto Onukid5f25d22018-05-22 16:02:17 -07001919 COMPRESS_TIME ? ONE_MINUTE
1920 : DEFAULT_EXEMPTED_SYNC_START_TIMEOUT);
1921
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001922 mUnexemptedSyncScheduledTimeoutMillis = mParser.getDurationMillis(
Kweku Adams0140ff82019-10-08 17:04:28 -07001923 KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION,
Kweku Adams4297b5d2020-02-06 15:56:12 -08001924 COMPRESS_TIME
1925 ? ONE_MINUTE : DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001926
1927 mSystemInteractionTimeoutMillis = mParser.getDurationMillis(
1928 KEY_SYSTEM_INTERACTION_HOLD_DURATION,
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07001929 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -07001930
1931 mInitialForegroundServiceStartTimeoutMillis = mParser.getDurationMillis(
1932 KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION,
1933 COMPRESS_TIME ? ONE_MINUTE :
1934 DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT);
Kweku Adams109cd9c2020-02-11 11:10:52 -08001935
1936 mInjector.mAutoRestrictedBucketDelayMs = Math.max(
1937 COMPRESS_TIME ? ONE_MINUTE : 2 * ONE_HOUR,
1938 mParser.getDurationMillis(KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS,
1939 COMPRESS_TIME
1940 ? ONE_MINUTE : DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS));
Amith Yamasani17fffee2017-09-29 13:17:43 -07001941 }
Kweku Adams1e8947c2018-11-05 18:06:13 -08001942
1943 // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
1944 // in case we need to change something based on the new values.
1945 setAppIdleEnabled(mInjector.isAppIdleEnabled());
Amith Yamasani17fffee2017-09-29 13:17:43 -07001946 }
1947
Kweku Adams4297b5d2020-02-06 15:56:12 -08001948 long[] parseLongArray(String values, long[] defaults, long[] minValues) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001949 if (values == null) return defaults;
1950 if (values.isEmpty()) {
1951 // Reset to defaults
1952 return defaults;
1953 } else {
1954 String[] thresholds = values.split("/");
1955 if (thresholds.length == THRESHOLD_BUCKETS.length) {
Kweku Adams4297b5d2020-02-06 15:56:12 -08001956 if (minValues.length != THRESHOLD_BUCKETS.length) {
1957 Slog.wtf(TAG, "minValues array is the wrong size");
1958 // Use zeroes as the minimums.
1959 minValues = new long[THRESHOLD_BUCKETS.length];
1960 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07001961 long[] array = new long[THRESHOLD_BUCKETS.length];
1962 for (int i = 0; i < THRESHOLD_BUCKETS.length; i++) {
Amith Yamasani761d3ff2017-12-14 17:50:03 -08001963 try {
1964 if (thresholds[i].startsWith("P") || thresholds[i].startsWith("p")) {
Kweku Adams4297b5d2020-02-06 15:56:12 -08001965 array[i] = Math.max(minValues[i],
1966 Duration.parse(thresholds[i]).toMillis());
Amith Yamasani761d3ff2017-12-14 17:50:03 -08001967 } else {
Kweku Adams4297b5d2020-02-06 15:56:12 -08001968 array[i] = Math.max(minValues[i], Long.parseLong(thresholds[i]));
Amith Yamasani761d3ff2017-12-14 17:50:03 -08001969 }
1970 } catch (NumberFormatException|DateTimeParseException e) {
1971 return defaults;
1972 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07001973 }
1974 return array;
1975 } else {
1976 return defaults;
1977 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07001978 }
1979 }
1980 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07001981}