blob: 687b1d4e0bde53034b34bccb9d6a210f2cb71e2b [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 Adams917f8a42020-02-26 17:18:03 -080026import static android.app.usage.UsageStatsManager.REASON_SUB_DEFAULT_APP_UPDATE;
27import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY;
Kweku Adamsc6a9b342020-01-08 18:37:26 -080028import static android.app.usage.UsageStatsManager.REASON_SUB_MASK;
Amith Yamasani3154dcf2018-03-27 18:24:04 -070029import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
Amith Yamasani119be9a2018-02-18 22:23:00 -080030import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
Makoto Onukid5f25d22018-05-22 16:02:17 -070031import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
32import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
Makoto Onuki75ad2492018-03-28 14:42:42 -070033import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START;
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -070034import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
Amith Yamasani119be9a2018-02-18 22:23:00 -080035import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
36import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
37import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
Kweku Adams1e8947c2018-11-05 18:06:13 -080038import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
39import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
Amith Yamasani119be9a2018-02-18 22:23:00 -080040import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
41import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
42import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
Michael Wachenschwanzc3295202019-02-20 17:19:52 -080043import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED;
Amith Yamasani119be9a2018-02-18 22:23:00 -080044import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080045import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
Amith Yamasani5a8cc722017-12-06 10:26:10 -080046import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080047import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
Amith Yamasani93885192017-12-13 11:52:10 -080048import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080049import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
Kweku Adamsc6a9b342020-01-08 18:37:26 -080050import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080051import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
Kweku Adams1e8947c2018-11-05 18:06:13 -080052
Kweku Adamsf35ed3702020-02-11 17:32:54 -080053import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
Amith Yamasani7e528f32017-10-05 16:06:16 -070054import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
Amith Yamasani7e528f32017-10-05 16:06:16 -070055
Kweku Adamsc4ee9982020-01-08 11:14:39 -080056import android.annotation.NonNull;
Kweku Adams95cd9522020-05-08 09:56:53 -070057import android.annotation.Nullable;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -080058import android.annotation.UserIdInt;
Amith Yamasani7e528f32017-10-05 16:06:16 -070059import android.app.ActivityManager;
60import android.app.AppGlobals;
Suprabh Shukla868bde22018-02-20 20:59:52 -080061import android.app.usage.AppStandbyInfo;
Amith Yamasani7e528f32017-10-05 16:06:16 -070062import android.app.usage.UsageEvents;
Jason Monk1918ef72018-03-14 09:20:39 -040063import android.app.usage.UsageStatsManager.StandbyBuckets;
Kweku Adamsaa461942020-03-16 11:59:05 -070064import android.app.usage.UsageStatsManager.SystemForcedReasons;
Amith Yamasani7e528f32017-10-05 16:06:16 -070065import android.appwidget.AppWidgetManager;
66import android.content.BroadcastReceiver;
67import android.content.ContentResolver;
68import android.content.Context;
69import android.content.Intent;
70import android.content.IntentFilter;
71import android.content.pm.ApplicationInfo;
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -080072import android.content.pm.CrossProfileAppsInternal;
Amith Yamasani7e528f32017-10-05 16:06:16 -070073import android.content.pm.PackageInfo;
74import android.content.pm.PackageManager;
75import android.content.pm.PackageManagerInternal;
76import android.content.pm.ParceledListSlice;
77import android.database.ContentObserver;
78import android.hardware.display.DisplayManager;
79import android.net.NetworkScoreManager;
Kweku Adamsf35ed3702020-02-11 17:32:54 -080080import android.os.BatteryManager;
Amith Yamasani7e528f32017-10-05 16:06:16 -070081import android.os.BatteryStats;
Kweku Adamsc6a9b342020-01-08 18:37:26 -080082import android.os.Build;
Amith Yamasani17fffee2017-09-29 13:17:43 -070083import android.os.Environment;
Amith Yamasani7e528f32017-10-05 16:06:16 -070084import android.os.Handler;
Kweku Adamseffeb2a2020-06-16 10:11:56 -070085import android.os.IDeviceIdleController;
Amith Yamasani7e528f32017-10-05 16:06:16 -070086import android.os.Looper;
87import android.os.Message;
88import android.os.PowerManager;
89import android.os.Process;
90import android.os.RemoteException;
91import android.os.ServiceManager;
92import android.os.SystemClock;
Amith Yamasani62b19912020-05-29 15:20:18 -070093import android.os.Trace;
Amith Yamasani7e528f32017-10-05 16:06:16 -070094import android.os.UserHandle;
Lei Yu4b976ad2018-04-19 10:38:58 -070095import android.provider.Settings.Global;
Amith Yamasani7e528f32017-10-05 16:06:16 -070096import android.telephony.TelephonyManager;
Sudheer Shanka101c3532018-01-08 16:28:42 -080097import android.util.ArraySet;
Amith Yamasani7e528f32017-10-05 16:06:16 -070098import android.util.KeyValueListParser;
99import android.util.Slog;
Sudheer Shanka101c3532018-01-08 16:28:42 -0800100import android.util.SparseArray;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700101import android.util.SparseIntArray;
102import android.util.TimeUtils;
103import android.view.Display;
Kweku Adamsc6a9b342020-01-08 18:37:26 -0800104import android.widget.Toast;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700105
Kweku Adamsc6a9b342020-01-08 18:37:26 -0800106import com.android.internal.R;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700107import com.android.internal.annotations.GuardedBy;
Sudheer Shanka101c3532018-01-08 16:28:42 -0800108import com.android.internal.annotations.VisibleForTesting;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700109import com.android.internal.app.IBatteryStats;
110import com.android.internal.os.SomeArgs;
111import com.android.internal.util.ArrayUtils;
Sudheer Shankac53c47f2018-01-16 12:01:00 -0800112import com.android.internal.util.ConcurrentUtils;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700113import com.android.internal.util.IndentingPrintWriter;
114import com.android.server.LocalServices;
Kweku Adams259403e2020-04-27 09:25:07 -0700115import com.android.server.pm.parsing.pkg.AndroidPackage;
Christopher Tated117b292018-01-05 17:32:36 -0800116import com.android.server.usage.AppIdleHistory.AppUsageHistory;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700117
Amith Yamasani17fffee2017-09-29 13:17:43 -0700118import java.io.File;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700119import java.io.PrintWriter;
Amith Yamasani761d3ff2017-12-14 17:50:03 -0800120import java.time.Duration;
121import java.time.format.DateTimeParseException;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700122import java.util.ArrayList;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700123import java.util.Arrays;
Kweku Adamsc4ee9982020-01-08 11:14:39 -0800124import java.util.Collections;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700125import java.util.List;
Sudheer Shanka101c3532018-01-08 16:28:42 -0800126import java.util.Set;
Sudheer Shankac53c47f2018-01-16 12:01:00 -0800127import java.util.concurrent.CountDownLatch;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700128
129/**
130 * Manages the standby state of an app, listening to various events.
Makoto Onukia0058b42018-05-22 16:32:23 -0700131 *
132 * Unit test:
Makoto Onukia72e04f2019-10-03 11:10:45 -0700133 atest com.android.server.usage.AppStandbyControllerTests
Amith Yamasani7e528f32017-10-05 16:06:16 -0700134 */
Makoto Onukia72e04f2019-10-03 11:10:45 -0700135public class AppStandbyController implements AppStandbyInternal {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700136
137 private static final String TAG = "AppStandbyController";
Kweku Adamsa52d5332020-03-04 10:37:57 -0800138 // Do not submit with true.
139 static final boolean DEBUG = false;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700140
141 static final boolean COMPRESS_TIME = false;
142 private static final long ONE_MINUTE = 60 * 1000;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700143 private static final long ONE_HOUR = ONE_MINUTE * 60;
144 private static final long ONE_DAY = ONE_HOUR * 24;
145
Kweku Adams4297b5d2020-02-06 15:56:12 -0800146 /**
147 * The minimum amount of time the screen must have been on before an app can time out from its
148 * current bucket to the next bucket.
149 */
150 private static final long[] SCREEN_TIME_THRESHOLDS = {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700151 0,
152 0,
Kweku Adams4297b5d2020-02-06 15:56:12 -0800153 COMPRESS_TIME ? 2 * ONE_MINUTE : 1 * ONE_HOUR,
154 COMPRESS_TIME ? 4 * ONE_MINUTE : 2 * ONE_HOUR,
155 COMPRESS_TIME ? 8 * ONE_MINUTE : 6 * ONE_HOUR
Amith Yamasani17fffee2017-09-29 13:17:43 -0700156 };
157
Kweku Adams4297b5d2020-02-06 15:56:12 -0800158 /** The minimum allowed values for each index in {@link #SCREEN_TIME_THRESHOLDS}. */
159 private static final long[] MINIMUM_SCREEN_TIME_THRESHOLDS = COMPRESS_TIME
160 ? new long[SCREEN_TIME_THRESHOLDS.length]
161 : new long[]{
162 0,
163 0,
164 0,
165 30 * ONE_MINUTE,
166 ONE_HOUR
167 };
168
169 /**
170 * The minimum amount of elapsed time that must have passed before an app can time out from its
171 * current bucket to the next bucket.
172 */
173 private static final long[] ELAPSED_TIME_THRESHOLDS = {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700174 0,
175 COMPRESS_TIME ? 1 * ONE_MINUTE : 12 * ONE_HOUR,
Amith Yamasani301e94a2017-11-17 16:35:44 -0800176 COMPRESS_TIME ? 4 * ONE_MINUTE : 24 * ONE_HOUR,
Kweku Adams4297b5d2020-02-06 15:56:12 -0800177 COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR,
Kweku Adams23aeb082020-04-13 08:34:36 -0700178 COMPRESS_TIME ? 32 * ONE_MINUTE : 30 * ONE_DAY
Amith Yamasani17fffee2017-09-29 13:17:43 -0700179 };
180
Kweku Adams4297b5d2020-02-06 15:56:12 -0800181 /** The minimum allowed values for each index in {@link #ELAPSED_TIME_THRESHOLDS}. */
182 private static final long[] MINIMUM_ELAPSED_TIME_THRESHOLDS = COMPRESS_TIME
183 ? new long[ELAPSED_TIME_THRESHOLDS.length]
184 : new long[]{
185 0,
186 ONE_HOUR,
187 ONE_HOUR,
188 2 * ONE_HOUR,
189 4 * ONE_DAY
190 };
191
192 private static final int[] THRESHOLD_BUCKETS = {
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800193 STANDBY_BUCKET_ACTIVE,
194 STANDBY_BUCKET_WORKING_SET,
195 STANDBY_BUCKET_FREQUENT,
Kweku Adams4297b5d2020-02-06 15:56:12 -0800196 STANDBY_BUCKET_RARE,
197 STANDBY_BUCKET_RESTRICTED
Amith Yamasani17fffee2017-09-29 13:17:43 -0700198 };
Amith Yamasani7e528f32017-10-05 16:06:16 -0700199
Amith Yamasani119be9a2018-02-18 22:23:00 -0800200 /** Default expiration time for bucket prediction. After this, use thresholds to downgrade. */
201 private static final long DEFAULT_PREDICTION_TIMEOUT = 12 * ONE_HOUR;
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800202
Sudheer Shankac53c47f2018-01-16 12:01:00 -0800203 /**
204 * Indicates the maximum wait time for admin data to be available;
205 */
206 private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
207
Kweku Adamsf197eef2020-06-16 11:59:37 -0700208 private static final int HEADLESS_APP_CHECK_FLAGS =
209 PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
210 | PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS;
211
Amith Yamasani7e528f32017-10-05 16:06:16 -0700212 // To name the lock for stack traces
213 static class Lock {}
214
215 /** Lock to protect the app's standby state. Required for calls into AppIdleHistory */
216 private final Object mAppIdleLock = new Lock();
217
218 /** Keeps the history and state for each app. */
219 @GuardedBy("mAppIdleLock")
220 private AppIdleHistory mAppIdleHistory;
221
Amith Yamasani93885192017-12-13 11:52:10 -0800222 @GuardedBy("mPackageAccessListeners")
Kweku Adamse6601762020-05-01 15:06:18 -0700223 private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>();
Amith Yamasani7e528f32017-10-05 16:06:16 -0700224
225 /** Whether we've queried the list of carrier privileged apps. */
226 @GuardedBy("mAppIdleLock")
227 private boolean mHaveCarrierPrivilegedApps;
228
229 /** List of carrier-privileged apps that should be excluded from standby */
230 @GuardedBy("mAppIdleLock")
231 private List<String> mCarrierPrivilegedApps;
232
Sudheer Shanka101c3532018-01-08 16:28:42 -0800233 @GuardedBy("mActiveAdminApps")
234 private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
235
Kweku Adams95cd9522020-05-08 09:56:53 -0700236 /**
237 * Set of system apps that are headless (don't have any declared activities, enabled or
238 * disabled). Presence in this map indicates that the app is a headless system app.
239 */
Kweku Adams8604fd72020-06-02 14:04:27 -0700240 @GuardedBy("mHeadlessSystemApps")
Kweku Adamsf197eef2020-06-16 11:59:37 -0700241 private final ArraySet<String> mHeadlessSystemApps = new ArraySet<>();
Kweku Adams95cd9522020-05-08 09:56:53 -0700242
Sudheer Shankac53c47f2018-01-16 12:01:00 -0800243 private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
244
Amith Yamasani62b19912020-05-29 15:20:18 -0700245 // Cache the active network scorer queried from the network scorer service
246 private volatile String mCachedNetworkScorer = null;
247 // The last time the network scorer service was queried
248 private volatile long mCachedNetworkScorerAtMillis = 0L;
249 // How long before querying the network scorer again. During this time, subsequent queries will
250 // get the cached value
251 private static final long NETWORK_SCORER_CACHE_DURATION_MILLIS = 5000L;
252
Amith Yamasani7e528f32017-10-05 16:06:16 -0700253 // Messages for the handler
254 static final int MSG_INFORM_LISTENERS = 3;
255 static final int MSG_FORCE_IDLE_STATE = 4;
256 static final int MSG_CHECK_IDLE_STATES = 5;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700257 static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
Kweku Adamse6601762020-05-01 15:06:18 -0700258 static final int MSG_PAROLE_STATE_CHANGED = 9;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700259 static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800260 /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
261 static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800262 static final int MSG_REPORT_SYNC_SCHEDULED = 12;
Makoto Onukid5f25d22018-05-22 16:02:17 -0700263 static final int MSG_REPORT_EXEMPTED_SYNC_START = 13;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700264
Amith Yamasani7e528f32017-10-05 16:06:16 -0700265 long mCheckIdleIntervalMillis;
Kweku Adams4297b5d2020-02-06 15:56:12 -0800266 /**
267 * The minimum amount of time the screen must have been on before an app can time out from its
268 * current bucket to the next bucket.
269 */
Amith Yamasani17fffee2017-09-29 13:17:43 -0700270 long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS;
Kweku Adams4297b5d2020-02-06 15:56:12 -0800271 /**
272 * The minimum amount of elapsed time that must have passed before an app can time out from its
273 * current bucket to the next bucket.
274 */
Amith Yamasani17fffee2017-09-29 13:17:43 -0700275 long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS;
Amith Yamasani7ec89412018-02-07 08:48:49 -0800276 /** Minimum time a strong usage event should keep the bucket elevated. */
277 long mStrongUsageTimeoutMillis;
278 /** Minimum time a notification seen event should keep the bucket elevated. */
279 long mNotificationSeenTimeoutMillis;
280 /** Minimum time a system update event should keep the buckets elevated. */
281 long mSystemUpdateUsageTimeoutMillis;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800282 /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */
283 long mPredictionTimeoutMillis;
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700284 /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */
285 long mSyncAdapterTimeoutMillis;
Makoto Onukid5f25d22018-05-22 16:02:17 -0700286 /**
287 * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
288 * non-doze
289 */
290 long mExemptedSyncScheduledNonDozeTimeoutMillis;
291 /**
292 * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
293 * doze
294 */
295 long mExemptedSyncScheduledDozeTimeoutMillis;
296 /**
297 * Maximum time an exempted sync should keep the buckets elevated, when sync is started.
298 */
299 long mExemptedSyncStartTimeoutMillis;
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800300 /**
301 * Maximum time an unexempted sync should keep the buckets elevated, when sync is scheduled
302 */
303 long mUnexemptedSyncScheduledTimeoutMillis;
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700304 /** Maximum time a system interaction should keep the buckets elevated. */
305 long mSystemInteractionTimeoutMillis;
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -0700306 /**
307 * Maximum time a foreground service start should keep the buckets elevated if the service
308 * start is the first usage of the app
309 */
310 long mInitialForegroundServiceStartTimeoutMillis;
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800311 /**
312 * User usage that would elevate an app's standby bucket will also elevate the standby bucket of
313 * cross profile connected apps. Explicit standby bucket setting via
314 * {@link #setAppStandbyBucket(String, int, int, int, int)} will not be propagated.
315 */
316 boolean mLinkCrossProfileApps;
Kweku Adams2d79ce52020-05-05 12:31:35 -0700317 /**
318 * Whether we should allow apps into the
319 * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not.
320 * If false, any attempts to put an app into the bucket will put the app into the
321 * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RARE} bucket instead.
322 */
323 private boolean mAllowRestrictedBucket;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700324
Makoto Onukia72e04f2019-10-03 11:10:45 -0700325 private volatile boolean mAppIdleEnabled;
Kweku Adamsf35ed3702020-02-11 17:32:54 -0800326 private boolean mIsCharging;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700327 private boolean mSystemServicesReady = false;
Amith Yamasani777b1532018-01-28 23:20:07 +0000328 // There was a system update, defaults need to be initialized after services are ready
329 private boolean mPendingInitializeDefaults;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700330
331 private volatile boolean mPendingOneTimeCheckIdleStates;
332
Christopher Tatea732f012017-10-26 17:26:53 -0700333 private final AppStandbyHandler mHandler;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700334 private final Context mContext;
335
Amith Yamasani7e528f32017-10-05 16:06:16 -0700336 private AppWidgetManager mAppWidgetManager;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700337 private PackageManager mPackageManager;
Amith Yamasani172612c2017-12-15 10:51:53 -0800338 Injector mInjector;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700339
Christopher Tated117b292018-01-05 17:32:36 -0800340 static final ArrayList<StandbyUpdateRecord> sStandbyUpdatePool = new ArrayList<>(4);
341
342 public static class StandbyUpdateRecord {
343 // Identity of the app whose standby state has changed
344 String packageName;
345 int userId;
346
347 // What the standby bucket the app is now in
348 int bucket;
349
350 // Whether the bucket change is because the user has started interacting with the app
351 boolean isUserInteraction;
352
Amith Yamasani119be9a2018-02-18 22:23:00 -0800353 // Reason for bucket change
354 int reason;
355
356 StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason,
357 boolean isInteraction) {
Christopher Tated117b292018-01-05 17:32:36 -0800358 this.packageName = pkgName;
359 this.userId = userId;
360 this.bucket = bucket;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800361 this.reason = reason;
Christopher Tated117b292018-01-05 17:32:36 -0800362 this.isUserInteraction = isInteraction;
363 }
364
365 public static StandbyUpdateRecord obtain(String pkgName, int userId,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800366 int bucket, int reason, boolean isInteraction) {
Christopher Tated117b292018-01-05 17:32:36 -0800367 synchronized (sStandbyUpdatePool) {
368 final int size = sStandbyUpdatePool.size();
369 if (size < 1) {
Amith Yamasani119be9a2018-02-18 22:23:00 -0800370 return new StandbyUpdateRecord(pkgName, userId, bucket, reason, isInteraction);
Christopher Tated117b292018-01-05 17:32:36 -0800371 }
372 StandbyUpdateRecord r = sStandbyUpdatePool.remove(size - 1);
373 r.packageName = pkgName;
374 r.userId = userId;
375 r.bucket = bucket;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800376 r.reason = reason;
Christopher Tated117b292018-01-05 17:32:36 -0800377 r.isUserInteraction = isInteraction;
378 return r;
379 }
380 }
381
382 public void recycle() {
383 synchronized (sStandbyUpdatePool) {
384 sStandbyUpdatePool.add(this);
385 }
386 }
387 }
Amith Yamasani7e528f32017-10-05 16:06:16 -0700388
Makoto Onukia72e04f2019-10-03 11:10:45 -0700389 public AppStandbyController(Context context, Looper looper) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700390 this(new Injector(context, looper));
391 }
392
393 AppStandbyController(Injector injector) {
394 mInjector = injector;
395 mContext = mInjector.getContext();
396 mHandler = new AppStandbyHandler(mInjector.getLooper());
Amith Yamasani7e528f32017-10-05 16:06:16 -0700397 mPackageManager = mContext.getPackageManager();
Amith Yamasani172612c2017-12-15 10:51:53 -0800398
Kweku Adamsf35ed3702020-02-11 17:32:54 -0800399 DeviceStateReceiver deviceStateReceiver = new DeviceStateReceiver();
400 IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
401 deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
Kweku Adamseffeb2a2020-06-16 10:11:56 -0700402 deviceStates.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
Kweku Adamsf35ed3702020-02-11 17:32:54 -0800403 mContext.registerReceiver(deviceStateReceiver, deviceStates);
404
Amith Yamasani7e528f32017-10-05 16:06:16 -0700405 synchronized (mAppIdleLock) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700406 mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(),
407 mInjector.elapsedRealtime());
Amith Yamasani7e528f32017-10-05 16:06:16 -0700408 }
409
410 IntentFilter packageFilter = new IntentFilter();
411 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
412 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
413 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
414 packageFilter.addDataScheme("package");
415
416 mContext.registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter,
417 null, mHandler);
418 }
419
Makoto Onukia72e04f2019-10-03 11:10:45 -0700420 @VisibleForTesting
Amith Yamasani172612c2017-12-15 10:51:53 -0800421 void setAppIdleEnabled(boolean enabled) {
Kweku Adamse6601762020-05-01 15:06:18 -0700422 synchronized (mAppIdleLock) {
423 if (mAppIdleEnabled != enabled) {
424 final boolean oldParoleState = isInParole();
425 mAppIdleEnabled = enabled;
426 if (isInParole() != oldParoleState) {
427 postParoleStateChanged();
428 }
429 }
430 }
431
Amith Yamasani172612c2017-12-15 10:51:53 -0800432 }
433
Makoto Onukia72e04f2019-10-03 11:10:45 -0700434 @Override
435 public boolean isAppIdleEnabled() {
436 return mAppIdleEnabled;
437 }
438
439 @Override
Amith Yamasani7e528f32017-10-05 16:06:16 -0700440 public void onBootPhase(int phase) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700441 mInjector.onBootPhase(phase);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700442 if (phase == PHASE_SYSTEM_SERVICES_READY) {
Amith Yamasani777b1532018-01-28 23:20:07 +0000443 Slog.d(TAG, "Setting app idle enabled state");
Amith Yamasani7e528f32017-10-05 16:06:16 -0700444 // Observe changes to the threshold
445 SettingsObserver settingsObserver = new SettingsObserver(mHandler);
446 settingsObserver.registerObserver();
447 settingsObserver.updateSettings();
448
449 mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700450
Amith Yamasani17fffee2017-09-29 13:17:43 -0700451 mInjector.registerDisplayListener(mDisplayListener, mHandler);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700452 synchronized (mAppIdleLock) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700453 mAppIdleHistory.updateDisplay(isDisplayOn(), mInjector.elapsedRealtime());
Amith Yamasani7e528f32017-10-05 16:06:16 -0700454 }
455
Amith Yamasani777b1532018-01-28 23:20:07 +0000456 mSystemServicesReady = true;
457
Kweku Adamseffeb2a2020-06-16 10:11:56 -0700458 // Offload to handler thread to avoid boot time impact.
459 mHandler.post(mInjector::updatePowerWhitelistCache);
460
Michael Wachenschwanzd1d8aa62019-02-28 16:38:37 -0800461 boolean userFileExists;
462 synchronized (mAppIdleLock) {
463 userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM);
464 }
465
Kweku Adams8604fd72020-06-02 14:04:27 -0700466 // Offload to handler thread to avoid boottime impact.
467 mHandler.post(this::loadHeadlessSystemAppCache);
Kweku Adamsc86da5f2020-05-28 12:26:35 -0700468
Michael Wachenschwanzd1d8aa62019-02-28 16:38:37 -0800469 if (mPendingInitializeDefaults || !userFileExists) {
Amith Yamasani777b1532018-01-28 23:20:07 +0000470 initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM);
471 }
472
Amith Yamasani7e528f32017-10-05 16:06:16 -0700473 if (mPendingOneTimeCheckIdleStates) {
474 postOneTimeCheckIdleStates();
475 }
Kweku Adamsf35ed3702020-02-11 17:32:54 -0800476 } else if (phase == PHASE_BOOT_COMPLETED) {
477 setChargingState(mInjector.isCharging());
Amith Yamasani7e528f32017-10-05 16:06:16 -0700478 }
479 }
480
Makoto Onukia72e04f2019-10-03 11:10:45 -0700481 private void reportContentProviderUsage(String authority, String providerPkgName, int userId) {
Amith Yamasani172612c2017-12-15 10:51:53 -0800482 if (!mAppIdleEnabled) return;
483
Amith Yamasani7e528f32017-10-05 16:06:16 -0700484 // Get sync adapters for the authority
485 String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
486 authority, userId);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800487 final long elapsedRealtime = mInjector.elapsedRealtime();
Amith Yamasani7e528f32017-10-05 16:06:16 -0700488 for (String packageName: packages) {
489 // Only force the sync adapters to active if the provider is not in the same package and
490 // the sync adapter is a system package.
491 try {
492 PackageInfo pi = mPackageManager.getPackageInfoAsUser(
493 packageName, PackageManager.MATCH_SYSTEM_ONLY, userId);
494 if (pi == null || pi.applicationInfo == null) {
495 continue;
496 }
497 if (!packageName.equals(providerPkgName)) {
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800498 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName,
499 userId);
Amith Yamasani803eab692017-11-09 17:47:04 -0800500 synchronized (mAppIdleLock) {
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800501 reportNoninteractiveUsageCrossUserLocked(packageName, userId,
502 STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER,
503 elapsedRealtime, mSyncAdapterTimeoutMillis, linkedProfiles);
Amith Yamasani803eab692017-11-09 17:47:04 -0800504 }
Amith Yamasani7e528f32017-10-05 16:06:16 -0700505 }
506 } catch (PackageManager.NameNotFoundException e) {
507 // Shouldn't happen
508 }
509 }
510 }
511
Makoto Onukia72e04f2019-10-03 11:10:45 -0700512 private void reportExemptedSyncScheduled(String packageName, int userId) {
Makoto Onukid5f25d22018-05-22 16:02:17 -0700513 if (!mAppIdleEnabled) return;
514
515 final int bucketToPromote;
516 final int usageReason;
517 final long durationMillis;
518
519 if (!mInjector.isDeviceIdleMode()) {
520 // Not dozing.
521 bucketToPromote = STANDBY_BUCKET_ACTIVE;
522 usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
523 durationMillis = mExemptedSyncScheduledNonDozeTimeoutMillis;
524 } else {
525 // Dozing.
526 bucketToPromote = STANDBY_BUCKET_WORKING_SET;
527 usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
528 durationMillis = mExemptedSyncScheduledDozeTimeoutMillis;
529 }
530
531 final long elapsedRealtime = mInjector.elapsedRealtime();
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800532 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
Makoto Onukid5f25d22018-05-22 16:02:17 -0700533 synchronized (mAppIdleLock) {
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800534 reportNoninteractiveUsageCrossUserLocked(packageName, userId, bucketToPromote,
535 usageReason, elapsedRealtime, durationMillis, linkedProfiles);
Makoto Onukid5f25d22018-05-22 16:02:17 -0700536 }
537 }
538
Makoto Onukia72e04f2019-10-03 11:10:45 -0700539 private void reportUnexemptedSyncScheduled(String packageName, int userId) {
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800540 if (!mAppIdleEnabled) return;
541
542 final long elapsedRealtime = mInjector.elapsedRealtime();
543 synchronized (mAppIdleLock) {
544 final int currentBucket =
545 mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
546 if (currentBucket == STANDBY_BUCKET_NEVER) {
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800547 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800548 // Bring the app out of the never bucket
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800549 reportNoninteractiveUsageCrossUserLocked(packageName, userId,
550 STANDBY_BUCKET_WORKING_SET, REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED,
551 elapsedRealtime, mUnexemptedSyncScheduledTimeoutMillis, linkedProfiles);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800552 }
553 }
554 }
555
Makoto Onukia72e04f2019-10-03 11:10:45 -0700556 private void reportExemptedSyncStart(String packageName, int userId) {
Makoto Onuki75ad2492018-03-28 14:42:42 -0700557 if (!mAppIdleEnabled) return;
558
559 final long elapsedRealtime = mInjector.elapsedRealtime();
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800560 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
Makoto Onuki75ad2492018-03-28 14:42:42 -0700561 synchronized (mAppIdleLock) {
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800562 reportNoninteractiveUsageCrossUserLocked(packageName, userId, STANDBY_BUCKET_ACTIVE,
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800563 REASON_SUB_USAGE_EXEMPTED_SYNC_START, elapsedRealtime,
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800564 mExemptedSyncStartTimeoutMillis, linkedProfiles);
Makoto Onuki75ad2492018-03-28 14:42:42 -0700565 }
566 }
567
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800568 /**
569 * Helper method to report indirect user usage of an app and handle reporting the usage
570 * against cross profile connected apps. <br>
571 * Use {@link #reportNoninteractiveUsageLocked(String, int, int, int, long, long)} if
572 * cross profile connected apps do not need to be handled.
573 */
574 private void reportNoninteractiveUsageCrossUserLocked(String packageName, int userId,
575 int bucket, int subReason, long elapsedRealtime, long nextCheckDelay,
576 List<UserHandle> otherProfiles) {
577 reportNoninteractiveUsageLocked(packageName, userId, bucket, subReason, elapsedRealtime,
578 nextCheckDelay);
579 final int size = otherProfiles.size();
580 for (int profileIndex = 0; profileIndex < size; profileIndex++) {
581 final int otherUserId = otherProfiles.get(profileIndex).getIdentifier();
582 reportNoninteractiveUsageLocked(packageName, otherUserId, bucket, subReason,
583 elapsedRealtime, nextCheckDelay);
584 }
585 }
586
587 /**
588 * Helper method to report indirect user usage of an app. <br>
589 * Use
590 * {@link #reportNoninteractiveUsageCrossUserLocked(String, int, int, int, long, long, List)}
591 * if cross profile connected apps need to be handled.
592 */
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800593 private void reportNoninteractiveUsageLocked(String packageName, int userId, int bucket,
594 int subReason, long elapsedRealtime, long nextCheckDelay) {
595 final AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, bucket,
596 subReason, 0, elapsedRealtime + nextCheckDelay);
597 mHandler.sendMessageDelayed(
598 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, packageName),
599 nextCheckDelay);
600 maybeInformListeners(packageName, userId, elapsedRealtime, appUsage.currentBucket,
601 appUsage.bucketingReason, false);
602 }
603
Kweku Adamsf35ed3702020-02-11 17:32:54 -0800604 @VisibleForTesting
605 void setChargingState(boolean isCharging) {
606 synchronized (mAppIdleLock) {
607 if (mIsCharging != isCharging) {
608 if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging);
609 mIsCharging = isCharging;
Kweku Adamse6601762020-05-01 15:06:18 -0700610 postParoleStateChanged();
Kweku Adamsf35ed3702020-02-11 17:32:54 -0800611 }
612 }
613 }
614
Makoto Onukia72e04f2019-10-03 11:10:45 -0700615 @Override
Kweku Adamse6601762020-05-01 15:06:18 -0700616 public boolean isInParole() {
617 return !mAppIdleEnabled || mIsCharging;
618 }
619
620 private void postParoleStateChanged() {
621 if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED");
622 mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED);
623 mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
624 }
625
626 @Override
Makoto Onukia72e04f2019-10-03 11:10:45 -0700627 public void postCheckIdleStates(int userId) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700628 mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
629 }
630
Makoto Onukia72e04f2019-10-03 11:10:45 -0700631 @Override
632 public void postOneTimeCheckIdleStates() {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700633 if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) {
Amith Yamasani7e528f32017-10-05 16:06:16 -0700634 // Not booted yet; wait for it!
635 mPendingOneTimeCheckIdleStates = true;
636 } else {
637 mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
638 mPendingOneTimeCheckIdleStates = false;
639 }
640 }
641
Makoto Onukia72e04f2019-10-03 11:10:45 -0700642 @VisibleForTesting
Amith Yamasani7e528f32017-10-05 16:06:16 -0700643 boolean checkIdleStates(int checkUserId) {
644 if (!mAppIdleEnabled) {
645 return false;
646 }
647
648 final int[] runningUserIds;
649 try {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700650 runningUserIds = mInjector.getRunningUserIds();
Amith Yamasani7e528f32017-10-05 16:06:16 -0700651 if (checkUserId != UserHandle.USER_ALL
652 && !ArrayUtils.contains(runningUserIds, checkUserId)) {
653 return false;
654 }
655 } catch (RemoteException re) {
656 throw re.rethrowFromSystemServer();
657 }
658
Amith Yamasani17fffee2017-09-29 13:17:43 -0700659 final long elapsedRealtime = mInjector.elapsedRealtime();
Amith Yamasani7e528f32017-10-05 16:06:16 -0700660 for (int i = 0; i < runningUserIds.length; i++) {
661 final int userId = runningUserIds[i];
662 if (checkUserId != UserHandle.USER_ALL && checkUserId != userId) {
663 continue;
664 }
665 if (DEBUG) {
666 Slog.d(TAG, "Checking idle state for user " + userId);
667 }
668 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
669 PackageManager.MATCH_DISABLED_COMPONENTS,
670 userId);
671 final int packageCount = packages.size();
672 for (int p = 0; p < packageCount; p++) {
673 final PackageInfo pi = packages.get(p);
674 final String packageName = pi.packageName;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800675 checkAndUpdateStandbyState(packageName, userId, pi.applicationInfo.uid,
676 elapsedRealtime);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700677 }
678 }
679 if (DEBUG) {
680 Slog.d(TAG, "checkIdleStates took "
Amith Yamasani17fffee2017-09-29 13:17:43 -0700681 + (mInjector.elapsedRealtime() - elapsedRealtime));
Amith Yamasani7e528f32017-10-05 16:06:16 -0700682 }
683 return true;
684 }
685
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800686 /** Check if we need to update the standby state of a specific app. */
687 private void checkAndUpdateStandbyState(String packageName, @UserIdInt int userId,
688 int uid, long elapsedRealtime) {
689 if (uid <= 0) {
690 try {
691 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
692 } catch (PackageManager.NameNotFoundException e) {
693 // Not a valid package for this user, nothing to do
694 // TODO: Remove any history of removed packages
695 return;
696 }
697 }
Kweku Adams95cd9522020-05-08 09:56:53 -0700698 final int minBucket = getAppMinBucket(packageName,
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800699 UserHandle.getAppId(uid),
700 userId);
701 if (DEBUG) {
Kweku Adams95cd9522020-05-08 09:56:53 -0700702 Slog.d(TAG, " Checking idle state for " + packageName
703 + " minBucket=" + minBucket);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800704 }
Kweku Adams95cd9522020-05-08 09:56:53 -0700705 if (minBucket <= STANDBY_BUCKET_ACTIVE) {
706 // No extra processing needed for ACTIVE or higher since apps can't drop into lower
707 // buckets.
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800708 synchronized (mAppIdleLock) {
709 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
Kweku Adams95cd9522020-05-08 09:56:53 -0700710 minBucket, REASON_MAIN_DEFAULT);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800711 }
712 maybeInformListeners(packageName, userId, elapsedRealtime,
Kweku Adams95cd9522020-05-08 09:56:53 -0700713 minBucket, REASON_MAIN_DEFAULT, false);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800714 } else {
715 synchronized (mAppIdleLock) {
716 final AppIdleHistory.AppUsageHistory app =
717 mAppIdleHistory.getAppUsageHistory(packageName,
718 userId, elapsedRealtime);
Amith Yamasani119be9a2018-02-18 22:23:00 -0800719 int reason = app.bucketingReason;
720 final int oldMainReason = reason & REASON_MAIN_MASK;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800721
722 // If the bucket was forced by the user/developer, leave it alone.
723 // A usage event will be the only way to bring it out of this forced state
Kweku Adamsc182d5e2020-01-08 18:37:26 -0800724 if (oldMainReason == REASON_MAIN_FORCED_BY_USER) {
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800725 return;
726 }
727 final int oldBucket = app.currentBucket;
Kweku Adams2d79ce52020-05-05 12:31:35 -0700728 if (oldBucket == STANDBY_BUCKET_NEVER) {
729 // None of this should bring an app out of the NEVER bucket.
730 return;
731 }
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800732 int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700733 boolean predictionLate = predictionTimedOut(app, elapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800734 // Compute age-based bucket
Amith Yamasani119be9a2018-02-18 22:23:00 -0800735 if (oldMainReason == REASON_MAIN_DEFAULT
736 || oldMainReason == REASON_MAIN_USAGE
737 || oldMainReason == REASON_MAIN_TIMEOUT
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700738 || predictionLate) {
739
740 if (!predictionLate && app.lastPredictedBucket >= STANDBY_BUCKET_ACTIVE
741 && app.lastPredictedBucket <= STANDBY_BUCKET_RARE) {
742 newBucket = app.lastPredictedBucket;
743 reason = REASON_MAIN_PREDICTED | REASON_SUB_PREDICTED_RESTORED;
744 if (DEBUG) {
745 Slog.d(TAG, "Restored predicted newBucket = " + newBucket);
746 }
747 } else {
748 newBucket = getBucketForLocked(packageName, userId,
749 elapsedRealtime);
750 if (DEBUG) {
751 Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket);
752 }
753 reason = REASON_MAIN_TIMEOUT;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800754 }
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800755 }
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700756
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800757 // Check if the app is within one of the timeouts for forced bucket elevation
758 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
759 if (newBucket >= STANDBY_BUCKET_ACTIVE
760 && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
761 newBucket = STANDBY_BUCKET_ACTIVE;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800762 reason = app.bucketingReason;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800763 if (DEBUG) {
764 Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
765 }
766 } else if (newBucket >= STANDBY_BUCKET_WORKING_SET
767 && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
768 newBucket = STANDBY_BUCKET_WORKING_SET;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800769 // If it was already there, keep the reason, else assume timeout to WS
770 reason = (newBucket == oldBucket)
771 ? app.bucketingReason
772 : REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800773 if (DEBUG) {
774 Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
775 }
776 }
Kweku Adamsc6a9b342020-01-08 18:37:26 -0800777
778 if (app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime
779 && elapsedTimeAdjusted - app.lastUsedByUserElapsedTime
Kweku Adams109cd9c2020-02-11 11:10:52 -0800780 >= mInjector.getAutoRestrictedBucketDelayMs()) {
Kweku Adamsc6a9b342020-01-08 18:37:26 -0800781 newBucket = STANDBY_BUCKET_RESTRICTED;
782 reason = app.lastRestrictReason;
783 if (DEBUG) {
784 Slog.d(TAG, "Bringing down to RESTRICTED due to timeout");
785 }
786 }
Kweku Adams2d79ce52020-05-05 12:31:35 -0700787 if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) {
788 newBucket = STANDBY_BUCKET_RARE;
789 // Leave the reason alone.
790 if (DEBUG) {
791 Slog.d(TAG, "Bringing up from RESTRICTED to RARE due to off switch");
792 }
793 }
Kweku Adams95cd9522020-05-08 09:56:53 -0700794 if (newBucket > minBucket) {
795 newBucket = minBucket;
796 // Leave the reason alone.
797 if (DEBUG) {
798 Slog.d(TAG, "Bringing up from " + newBucket + " to " + minBucket
799 + " due to min bucketing");
800 }
801 }
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800802 if (DEBUG) {
803 Slog.d(TAG, " Old bucket=" + oldBucket
804 + ", newBucket=" + newBucket);
805 }
Kweku Adams2d79ce52020-05-05 12:31:35 -0700806 if (oldBucket != newBucket || predictionLate) {
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800807 mAppIdleHistory.setAppStandbyBucket(packageName, userId,
808 elapsedRealtime, newBucket, reason);
809 maybeInformListeners(packageName, userId, elapsedRealtime,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800810 newBucket, reason, false);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800811 }
812 }
813 }
814 }
815
Amith Yamasani119be9a2018-02-18 22:23:00 -0800816 /** Returns true if there hasn't been a prediction for the app in a while. */
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800817 private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700818 return app.lastPredictedTime > 0
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800819 && mAppIdleHistory.getElapsedTime(elapsedRealtime)
Amith Yamasani119be9a2018-02-18 22:23:00 -0800820 - app.lastPredictedTime > mPredictionTimeoutMillis;
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800821 }
822
Amith Yamasani119be9a2018-02-18 22:23:00 -0800823 /** Inform listeners if the bucket has changed since it was last reported to listeners */
Amith Yamasani17fffee2017-09-29 13:17:43 -0700824 private void maybeInformListeners(String packageName, int userId,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800825 long elapsedRealtime, int bucket, int reason, boolean userStartedInteracting) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700826 synchronized (mAppIdleLock) {
827 if (mAppIdleHistory.shouldInformListeners(packageName, userId,
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800828 elapsedRealtime, bucket)) {
Amith Yamasani119be9a2018-02-18 22:23:00 -0800829 final StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId,
830 bucket, reason, userStartedInteracting);
Amith Yamasani777b1532018-01-28 23:20:07 +0000831 if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket);
Amith Yamasani119be9a2018-02-18 22:23:00 -0800832 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, r));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700833 }
834 }
835 }
836
Amith Yamasani119be9a2018-02-18 22:23:00 -0800837 /**
838 * Evaluates next bucket based on time since last used and the bucketing thresholds.
839 * @param packageName the app
840 * @param userId the user
841 * @param elapsedRealtime as the name suggests, current elapsed time
842 * @return the bucket for the app, based on time since last used
843 */
Andreas Gampebbab23f2018-02-07 15:34:27 -0800844 @GuardedBy("mAppIdleLock")
Makoto Onukia72e04f2019-10-03 11:10:45 -0700845 @StandbyBuckets
846 private int getBucketForLocked(String packageName, int userId,
Amith Yamasani17fffee2017-09-29 13:17:43 -0700847 long elapsedRealtime) {
848 int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId,
849 elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds);
850 return THRESHOLD_BUCKETS[bucketIndex];
851 }
852
Amith Yamasani7e528f32017-10-05 16:06:16 -0700853 private void notifyBatteryStats(String packageName, int userId, boolean idle) {
854 try {
855 final int uid = mPackageManager.getPackageUidAsUser(packageName,
856 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
857 if (idle) {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700858 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
Amith Yamasani7e528f32017-10-05 16:06:16 -0700859 packageName, uid);
860 } else {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700861 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
Amith Yamasani7e528f32017-10-05 16:06:16 -0700862 packageName, uid);
863 }
864 } catch (PackageManager.NameNotFoundException | RemoteException e) {
865 }
866 }
867
Makoto Onukia72e04f2019-10-03 11:10:45 -0700868 @Override
Michael Wachenschwanz793da642020-06-11 16:14:48 -0700869 public void reportEvent(UsageEvents.Event event, int userId) {
Amith Yamasani172612c2017-12-15 10:51:53 -0800870 if (!mAppIdleEnabled) return;
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800871 final int eventType = event.getEventType();
872 if ((eventType == UsageEvents.Event.ACTIVITY_RESUMED
873 || eventType == UsageEvents.Event.ACTIVITY_PAUSED
874 || eventType == UsageEvents.Event.SYSTEM_INTERACTION
875 || eventType == UsageEvents.Event.USER_INTERACTION
876 || eventType == UsageEvents.Event.NOTIFICATION_SEEN
877 || eventType == UsageEvents.Event.SLICE_PINNED
878 || eventType == UsageEvents.Event.SLICE_PINNED_PRIV
879 || eventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) {
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800880 final String pkg = event.getPackageName();
881 final List<UserHandle> linkedProfiles = getCrossProfileTargets(pkg, userId);
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800882 synchronized (mAppIdleLock) {
Michael Wachenschwanz793da642020-06-11 16:14:48 -0700883 final long elapsedRealtime = mInjector.elapsedRealtime();
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800884 reportEventLocked(pkg, eventType, elapsedRealtime, userId);
885
886 final int size = linkedProfiles.size();
887 for (int profileIndex = 0; profileIndex < size; profileIndex++) {
888 final int linkedUserId = linkedProfiles.get(profileIndex).getIdentifier();
889 reportEventLocked(pkg, eventType, elapsedRealtime, linkedUserId);
890 }
Amith Yamasani7e528f32017-10-05 16:06:16 -0700891 }
892 }
Amith Yamasani7e528f32017-10-05 16:06:16 -0700893 }
894
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800895 private void reportEventLocked(String pkg, int eventType, long elapsedRealtime, int userId) {
896 // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
897 // about apps that are on some kind of whitelist anyway.
898 final boolean previouslyIdle = mAppIdleHistory.isIdle(
899 pkg, userId, elapsedRealtime);
900
901 final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory(
902 pkg, userId, elapsedRealtime);
903 final int prevBucket = appHistory.currentBucket;
904 final int prevBucketReason = appHistory.bucketingReason;
905 final long nextCheckDelay;
906 final int subReason = usageEventToSubReason(eventType);
907 final int reason = REASON_MAIN_USAGE | subReason;
908 if (eventType == UsageEvents.Event.NOTIFICATION_SEEN
909 || eventType == UsageEvents.Event.SLICE_PINNED) {
910 // Mild usage elevates to WORKING_SET but doesn't change usage time.
Kweku Adams12752132020-02-18 15:36:48 -0800911 mAppIdleHistory.reportUsage(appHistory, pkg, userId,
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800912 STANDBY_BUCKET_WORKING_SET, subReason,
913 0, elapsedRealtime + mNotificationSeenTimeoutMillis);
914 nextCheckDelay = mNotificationSeenTimeoutMillis;
915 } else if (eventType == UsageEvents.Event.SYSTEM_INTERACTION) {
Kweku Adams12752132020-02-18 15:36:48 -0800916 mAppIdleHistory.reportUsage(appHistory, pkg, userId,
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800917 STANDBY_BUCKET_ACTIVE, subReason,
918 0, elapsedRealtime + mSystemInteractionTimeoutMillis);
919 nextCheckDelay = mSystemInteractionTimeoutMillis;
920 } else if (eventType == UsageEvents.Event.FOREGROUND_SERVICE_START) {
921 // Only elevate bucket if this is the first usage of the app
922 if (prevBucket != STANDBY_BUCKET_NEVER) return;
Kweku Adams12752132020-02-18 15:36:48 -0800923 mAppIdleHistory.reportUsage(appHistory, pkg, userId,
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800924 STANDBY_BUCKET_ACTIVE, subReason,
925 0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis);
926 nextCheckDelay = mInitialForegroundServiceStartTimeoutMillis;
927 } else {
Kweku Adams12752132020-02-18 15:36:48 -0800928 mAppIdleHistory.reportUsage(appHistory, pkg, userId,
Michael Wachenschwanz081ce5d2020-02-10 12:47:53 -0800929 STANDBY_BUCKET_ACTIVE, subReason,
930 elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
931 nextCheckDelay = mStrongUsageTimeoutMillis;
932 }
933 if (appHistory.currentBucket != prevBucket) {
934 mHandler.sendMessageDelayed(
935 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkg),
936 nextCheckDelay);
937 final boolean userStartedInteracting =
938 appHistory.currentBucket == STANDBY_BUCKET_ACTIVE
939 && (prevBucketReason & REASON_MAIN_MASK) != REASON_MAIN_USAGE;
940 maybeInformListeners(pkg, userId, elapsedRealtime,
941 appHistory.currentBucket, reason, userStartedInteracting);
942 }
943
944 if (previouslyIdle) {
945 notifyBatteryStats(pkg, userId, false);
946 }
947 }
948
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -0800949 /**
950 * Note: don't call this with the lock held since it makes calls to other system services.
951 */
952 private @NonNull List<UserHandle> getCrossProfileTargets(String pkg, int userId) {
953 synchronized (mAppIdleLock) {
954 if (!mLinkCrossProfileApps) return Collections.emptyList();
955 }
956 return mInjector.getValidCrossProfileTargets(pkg, userId);
957 }
958
Amith Yamasani119be9a2018-02-18 22:23:00 -0800959 private int usageEventToSubReason(int eventType) {
960 switch (eventType) {
Hui Yu03d12402018-12-06 18:00:37 -0800961 case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
962 case UsageEvents.Event.ACTIVITY_PAUSED: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800963 case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION;
964 case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION;
965 case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN;
Amith Yamasani80c4be82018-03-26 10:54:04 -0700966 case UsageEvents.Event.SLICE_PINNED: return REASON_SUB_USAGE_SLICE_PINNED;
967 case UsageEvents.Event.SLICE_PINNED_PRIV: return REASON_SUB_USAGE_SLICE_PINNED_PRIV;
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -0700968 case UsageEvents.Event.FOREGROUND_SERVICE_START:
969 return REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800970 default: return 0;
971 }
972 }
973
Makoto Onukia72e04f2019-10-03 11:10:45 -0700974 @VisibleForTesting
Amith Yamasani7e528f32017-10-05 16:06:16 -0700975 void forceIdleState(String packageName, int userId, boolean idle) {
Amith Yamasani172612c2017-12-15 10:51:53 -0800976 if (!mAppIdleEnabled) return;
977
Amith Yamasani7e528f32017-10-05 16:06:16 -0700978 final int appId = getAppId(packageName);
979 if (appId < 0) return;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700980 final long elapsedRealtime = mInjector.elapsedRealtime();
Amith Yamasani7e528f32017-10-05 16:06:16 -0700981
982 final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
983 userId, elapsedRealtime);
Christopher Tatea732f012017-10-26 17:26:53 -0700984 final int standbyBucket;
Amith Yamasani7e528f32017-10-05 16:06:16 -0700985 synchronized (mAppIdleLock) {
Christopher Tatea732f012017-10-26 17:26:53 -0700986 standbyBucket = mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700987 }
988 final boolean stillIdle = isAppIdleFiltered(packageName, appId,
989 userId, elapsedRealtime);
990 // Inform listeners if necessary
991 if (previouslyIdle != stillIdle) {
Amith Yamasani119be9a2018-02-18 22:23:00 -0800992 maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket,
Kweku Adamsc182d5e2020-01-08 18:37:26 -0800993 REASON_MAIN_FORCED_BY_USER, false);
Amith Yamasani7e528f32017-10-05 16:06:16 -0700994 if (!stillIdle) {
995 notifyBatteryStats(packageName, userId, idle);
996 }
997 }
998 }
999
Makoto Onukia72e04f2019-10-03 11:10:45 -07001000 @Override
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001001 public void setLastJobRunTime(String packageName, int userId, long elapsedRealtime) {
1002 synchronized (mAppIdleLock) {
1003 mAppIdleHistory.setLastJobRunTime(packageName, userId, elapsedRealtime);
1004 }
1005 }
1006
Makoto Onukia72e04f2019-10-03 11:10:45 -07001007 @Override
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001008 public long getTimeSinceLastJobRun(String packageName, int userId) {
1009 final long elapsedRealtime = mInjector.elapsedRealtime();
1010 synchronized (mAppIdleLock) {
1011 return mAppIdleHistory.getTimeSinceLastJobRun(packageName, userId, elapsedRealtime);
1012 }
1013 }
1014
Makoto Onukia72e04f2019-10-03 11:10:45 -07001015 @Override
Amith Yamasani7e528f32017-10-05 16:06:16 -07001016 public void onUserRemoved(int userId) {
1017 synchronized (mAppIdleLock) {
1018 mAppIdleHistory.onUserRemoved(userId);
Sudheer Shanka101c3532018-01-08 16:28:42 -08001019 synchronized (mActiveAdminApps) {
1020 mActiveAdminApps.remove(userId);
1021 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07001022 }
1023 }
1024
1025 private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
1026 synchronized (mAppIdleLock) {
1027 return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
1028 }
1029 }
1030
Makoto Onukia72e04f2019-10-03 11:10:45 -07001031 @Override
1032 public void addListener(AppIdleStateChangeListener listener) {
Amith Yamasani93885192017-12-13 11:52:10 -08001033 synchronized (mPackageAccessListeners) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001034 if (!mPackageAccessListeners.contains(listener)) {
1035 mPackageAccessListeners.add(listener);
1036 }
1037 }
1038 }
1039
Makoto Onukia72e04f2019-10-03 11:10:45 -07001040 @Override
1041 public void removeListener(AppIdleStateChangeListener listener) {
Amith Yamasani93885192017-12-13 11:52:10 -08001042 synchronized (mPackageAccessListeners) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001043 mPackageAccessListeners.remove(listener);
1044 }
1045 }
1046
Makoto Onukia72e04f2019-10-03 11:10:45 -07001047 @Override
1048 public int getAppId(String packageName) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001049 try {
1050 ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName,
1051 PackageManager.MATCH_ANY_USER
1052 | PackageManager.MATCH_DISABLED_COMPONENTS);
1053 return ai.uid;
1054 } catch (PackageManager.NameNotFoundException re) {
1055 return -1;
1056 }
1057 }
1058
Makoto Onukia72e04f2019-10-03 11:10:45 -07001059 @Override
Kweku Adamsdf33ae12019-10-08 11:51:41 -07001060 public boolean isAppIdleFiltered(String packageName, int userId, long elapsedRealtime,
Amith Yamasani7e528f32017-10-05 16:06:16 -07001061 boolean shouldObfuscateInstantApps) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001062 if (shouldObfuscateInstantApps &&
Amith Yamasani17fffee2017-09-29 13:17:43 -07001063 mInjector.isPackageEphemeral(userId, packageName)) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001064 return false;
1065 }
1066 return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
1067 }
1068
Kweku Adams95cd9522020-05-08 09:56:53 -07001069 @StandbyBuckets
1070 private int getAppMinBucket(String packageName, int userId) {
1071 try {
1072 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
1073 return getAppMinBucket(packageName, UserHandle.getAppId(uid), userId);
1074 } catch (PackageManager.NameNotFoundException e) {
1075 // Not a valid package for this user, nothing to do
1076 return STANDBY_BUCKET_NEVER;
1077 }
1078 }
1079
1080 /**
1081 * Return the lowest bucket this app should ever enter.
1082 */
1083 @StandbyBuckets
1084 private int getAppMinBucket(String packageName, int appId, int userId) {
1085 if (packageName == null) return STANDBY_BUCKET_NEVER;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001086 // If not enabled at all, of course nobody is ever idle.
1087 if (!mAppIdleEnabled) {
Kweku Adams95cd9522020-05-08 09:56:53 -07001088 return STANDBY_BUCKET_EXEMPTED;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001089 }
1090 if (appId < Process.FIRST_APPLICATION_UID) {
1091 // System uids never go idle.
Kweku Adams95cd9522020-05-08 09:56:53 -07001092 return STANDBY_BUCKET_EXEMPTED;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001093 }
1094 if (packageName.equals("android")) {
1095 // Nor does the framework (which should be redundant with the above, but for MR1 we will
1096 // retain this for safety).
Kweku Adams95cd9522020-05-08 09:56:53 -07001097 return STANDBY_BUCKET_EXEMPTED;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001098 }
1099 if (mSystemServicesReady) {
Kweku Adamseffeb2a2020-06-16 10:11:56 -07001100 // We allow all whitelisted apps, including those that don't want to be whitelisted
1101 // for idle mode, because app idle (aka app standby) is really not as big an issue
1102 // for controlling who participates vs. doze mode.
1103 if (mInjector.isNonIdleWhitelisted(packageName)) {
1104 return STANDBY_BUCKET_EXEMPTED;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001105 }
1106
1107 if (isActiveDeviceAdmin(packageName, userId)) {
Kweku Adams95cd9522020-05-08 09:56:53 -07001108 return STANDBY_BUCKET_EXEMPTED;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001109 }
1110
1111 if (isActiveNetworkScorer(packageName)) {
Kweku Adams95cd9522020-05-08 09:56:53 -07001112 return STANDBY_BUCKET_EXEMPTED;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001113 }
1114
1115 if (mAppWidgetManager != null
1116 && mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) {
Kweku Adams107be822020-05-14 08:02:45 -07001117 return STANDBY_BUCKET_ACTIVE;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001118 }
1119
1120 if (isDeviceProvisioningPackage(packageName)) {
Kweku Adams95cd9522020-05-08 09:56:53 -07001121 return STANDBY_BUCKET_EXEMPTED;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001122 }
1123 }
1124
1125 // Check this last, as it can be the most expensive check
1126 if (isCarrierApp(packageName)) {
Kweku Adams95cd9522020-05-08 09:56:53 -07001127 return STANDBY_BUCKET_EXEMPTED;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001128 }
1129
Kweku Adams95cd9522020-05-08 09:56:53 -07001130 if (isHeadlessSystemApp(packageName)) {
1131 return STANDBY_BUCKET_ACTIVE;
1132 }
1133
1134 return STANDBY_BUCKET_NEVER;
1135 }
1136
1137 private boolean isHeadlessSystemApp(String packageName) {
Kweku Adams8604fd72020-06-02 14:04:27 -07001138 synchronized (mHeadlessSystemApps) {
Kweku Adamsf197eef2020-06-16 11:59:37 -07001139 return mHeadlessSystemApps.contains(packageName);
Kweku Adams8604fd72020-06-02 14:04:27 -07001140 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07001141 }
1142
Makoto Onukia72e04f2019-10-03 11:10:45 -07001143 @Override
1144 public boolean isAppIdleFiltered(String packageName, int appId, int userId,
Amith Yamasani7e528f32017-10-05 16:06:16 -07001145 long elapsedRealtime) {
Kweku Adams95cd9522020-05-08 09:56:53 -07001146 if (getAppMinBucket(packageName, appId, userId) < AppIdleHistory.IDLE_BUCKET_CUTOFF) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001147 return false;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001148 } else {
Kweku Adamsf35ed3702020-02-11 17:32:54 -08001149 synchronized (mAppIdleLock) {
1150 if (!mAppIdleEnabled || mIsCharging) {
1151 return false;
1152 }
1153 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07001154 return isAppIdleUnfiltered(packageName, userId, elapsedRealtime);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001155 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07001156 }
1157
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001158 static boolean isUserUsage(int reason) {
1159 if ((reason & REASON_MAIN_MASK) == REASON_MAIN_USAGE) {
1160 final int subReason = reason & REASON_SUB_MASK;
1161 return subReason == REASON_SUB_USAGE_USER_INTERACTION
1162 || subReason == REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
1163 }
1164 return false;
1165 }
1166
Makoto Onukia72e04f2019-10-03 11:10:45 -07001167 @Override
1168 public int[] getIdleUidsForUser(int userId) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001169 if (!mAppIdleEnabled) {
1170 return new int[0];
1171 }
1172
Amith Yamasani62b19912020-05-29 15:20:18 -07001173 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "getIdleUidsForUser");
1174
Amith Yamasani17fffee2017-09-29 13:17:43 -07001175 final long elapsedRealtime = mInjector.elapsedRealtime();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001176
1177 List<ApplicationInfo> apps;
1178 try {
1179 ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager()
1180 .getInstalledApplications(/* flags= */ 0, userId);
1181 if (slice == null) {
1182 return new int[0];
1183 }
1184 apps = slice.getList();
1185 } catch (RemoteException e) {
1186 throw e.rethrowFromSystemServer();
1187 }
1188
1189 // State of each uid. Key is the uid. Value lower 16 bits is the number of apps
1190 // associated with that uid, upper 16 bits is the number of those apps that is idle.
1191 SparseIntArray uidStates = new SparseIntArray();
1192
1193 // Now resolve all app state. Iterating over all apps, keeping track of how many
1194 // we find for each uid and how many of those are idle.
1195 for (int i = apps.size() - 1; i >= 0; i--) {
1196 ApplicationInfo ai = apps.get(i);
1197
1198 // Check whether this app is idle.
1199 boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid),
1200 userId, elapsedRealtime);
1201
1202 int index = uidStates.indexOfKey(ai.uid);
1203 if (index < 0) {
1204 uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0));
1205 } else {
1206 int value = uidStates.valueAt(index);
1207 uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0));
1208 }
1209 }
Amith Yamasani62b19912020-05-29 15:20:18 -07001210
Amith Yamasani7e528f32017-10-05 16:06:16 -07001211 if (DEBUG) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001212 Slog.d(TAG, "getIdleUids took " + (mInjector.elapsedRealtime() - elapsedRealtime));
Amith Yamasani7e528f32017-10-05 16:06:16 -07001213 }
1214 int numIdle = 0;
1215 for (int i = uidStates.size() - 1; i >= 0; i--) {
1216 int value = uidStates.valueAt(i);
1217 if ((value&0x7fff) == (value>>16)) {
1218 numIdle++;
1219 }
1220 }
1221
1222 int[] res = new int[numIdle];
1223 numIdle = 0;
1224 for (int i = uidStates.size() - 1; i >= 0; i--) {
1225 int value = uidStates.valueAt(i);
1226 if ((value&0x7fff) == (value>>16)) {
1227 res[numIdle] = uidStates.keyAt(i);
1228 numIdle++;
1229 }
1230 }
1231
Amith Yamasani62b19912020-05-29 15:20:18 -07001232 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1233
Amith Yamasani7e528f32017-10-05 16:06:16 -07001234 return res;
1235 }
1236
Makoto Onukia72e04f2019-10-03 11:10:45 -07001237 @Override
1238 public void setAppIdleAsync(String packageName, boolean idle, int userId) {
Amith Yamasani172612c2017-12-15 10:51:53 -08001239 if (packageName == null || !mAppIdleEnabled) return;
Amith Yamasani7e528f32017-10-05 16:06:16 -07001240
1241 mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
1242 .sendToTarget();
1243 }
1244
Makoto Onukia72e04f2019-10-03 11:10:45 -07001245 @Override
Christopher Tatea732f012017-10-26 17:26:53 -07001246 @StandbyBuckets public int getAppStandbyBucket(String packageName, int userId,
Amith Yamasani17fffee2017-09-29 13:17:43 -07001247 long elapsedRealtime, boolean shouldObfuscateInstantApps) {
Amith Yamasani172612c2017-12-15 10:51:53 -08001248 if (!mAppIdleEnabled || (shouldObfuscateInstantApps
1249 && mInjector.isPackageEphemeral(userId, packageName))) {
Amith Yamasaniafbccb72017-11-27 10:44:24 -08001250 return STANDBY_BUCKET_ACTIVE;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001251 }
1252
Amith Yamasanie8789312017-12-10 14:34:26 -08001253 synchronized (mAppIdleLock) {
1254 return mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
1255 }
1256 }
1257
Kweku Adamsaa461942020-03-16 11:59:05 -07001258 @VisibleForTesting
1259 int getAppStandbyBucketReason(String packageName, int userId, long elapsedRealtime) {
1260 synchronized (mAppIdleLock) {
1261 return mAppIdleHistory.getAppStandbyReason(packageName, userId, elapsedRealtime);
1262 }
1263 }
1264
Makoto Onukia72e04f2019-10-03 11:10:45 -07001265 @Override
Suprabh Shukla868bde22018-02-20 20:59:52 -08001266 public List<AppStandbyInfo> getAppStandbyBuckets(int userId) {
Amith Yamasanie8789312017-12-10 14:34:26 -08001267 synchronized (mAppIdleLock) {
Suprabh Shukla868bde22018-02-20 20:59:52 -08001268 return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled);
Amith Yamasanie8789312017-12-10 14:34:26 -08001269 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07001270 }
1271
Kweku Adamsc4ee9982020-01-08 11:14:39 -08001272 @Override
Kweku Adamsaa461942020-03-16 11:59:05 -07001273 public void restrictApp(@NonNull String packageName, int userId,
1274 @SystemForcedReasons int restrictReason) {
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001275 // If the package is not installed, don't allow the bucket to be set.
1276 if (!mInjector.isPackageInstalled(packageName, 0, userId)) {
1277 Slog.e(TAG, "Tried to restrict uninstalled app: " + packageName);
1278 return;
1279 }
1280
1281 final int reason = REASON_MAIN_FORCED_BY_SYSTEM | (REASON_SUB_MASK & restrictReason);
1282 final long nowElapsed = mInjector.elapsedRealtime();
Kweku Adams2d79ce52020-05-05 12:31:35 -07001283 final int bucket = mAllowRestrictedBucket ? STANDBY_BUCKET_RESTRICTED : STANDBY_BUCKET_RARE;
1284 setAppStandbyBucket(packageName, userId, bucket, reason, nowElapsed, false);
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001285 }
1286
1287 @Override
Kweku Adamsc4ee9982020-01-08 11:14:39 -08001288 public void setAppStandbyBucket(@NonNull String packageName, int bucket, int userId,
1289 int callingUid, int callingPid) {
1290 setAppStandbyBuckets(
1291 Collections.singletonList(new AppStandbyInfo(packageName, bucket)),
1292 userId, callingUid, callingPid);
Makoto Onukia0058b42018-05-22 16:32:23 -07001293 }
1294
Makoto Onukia72e04f2019-10-03 11:10:45 -07001295 @Override
Kweku Adamsc4ee9982020-01-08 11:14:39 -08001296 public void setAppStandbyBuckets(@NonNull List<AppStandbyInfo> appBuckets, int userId,
1297 int callingUid, int callingPid) {
1298 userId = ActivityManager.handleIncomingUser(
1299 callingPid, callingUid, userId, false, true, "setAppStandbyBucket", null);
1300 final boolean shellCaller = callingUid == Process.ROOT_UID
1301 || callingUid == Process.SHELL_UID;
Kweku Adamsc182d5e2020-01-08 18:37:26 -08001302 final int reason;
1303 // The Settings app runs in the system UID but in a separate process. Assume
1304 // things coming from other processes are due to the user.
1305 if ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && callingPid != Process.myPid())
1306 || shellCaller) {
1307 reason = REASON_MAIN_FORCED_BY_USER;
1308 } else if (UserHandle.isCore(callingUid)) {
1309 reason = REASON_MAIN_FORCED_BY_SYSTEM;
1310 } else {
1311 reason = REASON_MAIN_PREDICTED;
1312 }
Kweku Adamsc4ee9982020-01-08 11:14:39 -08001313 final int packageFlags = PackageManager.MATCH_ANY_USER
1314 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
1315 | PackageManager.MATCH_DIRECT_BOOT_AWARE;
1316 final int numApps = appBuckets.size();
1317 final long elapsedRealtime = mInjector.elapsedRealtime();
1318 for (int i = 0; i < numApps; ++i) {
1319 final AppStandbyInfo bucketInfo = appBuckets.get(i);
1320 final String packageName = bucketInfo.mPackageName;
1321 final int bucket = bucketInfo.mStandbyBucket;
1322 if (bucket < STANDBY_BUCKET_ACTIVE || bucket > STANDBY_BUCKET_NEVER) {
1323 throw new IllegalArgumentException("Cannot set the standby bucket to " + bucket);
1324 }
1325 final int packageUid = mInjector.getPackageManagerInternal()
1326 .getPackageUid(packageName, packageFlags, userId);
1327 // Caller cannot set their own standby state
1328 if (packageUid == callingUid) {
1329 throw new IllegalArgumentException("Cannot set your own standby bucket");
1330 }
1331 if (packageUid < 0) {
1332 throw new IllegalArgumentException(
1333 "Cannot set standby bucket for non existent package (" + packageName + ")");
1334 }
1335 setAppStandbyBucket(packageName, userId, bucket, reason, elapsedRealtime, shellCaller);
1336 }
1337 }
1338
1339 @VisibleForTesting
1340 void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
1341 int reason) {
1342 setAppStandbyBucket(
1343 packageName, userId, newBucket, reason, mInjector.elapsedRealtime(), false);
1344 }
1345
1346 private void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
Makoto Onukia0058b42018-05-22 16:32:23 -07001347 int reason, long elapsedRealtime, boolean resetTimeout) {
Kweku Adams52b52a62020-05-26 12:21:16 -07001348 if (!mAppIdleEnabled) return;
1349
Amith Yamasanie8789312017-12-10 14:34:26 -08001350 synchronized (mAppIdleLock) {
Varun Shah7609b752018-10-15 15:07:47 -07001351 // If the package is not installed, don't allow the bucket to be set.
1352 if (!mInjector.isPackageInstalled(packageName, 0, userId)) {
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001353 Slog.e(TAG, "Tried to set bucket of uninstalled app: " + packageName);
Varun Shah7609b752018-10-15 15:07:47 -07001354 return;
1355 }
Kweku Adams2d79ce52020-05-05 12:31:35 -07001356 if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) {
1357 newBucket = STANDBY_BUCKET_RARE;
1358 }
Amith Yamasani93885192017-12-13 11:52:10 -08001359 AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
1360 userId, elapsedRealtime);
Amith Yamasani119be9a2018-02-18 22:23:00 -08001361 boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED;
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001362
Amith Yamasani93885192017-12-13 11:52:10 -08001363 // Don't allow changing bucket if higher than ACTIVE
1364 if (app.currentBucket < STANDBY_BUCKET_ACTIVE) return;
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001365
Kweku Adams496594c2020-03-16 12:26:01 -07001366 // Don't allow prediction to change from/to NEVER.
1367 if ((app.currentBucket == STANDBY_BUCKET_NEVER || newBucket == STANDBY_BUCKET_NEVER)
Amith Yamasani93885192017-12-13 11:52:10 -08001368 && predicted) {
1369 return;
1370 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001371
Kweku Adamsaa461942020-03-16 11:59:05 -07001372 final boolean wasForcedBySystem =
1373 (app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM;
1374
Amith Yamasani93885192017-12-13 11:52:10 -08001375 // If the bucket was forced, don't allow prediction to override
Kweku Adamsc182d5e2020-01-08 18:37:26 -08001376 if (predicted
1377 && ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER
Kweku Adamsaa461942020-03-16 11:59:05 -07001378 || wasForcedBySystem)) {
1379 return;
1380 }
1381
1382 final boolean isForcedBySystem =
1383 (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM;
1384
1385 if (app.currentBucket == newBucket && wasForcedBySystem && isForcedBySystem) {
1386 mAppIdleHistory
1387 .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason);
1388 // Keep track of all restricting reasons
1389 reason = REASON_MAIN_FORCED_BY_SYSTEM
1390 | (app.bucketingReason & REASON_SUB_MASK)
1391 | (reason & REASON_SUB_MASK);
1392 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
1393 newBucket, reason, resetTimeout);
Kweku Adamsc182d5e2020-01-08 18:37:26 -08001394 return;
1395 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001396
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001397 final boolean isForcedByUser =
1398 (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER;
1399
Kweku Adams496594c2020-03-16 12:26:01 -07001400 if (app.currentBucket == STANDBY_BUCKET_RESTRICTED) {
1401 if ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_TIMEOUT) {
1402 if (predicted && newBucket >= STANDBY_BUCKET_RARE) {
1403 // Predicting into RARE or below means we don't expect the user to use the
1404 // app anytime soon, so don't elevate it from RESTRICTED.
1405 return;
1406 }
1407 } else if (!isUserUsage(reason) && !isForcedByUser) {
1408 // If the current bucket is RESTRICTED, only user force or usage should bring
1409 // it out, unless the app was put into the bucket due to timing out.
1410 return;
1411 }
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001412 }
1413
1414 if (newBucket == STANDBY_BUCKET_RESTRICTED) {
1415 mAppIdleHistory
1416 .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason);
1417
1418 if (isForcedByUser) {
1419 // Only user force can bypass the delay restriction. If the user forced the
1420 // app into the RESTRICTED bucket, then a toast confirming the action
1421 // shouldn't be surprising.
1422 if (Build.IS_DEBUGGABLE) {
1423 Toast.makeText(mContext,
1424 // Since AppStandbyController sits low in the lock hierarchy,
1425 // make sure not to call out with the lock held.
1426 mHandler.getLooper(),
1427 mContext.getResources().getString(
1428 R.string.as_app_forced_to_restricted_bucket, packageName),
1429 Toast.LENGTH_SHORT)
1430 .show();
1431 } else {
1432 Slog.i(TAG, packageName + " restricted by user");
1433 }
1434 } else {
1435 final long timeUntilRestrictPossibleMs = app.lastUsedByUserElapsedTime
Kweku Adams109cd9c2020-02-11 11:10:52 -08001436 + mInjector.getAutoRestrictedBucketDelayMs() - elapsedRealtime;
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001437 if (timeUntilRestrictPossibleMs > 0) {
1438 Slog.w(TAG, "Tried to restrict recently used app: " + packageName
1439 + " due to " + reason);
1440 mHandler.sendMessageDelayed(
1441 mHandler.obtainMessage(
1442 MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, packageName),
1443 timeUntilRestrictPossibleMs);
1444 return;
1445 }
1446 }
1447 }
1448
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001449 // If the bucket is required to stay in a higher state for a specified duration, don't
1450 // override unless the duration has passed
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08001451 if (predicted) {
1452 // Check if the app is within one of the timeouts for forced bucket elevation
1453 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
Amith Yamasani3154dcf2018-03-27 18:24:04 -07001454 // In case of not using the prediction, just keep track of it for applying after
1455 // ACTIVE or WORKING_SET timeout.
1456 mAppIdleHistory.updateLastPrediction(app, elapsedTimeAdjusted, newBucket);
1457
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08001458 if (newBucket > STANDBY_BUCKET_ACTIVE
1459 && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
1460 newBucket = STANDBY_BUCKET_ACTIVE;
Amith Yamasani119be9a2018-02-18 22:23:00 -08001461 reason = app.bucketingReason;
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08001462 if (DEBUG) {
1463 Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
1464 }
1465 } else if (newBucket > STANDBY_BUCKET_WORKING_SET
1466 && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
1467 newBucket = STANDBY_BUCKET_WORKING_SET;
Amith Yamasani119be9a2018-02-18 22:23:00 -08001468 if (app.currentBucket != newBucket) {
1469 reason = REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT;
1470 } else {
1471 reason = app.bucketingReason;
1472 }
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08001473 if (DEBUG) {
1474 Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
1475 }
Kweku Adams54391332020-04-08 14:56:46 -07001476 } else if (newBucket == STANDBY_BUCKET_RARE
Kweku Adams2d79ce52020-05-05 12:31:35 -07001477 && mAllowRestrictedBucket
Kweku Adams54391332020-04-08 14:56:46 -07001478 && getBucketForLocked(packageName, userId, elapsedRealtime)
1479 == STANDBY_BUCKET_RESTRICTED) {
1480 // Prediction doesn't think the app will be used anytime soon and
1481 // it's been long enough that it could just time out into restricted,
1482 // so time it out there instead. Using TIMEOUT will allow prediction
1483 // to raise the bucket when it needs to.
1484 newBucket = STANDBY_BUCKET_RESTRICTED;
1485 reason = REASON_MAIN_TIMEOUT;
1486 if (DEBUG) {
1487 Slog.d(TAG,
1488 "Prediction to RARE overridden by timeout into RESTRICTED");
1489 }
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08001490 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001491 }
1492
Kweku Adams95cd9522020-05-08 09:56:53 -07001493 // Make sure we don't put the app in a lower bucket than it's supposed to be in.
1494 newBucket = Math.min(newBucket, getAppMinBucket(packageName, userId));
Amith Yamasanie8789312017-12-10 14:34:26 -08001495 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
Makoto Onukia0058b42018-05-22 16:32:23 -07001496 reason, resetTimeout);
Amith Yamasanie8789312017-12-10 14:34:26 -08001497 }
Amith Yamasani119be9a2018-02-18 22:23:00 -08001498 maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false);
Amith Yamasani17fffee2017-09-29 13:17:43 -07001499 }
1500
Sudheer Shanka101c3532018-01-08 16:28:42 -08001501 @VisibleForTesting
1502 boolean isActiveDeviceAdmin(String packageName, int userId) {
1503 synchronized (mActiveAdminApps) {
1504 final Set<String> adminPkgs = mActiveAdminApps.get(userId);
1505 return adminPkgs != null && adminPkgs.contains(packageName);
1506 }
1507 }
1508
Makoto Onukia72e04f2019-10-03 11:10:45 -07001509 @Override
Sudheer Shanka101c3532018-01-08 16:28:42 -08001510 public void addActiveDeviceAdmin(String adminPkg, int userId) {
1511 synchronized (mActiveAdminApps) {
1512 Set<String> adminPkgs = mActiveAdminApps.get(userId);
1513 if (adminPkgs == null) {
1514 adminPkgs = new ArraySet<>();
1515 mActiveAdminApps.put(userId, adminPkgs);
1516 }
1517 adminPkgs.add(adminPkg);
1518 }
1519 }
1520
Makoto Onukia72e04f2019-10-03 11:10:45 -07001521 @Override
Sudheer Shanka101c3532018-01-08 16:28:42 -08001522 public void setActiveAdminApps(Set<String> adminPkgs, int userId) {
1523 synchronized (mActiveAdminApps) {
1524 if (adminPkgs == null) {
1525 mActiveAdminApps.remove(userId);
1526 } else {
1527 mActiveAdminApps.put(userId, adminPkgs);
1528 }
1529 }
1530 }
1531
Makoto Onukia72e04f2019-10-03 11:10:45 -07001532 @Override
Sudheer Shankac53c47f2018-01-16 12:01:00 -08001533 public void onAdminDataAvailable() {
1534 mAdminDataAvailableLatch.countDown();
1535 }
1536
1537 /**
1538 * This will only ever be called once - during device boot.
1539 */
1540 private void waitForAdminData() {
1541 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
1542 ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch,
1543 WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data");
1544 }
1545 }
1546
Makoto Onukia72e04f2019-10-03 11:10:45 -07001547 @VisibleForTesting
Sudheer Shanka101c3532018-01-08 16:28:42 -08001548 Set<String> getActiveAdminAppsForTest(int userId) {
1549 synchronized (mActiveAdminApps) {
1550 return mActiveAdminApps.get(userId);
1551 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07001552 }
1553
1554 /**
1555 * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
1556 * returns {@code false}.
1557 */
1558 private boolean isDeviceProvisioningPackage(String packageName) {
1559 String deviceProvisioningPackage = mContext.getResources().getString(
1560 com.android.internal.R.string.config_deviceProvisioningPackage);
1561 return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
1562 }
1563
1564 private boolean isCarrierApp(String packageName) {
1565 synchronized (mAppIdleLock) {
1566 if (!mHaveCarrierPrivilegedApps) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001567 fetchCarrierPrivilegedAppsLocked();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001568 }
1569 if (mCarrierPrivilegedApps != null) {
1570 return mCarrierPrivilegedApps.contains(packageName);
1571 }
1572 return false;
1573 }
1574 }
1575
Makoto Onukia72e04f2019-10-03 11:10:45 -07001576 @Override
1577 public void clearCarrierPrivilegedApps() {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001578 if (DEBUG) {
1579 Slog.i(TAG, "Clearing carrier privileged apps list");
1580 }
1581 synchronized (mAppIdleLock) {
1582 mHaveCarrierPrivilegedApps = false;
1583 mCarrierPrivilegedApps = null; // Need to be refetched.
1584 }
1585 }
1586
1587 @GuardedBy("mAppIdleLock")
Amith Yamasani17fffee2017-09-29 13:17:43 -07001588 private void fetchCarrierPrivilegedAppsLocked() {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001589 TelephonyManager telephonyManager =
1590 mContext.getSystemService(TelephonyManager.class);
Shuo Qian6f27c572019-12-03 23:52:13 +00001591 mCarrierPrivilegedApps =
1592 telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001593 mHaveCarrierPrivilegedApps = true;
1594 if (DEBUG) {
1595 Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
1596 }
1597 }
1598
1599 private boolean isActiveNetworkScorer(String packageName) {
Amith Yamasani62b19912020-05-29 15:20:18 -07001600 // Validity of network scorer cache is limited to a few seconds. Fetch it again
1601 // if longer since query.
1602 // This is a temporary optimization until there's a callback mechanism for changes to network scorer.
1603 final long now = SystemClock.elapsedRealtime();
1604 if (mCachedNetworkScorer == null
1605 || mCachedNetworkScorerAtMillis < now - NETWORK_SCORER_CACHE_DURATION_MILLIS) {
1606 mCachedNetworkScorer = mInjector.getActiveNetworkScorer();
1607 mCachedNetworkScorerAtMillis = now;
1608 }
1609 return packageName != null && packageName.equals(mCachedNetworkScorer);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001610 }
1611
Makoto Onukia72e04f2019-10-03 11:10:45 -07001612 private void informListeners(String packageName, int userId, int bucket, int reason,
Amith Yamasani119be9a2018-02-18 22:23:00 -08001613 boolean userInteraction) {
Amith Yamasaniafbccb72017-11-27 10:44:24 -08001614 final boolean idle = bucket >= STANDBY_BUCKET_RARE;
Amith Yamasani93885192017-12-13 11:52:10 -08001615 synchronized (mPackageAccessListeners) {
1616 for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
Amith Yamasani119be9a2018-02-18 22:23:00 -08001617 listener.onAppIdleStateChanged(packageName, userId, idle, bucket, reason);
Christopher Tated117b292018-01-05 17:32:36 -08001618 if (userInteraction) {
1619 listener.onUserInteractionStarted(packageName, userId);
1620 }
Amith Yamasani93885192017-12-13 11:52:10 -08001621 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07001622 }
1623 }
1624
Kweku Adamse6601762020-05-01 15:06:18 -07001625 private void informParoleStateChanged() {
1626 final boolean paroled = isInParole();
1627 synchronized (mPackageAccessListeners) {
1628 for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
1629 listener.onParoleStateChanged(paroled);
1630 }
1631 }
1632 }
1633
Amith Yamasani7e528f32017-10-05 16:06:16 -07001634
Makoto Onukia72e04f2019-10-03 11:10:45 -07001635 @Override
Michael Wachenschwanz793da642020-06-11 16:14:48 -07001636 public void flushToDisk() {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001637 synchronized (mAppIdleLock) {
Michael Wachenschwanz793da642020-06-11 16:14:48 -07001638 mAppIdleHistory.writeAppIdleTimes();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001639 mAppIdleHistory.writeAppIdleDurations();
1640 }
1641 }
1642
Makoto Onukia72e04f2019-10-03 11:10:45 -07001643 private boolean isDisplayOn() {
Amith Yamasani17fffee2017-09-29 13:17:43 -07001644 return mInjector.isDefaultDisplayOn();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001645 }
1646
Makoto Onukia72e04f2019-10-03 11:10:45 -07001647 @VisibleForTesting
Amith Yamasani7e528f32017-10-05 16:06:16 -07001648 void clearAppIdleForPackage(String packageName, int userId) {
1649 synchronized (mAppIdleLock) {
1650 mAppIdleHistory.clearUsage(packageName, userId);
1651 }
1652 }
1653
Kweku Adams917f8a42020-02-26 17:18:03 -08001654 /**
1655 * Remove an app from the {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED}
1656 * bucket if it was forced into the bucket by the system because it was buggy.
1657 */
1658 @VisibleForTesting
1659 void maybeUnrestrictBuggyApp(String packageName, int userId) {
1660 synchronized (mAppIdleLock) {
1661 final long elapsedRealtime = mInjector.elapsedRealtime();
1662 final AppIdleHistory.AppUsageHistory app =
1663 mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime);
1664 if (app.currentBucket != STANDBY_BUCKET_RESTRICTED
1665 || (app.bucketingReason & REASON_MAIN_MASK) != REASON_MAIN_FORCED_BY_SYSTEM) {
1666 return;
1667 }
1668
1669 final int newBucket;
1670 final int newReason;
1671 if ((app.bucketingReason & REASON_SUB_MASK) == REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY) {
1672 // If bugginess was the only reason the app should be restricted, then lift it out.
1673 newBucket = STANDBY_BUCKET_RARE;
1674 newReason = REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_APP_UPDATE;
1675 } else {
1676 // There's another reason the app was restricted. Remove the buggy bit and call
1677 // it a day.
1678 newBucket = STANDBY_BUCKET_RESTRICTED;
1679 newReason = app.bucketingReason & ~REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY;
1680 }
1681 mAppIdleHistory.setAppStandbyBucket(
1682 packageName, userId, elapsedRealtime, newBucket, newReason);
1683 }
1684 }
1685
Amith Yamasani7e528f32017-10-05 16:06:16 -07001686 private class PackageReceiver extends BroadcastReceiver {
1687 @Override
1688 public void onReceive(Context context, Intent intent) {
1689 final String action = intent.getAction();
Kweku Adams95cd9522020-05-08 09:56:53 -07001690 final String pkgName = intent.getData().getSchemeSpecificPart();
1691 final int userId = getSendingUserId();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001692 if (Intent.ACTION_PACKAGE_ADDED.equals(action)
1693 || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
1694 clearCarrierPrivilegedApps();
Kweku Adams95cd9522020-05-08 09:56:53 -07001695 // ACTION_PACKAGE_ADDED is called even for system app downgrades.
1696 evaluateSystemAppException(pkgName, userId);
Kweku Adamsc86da5f2020-05-28 12:26:35 -07001697 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkgName)
1698 .sendToTarget();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001699 }
1700 if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
Kweku Adams917f8a42020-02-26 17:18:03 -08001701 Intent.ACTION_PACKAGE_ADDED.equals(action))) {
Kweku Adams917f8a42020-02-26 17:18:03 -08001702 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1703 maybeUnrestrictBuggyApp(pkgName, userId);
1704 } else {
1705 clearAppIdleForPackage(pkgName, userId);
1706 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07001707 }
1708 }
1709 }
1710
Kweku Adams95cd9522020-05-08 09:56:53 -07001711 private void evaluateSystemAppException(String packageName, int userId) {
1712 if (!mSystemServicesReady) {
Kweku Adamsc86da5f2020-05-28 12:26:35 -07001713 // The app will be evaluated in when services are ready.
Kweku Adams95cd9522020-05-08 09:56:53 -07001714 return;
1715 }
1716 try {
Kweku Adamsf197eef2020-06-16 11:59:37 -07001717 PackageInfo pi = mPackageManager.getPackageInfoAsUser(
1718 packageName, HEADLESS_APP_CHECK_FLAGS, userId);
Kweku Adams95cd9522020-05-08 09:56:53 -07001719 evaluateSystemAppException(pi);
1720 } catch (PackageManager.NameNotFoundException e) {
Kweku Adams8604fd72020-06-02 14:04:27 -07001721 synchronized (mHeadlessSystemApps) {
1722 mHeadlessSystemApps.remove(packageName);
1723 }
Kweku Adams95cd9522020-05-08 09:56:53 -07001724 }
1725 }
1726
Kweku Adams8604fd72020-06-02 14:04:27 -07001727 /** Returns true if the exception status changed. */
1728 private boolean evaluateSystemAppException(@Nullable PackageInfo pkgInfo) {
1729 if (pkgInfo == null || pkgInfo.applicationInfo == null
Kweku Adamsf197eef2020-06-16 11:59:37 -07001730 || (!pkgInfo.applicationInfo.isSystemApp()
1731 && !pkgInfo.applicationInfo.isUpdatedSystemApp())) {
Kweku Adams8604fd72020-06-02 14:04:27 -07001732 return false;
1733 }
1734 synchronized (mHeadlessSystemApps) {
1735 if (pkgInfo.activities == null || pkgInfo.activities.length == 0) {
1736 // Headless system app.
Kweku Adamsf197eef2020-06-16 11:59:37 -07001737 return mHeadlessSystemApps.add(pkgInfo.packageName);
Kweku Adams8604fd72020-06-02 14:04:27 -07001738 } else {
Kweku Adamsf197eef2020-06-16 11:59:37 -07001739 return mHeadlessSystemApps.remove(pkgInfo.packageName);
Kweku Adams95cd9522020-05-08 09:56:53 -07001740 }
1741 }
1742 }
1743
Kweku Adamsc86da5f2020-05-28 12:26:35 -07001744 /** Call on a system version update to temporarily reset system app buckets. */
Makoto Onukia72e04f2019-10-03 11:10:45 -07001745 @Override
1746 public void initializeDefaultsForSystemApps(int userId) {
Amith Yamasani777b1532018-01-28 23:20:07 +00001747 if (!mSystemServicesReady) {
1748 // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled
1749 mPendingInitializeDefaults = true;
1750 return;
1751 }
1752 Slog.d(TAG, "Initializing defaults for system apps on user " + userId + ", "
1753 + "appIdleEnabled=" + mAppIdleEnabled);
Amith Yamasani17fffee2017-09-29 13:17:43 -07001754 final long elapsedRealtime = mInjector.elapsedRealtime();
Amith Yamasani7e528f32017-10-05 16:06:16 -07001755 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
Kweku Adamsc86da5f2020-05-28 12:26:35 -07001756 PackageManager.MATCH_DISABLED_COMPONENTS,
Amith Yamasani7e528f32017-10-05 16:06:16 -07001757 userId);
1758 final int packageCount = packages.size();
1759 synchronized (mAppIdleLock) {
1760 for (int i = 0; i < packageCount; i++) {
1761 final PackageInfo pi = packages.get(i);
1762 String packageName = pi.packageName;
1763 if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08001764 // Mark app as used for 2 hours. After that it can timeout to whatever the
Amith Yamasani53f06ea2018-01-05 17:53:46 -08001765 // past usage pattern was.
Amith Yamasani119be9a2018-02-18 22:23:00 -08001766 mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE,
1767 REASON_SUB_USAGE_SYSTEM_UPDATE, 0,
Amith Yamasani7ec89412018-02-07 08:48:49 -08001768 elapsedRealtime + mSystemUpdateUsageTimeoutMillis);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001769 }
1770 }
Michael Wachenschwanzd1d8aa62019-02-28 16:38:37 -08001771 // Immediately persist defaults to disk
1772 mAppIdleHistory.writeAppIdleTimes(userId);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001773 }
1774 }
1775
Kweku Adamseffeb2a2020-06-16 10:11:56 -07001776 /** Call on system boot to get the initial set of headless system apps. */
Kweku Adamsc86da5f2020-05-28 12:26:35 -07001777 private void loadHeadlessSystemAppCache() {
1778 Slog.d(TAG, "Loading headless system app cache. appIdleEnabled=" + mAppIdleEnabled);
1779 final List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
Kweku Adamsf197eef2020-06-16 11:59:37 -07001780 HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM);
Kweku Adamsc86da5f2020-05-28 12:26:35 -07001781 final int packageCount = packages.size();
1782 for (int i = 0; i < packageCount; i++) {
Kweku Adams8604fd72020-06-02 14:04:27 -07001783 PackageInfo pkgInfo = packages.get(i);
1784 if (pkgInfo != null && evaluateSystemAppException(pkgInfo)) {
1785 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE,
1786 UserHandle.USER_SYSTEM, -1, pkgInfo.packageName)
1787 .sendToTarget();
1788 }
Kweku Adamsc86da5f2020-05-28 12:26:35 -07001789 }
1790 }
1791
Makoto Onukia72e04f2019-10-03 11:10:45 -07001792 @Override
1793 public void postReportContentProviderUsage(String name, String packageName, int userId) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001794 SomeArgs args = SomeArgs.obtain();
1795 args.arg1 = name;
1796 args.arg2 = packageName;
1797 args.arg3 = userId;
1798 mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, args)
1799 .sendToTarget();
1800 }
1801
Makoto Onukia72e04f2019-10-03 11:10:45 -07001802 @Override
1803 public void postReportSyncScheduled(String packageName, int userId, boolean exempted) {
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001804 mHandler.obtainMessage(MSG_REPORT_SYNC_SCHEDULED, userId, exempted ? 1 : 0, packageName)
Makoto Onukid5f25d22018-05-22 16:02:17 -07001805 .sendToTarget();
1806 }
1807
Makoto Onukia72e04f2019-10-03 11:10:45 -07001808 @Override
1809 public void postReportExemptedSyncStart(String packageName, int userId) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001810 mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName)
1811 .sendToTarget();
1812 }
1813
Makoto Onukia72e04f2019-10-03 11:10:45 -07001814 @Override
Michael Wachenschwanz793da642020-06-11 16:14:48 -07001815 public void dumpUsers(IndentingPrintWriter idpw, int[] userIds, List<String> pkgs) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001816 synchronized (mAppIdleLock) {
Michael Wachenschwanz793da642020-06-11 16:14:48 -07001817 mAppIdleHistory.dumpUsers(idpw, userIds, pkgs);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001818 }
1819 }
1820
Makoto Onukia72e04f2019-10-03 11:10:45 -07001821 @Override
1822 public void dumpState(String[] args, PrintWriter pw) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07001823 synchronized (mAppIdleLock) {
1824 pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
1825 + "): " + mCarrierPrivilegedApps);
1826 }
1827
1828 pw.println();
1829 pw.println("Settings:");
1830
Amith Yamasani7e528f32017-10-05 16:06:16 -07001831 pw.print(" mCheckIdleIntervalMillis=");
1832 TimeUtils.formatDuration(mCheckIdleIntervalMillis, pw);
1833 pw.println();
1834
Esteban Talavera5b79bfa2018-07-05 15:15:22 +01001835 pw.print(" mStrongUsageTimeoutMillis=");
1836 TimeUtils.formatDuration(mStrongUsageTimeoutMillis, pw);
1837 pw.println();
1838 pw.print(" mNotificationSeenTimeoutMillis=");
1839 TimeUtils.formatDuration(mNotificationSeenTimeoutMillis, pw);
1840 pw.println();
1841 pw.print(" mSyncAdapterTimeoutMillis=");
1842 TimeUtils.formatDuration(mSyncAdapterTimeoutMillis, pw);
1843 pw.println();
1844 pw.print(" mSystemInteractionTimeoutMillis=");
1845 TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw);
1846 pw.println();
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -07001847 pw.print(" mInitialForegroundServiceStartTimeoutMillis=");
1848 TimeUtils.formatDuration(mInitialForegroundServiceStartTimeoutMillis, pw);
1849 pw.println();
Esteban Talavera5b79bfa2018-07-05 15:15:22 +01001850
1851 pw.print(" mPredictionTimeoutMillis=");
1852 TimeUtils.formatDuration(mPredictionTimeoutMillis, pw);
1853 pw.println();
1854
Makoto Onukid5f25d22018-05-22 16:02:17 -07001855 pw.print(" mExemptedSyncScheduledNonDozeTimeoutMillis=");
1856 TimeUtils.formatDuration(mExemptedSyncScheduledNonDozeTimeoutMillis, pw);
1857 pw.println();
1858 pw.print(" mExemptedSyncScheduledDozeTimeoutMillis=");
1859 TimeUtils.formatDuration(mExemptedSyncScheduledDozeTimeoutMillis, pw);
1860 pw.println();
1861 pw.print(" mExemptedSyncStartTimeoutMillis=");
1862 TimeUtils.formatDuration(mExemptedSyncStartTimeoutMillis, pw);
1863 pw.println();
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001864 pw.print(" mUnexemptedSyncScheduledTimeoutMillis=");
1865 TimeUtils.formatDuration(mUnexemptedSyncScheduledTimeoutMillis, pw);
1866 pw.println();
Makoto Onukid5f25d22018-05-22 16:02:17 -07001867
Esteban Talavera5b79bfa2018-07-05 15:15:22 +01001868 pw.print(" mSystemUpdateUsageTimeoutMillis=");
1869 TimeUtils.formatDuration(mSystemUpdateUsageTimeoutMillis, pw);
1870 pw.println();
1871
Amith Yamasani7e528f32017-10-05 16:06:16 -07001872 pw.println();
1873 pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
Kweku Adams2d79ce52020-05-05 12:31:35 -07001874 pw.print(" mAllowRestrictedBucket=");
1875 pw.print(mAllowRestrictedBucket);
Kweku Adamsf35ed3702020-02-11 17:32:54 -08001876 pw.print(" mIsCharging=");
1877 pw.print(mIsCharging);
Amith Yamasani7e528f32017-10-05 16:06:16 -07001878 pw.println();
Amith Yamasani17fffee2017-09-29 13:17:43 -07001879 pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds));
1880 pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds));
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -07001881 pw.println();
Kweku Adamsc86da5f2020-05-28 12:26:35 -07001882
1883 pw.println("mHeadlessSystemApps=[");
Kweku Adams8604fd72020-06-02 14:04:27 -07001884 synchronized (mHeadlessSystemApps) {
1885 for (int i = mHeadlessSystemApps.size() - 1; i >= 0; --i) {
1886 pw.print(" ");
Kweku Adamsf197eef2020-06-16 11:59:37 -07001887 pw.print(mHeadlessSystemApps.valueAt(i));
Kweku Adams8604fd72020-06-02 14:04:27 -07001888 pw.println(",");
1889 }
Kweku Adamsc86da5f2020-05-28 12:26:35 -07001890 }
1891 pw.println("]");
1892 pw.println();
Kweku Adamseffeb2a2020-06-16 10:11:56 -07001893
1894 mInjector.dump(pw);
Amith Yamasani17fffee2017-09-29 13:17:43 -07001895 }
1896
1897 /**
1898 * Injector for interaction with external code. Override methods to provide a mock
1899 * implementation for tests.
1900 * onBootPhase() must be called with at least the PHASE_SYSTEM_SERVICES_READY
1901 */
1902 static class Injector {
1903
1904 private final Context mContext;
1905 private final Looper mLooper;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001906 private IBatteryStats mBatteryStats;
Kweku Adamsf35ed3702020-02-11 17:32:54 -08001907 private BatteryManager mBatteryManager;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001908 private PackageManagerInternal mPackageManagerInternal;
1909 private DisplayManager mDisplayManager;
Makoto Onukid5f25d22018-05-22 16:02:17 -07001910 private PowerManager mPowerManager;
Kweku Adamseffeb2a2020-06-16 10:11:56 -07001911 private IDeviceIdleController mDeviceIdleController;
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -08001912 private CrossProfileAppsInternal mCrossProfileAppsInternal;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001913 int mBootPhase;
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001914 /**
1915 * The minimum amount of time required since the last user interaction before an app can be
Kweku Adams109cd9c2020-02-11 11:10:52 -08001916 * automatically placed in the RESTRICTED bucket.
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001917 */
Kweku Adams109cd9c2020-02-11 11:10:52 -08001918 long mAutoRestrictedBucketDelayMs = ONE_DAY;
Kweku Adamseffeb2a2020-06-16 10:11:56 -07001919 /**
1920 * Cached set of apps that are power whitelisted, including those not whitelisted from idle.
1921 */
1922 @GuardedBy("mPowerWhitelistedApps")
1923 private final ArraySet<String> mPowerWhitelistedApps = new ArraySet<>();
Amith Yamasani17fffee2017-09-29 13:17:43 -07001924
1925 Injector(Context context, Looper looper) {
1926 mContext = context;
1927 mLooper = looper;
1928 }
1929
1930 Context getContext() {
1931 return mContext;
1932 }
1933
1934 Looper getLooper() {
1935 return mLooper;
1936 }
1937
1938 void onBootPhase(int phase) {
1939 if (phase == PHASE_SYSTEM_SERVICES_READY) {
Kweku Adamseffeb2a2020-06-16 10:11:56 -07001940 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1941 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Amith Yamasani17fffee2017-09-29 13:17:43 -07001942 mBatteryStats = IBatteryStats.Stub.asInterface(
1943 ServiceManager.getService(BatteryStats.SERVICE_NAME));
1944 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
1945 mDisplayManager = (DisplayManager) mContext.getSystemService(
1946 Context.DISPLAY_SERVICE);
Makoto Onukid5f25d22018-05-22 16:02:17 -07001947 mPowerManager = mContext.getSystemService(PowerManager.class);
Kweku Adamsf35ed3702020-02-11 17:32:54 -08001948 mBatteryManager = mContext.getSystemService(BatteryManager.class);
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -08001949 mCrossProfileAppsInternal = LocalServices.getService(
1950 CrossProfileAppsInternal.class);
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001951
1952 final ActivityManager activityManager =
1953 (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
1954 if (activityManager.isLowRamDevice() || ActivityManager.isSmallBatteryDevice()) {
Kweku Adams109cd9c2020-02-11 11:10:52 -08001955 mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR;
Kweku Adamsc6a9b342020-01-08 18:37:26 -08001956 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07001957 }
1958 mBootPhase = phase;
1959 }
1960
1961 int getBootPhase() {
1962 return mBootPhase;
1963 }
1964
1965 /**
1966 * Returns the elapsed realtime since the device started. Override this
1967 * to control the clock.
1968 * @return elapsed realtime
1969 */
1970 long elapsedRealtime() {
1971 return SystemClock.elapsedRealtime();
1972 }
1973
1974 long currentTimeMillis() {
1975 return System.currentTimeMillis();
1976 }
1977
1978 boolean isAppIdleEnabled() {
Amith Yamasani172612c2017-12-15 10:51:53 -08001979 final boolean buildFlag = mContext.getResources().getBoolean(
Amith Yamasani17fffee2017-09-29 13:17:43 -07001980 com.android.internal.R.bool.config_enableAutoPowerModes);
Lei Yu4b976ad2018-04-19 10:38:58 -07001981 final boolean runtimeFlag = Global.getInt(mContext.getContentResolver(),
1982 Global.APP_STANDBY_ENABLED, 1) == 1
1983 && Global.getInt(mContext.getContentResolver(),
1984 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1) == 1;
Amith Yamasani172612c2017-12-15 10:51:53 -08001985 return buildFlag && runtimeFlag;
Amith Yamasani17fffee2017-09-29 13:17:43 -07001986 }
1987
Kweku Adamsf35ed3702020-02-11 17:32:54 -08001988 boolean isCharging() {
1989 return mBatteryManager.isCharging();
1990 }
1991
Kweku Adamseffeb2a2020-06-16 10:11:56 -07001992 boolean isNonIdleWhitelisted(String packageName) {
1993 if (mBootPhase < PHASE_SYSTEM_SERVICES_READY) {
1994 return false;
1995 }
1996 synchronized (mPowerWhitelistedApps) {
1997 return mPowerWhitelistedApps.contains(packageName);
1998 }
1999 }
2000
2001 private void updatePowerWhitelistCache() {
2002 if (mBootPhase < PHASE_SYSTEM_SERVICES_READY) {
2003 return;
2004 }
2005 try {
2006 // Don't call out to DeviceIdleController with the lock held.
2007 final String[] whitelistedPkgs =
2008 mDeviceIdleController.getFullPowerWhitelistExceptIdle();
2009 synchronized (mPowerWhitelistedApps) {
2010 mPowerWhitelistedApps.clear();
2011 final int len = whitelistedPkgs.length;
2012 for (int i = 0; i < len; ++i) {
2013 mPowerWhitelistedApps.add(whitelistedPkgs[i]);
2014 }
2015 }
2016 } catch (RemoteException e) {
2017 // Should not happen.
2018 Slog.wtf(TAG, "Failed to get power whitelist", e);
2019 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07002020 }
2021
Kweku Adams2d79ce52020-05-05 12:31:35 -07002022 boolean isRestrictedBucketEnabled() {
2023 return Global.getInt(mContext.getContentResolver(),
2024 Global.ENABLE_RESTRICTED_BUCKET,
2025 Global.DEFAULT_ENABLE_RESTRICTED_BUCKET) == 1;
2026 }
2027
Amith Yamasani17fffee2017-09-29 13:17:43 -07002028 File getDataSystemDirectory() {
2029 return Environment.getDataSystemDirectory();
2030 }
2031
Kweku Adams109cd9c2020-02-11 11:10:52 -08002032 /**
2033 * Return the minimum amount of time that must have passed since the last user usage before
2034 * an app can be automatically put into the
2035 * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket.
2036 */
2037 long getAutoRestrictedBucketDelayMs() {
2038 return mAutoRestrictedBucketDelayMs;
Kweku Adamsc6a9b342020-01-08 18:37:26 -08002039 }
2040
Amith Yamasani17fffee2017-09-29 13:17:43 -07002041 void noteEvent(int event, String packageName, int uid) throws RemoteException {
2042 mBatteryStats.noteEvent(event, packageName, uid);
2043 }
2044
Kweku Adamsc4ee9982020-01-08 11:14:39 -08002045 PackageManagerInternal getPackageManagerInternal() {
2046 return mPackageManagerInternal;
2047 }
2048
Amith Yamasani17fffee2017-09-29 13:17:43 -07002049 boolean isPackageEphemeral(int userId, String packageName) {
2050 return mPackageManagerInternal.isPackageEphemeral(userId, packageName);
2051 }
2052
Varun Shah7609b752018-10-15 15:07:47 -07002053 boolean isPackageInstalled(String packageName, int flags, int userId) {
2054 return mPackageManagerInternal.getPackageUid(packageName, flags, userId) >= 0;
2055 }
2056
Amith Yamasani17fffee2017-09-29 13:17:43 -07002057 int[] getRunningUserIds() throws RemoteException {
2058 return ActivityManager.getService().getRunningUserIds();
2059 }
2060
2061 boolean isDefaultDisplayOn() {
2062 return mDisplayManager
2063 .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON;
2064 }
2065
2066 void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) {
2067 mDisplayManager.registerDisplayListener(listener, handler);
2068 }
2069
2070 String getActiveNetworkScorer() {
2071 NetworkScoreManager nsm = (NetworkScoreManager) mContext.getSystemService(
2072 Context.NETWORK_SCORE_SERVICE);
2073 return nsm.getActiveScorerPackage();
2074 }
2075
2076 public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName,
2077 int userId) {
2078 return appWidgetManager.isBoundWidgetPackage(packageName, userId);
2079 }
Amith Yamasani301e94a2017-11-17 16:35:44 -08002080
2081 String getAppIdleSettings() {
Lei Yu4b976ad2018-04-19 10:38:58 -07002082 return Global.getString(mContext.getContentResolver(),
2083 Global.APP_IDLE_CONSTANTS);
Amith Yamasani301e94a2017-11-17 16:35:44 -08002084 }
Makoto Onukid5f25d22018-05-22 16:02:17 -07002085
2086 /** Whether the device is in doze or not. */
2087 public boolean isDeviceIdleMode() {
2088 return mPowerManager.isDeviceIdleMode();
2089 }
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -08002090
2091 public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
2092 final int uid = mPackageManagerInternal.getPackageUidInternal(pkg, 0, userId);
Kweku Adams259403e2020-04-27 09:25:07 -07002093 final AndroidPackage aPkg = mPackageManagerInternal.getPackage(uid);
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -08002094 if (uid < 0
Kweku Adams259403e2020-04-27 09:25:07 -07002095 || aPkg == null
2096 || !aPkg.isCrossProfile()
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -08002097 || !mCrossProfileAppsInternal
2098 .verifyUidHasInteractAcrossProfilePermission(pkg, uid)) {
Kweku Adams259403e2020-04-27 09:25:07 -07002099 if (uid >= 0 && aPkg == null) {
2100 Slog.wtf(TAG, "Null package retrieved for UID " + uid);
2101 }
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -08002102 return Collections.emptyList();
2103 }
2104 return mCrossProfileAppsInternal.getTargetUserProfiles(pkg, userId);
2105 }
Kweku Adamseffeb2a2020-06-16 10:11:56 -07002106
2107 void dump(PrintWriter pw) {
2108 pw.println("mPowerWhitelistedApps=[");
2109 synchronized (mPowerWhitelistedApps) {
2110 for (int i = mPowerWhitelistedApps.size() - 1; i >= 0; --i) {
2111 pw.print(" ");
2112 pw.print(mPowerWhitelistedApps.valueAt(i));
2113 pw.println(",");
2114 }
2115 }
2116 pw.println("]");
2117 pw.println();
2118 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07002119 }
2120
2121 class AppStandbyHandler extends Handler {
2122
2123 AppStandbyHandler(Looper looper) {
2124 super(looper);
2125 }
2126
2127 @Override
2128 public void handleMessage(Message msg) {
2129 switch (msg.what) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07002130 case MSG_INFORM_LISTENERS:
Christopher Tated117b292018-01-05 17:32:36 -08002131 StandbyUpdateRecord r = (StandbyUpdateRecord) msg.obj;
Amith Yamasani119be9a2018-02-18 22:23:00 -08002132 informListeners(r.packageName, r.userId, r.bucket, r.reason,
2133 r.isUserInteraction);
Christopher Tated117b292018-01-05 17:32:36 -08002134 r.recycle();
Amith Yamasani17fffee2017-09-29 13:17:43 -07002135 break;
2136
Amith Yamasani7e528f32017-10-05 16:06:16 -07002137 case MSG_FORCE_IDLE_STATE:
2138 forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1);
2139 break;
2140
2141 case MSG_CHECK_IDLE_STATES:
Amith Yamasani172612c2017-12-15 10:51:53 -08002142 if (checkIdleStates(msg.arg1) && mAppIdleEnabled) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07002143 mHandler.sendMessageDelayed(mHandler.obtainMessage(
2144 MSG_CHECK_IDLE_STATES, msg.arg1, 0),
2145 mCheckIdleIntervalMillis);
2146 }
2147 break;
2148
2149 case MSG_ONE_TIME_CHECK_IDLE_STATES:
2150 mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
Sudheer Shankac53c47f2018-01-16 12:01:00 -08002151 waitForAdminData();
Amith Yamasani7e528f32017-10-05 16:06:16 -07002152 checkIdleStates(UserHandle.USER_ALL);
2153 break;
2154
Amith Yamasani7e528f32017-10-05 16:06:16 -07002155 case MSG_REPORT_CONTENT_PROVIDER_USAGE:
2156 SomeArgs args = (SomeArgs) msg.obj;
2157 reportContentProviderUsage((String) args.arg1, // authority name
2158 (String) args.arg2, // package name
2159 (int) args.arg3); // userId
2160 args.recycle();
2161 break;
2162
Kweku Adamse6601762020-05-01 15:06:18 -07002163 case MSG_PAROLE_STATE_CHANGED:
2164 if (DEBUG) Slog.d(TAG, "Parole state: " + isInParole());
2165 informParoleStateChanged();
2166 break;
2167
Amith Yamasanibbbad9c2018-02-10 16:46:38 -08002168 case MSG_CHECK_PACKAGE_IDLE_STATE:
2169 checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
2170 mInjector.elapsedRealtime());
2171 break;
Makoto Onuki75ad2492018-03-28 14:42:42 -07002172
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002173 case MSG_REPORT_SYNC_SCHEDULED:
Michael Wachenschwanz1103ff22020-02-11 20:40:26 -08002174 final boolean exempted = msg.arg2 > 0 ? true : false;
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002175 if (exempted) {
2176 reportExemptedSyncScheduled((String) msg.obj, msg.arg1);
2177 } else {
2178 reportUnexemptedSyncScheduled((String) msg.obj, msg.arg1);
2179 }
Makoto Onukid5f25d22018-05-22 16:02:17 -07002180 break;
2181
Makoto Onuki75ad2492018-03-28 14:42:42 -07002182 case MSG_REPORT_EXEMPTED_SYNC_START:
2183 reportExemptedSyncStart((String) msg.obj, msg.arg1);
2184 break;
2185
Amith Yamasani7e528f32017-10-05 16:06:16 -07002186 default:
2187 super.handleMessage(msg);
2188 break;
2189
2190 }
2191 }
2192 };
2193
Kweku Adamsf35ed3702020-02-11 17:32:54 -08002194 private class DeviceStateReceiver extends BroadcastReceiver {
Michael Wachenschwanz113a0fa2018-03-30 12:45:18 -07002195 @Override
Kweku Adamsf35ed3702020-02-11 17:32:54 -08002196 public void onReceive(Context context, Intent intent) {
2197 switch (intent.getAction()) {
2198 case BatteryManager.ACTION_CHARGING:
2199 setChargingState(true);
2200 break;
2201 case BatteryManager.ACTION_DISCHARGING:
2202 setChargingState(false);
2203 break;
Kweku Adamseffeb2a2020-06-16 10:11:56 -07002204 case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
2205 if (mSystemServicesReady) {
2206 mHandler.post(mInjector::updatePowerWhitelistCache);
2207 }
2208 break;
Kweku Adamsf35ed3702020-02-11 17:32:54 -08002209 }
Michael Wachenschwanz113a0fa2018-03-30 12:45:18 -07002210 }
Kweku Adamsf35ed3702020-02-11 17:32:54 -08002211 }
Michael Wachenschwanz113a0fa2018-03-30 12:45:18 -07002212
Amith Yamasani7e528f32017-10-05 16:06:16 -07002213 private final DisplayManager.DisplayListener mDisplayListener
2214 = new DisplayManager.DisplayListener() {
2215
2216 @Override public void onDisplayAdded(int displayId) {
2217 }
2218
2219 @Override public void onDisplayRemoved(int displayId) {
2220 }
2221
2222 @Override public void onDisplayChanged(int displayId) {
2223 if (displayId == Display.DEFAULT_DISPLAY) {
2224 final boolean displayOn = isDisplayOn();
2225 synchronized (mAppIdleLock) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07002226 mAppIdleHistory.updateDisplay(displayOn, mInjector.elapsedRealtime());
Amith Yamasani7e528f32017-10-05 16:06:16 -07002227 }
2228 }
2229 }
2230 };
2231
2232 /**
Lei Yu4b976ad2018-04-19 10:38:58 -07002233 * Observe settings changes for {@link Global#APP_IDLE_CONSTANTS}.
Amith Yamasani7e528f32017-10-05 16:06:16 -07002234 */
2235 private class SettingsObserver extends ContentObserver {
Amith Yamasani17fffee2017-09-29 13:17:43 -07002236 private static final String KEY_SCREEN_TIME_THRESHOLDS = "screen_thresholds";
2237 private static final String KEY_ELAPSED_TIME_THRESHOLDS = "elapsed_thresholds";
Amith Yamasani7ec89412018-02-07 08:48:49 -08002238 private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration";
2239 private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION =
2240 "notification_seen_duration";
2241 private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION =
2242 "system_update_usage_duration";
Amith Yamasani119be9a2018-02-18 22:23:00 -08002243 private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout";
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07002244 private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration";
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002245 private static final String KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION =
2246 "exempted_sync_scheduled_nd_duration";
2247 private static final String KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION =
2248 "exempted_sync_scheduled_d_duration";
2249 private static final String KEY_EXEMPTED_SYNC_START_HOLD_DURATION =
2250 "exempted_sync_start_duration";
2251 private static final String KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION =
2252 "unexempted_sync_scheduled_duration";
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07002253 private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
2254 "system_interaction_duration";
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -07002255 private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION =
2256 "initial_foreground_service_start_duration";
Kweku Adams109cd9c2020-02-11 11:10:52 -08002257 private static final String KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS =
2258 "auto_restricted_bucket_delay_ms";
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -08002259 private static final String KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS =
2260 "cross_profile_apps_share_standby_buckets";
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07002261 public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
2262 public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR;
2263 public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
2264 public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
2265 public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
Makoto Onukid5f25d22018-05-22 16:02:17 -07002266 public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = 10 * ONE_MINUTE;
2267 public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 4 * ONE_HOUR;
2268 public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE;
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002269 public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE;
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -07002270 public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE;
Kweku Adams109cd9c2020-02-11 11:10:52 -08002271 public static final long DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS = ONE_DAY;
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -08002272 public static final boolean DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = true;
Amith Yamasani7e528f32017-10-05 16:06:16 -07002273
2274 private final KeyValueListParser mParser = new KeyValueListParser(',');
2275
2276 SettingsObserver(Handler handler) {
2277 super(handler);
2278 }
2279
2280 void registerObserver() {
Lei Yu4b976ad2018-04-19 10:38:58 -07002281 final ContentResolver cr = mContext.getContentResolver();
2282 cr.registerContentObserver(Global.getUriFor(Global.APP_IDLE_CONSTANTS), false, this);
2283 cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this);
Kweku Adams2d79ce52020-05-05 12:31:35 -07002284 cr.registerContentObserver(Global.getUriFor(Global.ENABLE_RESTRICTED_BUCKET),
2285 false, this);
Lei Yu4b976ad2018-04-19 10:38:58 -07002286 cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED),
2287 false, this);
Amith Yamasani7e528f32017-10-05 16:06:16 -07002288 }
2289
2290 @Override
2291 public void onChange(boolean selfChange) {
2292 updateSettings();
2293 postOneTimeCheckIdleStates();
2294 }
2295
2296 void updateSettings() {
Amith Yamasani172612c2017-12-15 10:51:53 -08002297 if (DEBUG) {
2298 Slog.d(TAG,
Lei Yu4b976ad2018-04-19 10:38:58 -07002299 "appidle=" + Global.getString(mContext.getContentResolver(),
2300 Global.APP_STANDBY_ENABLED));
2301 Slog.d(TAG,
2302 "adaptivebat=" + Global.getString(mContext.getContentResolver(),
2303 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED));
2304 Slog.d(TAG, "appidleconstants=" + Global.getString(
Amith Yamasani172612c2017-12-15 10:51:53 -08002305 mContext.getContentResolver(),
Lei Yu4b976ad2018-04-19 10:38:58 -07002306 Global.APP_IDLE_CONSTANTS));
Amith Yamasani172612c2017-12-15 10:51:53 -08002307 }
Amith Yamasani172612c2017-12-15 10:51:53 -08002308
2309 // Look at global settings for this.
2310 // TODO: Maybe apply different thresholds for different users.
2311 try {
2312 mParser.setString(mInjector.getAppIdleSettings());
2313 } catch (IllegalArgumentException e) {
2314 Slog.e(TAG, "Bad value for app idle settings: " + e.getMessage());
2315 // fallthrough, mParser is empty and all defaults will be returned.
2316 }
2317
Amith Yamasani7e528f32017-10-05 16:06:16 -07002318 synchronized (mAppIdleLock) {
Amith Yamasani7e528f32017-10-05 16:06:16 -07002319
Amith Yamasani17fffee2017-09-29 13:17:43 -07002320 String screenThresholdsValue = mParser.getString(KEY_SCREEN_TIME_THRESHOLDS, null);
2321 mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue,
Kweku Adams4297b5d2020-02-06 15:56:12 -08002322 SCREEN_TIME_THRESHOLDS, MINIMUM_SCREEN_TIME_THRESHOLDS);
Amith Yamasani17fffee2017-09-29 13:17:43 -07002323
Amith Yamasani84cd7b72017-11-07 13:59:37 -08002324 String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS,
2325 null);
Amith Yamasani17fffee2017-09-29 13:17:43 -07002326 mAppStandbyElapsedThresholds = parseLongArray(elapsedThresholdsValue,
Kweku Adams4297b5d2020-02-06 15:56:12 -08002327 ELAPSED_TIME_THRESHOLDS, MINIMUM_ELAPSED_TIME_THRESHOLDS);
Amith Yamasania0ef1ca2017-11-20 09:43:56 -08002328 mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4,
2329 COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002330 mStrongUsageTimeoutMillis = mParser.getDurationMillis(
2331 KEY_STRONG_USAGE_HOLD_DURATION,
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07002332 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STRONG_USAGE_TIMEOUT);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002333 mNotificationSeenTimeoutMillis = mParser.getDurationMillis(
2334 KEY_NOTIFICATION_SEEN_HOLD_DURATION,
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07002335 COMPRESS_TIME ? 12 * ONE_MINUTE : DEFAULT_NOTIFICATION_TIMEOUT);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002336 mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis(
2337 KEY_SYSTEM_UPDATE_HOLD_DURATION,
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07002338 COMPRESS_TIME ? 2 * ONE_MINUTE : DEFAULT_SYSTEM_UPDATE_TIMEOUT);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002339 mPredictionTimeoutMillis = mParser.getDurationMillis(
2340 KEY_PREDICTION_TIMEOUT,
Amith Yamasani119be9a2018-02-18 22:23:00 -08002341 COMPRESS_TIME ? 10 * ONE_MINUTE : DEFAULT_PREDICTION_TIMEOUT);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002342 mSyncAdapterTimeoutMillis = mParser.getDurationMillis(
2343 KEY_SYNC_ADAPTER_HOLD_DURATION,
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07002344 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT);
Makoto Onukid5f25d22018-05-22 16:02:17 -07002345
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002346 mExemptedSyncScheduledNonDozeTimeoutMillis = mParser.getDurationMillis(
2347 KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION,
Makoto Onukid5f25d22018-05-22 16:02:17 -07002348 COMPRESS_TIME ? (ONE_MINUTE / 2)
2349 : DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT);
2350
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002351 mExemptedSyncScheduledDozeTimeoutMillis = mParser.getDurationMillis(
2352 KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION,
Makoto Onukid5f25d22018-05-22 16:02:17 -07002353 COMPRESS_TIME ? ONE_MINUTE
2354 : DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT);
2355
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002356 mExemptedSyncStartTimeoutMillis = mParser.getDurationMillis(
2357 KEY_EXEMPTED_SYNC_START_HOLD_DURATION,
Makoto Onukid5f25d22018-05-22 16:02:17 -07002358 COMPRESS_TIME ? ONE_MINUTE
2359 : DEFAULT_EXEMPTED_SYNC_START_TIMEOUT);
2360
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002361 mUnexemptedSyncScheduledTimeoutMillis = mParser.getDurationMillis(
Kweku Adams0140ff82019-10-08 17:04:28 -07002362 KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION,
Kweku Adams4297b5d2020-02-06 15:56:12 -08002363 COMPRESS_TIME
2364 ? ONE_MINUTE : DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT);
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08002365
2366 mSystemInteractionTimeoutMillis = mParser.getDurationMillis(
2367 KEY_SYSTEM_INTERACTION_HOLD_DURATION,
Amith Yamasani7f53c7b2018-03-25 21:55:50 -07002368 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
Michael Wachenschwanz6ced0ee2019-04-15 16:43:28 -07002369
2370 mInitialForegroundServiceStartTimeoutMillis = mParser.getDurationMillis(
2371 KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION,
2372 COMPRESS_TIME ? ONE_MINUTE :
2373 DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT);
Kweku Adams109cd9c2020-02-11 11:10:52 -08002374
2375 mInjector.mAutoRestrictedBucketDelayMs = Math.max(
2376 COMPRESS_TIME ? ONE_MINUTE : 2 * ONE_HOUR,
2377 mParser.getDurationMillis(KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS,
2378 COMPRESS_TIME
2379 ? ONE_MINUTE : DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS));
Michael Wachenschwanz9a3501d2020-02-10 23:17:28 -08002380
2381 mLinkCrossProfileApps = mParser.getBoolean(
2382 KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS,
2383 DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS);
Kweku Adams2d79ce52020-05-05 12:31:35 -07002384
2385 mAllowRestrictedBucket = mInjector.isRestrictedBucketEnabled();
Amith Yamasani17fffee2017-09-29 13:17:43 -07002386 }
Kweku Adams1e8947c2018-11-05 18:06:13 -08002387
2388 // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
2389 // in case we need to change something based on the new values.
2390 setAppIdleEnabled(mInjector.isAppIdleEnabled());
Amith Yamasani17fffee2017-09-29 13:17:43 -07002391 }
2392
Kweku Adams4297b5d2020-02-06 15:56:12 -08002393 long[] parseLongArray(String values, long[] defaults, long[] minValues) {
Amith Yamasani17fffee2017-09-29 13:17:43 -07002394 if (values == null) return defaults;
2395 if (values.isEmpty()) {
2396 // Reset to defaults
2397 return defaults;
2398 } else {
2399 String[] thresholds = values.split("/");
2400 if (thresholds.length == THRESHOLD_BUCKETS.length) {
Kweku Adams4297b5d2020-02-06 15:56:12 -08002401 if (minValues.length != THRESHOLD_BUCKETS.length) {
2402 Slog.wtf(TAG, "minValues array is the wrong size");
2403 // Use zeroes as the minimums.
2404 minValues = new long[THRESHOLD_BUCKETS.length];
2405 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07002406 long[] array = new long[THRESHOLD_BUCKETS.length];
2407 for (int i = 0; i < THRESHOLD_BUCKETS.length; i++) {
Amith Yamasani761d3ff2017-12-14 17:50:03 -08002408 try {
2409 if (thresholds[i].startsWith("P") || thresholds[i].startsWith("p")) {
Kweku Adams4297b5d2020-02-06 15:56:12 -08002410 array[i] = Math.max(minValues[i],
2411 Duration.parse(thresholds[i]).toMillis());
Amith Yamasani761d3ff2017-12-14 17:50:03 -08002412 } else {
Kweku Adams4297b5d2020-02-06 15:56:12 -08002413 array[i] = Math.max(minValues[i], Long.parseLong(thresholds[i]));
Amith Yamasani761d3ff2017-12-14 17:50:03 -08002414 }
2415 } catch (NumberFormatException|DateTimeParseException e) {
2416 return defaults;
2417 }
Amith Yamasani17fffee2017-09-29 13:17:43 -07002418 }
2419 return array;
2420 } else {
2421 return defaults;
2422 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07002423 }
2424 }
2425 }
Amith Yamasani7e528f32017-10-05 16:06:16 -07002426}