1 /**
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 
17 package com.android.server.usage;
18 
19 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
20 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
21 import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK;
22 import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
23 import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
24 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
25 import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
26 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
27 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
28 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
29 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START;
30 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
31 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
32 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
33 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
34 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
35 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
36 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
37 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
38 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
39 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED;
40 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
41 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
42 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
43 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
44 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
45 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
46 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
47 
48 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
49 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
50 
51 import android.annotation.UserIdInt;
52 import android.app.ActivityManager;
53 import android.app.AppGlobals;
54 import android.app.usage.AppStandbyInfo;
55 import android.app.usage.UsageEvents;
56 import android.app.usage.UsageStatsManager.StandbyBuckets;
57 import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
58 import android.appwidget.AppWidgetManager;
59 import android.content.BroadcastReceiver;
60 import android.content.ContentResolver;
61 import android.content.Context;
62 import android.content.Intent;
63 import android.content.IntentFilter;
64 import android.content.pm.ApplicationInfo;
65 import android.content.pm.PackageInfo;
66 import android.content.pm.PackageManager;
67 import android.content.pm.PackageManagerInternal;
68 import android.content.pm.ParceledListSlice;
69 import android.database.ContentObserver;
70 import android.hardware.display.DisplayManager;
71 import android.net.ConnectivityManager;
72 import android.net.Network;
73 import android.net.NetworkInfo;
74 import android.net.NetworkRequest;
75 import android.net.NetworkScoreManager;
76 import android.os.BatteryManager;
77 import android.os.BatteryStats;
78 import android.os.Environment;
79 import android.os.Handler;
80 import android.os.IDeviceIdleController;
81 import android.os.Looper;
82 import android.os.Message;
83 import android.os.PowerManager;
84 import android.os.Process;
85 import android.os.RemoteException;
86 import android.os.ServiceManager;
87 import android.os.SystemClock;
88 import android.os.UserHandle;
89 import android.provider.Settings.Global;
90 import android.telephony.TelephonyManager;
91 import android.util.ArraySet;
92 import android.util.KeyValueListParser;
93 import android.util.Slog;
94 import android.util.SparseArray;
95 import android.util.SparseIntArray;
96 import android.util.TimeUtils;
97 import android.view.Display;
98 
99 import com.android.internal.annotations.GuardedBy;
100 import com.android.internal.annotations.VisibleForTesting;
101 import com.android.internal.app.IBatteryStats;
102 import com.android.internal.os.SomeArgs;
103 import com.android.internal.util.ArrayUtils;
104 import com.android.internal.util.ConcurrentUtils;
105 import com.android.internal.util.IndentingPrintWriter;
106 import com.android.server.LocalServices;
107 import com.android.server.usage.AppIdleHistory.AppUsageHistory;
108 
109 import java.io.File;
110 import java.io.PrintWriter;
111 import java.time.Duration;
112 import java.time.format.DateTimeParseException;
113 import java.util.ArrayList;
114 import java.util.Arrays;
115 import java.util.List;
116 import java.util.Set;
117 import java.util.concurrent.CountDownLatch;
118 
119 /**
120  * Manages the standby state of an app, listening to various events.
121  *
122  * Unit test:
123    atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
124  */
125 public class AppStandbyController {
126 
127     private static final String TAG = "AppStandbyController";
128     static final boolean DEBUG = false;
129 
130     static final boolean COMPRESS_TIME = false;
131     private static final long ONE_MINUTE = 60 * 1000;
132     private static final long ONE_HOUR = ONE_MINUTE * 60;
133     private static final long ONE_DAY = ONE_HOUR * 24;
134 
135     static final long[] SCREEN_TIME_THRESHOLDS = {
136             0,
137             0,
138             COMPRESS_TIME ? 120 * 1000 : 1 * ONE_HOUR,
139             COMPRESS_TIME ? 240 * 1000 : 2 * ONE_HOUR
140     };
141 
142     static final long[] ELAPSED_TIME_THRESHOLDS = {
143             0,
144             COMPRESS_TIME ?  1 * ONE_MINUTE : 12 * ONE_HOUR,
145             COMPRESS_TIME ?  4 * ONE_MINUTE : 24 * ONE_HOUR,
146             COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR
147     };
148 
149     static final int[] THRESHOLD_BUCKETS = {
150             STANDBY_BUCKET_ACTIVE,
151             STANDBY_BUCKET_WORKING_SET,
152             STANDBY_BUCKET_FREQUENT,
153             STANDBY_BUCKET_RARE
154     };
155 
156     /** Default expiration time for bucket prediction. After this, use thresholds to downgrade. */
157     private static final long DEFAULT_PREDICTION_TIMEOUT = 12 * ONE_HOUR;
158 
159     /**
160      * Indicates the maximum wait time for admin data to be available;
161      */
162     private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
163 
164     // To name the lock for stack traces
165     static class Lock {}
166 
167     /** Lock to protect the app's standby state. Required for calls into AppIdleHistory */
168     private final Object mAppIdleLock = new Lock();
169 
170     /** Keeps the history and state for each app. */
171     @GuardedBy("mAppIdleLock")
172     private AppIdleHistory mAppIdleHistory;
173 
174     @GuardedBy("mPackageAccessListeners")
175     private ArrayList<AppIdleStateChangeListener>
176             mPackageAccessListeners = new ArrayList<>();
177 
178     /** Whether we've queried the list of carrier privileged apps. */
179     @GuardedBy("mAppIdleLock")
180     private boolean mHaveCarrierPrivilegedApps;
181 
182     /** List of carrier-privileged apps that should be excluded from standby */
183     @GuardedBy("mAppIdleLock")
184     private List<String> mCarrierPrivilegedApps;
185 
186     @GuardedBy("mActiveAdminApps")
187     private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
188 
189     private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
190 
191     // Messages for the handler
192     static final int MSG_INFORM_LISTENERS = 3;
193     static final int MSG_FORCE_IDLE_STATE = 4;
194     static final int MSG_CHECK_IDLE_STATES = 5;
195     static final int MSG_CHECK_PAROLE_TIMEOUT = 6;
196     static final int MSG_PAROLE_END_TIMEOUT = 7;
197     static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
198     static final int MSG_PAROLE_STATE_CHANGED = 9;
199     static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
200     /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
201     static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
202     static final int MSG_REPORT_SYNC_SCHEDULED = 12;
203     static final int MSG_REPORT_EXEMPTED_SYNC_START = 13;
204     static final int MSG_UPDATE_STABLE_CHARGING= 14;
205 
206     long mCheckIdleIntervalMillis;
207     long mAppIdleParoleIntervalMillis;
208     long mAppIdleParoleWindowMillis;
209     long mAppIdleParoleDurationMillis;
210     long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS;
211     long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS;
212     /** Minimum time a strong usage event should keep the bucket elevated. */
213     long mStrongUsageTimeoutMillis;
214     /** Minimum time a notification seen event should keep the bucket elevated. */
215     long mNotificationSeenTimeoutMillis;
216     /** Minimum time a system update event should keep the buckets elevated. */
217     long mSystemUpdateUsageTimeoutMillis;
218     /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */
219     long mPredictionTimeoutMillis;
220     /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */
221     long mSyncAdapterTimeoutMillis;
222     /**
223      * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
224      * non-doze
225      */
226     long mExemptedSyncScheduledNonDozeTimeoutMillis;
227     /**
228      * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
229      * doze
230      */
231     long mExemptedSyncScheduledDozeTimeoutMillis;
232     /**
233      * Maximum time an exempted sync should keep the buckets elevated, when sync is started.
234      */
235     long mExemptedSyncStartTimeoutMillis;
236     /**
237      * Maximum time an unexempted sync should keep the buckets elevated, when sync is scheduled
238      */
239     long mUnexemptedSyncScheduledTimeoutMillis;
240     /** Maximum time a system interaction should keep the buckets elevated. */
241     long mSystemInteractionTimeoutMillis;
242     /**
243      * Maximum time a foreground service start should keep the buckets elevated if the service
244      * start is the first usage of the app
245      */
246     long mInitialForegroundServiceStartTimeoutMillis;
247     /** The length of time phone must be charging before considered stable enough to run jobs  */
248     long mStableChargingThresholdMillis;
249 
250     volatile boolean mAppIdleEnabled;
251     boolean mAppIdleTempParoled;
252     boolean mCharging;
253     boolean mChargingStable;
254     private long mLastAppIdleParoledTime;
255     private boolean mSystemServicesReady = false;
256     // There was a system update, defaults need to be initialized after services are ready
257     private boolean mPendingInitializeDefaults;
258 
259     private final DeviceStateReceiver mDeviceStateReceiver;
260 
261     private volatile boolean mPendingOneTimeCheckIdleStates;
262 
263     private final AppStandbyHandler mHandler;
264     private final Context mContext;
265 
266     // TODO: Provide a mechanism to set an external bucketing service
267 
268     private AppWidgetManager mAppWidgetManager;
269     private ConnectivityManager mConnectivityManager;
270     private PowerManager mPowerManager;
271     private PackageManager mPackageManager;
272     Injector mInjector;
273 
274     static final ArrayList<StandbyUpdateRecord> sStandbyUpdatePool = new ArrayList<>(4);
275 
276     public static class StandbyUpdateRecord {
277         // Identity of the app whose standby state has changed
278         String packageName;
279         int userId;
280 
281         // What the standby bucket the app is now in
282         int bucket;
283 
284         // Whether the bucket change is because the user has started interacting with the app
285         boolean isUserInteraction;
286 
287         // Reason for bucket change
288         int reason;
289 
StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason, boolean isInteraction)290         StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason,
291                 boolean isInteraction) {
292             this.packageName = pkgName;
293             this.userId = userId;
294             this.bucket = bucket;
295             this.reason = reason;
296             this.isUserInteraction = isInteraction;
297         }
298 
obtain(String pkgName, int userId, int bucket, int reason, boolean isInteraction)299         public static StandbyUpdateRecord obtain(String pkgName, int userId,
300                 int bucket, int reason, boolean isInteraction) {
301             synchronized (sStandbyUpdatePool) {
302                 final int size = sStandbyUpdatePool.size();
303                 if (size < 1) {
304                     return new StandbyUpdateRecord(pkgName, userId, bucket, reason, isInteraction);
305                 }
306                 StandbyUpdateRecord r = sStandbyUpdatePool.remove(size - 1);
307                 r.packageName = pkgName;
308                 r.userId = userId;
309                 r.bucket = bucket;
310                 r.reason = reason;
311                 r.isUserInteraction = isInteraction;
312                 return r;
313             }
314         }
315 
recycle()316         public void recycle() {
317             synchronized (sStandbyUpdatePool) {
318                 sStandbyUpdatePool.add(this);
319             }
320         }
321     }
322 
AppStandbyController(Context context, Looper looper)323     AppStandbyController(Context context, Looper looper) {
324         this(new Injector(context, looper));
325     }
326 
AppStandbyController(Injector injector)327     AppStandbyController(Injector injector) {
328         mInjector = injector;
329         mContext = mInjector.getContext();
330         mHandler = new AppStandbyHandler(mInjector.getLooper());
331         mPackageManager = mContext.getPackageManager();
332         mDeviceStateReceiver = new DeviceStateReceiver();
333 
334         IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
335         deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
336         deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
337         mContext.registerReceiver(mDeviceStateReceiver, deviceStates);
338 
339         synchronized (mAppIdleLock) {
340             mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(),
341                     mInjector.elapsedRealtime());
342         }
343 
344         IntentFilter packageFilter = new IntentFilter();
345         packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
346         packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
347         packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
348         packageFilter.addDataScheme("package");
349 
350         mContext.registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter,
351                 null, mHandler);
352     }
353 
setAppIdleEnabled(boolean enabled)354     void setAppIdleEnabled(boolean enabled) {
355         synchronized (mAppIdleLock) {
356             if (mAppIdleEnabled != enabled) {
357                 final boolean oldParoleState = isParoledOrCharging();
358                 mAppIdleEnabled = enabled;
359                 if (isParoledOrCharging() != oldParoleState) {
360                     postParoleStateChanged();
361                 }
362             }
363         }
364     }
365 
onBootPhase(int phase)366     public void onBootPhase(int phase) {
367         mInjector.onBootPhase(phase);
368         if (phase == PHASE_SYSTEM_SERVICES_READY) {
369             Slog.d(TAG, "Setting app idle enabled state");
370             // Observe changes to the threshold
371             SettingsObserver settingsObserver = new SettingsObserver(mHandler);
372             settingsObserver.registerObserver();
373             settingsObserver.updateSettings();
374 
375             mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class);
376             mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
377             mPowerManager = mContext.getSystemService(PowerManager.class);
378 
379             mInjector.registerDisplayListener(mDisplayListener, mHandler);
380             synchronized (mAppIdleLock) {
381                 mAppIdleHistory.updateDisplay(isDisplayOn(), mInjector.elapsedRealtime());
382             }
383 
384             mSystemServicesReady = true;
385 
386             boolean userFileExists;
387             synchronized (mAppIdleLock) {
388                 userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM);
389             }
390 
391             if (mPendingInitializeDefaults || !userFileExists) {
392                 initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM);
393             }
394 
395             if (mPendingOneTimeCheckIdleStates) {
396                 postOneTimeCheckIdleStates();
397             }
398         } else if (phase == PHASE_BOOT_COMPLETED) {
399             setChargingState(mInjector.isCharging());
400         }
401     }
402 
reportContentProviderUsage(String authority, String providerPkgName, int userId)403     void reportContentProviderUsage(String authority, String providerPkgName, int userId) {
404         if (!mAppIdleEnabled) return;
405 
406         // Get sync adapters for the authority
407         String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
408                 authority, userId);
409         final long elapsedRealtime = mInjector.elapsedRealtime();
410         for (String packageName: packages) {
411             // Only force the sync adapters to active if the provider is not in the same package and
412             // the sync adapter is a system package.
413             try {
414                 PackageInfo pi = mPackageManager.getPackageInfoAsUser(
415                         packageName, PackageManager.MATCH_SYSTEM_ONLY, userId);
416                 if (pi == null || pi.applicationInfo == null) {
417                     continue;
418                 }
419                 if (!packageName.equals(providerPkgName)) {
420                     synchronized (mAppIdleLock) {
421                         AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
422                                 STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER,
423                                 0,
424                                 elapsedRealtime + mSyncAdapterTimeoutMillis);
425                         maybeInformListeners(packageName, userId, elapsedRealtime,
426                                 appUsage.currentBucket, appUsage.bucketingReason, false);
427                     }
428                 }
429             } catch (PackageManager.NameNotFoundException e) {
430                 // Shouldn't happen
431             }
432         }
433     }
434 
reportExemptedSyncScheduled(String packageName, int userId)435     void reportExemptedSyncScheduled(String packageName, int userId) {
436         if (!mAppIdleEnabled) return;
437 
438         final int bucketToPromote;
439         final int usageReason;
440         final long durationMillis;
441 
442         if (!mInjector.isDeviceIdleMode()) {
443             // Not dozing.
444             bucketToPromote = STANDBY_BUCKET_ACTIVE;
445             usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
446             durationMillis = mExemptedSyncScheduledNonDozeTimeoutMillis;
447         } else {
448             // Dozing.
449             bucketToPromote = STANDBY_BUCKET_WORKING_SET;
450             usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
451             durationMillis = mExemptedSyncScheduledDozeTimeoutMillis;
452         }
453 
454         final long elapsedRealtime = mInjector.elapsedRealtime();
455 
456         synchronized (mAppIdleLock) {
457             AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
458                     bucketToPromote, usageReason,
459                     0,
460                     elapsedRealtime + durationMillis);
461             maybeInformListeners(packageName, userId, elapsedRealtime,
462                     appUsage.currentBucket, appUsage.bucketingReason, false);
463         }
464     }
465 
reportUnexemptedSyncScheduled(String packageName, int userId)466     void reportUnexemptedSyncScheduled(String packageName, int userId) {
467         if (!mAppIdleEnabled) return;
468 
469         final long elapsedRealtime = mInjector.elapsedRealtime();
470         synchronized (mAppIdleLock) {
471             final int currentBucket =
472                     mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
473             if (currentBucket == STANDBY_BUCKET_NEVER) {
474                 // Bring the app out of the never bucket
475                 AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
476                         STANDBY_BUCKET_WORKING_SET, REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED,
477                         0,
478                         elapsedRealtime + mUnexemptedSyncScheduledTimeoutMillis);
479                 maybeInformListeners(packageName, userId, elapsedRealtime,
480                         appUsage.currentBucket, appUsage.bucketingReason, false);
481             }
482         }
483     }
484 
reportExemptedSyncStart(String packageName, int userId)485     void reportExemptedSyncStart(String packageName, int userId) {
486         if (!mAppIdleEnabled) return;
487 
488         final long elapsedRealtime = mInjector.elapsedRealtime();
489 
490         synchronized (mAppIdleLock) {
491             AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
492                     STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_EXEMPTED_SYNC_START,
493                     0,
494                     elapsedRealtime + mExemptedSyncStartTimeoutMillis);
495             maybeInformListeners(packageName, userId, elapsedRealtime,
496                     appUsage.currentBucket, appUsage.bucketingReason, false);
497         }
498     }
499 
setChargingState(boolean charging)500     void setChargingState(boolean charging) {
501         synchronized (mAppIdleLock) {
502             if (mCharging != charging) {
503                 mCharging = charging;
504                 if (DEBUG) Slog.d(TAG, "Setting mCharging to " + charging);
505                 if (charging) {
506                     if (DEBUG) {
507                         Slog.d(TAG, "Scheduling MSG_UPDATE_STABLE_CHARGING  delay = "
508                                 + mStableChargingThresholdMillis);
509                     }
510                     mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STABLE_CHARGING,
511                             mStableChargingThresholdMillis);
512                 } else {
513                     mHandler.removeMessages(MSG_UPDATE_STABLE_CHARGING);
514                     updateChargingStableState();
515                 }
516             }
517         }
518     }
519 
updateChargingStableState()520     void updateChargingStableState() {
521         synchronized (mAppIdleLock) {
522             if (mChargingStable != mCharging) {
523                 if (DEBUG) Slog.d(TAG, "Setting mChargingStable to " + mCharging);
524                 mChargingStable = mCharging;
525                 postParoleStateChanged();
526             }
527         }
528     }
529 
530     /** Paroled here means temporary pardon from being inactive */
setAppIdleParoled(boolean paroled)531     void setAppIdleParoled(boolean paroled) {
532         synchronized (mAppIdleLock) {
533             final long now = mInjector.currentTimeMillis();
534             if (mAppIdleTempParoled != paroled) {
535                 mAppIdleTempParoled = paroled;
536                 if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled);
537                 if (paroled) {
538                     postParoleEndTimeout();
539                 } else {
540                     mLastAppIdleParoledTime = now;
541                     postNextParoleTimeout(now, false);
542                 }
543                 postParoleStateChanged();
544             }
545         }
546     }
547 
isParoledOrCharging()548     boolean isParoledOrCharging() {
549         if (!mAppIdleEnabled) return true;
550         synchronized (mAppIdleLock) {
551             // Only consider stable charging when determining charge state.
552             return mAppIdleTempParoled || mChargingStable;
553         }
554     }
555 
postNextParoleTimeout(long now, boolean forced)556     private void postNextParoleTimeout(long now, boolean forced) {
557         if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
558         mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
559         // Compute when the next parole needs to happen. We check more frequently than necessary
560         // since the message handler delays are based on elapsedRealTime and not wallclock time.
561         // The comparison is done in wallclock time.
562         long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis) - now;
563         if (forced) {
564             // Set next timeout for the end of the parole window
565             // If parole is not set by the end of the window it will be forced
566             timeLeft += mAppIdleParoleWindowMillis;
567         }
568         if (timeLeft < 0) {
569             timeLeft = 0;
570         }
571         mHandler.sendEmptyMessageDelayed(MSG_CHECK_PAROLE_TIMEOUT, timeLeft);
572     }
573 
postParoleEndTimeout()574     private void postParoleEndTimeout() {
575         if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_END_TIMEOUT");
576         mHandler.removeMessages(MSG_PAROLE_END_TIMEOUT);
577         mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, mAppIdleParoleDurationMillis);
578     }
579 
postParoleStateChanged()580     private void postParoleStateChanged() {
581         if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED");
582         mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED);
583         mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
584     }
585 
postCheckIdleStates(int userId)586     void postCheckIdleStates(int userId) {
587         mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
588     }
589 
590     /**
591      * We send a different message to check idle states once, otherwise we would end up
592      * scheduling a series of repeating checkIdleStates each time we fired off one.
593      */
postOneTimeCheckIdleStates()594     void postOneTimeCheckIdleStates() {
595         if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) {
596             // Not booted yet; wait for it!
597             mPendingOneTimeCheckIdleStates = true;
598         } else {
599             mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
600             mPendingOneTimeCheckIdleStates = false;
601         }
602     }
603 
604     /**
605      * Check all running users' or specified user's apps to see if they enter an idle state.
606      * @return Returns whether checking should continue periodically.
607      */
checkIdleStates(int checkUserId)608     boolean checkIdleStates(int checkUserId) {
609         if (!mAppIdleEnabled) {
610             return false;
611         }
612 
613         final int[] runningUserIds;
614         try {
615             runningUserIds = mInjector.getRunningUserIds();
616             if (checkUserId != UserHandle.USER_ALL
617                     && !ArrayUtils.contains(runningUserIds, checkUserId)) {
618                 return false;
619             }
620         } catch (RemoteException re) {
621             throw re.rethrowFromSystemServer();
622         }
623 
624         final long elapsedRealtime = mInjector.elapsedRealtime();
625         for (int i = 0; i < runningUserIds.length; i++) {
626             final int userId = runningUserIds[i];
627             if (checkUserId != UserHandle.USER_ALL && checkUserId != userId) {
628                 continue;
629             }
630             if (DEBUG) {
631                 Slog.d(TAG, "Checking idle state for user " + userId);
632             }
633             List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
634                     PackageManager.MATCH_DISABLED_COMPONENTS,
635                     userId);
636             final int packageCount = packages.size();
637             for (int p = 0; p < packageCount; p++) {
638                 final PackageInfo pi = packages.get(p);
639                 final String packageName = pi.packageName;
640                 checkAndUpdateStandbyState(packageName, userId, pi.applicationInfo.uid,
641                         elapsedRealtime);
642             }
643         }
644         if (DEBUG) {
645             Slog.d(TAG, "checkIdleStates took "
646                     + (mInjector.elapsedRealtime() - elapsedRealtime));
647         }
648         return true;
649     }
650 
651     /** Check if we need to update the standby state of a specific app. */
checkAndUpdateStandbyState(String packageName, @UserIdInt int userId, int uid, long elapsedRealtime)652     private void checkAndUpdateStandbyState(String packageName, @UserIdInt int userId,
653             int uid, long elapsedRealtime) {
654         if (uid <= 0) {
655             try {
656                 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
657             } catch (PackageManager.NameNotFoundException e) {
658                 // Not a valid package for this user, nothing to do
659                 // TODO: Remove any history of removed packages
660                 return;
661             }
662         }
663         final boolean isSpecial = isAppSpecial(packageName,
664                 UserHandle.getAppId(uid),
665                 userId);
666         if (DEBUG) {
667             Slog.d(TAG, "   Checking idle state for " + packageName + " special=" +
668                     isSpecial);
669         }
670         if (isSpecial) {
671             synchronized (mAppIdleLock) {
672                 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
673                         STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT);
674             }
675             maybeInformListeners(packageName, userId, elapsedRealtime,
676                     STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT, false);
677         } else {
678             synchronized (mAppIdleLock) {
679                 final AppIdleHistory.AppUsageHistory app =
680                         mAppIdleHistory.getAppUsageHistory(packageName,
681                         userId, elapsedRealtime);
682                 int reason = app.bucketingReason;
683                 final int oldMainReason = reason & REASON_MAIN_MASK;
684 
685                 // If the bucket was forced by the user/developer, leave it alone.
686                 // A usage event will be the only way to bring it out of this forced state
687                 if (oldMainReason == REASON_MAIN_FORCED) {
688                     return;
689                 }
690                 final int oldBucket = app.currentBucket;
691                 int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
692                 boolean predictionLate = predictionTimedOut(app, elapsedRealtime);
693                 // Compute age-based bucket
694                 if (oldMainReason == REASON_MAIN_DEFAULT
695                         || oldMainReason == REASON_MAIN_USAGE
696                         || oldMainReason == REASON_MAIN_TIMEOUT
697                         || predictionLate) {
698 
699                     if (!predictionLate && app.lastPredictedBucket >= STANDBY_BUCKET_ACTIVE
700                             && app.lastPredictedBucket <= STANDBY_BUCKET_RARE) {
701                         newBucket = app.lastPredictedBucket;
702                         reason = REASON_MAIN_PREDICTED | REASON_SUB_PREDICTED_RESTORED;
703                         if (DEBUG) {
704                             Slog.d(TAG, "Restored predicted newBucket = " + newBucket);
705                         }
706                     } else {
707                         newBucket = getBucketForLocked(packageName, userId,
708                                 elapsedRealtime);
709                         if (DEBUG) {
710                             Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket);
711                         }
712                         reason = REASON_MAIN_TIMEOUT;
713                     }
714                 }
715 
716                 // Check if the app is within one of the timeouts for forced bucket elevation
717                 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
718                 if (newBucket >= STANDBY_BUCKET_ACTIVE
719                         && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
720                     newBucket = STANDBY_BUCKET_ACTIVE;
721                     reason = app.bucketingReason;
722                     if (DEBUG) {
723                         Slog.d(TAG, "    Keeping at ACTIVE due to min timeout");
724                     }
725                 } else if (newBucket >= STANDBY_BUCKET_WORKING_SET
726                         && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
727                     newBucket = STANDBY_BUCKET_WORKING_SET;
728                     // If it was already there, keep the reason, else assume timeout to WS
729                     reason = (newBucket == oldBucket)
730                             ? app.bucketingReason
731                             : REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT;
732                     if (DEBUG) {
733                         Slog.d(TAG, "    Keeping at WORKING_SET due to min timeout");
734                     }
735                 }
736                 if (DEBUG) {
737                     Slog.d(TAG, "     Old bucket=" + oldBucket
738                             + ", newBucket=" + newBucket);
739                 }
740                 if (oldBucket < newBucket || predictionLate) {
741                     mAppIdleHistory.setAppStandbyBucket(packageName, userId,
742                             elapsedRealtime, newBucket, reason);
743                     maybeInformListeners(packageName, userId, elapsedRealtime,
744                             newBucket, reason, false);
745                 }
746             }
747         }
748     }
749 
750     /** Returns true if there hasn't been a prediction for the app in a while. */
predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime)751     private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
752         return app.lastPredictedTime > 0
753                 && mAppIdleHistory.getElapsedTime(elapsedRealtime)
754                     - app.lastPredictedTime > mPredictionTimeoutMillis;
755     }
756 
757     /** Inform listeners if the bucket has changed since it was last reported to listeners */
maybeInformListeners(String packageName, int userId, long elapsedRealtime, int bucket, int reason, boolean userStartedInteracting)758     private void maybeInformListeners(String packageName, int userId,
759             long elapsedRealtime, int bucket, int reason, boolean userStartedInteracting) {
760         synchronized (mAppIdleLock) {
761             if (mAppIdleHistory.shouldInformListeners(packageName, userId,
762                     elapsedRealtime, bucket)) {
763                 final StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId,
764                         bucket, reason, userStartedInteracting);
765                 if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket);
766                 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, r));
767             }
768         }
769     }
770 
771     /**
772      * Evaluates next bucket based on time since last used and the bucketing thresholds.
773      * @param packageName the app
774      * @param userId the user
775      * @param elapsedRealtime as the name suggests, current elapsed time
776      * @return the bucket for the app, based on time since last used
777      */
778     @GuardedBy("mAppIdleLock")
getBucketForLocked(String packageName, int userId, long elapsedRealtime)779     @StandbyBuckets int getBucketForLocked(String packageName, int userId,
780             long elapsedRealtime) {
781         int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId,
782                 elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds);
783         return THRESHOLD_BUCKETS[bucketIndex];
784     }
785 
786     /**
787      * Check if it's been a while since last parole and let idle apps do some work.
788      * If network is not available, delay parole until it is available up until the end of the
789      * parole window. Force the parole to be set if end of the parole window is reached.
790      */
checkParoleTimeout()791     void checkParoleTimeout() {
792         boolean setParoled = false;
793         boolean waitForNetwork = false;
794         NetworkInfo activeNetwork = mConnectivityManager.getActiveNetworkInfo();
795         boolean networkActive = activeNetwork != null &&
796                 activeNetwork.isConnected();
797 
798         synchronized (mAppIdleLock) {
799             final long now = mInjector.currentTimeMillis();
800             if (!mAppIdleTempParoled) {
801                 final long timeSinceLastParole = now - mLastAppIdleParoledTime;
802                 if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
803                     if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
804                     if (networkActive) {
805                         // If network is active set parole
806                         setParoled = true;
807                     } else {
808                         if (timeSinceLastParole
809                                 > mAppIdleParoleIntervalMillis + mAppIdleParoleWindowMillis) {
810                             if (DEBUG) Slog.d(TAG, "Crossed end of parole window, force parole");
811                             setParoled = true;
812                         } else {
813                             if (DEBUG) Slog.d(TAG, "Network unavailable, delaying parole");
814                             waitForNetwork = true;
815                             postNextParoleTimeout(now, true);
816                         }
817                     }
818                 } else {
819                     if (DEBUG) Slog.d(TAG, "Not long enough to go to parole");
820                     postNextParoleTimeout(now, false);
821                 }
822             }
823         }
824         if (waitForNetwork) {
825             mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
826         }
827         if (setParoled) {
828             // Set parole if network is available
829             setAppIdleParoled(true);
830         }
831     }
832 
notifyBatteryStats(String packageName, int userId, boolean idle)833     private void notifyBatteryStats(String packageName, int userId, boolean idle) {
834         try {
835             final int uid = mPackageManager.getPackageUidAsUser(packageName,
836                     PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
837             if (idle) {
838                 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
839                         packageName, uid);
840             } else {
841                 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
842                         packageName, uid);
843             }
844         } catch (PackageManager.NameNotFoundException | RemoteException e) {
845         }
846     }
847 
onDeviceIdleModeChanged()848     void onDeviceIdleModeChanged() {
849         final boolean deviceIdle = mPowerManager.isDeviceIdleMode();
850         if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
851         boolean paroled = false;
852         synchronized (mAppIdleLock) {
853             final long timeSinceLastParole =
854                     mInjector.currentTimeMillis() - mLastAppIdleParoledTime;
855             if (!deviceIdle
856                     && timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
857                 if (DEBUG) {
858                     Slog.i(TAG,
859                             "Bringing idle apps out of inactive state due to deviceIdleMode=false");
860                 }
861                 paroled = true;
862             } else if (deviceIdle) {
863                 if (DEBUG) Slog.i(TAG, "Device idle, back to prison");
864                 paroled = false;
865             } else {
866                 return;
867             }
868         }
869         setAppIdleParoled(paroled);
870     }
871 
reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId)872     void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) {
873         if (!mAppIdleEnabled) return;
874         synchronized (mAppIdleLock) {
875             // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
876             // about apps that are on some kind of whitelist anyway.
877             final boolean previouslyIdle = mAppIdleHistory.isIdle(
878                     event.mPackage, userId, elapsedRealtime);
879             // Inform listeners if necessary
880             if ((event.mEventType == UsageEvents.Event.ACTIVITY_RESUMED
881                     || event.mEventType == UsageEvents.Event.ACTIVITY_PAUSED
882                     || event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION
883                     || event.mEventType == UsageEvents.Event.USER_INTERACTION
884                     || event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN
885                     || event.mEventType == UsageEvents.Event.SLICE_PINNED
886                     || event.mEventType == UsageEvents.Event.SLICE_PINNED_PRIV
887                     || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) {
888 
889                 final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory(
890                         event.mPackage, userId, elapsedRealtime);
891                 final int prevBucket = appHistory.currentBucket;
892                 final int prevBucketReason = appHistory.bucketingReason;
893                 final long nextCheckTime;
894                 final int subReason = usageEventToSubReason(event.mEventType);
895                 final int reason = REASON_MAIN_USAGE | subReason;
896                 if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN
897                         || event.mEventType == UsageEvents.Event.SLICE_PINNED) {
898                     // Mild usage elevates to WORKING_SET but doesn't change usage time.
899                     mAppIdleHistory.reportUsage(appHistory, event.mPackage,
900                             STANDBY_BUCKET_WORKING_SET, subReason,
901                             0, elapsedRealtime + mNotificationSeenTimeoutMillis);
902                     nextCheckTime = mNotificationSeenTimeoutMillis;
903                 } else if (event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION) {
904                     mAppIdleHistory.reportUsage(appHistory, event.mPackage,
905                             STANDBY_BUCKET_ACTIVE, subReason,
906                             0, elapsedRealtime + mSystemInteractionTimeoutMillis);
907                     nextCheckTime = mSystemInteractionTimeoutMillis;
908                 } else if (event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START) {
909                     // Only elevate bucket if this is the first usage of the app
910                     if (prevBucket != STANDBY_BUCKET_NEVER) return;
911                     mAppIdleHistory.reportUsage(appHistory, event.mPackage,
912                             STANDBY_BUCKET_ACTIVE, subReason,
913                             0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis);
914                     nextCheckTime = mInitialForegroundServiceStartTimeoutMillis;
915                 } else {
916                     mAppIdleHistory.reportUsage(appHistory, event.mPackage,
917                             STANDBY_BUCKET_ACTIVE, subReason,
918                             elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
919                     nextCheckTime = mStrongUsageTimeoutMillis;
920                 }
921                 mHandler.sendMessageDelayed(mHandler.obtainMessage
922                         (MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, event.mPackage),
923                         nextCheckTime);
924                 final boolean userStartedInteracting =
925                         appHistory.currentBucket == STANDBY_BUCKET_ACTIVE &&
926                         prevBucket != appHistory.currentBucket &&
927                         (prevBucketReason & REASON_MAIN_MASK) != REASON_MAIN_USAGE;
928                 maybeInformListeners(event.mPackage, userId, elapsedRealtime,
929                         appHistory.currentBucket, reason, userStartedInteracting);
930 
931                 if (previouslyIdle) {
932                     notifyBatteryStats(event.mPackage, userId, false);
933                 }
934             }
935         }
936     }
937 
usageEventToSubReason(int eventType)938     private int usageEventToSubReason(int eventType) {
939         switch (eventType) {
940             case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
941             case UsageEvents.Event.ACTIVITY_PAUSED: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
942             case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION;
943             case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION;
944             case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN;
945             case UsageEvents.Event.SLICE_PINNED: return REASON_SUB_USAGE_SLICE_PINNED;
946             case UsageEvents.Event.SLICE_PINNED_PRIV: return REASON_SUB_USAGE_SLICE_PINNED_PRIV;
947             case UsageEvents.Event.FOREGROUND_SERVICE_START:
948                 return REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
949             default: return 0;
950         }
951     }
952 
953     /**
954      * Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle,
955      * then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind
956      * the threshold for idle.
957      *
958      * This method is always called from the handler thread, so not much synchronization is
959      * required.
960      */
forceIdleState(String packageName, int userId, boolean idle)961     void forceIdleState(String packageName, int userId, boolean idle) {
962         if (!mAppIdleEnabled) return;
963 
964         final int appId = getAppId(packageName);
965         if (appId < 0) return;
966         final long elapsedRealtime = mInjector.elapsedRealtime();
967 
968         final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
969                 userId, elapsedRealtime);
970         final int standbyBucket;
971         synchronized (mAppIdleLock) {
972             standbyBucket = mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime);
973         }
974         final boolean stillIdle = isAppIdleFiltered(packageName, appId,
975                 userId, elapsedRealtime);
976         // Inform listeners if necessary
977         if (previouslyIdle != stillIdle) {
978             maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket,
979                     REASON_MAIN_FORCED, false);
980             if (!stillIdle) {
981                 notifyBatteryStats(packageName, userId, idle);
982             }
983         }
984     }
985 
setLastJobRunTime(String packageName, int userId, long elapsedRealtime)986     public void setLastJobRunTime(String packageName, int userId, long elapsedRealtime) {
987         synchronized (mAppIdleLock) {
988             mAppIdleHistory.setLastJobRunTime(packageName, userId, elapsedRealtime);
989         }
990     }
991 
getTimeSinceLastJobRun(String packageName, int userId)992     public long getTimeSinceLastJobRun(String packageName, int userId) {
993         final long elapsedRealtime = mInjector.elapsedRealtime();
994         synchronized (mAppIdleLock) {
995             return mAppIdleHistory.getTimeSinceLastJobRun(packageName, userId, elapsedRealtime);
996         }
997     }
998 
onUserRemoved(int userId)999     public void onUserRemoved(int userId) {
1000         synchronized (mAppIdleLock) {
1001             mAppIdleHistory.onUserRemoved(userId);
1002             synchronized (mActiveAdminApps) {
1003                 mActiveAdminApps.remove(userId);
1004             }
1005         }
1006     }
1007 
isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime)1008     private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
1009         synchronized (mAppIdleLock) {
1010             return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
1011         }
1012     }
1013 
addListener(AppIdleStateChangeListener listener)1014     void addListener(AppIdleStateChangeListener listener) {
1015         synchronized (mPackageAccessListeners) {
1016             if (!mPackageAccessListeners.contains(listener)) {
1017                 mPackageAccessListeners.add(listener);
1018             }
1019         }
1020     }
1021 
removeListener(AppIdleStateChangeListener listener)1022     void removeListener(AppIdleStateChangeListener listener) {
1023         synchronized (mPackageAccessListeners) {
1024             mPackageAccessListeners.remove(listener);
1025         }
1026     }
1027 
getAppId(String packageName)1028     int getAppId(String packageName) {
1029         try {
1030             ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName,
1031                     PackageManager.MATCH_ANY_USER
1032                             | PackageManager.MATCH_DISABLED_COMPONENTS);
1033             return ai.uid;
1034         } catch (PackageManager.NameNotFoundException re) {
1035             return -1;
1036         }
1037     }
1038 
isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps)1039     boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime,
1040             boolean shouldObfuscateInstantApps) {
1041         if (isParoledOrCharging()) {
1042             return false;
1043         }
1044         if (shouldObfuscateInstantApps &&
1045                 mInjector.isPackageEphemeral(userId, packageName)) {
1046             return false;
1047         }
1048         return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
1049     }
1050 
1051     /** Returns true if this app should be whitelisted for some reason, to never go into standby */
isAppSpecial(String packageName, int appId, int userId)1052     boolean isAppSpecial(String packageName, int appId, int userId) {
1053         if (packageName == null) return false;
1054         // If not enabled at all, of course nobody is ever idle.
1055         if (!mAppIdleEnabled) {
1056             return true;
1057         }
1058         if (appId < Process.FIRST_APPLICATION_UID) {
1059             // System uids never go idle.
1060             return true;
1061         }
1062         if (packageName.equals("android")) {
1063             // Nor does the framework (which should be redundant with the above, but for MR1 we will
1064             // retain this for safety).
1065             return true;
1066         }
1067         if (mSystemServicesReady) {
1068             try {
1069                 // We allow all whitelisted apps, including those that don't want to be whitelisted
1070                 // for idle mode, because app idle (aka app standby) is really not as big an issue
1071                 // for controlling who participates vs. doze mode.
1072                 if (mInjector.isPowerSaveWhitelistExceptIdleApp(packageName)) {
1073                     return true;
1074                 }
1075             } catch (RemoteException re) {
1076                 throw re.rethrowFromSystemServer();
1077             }
1078 
1079             if (isActiveDeviceAdmin(packageName, userId)) {
1080                 return true;
1081             }
1082 
1083             if (isActiveNetworkScorer(packageName)) {
1084                 return true;
1085             }
1086 
1087             if (mAppWidgetManager != null
1088                     && mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) {
1089                 return true;
1090             }
1091 
1092             if (isDeviceProvisioningPackage(packageName)) {
1093                 return true;
1094             }
1095         }
1096 
1097         // Check this last, as it can be the most expensive check
1098         if (isCarrierApp(packageName)) {
1099             return true;
1100         }
1101 
1102         return false;
1103     }
1104 
1105     /**
1106      * Checks if an app has been idle for a while and filters out apps that are excluded.
1107      * It returns false if the current system state allows all apps to be considered active.
1108      * This happens if the device is plugged in or temporarily allowed to make exceptions.
1109      * Called by interface impls.
1110      */
isAppIdleFiltered(String packageName, int appId, int userId, long elapsedRealtime)1111     boolean isAppIdleFiltered(String packageName, int appId, int userId,
1112             long elapsedRealtime) {
1113         if (isAppSpecial(packageName, appId, userId)) {
1114             return false;
1115         } else {
1116             return isAppIdleUnfiltered(packageName, userId, elapsedRealtime);
1117         }
1118     }
1119 
getIdleUidsForUser(int userId)1120     int[] getIdleUidsForUser(int userId) {
1121         if (!mAppIdleEnabled) {
1122             return new int[0];
1123         }
1124 
1125         final long elapsedRealtime = mInjector.elapsedRealtime();
1126 
1127         List<ApplicationInfo> apps;
1128         try {
1129             ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager()
1130                     .getInstalledApplications(/* flags= */ 0, userId);
1131             if (slice == null) {
1132                 return new int[0];
1133             }
1134             apps = slice.getList();
1135         } catch (RemoteException e) {
1136             throw e.rethrowFromSystemServer();
1137         }
1138 
1139         // State of each uid.  Key is the uid.  Value lower 16 bits is the number of apps
1140         // associated with that uid, upper 16 bits is the number of those apps that is idle.
1141         SparseIntArray uidStates = new SparseIntArray();
1142 
1143         // Now resolve all app state.  Iterating over all apps, keeping track of how many
1144         // we find for each uid and how many of those are idle.
1145         for (int i = apps.size() - 1; i >= 0; i--) {
1146             ApplicationInfo ai = apps.get(i);
1147 
1148             // Check whether this app is idle.
1149             boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid),
1150                     userId, elapsedRealtime);
1151 
1152             int index = uidStates.indexOfKey(ai.uid);
1153             if (index < 0) {
1154                 uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0));
1155             } else {
1156                 int value = uidStates.valueAt(index);
1157                 uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0));
1158             }
1159         }
1160         if (DEBUG) {
1161             Slog.d(TAG, "getIdleUids took " + (mInjector.elapsedRealtime() - elapsedRealtime));
1162         }
1163         int numIdle = 0;
1164         for (int i = uidStates.size() - 1; i >= 0; i--) {
1165             int value = uidStates.valueAt(i);
1166             if ((value&0x7fff) == (value>>16)) {
1167                 numIdle++;
1168             }
1169         }
1170 
1171         int[] res = new int[numIdle];
1172         numIdle = 0;
1173         for (int i = uidStates.size() - 1; i >= 0; i--) {
1174             int value = uidStates.valueAt(i);
1175             if ((value&0x7fff) == (value>>16)) {
1176                 res[numIdle] = uidStates.keyAt(i);
1177                 numIdle++;
1178             }
1179         }
1180 
1181         return res;
1182     }
1183 
setAppIdleAsync(String packageName, boolean idle, int userId)1184     void setAppIdleAsync(String packageName, boolean idle, int userId) {
1185         if (packageName == null || !mAppIdleEnabled) return;
1186 
1187         mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
1188                 .sendToTarget();
1189     }
1190 
getAppStandbyBucket(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps)1191     @StandbyBuckets public int getAppStandbyBucket(String packageName, int userId,
1192             long elapsedRealtime, boolean shouldObfuscateInstantApps) {
1193         if (!mAppIdleEnabled || (shouldObfuscateInstantApps
1194                 && mInjector.isPackageEphemeral(userId, packageName))) {
1195             return STANDBY_BUCKET_ACTIVE;
1196         }
1197 
1198         synchronized (mAppIdleLock) {
1199             return mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
1200         }
1201     }
1202 
getAppStandbyBuckets(int userId)1203     public List<AppStandbyInfo> getAppStandbyBuckets(int userId) {
1204         synchronized (mAppIdleLock) {
1205             return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled);
1206         }
1207     }
1208 
setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime)1209     void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
1210             int reason, long elapsedRealtime) {
1211         setAppStandbyBucket(packageName, userId, newBucket, reason, elapsedRealtime, false);
1212     }
1213 
setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime, boolean resetTimeout)1214     void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
1215             int reason, long elapsedRealtime, boolean resetTimeout) {
1216         synchronized (mAppIdleLock) {
1217             // If the package is not installed, don't allow the bucket to be set.
1218             if (!mInjector.isPackageInstalled(packageName, 0, userId)) {
1219                 return;
1220             }
1221             AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
1222                     userId, elapsedRealtime);
1223             boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED;
1224 
1225             // Don't allow changing bucket if higher than ACTIVE
1226             if (app.currentBucket < STANDBY_BUCKET_ACTIVE) return;
1227 
1228             // Don't allow prediction to change from/to NEVER
1229             if ((app.currentBucket == STANDBY_BUCKET_NEVER
1230                     || newBucket == STANDBY_BUCKET_NEVER)
1231                     && predicted) {
1232                 return;
1233             }
1234 
1235             // If the bucket was forced, don't allow prediction to override
1236             if ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED && predicted) return;
1237 
1238             // If the bucket is required to stay in a higher state for a specified duration, don't
1239             // override unless the duration has passed
1240             if (predicted) {
1241                 // Check if the app is within one of the timeouts for forced bucket elevation
1242                 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
1243                 // In case of not using the prediction, just keep track of it for applying after
1244                 // ACTIVE or WORKING_SET timeout.
1245                 mAppIdleHistory.updateLastPrediction(app, elapsedTimeAdjusted, newBucket);
1246 
1247                 if (newBucket > STANDBY_BUCKET_ACTIVE
1248                         && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
1249                     newBucket = STANDBY_BUCKET_ACTIVE;
1250                     reason = app.bucketingReason;
1251                     if (DEBUG) {
1252                         Slog.d(TAG, "    Keeping at ACTIVE due to min timeout");
1253                     }
1254                 } else if (newBucket > STANDBY_BUCKET_WORKING_SET
1255                         && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
1256                     newBucket = STANDBY_BUCKET_WORKING_SET;
1257                     if (app.currentBucket != newBucket) {
1258                         reason = REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT;
1259                     } else {
1260                         reason = app.bucketingReason;
1261                     }
1262                     if (DEBUG) {
1263                         Slog.d(TAG, "    Keeping at WORKING_SET due to min timeout");
1264                     }
1265                 }
1266             }
1267 
1268             mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
1269                     reason, resetTimeout);
1270         }
1271         maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false);
1272     }
1273 
1274     @VisibleForTesting
isActiveDeviceAdmin(String packageName, int userId)1275     boolean isActiveDeviceAdmin(String packageName, int userId) {
1276         synchronized (mActiveAdminApps) {
1277             final Set<String> adminPkgs = mActiveAdminApps.get(userId);
1278             return adminPkgs != null && adminPkgs.contains(packageName);
1279         }
1280     }
1281 
addActiveDeviceAdmin(String adminPkg, int userId)1282     public void addActiveDeviceAdmin(String adminPkg, int userId) {
1283         synchronized (mActiveAdminApps) {
1284             Set<String> adminPkgs = mActiveAdminApps.get(userId);
1285             if (adminPkgs == null) {
1286                 adminPkgs = new ArraySet<>();
1287                 mActiveAdminApps.put(userId, adminPkgs);
1288             }
1289             adminPkgs.add(adminPkg);
1290         }
1291     }
1292 
setActiveAdminApps(Set<String> adminPkgs, int userId)1293     public void setActiveAdminApps(Set<String> adminPkgs, int userId) {
1294         synchronized (mActiveAdminApps) {
1295             if (adminPkgs == null) {
1296                 mActiveAdminApps.remove(userId);
1297             } else {
1298                 mActiveAdminApps.put(userId, adminPkgs);
1299             }
1300         }
1301     }
1302 
onAdminDataAvailable()1303     public void onAdminDataAvailable() {
1304         mAdminDataAvailableLatch.countDown();
1305     }
1306 
1307     /**
1308      * This will only ever be called once - during device boot.
1309      */
waitForAdminData()1310     private void waitForAdminData() {
1311         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
1312             ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch,
1313                     WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data");
1314         }
1315     }
1316 
getActiveAdminAppsForTest(int userId)1317     Set<String> getActiveAdminAppsForTest(int userId) {
1318         synchronized (mActiveAdminApps) {
1319             return mActiveAdminApps.get(userId);
1320         }
1321     }
1322 
1323     /**
1324      * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
1325      * returns {@code false}.
1326      */
isDeviceProvisioningPackage(String packageName)1327     private boolean isDeviceProvisioningPackage(String packageName) {
1328         String deviceProvisioningPackage = mContext.getResources().getString(
1329                 com.android.internal.R.string.config_deviceProvisioningPackage);
1330         return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
1331     }
1332 
isCarrierApp(String packageName)1333     private boolean isCarrierApp(String packageName) {
1334         synchronized (mAppIdleLock) {
1335             if (!mHaveCarrierPrivilegedApps) {
1336                 fetchCarrierPrivilegedAppsLocked();
1337             }
1338             if (mCarrierPrivilegedApps != null) {
1339                 return mCarrierPrivilegedApps.contains(packageName);
1340             }
1341             return false;
1342         }
1343     }
1344 
clearCarrierPrivilegedApps()1345     void clearCarrierPrivilegedApps() {
1346         if (DEBUG) {
1347             Slog.i(TAG, "Clearing carrier privileged apps list");
1348         }
1349         synchronized (mAppIdleLock) {
1350             mHaveCarrierPrivilegedApps = false;
1351             mCarrierPrivilegedApps = null; // Need to be refetched.
1352         }
1353     }
1354 
1355     @GuardedBy("mAppIdleLock")
fetchCarrierPrivilegedAppsLocked()1356     private void fetchCarrierPrivilegedAppsLocked() {
1357         TelephonyManager telephonyManager =
1358                 mContext.getSystemService(TelephonyManager.class);
1359         mCarrierPrivilegedApps =
1360                 telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions();
1361         mHaveCarrierPrivilegedApps = true;
1362         if (DEBUG) {
1363             Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
1364         }
1365     }
1366 
isActiveNetworkScorer(String packageName)1367     private boolean isActiveNetworkScorer(String packageName) {
1368         String activeScorer = mInjector.getActiveNetworkScorer();
1369         return packageName != null && packageName.equals(activeScorer);
1370     }
1371 
informListeners(String packageName, int userId, int bucket, int reason, boolean userInteraction)1372     void informListeners(String packageName, int userId, int bucket, int reason,
1373             boolean userInteraction) {
1374         final boolean idle = bucket >= STANDBY_BUCKET_RARE;
1375         synchronized (mPackageAccessListeners) {
1376             for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
1377                 listener.onAppIdleStateChanged(packageName, userId, idle, bucket, reason);
1378                 if (userInteraction) {
1379                     listener.onUserInteractionStarted(packageName, userId);
1380                 }
1381             }
1382         }
1383     }
1384 
informParoleStateChanged()1385     void informParoleStateChanged() {
1386         final boolean paroled = isParoledOrCharging();
1387         synchronized (mPackageAccessListeners) {
1388             for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
1389                 listener.onParoleStateChanged(paroled);
1390             }
1391         }
1392     }
1393 
flushToDisk(int userId)1394     void flushToDisk(int userId) {
1395         synchronized (mAppIdleLock) {
1396             mAppIdleHistory.writeAppIdleTimes(userId);
1397         }
1398     }
1399 
flushDurationsToDisk()1400     void flushDurationsToDisk() {
1401         // Persist elapsed and screen on time. If this fails for whatever reason, the apps will be
1402         // considered not-idle, which is the safest outcome in such an event.
1403         synchronized (mAppIdleLock) {
1404             mAppIdleHistory.writeAppIdleDurations();
1405         }
1406     }
1407 
isDisplayOn()1408     boolean isDisplayOn() {
1409         return mInjector.isDefaultDisplayOn();
1410     }
1411 
clearAppIdleForPackage(String packageName, int userId)1412     void clearAppIdleForPackage(String packageName, int userId) {
1413         synchronized (mAppIdleLock) {
1414             mAppIdleHistory.clearUsage(packageName, userId);
1415         }
1416     }
1417 
1418     private class PackageReceiver extends BroadcastReceiver {
1419         @Override
onReceive(Context context, Intent intent)1420         public void onReceive(Context context, Intent intent) {
1421             final String action = intent.getAction();
1422             if (Intent.ACTION_PACKAGE_ADDED.equals(action)
1423                     || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
1424                 clearCarrierPrivilegedApps();
1425             }
1426             if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
1427                     Intent.ACTION_PACKAGE_ADDED.equals(action))
1428                     && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1429                 clearAppIdleForPackage(intent.getData().getSchemeSpecificPart(),
1430                         getSendingUserId());
1431             }
1432         }
1433     }
1434 
initializeDefaultsForSystemApps(int userId)1435     void initializeDefaultsForSystemApps(int userId) {
1436         if (!mSystemServicesReady) {
1437             // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled
1438             mPendingInitializeDefaults = true;
1439             return;
1440         }
1441         Slog.d(TAG, "Initializing defaults for system apps on user " + userId + ", "
1442                 + "appIdleEnabled=" + mAppIdleEnabled);
1443         final long elapsedRealtime = mInjector.elapsedRealtime();
1444         List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
1445                 PackageManager.MATCH_DISABLED_COMPONENTS,
1446                 userId);
1447         final int packageCount = packages.size();
1448         synchronized (mAppIdleLock) {
1449             for (int i = 0; i < packageCount; i++) {
1450                 final PackageInfo pi = packages.get(i);
1451                 String packageName = pi.packageName;
1452                 if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
1453                     // Mark app as used for 2 hours. After that it can timeout to whatever the
1454                     // past usage pattern was.
1455                     mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE,
1456                             REASON_SUB_USAGE_SYSTEM_UPDATE, 0,
1457                             elapsedRealtime + mSystemUpdateUsageTimeoutMillis);
1458                 }
1459             }
1460             // Immediately persist defaults to disk
1461             mAppIdleHistory.writeAppIdleTimes(userId);
1462         }
1463     }
1464 
postReportContentProviderUsage(String name, String packageName, int userId)1465     void postReportContentProviderUsage(String name, String packageName, int userId) {
1466         SomeArgs args = SomeArgs.obtain();
1467         args.arg1 = name;
1468         args.arg2 = packageName;
1469         args.arg3 = userId;
1470         mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, args)
1471                 .sendToTarget();
1472     }
1473 
postReportSyncScheduled(String packageName, int userId, boolean exempted)1474     void postReportSyncScheduled(String packageName, int userId, boolean exempted) {
1475         mHandler.obtainMessage(MSG_REPORT_SYNC_SCHEDULED, userId, exempted ? 1 : 0, packageName)
1476                 .sendToTarget();
1477     }
1478 
postReportExemptedSyncStart(String packageName, int userId)1479     void postReportExemptedSyncStart(String packageName, int userId) {
1480         mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName)
1481                 .sendToTarget();
1482     }
1483 
dumpUser(IndentingPrintWriter idpw, int userId, String pkg)1484     void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) {
1485         synchronized (mAppIdleLock) {
1486             mAppIdleHistory.dump(idpw, userId, pkg);
1487         }
1488     }
1489 
dumpState(String[] args, PrintWriter pw)1490     void dumpState(String[] args, PrintWriter pw) {
1491         synchronized (mAppIdleLock) {
1492             pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
1493                     + "): " + mCarrierPrivilegedApps);
1494         }
1495 
1496         final long now = System.currentTimeMillis();
1497 
1498         pw.println();
1499         pw.println("Settings:");
1500 
1501         pw.print("  mCheckIdleIntervalMillis=");
1502         TimeUtils.formatDuration(mCheckIdleIntervalMillis, pw);
1503         pw.println();
1504 
1505         pw.print("  mAppIdleParoleIntervalMillis=");
1506         TimeUtils.formatDuration(mAppIdleParoleIntervalMillis, pw);
1507         pw.println();
1508 
1509         pw.print("  mAppIdleParoleWindowMillis=");
1510         TimeUtils.formatDuration(mAppIdleParoleWindowMillis, pw);
1511         pw.println();
1512 
1513         pw.print("  mAppIdleParoleDurationMillis=");
1514         TimeUtils.formatDuration(mAppIdleParoleDurationMillis, pw);
1515         pw.println();
1516 
1517         pw.print("  mStrongUsageTimeoutMillis=");
1518         TimeUtils.formatDuration(mStrongUsageTimeoutMillis, pw);
1519         pw.println();
1520         pw.print("  mNotificationSeenTimeoutMillis=");
1521         TimeUtils.formatDuration(mNotificationSeenTimeoutMillis, pw);
1522         pw.println();
1523         pw.print("  mSyncAdapterTimeoutMillis=");
1524         TimeUtils.formatDuration(mSyncAdapterTimeoutMillis, pw);
1525         pw.println();
1526         pw.print("  mSystemInteractionTimeoutMillis=");
1527         TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw);
1528         pw.println();
1529         pw.print("  mInitialForegroundServiceStartTimeoutMillis=");
1530         TimeUtils.formatDuration(mInitialForegroundServiceStartTimeoutMillis, pw);
1531         pw.println();
1532 
1533         pw.print("  mPredictionTimeoutMillis=");
1534         TimeUtils.formatDuration(mPredictionTimeoutMillis, pw);
1535         pw.println();
1536 
1537         pw.print("  mExemptedSyncScheduledNonDozeTimeoutMillis=");
1538         TimeUtils.formatDuration(mExemptedSyncScheduledNonDozeTimeoutMillis, pw);
1539         pw.println();
1540         pw.print("  mExemptedSyncScheduledDozeTimeoutMillis=");
1541         TimeUtils.formatDuration(mExemptedSyncScheduledDozeTimeoutMillis, pw);
1542         pw.println();
1543         pw.print("  mExemptedSyncStartTimeoutMillis=");
1544         TimeUtils.formatDuration(mExemptedSyncStartTimeoutMillis, pw);
1545         pw.println();
1546         pw.print("  mUnexemptedSyncScheduledTimeoutMillis=");
1547         TimeUtils.formatDuration(mUnexemptedSyncScheduledTimeoutMillis, pw);
1548         pw.println();
1549 
1550         pw.print("  mSystemUpdateUsageTimeoutMillis=");
1551         TimeUtils.formatDuration(mSystemUpdateUsageTimeoutMillis, pw);
1552         pw.println();
1553 
1554         pw.print("  mStableChargingThresholdMillis=");
1555         TimeUtils.formatDuration(mStableChargingThresholdMillis, pw);
1556         pw.println();
1557 
1558         pw.println();
1559         pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
1560         pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
1561         pw.print(" mCharging="); pw.print(mCharging);
1562         pw.print(" mChargingStable="); pw.print(mChargingStable);
1563         pw.print(" mLastAppIdleParoledTime=");
1564         TimeUtils.formatDuration(now - mLastAppIdleParoledTime, pw);
1565         pw.println();
1566         pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds));
1567         pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds));
1568         pw.print("mStableChargingThresholdMillis=");
1569         TimeUtils.formatDuration(mStableChargingThresholdMillis, pw);
1570         pw.println();
1571     }
1572 
1573     /**
1574      * Injector for interaction with external code. Override methods to provide a mock
1575      * implementation for tests.
1576      * onBootPhase() must be called with at least the PHASE_SYSTEM_SERVICES_READY
1577      */
1578     static class Injector {
1579 
1580         private final Context mContext;
1581         private final Looper mLooper;
1582         private IDeviceIdleController mDeviceIdleController;
1583         private IBatteryStats mBatteryStats;
1584         private PackageManagerInternal mPackageManagerInternal;
1585         private DisplayManager mDisplayManager;
1586         private PowerManager mPowerManager;
1587         int mBootPhase;
1588 
Injector(Context context, Looper looper)1589         Injector(Context context, Looper looper) {
1590             mContext = context;
1591             mLooper = looper;
1592         }
1593 
getContext()1594         Context getContext() {
1595             return mContext;
1596         }
1597 
getLooper()1598         Looper getLooper() {
1599             return mLooper;
1600         }
1601 
onBootPhase(int phase)1602         void onBootPhase(int phase) {
1603             if (phase == PHASE_SYSTEM_SERVICES_READY) {
1604                 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1605                         ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
1606                 mBatteryStats = IBatteryStats.Stub.asInterface(
1607                         ServiceManager.getService(BatteryStats.SERVICE_NAME));
1608                 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
1609                 mDisplayManager = (DisplayManager) mContext.getSystemService(
1610                         Context.DISPLAY_SERVICE);
1611                 mPowerManager = mContext.getSystemService(PowerManager.class);
1612             }
1613             mBootPhase = phase;
1614         }
1615 
getBootPhase()1616         int getBootPhase() {
1617             return mBootPhase;
1618         }
1619 
1620         /**
1621          * Returns the elapsed realtime since the device started. Override this
1622          * to control the clock.
1623          * @return elapsed realtime
1624          */
elapsedRealtime()1625         long elapsedRealtime() {
1626             return SystemClock.elapsedRealtime();
1627         }
1628 
currentTimeMillis()1629         long currentTimeMillis() {
1630             return System.currentTimeMillis();
1631         }
1632 
isAppIdleEnabled()1633         boolean isAppIdleEnabled() {
1634             final boolean buildFlag = mContext.getResources().getBoolean(
1635                     com.android.internal.R.bool.config_enableAutoPowerModes);
1636             final boolean runtimeFlag = Global.getInt(mContext.getContentResolver(),
1637                     Global.APP_STANDBY_ENABLED, 1) == 1
1638                     && Global.getInt(mContext.getContentResolver(),
1639                     Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1) == 1;
1640             return buildFlag && runtimeFlag;
1641         }
1642 
isCharging()1643         boolean isCharging() {
1644             return mContext.getSystemService(BatteryManager.class).isCharging();
1645         }
1646 
isPowerSaveWhitelistExceptIdleApp(String packageName)1647         boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
1648             return mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName);
1649         }
1650 
getDataSystemDirectory()1651         File getDataSystemDirectory() {
1652             return Environment.getDataSystemDirectory();
1653         }
1654 
noteEvent(int event, String packageName, int uid)1655         void noteEvent(int event, String packageName, int uid) throws RemoteException {
1656             mBatteryStats.noteEvent(event, packageName, uid);
1657         }
1658 
isPackageEphemeral(int userId, String packageName)1659         boolean isPackageEphemeral(int userId, String packageName) {
1660             return mPackageManagerInternal.isPackageEphemeral(userId, packageName);
1661         }
1662 
isPackageInstalled(String packageName, int flags, int userId)1663         boolean isPackageInstalled(String packageName, int flags, int userId) {
1664             return mPackageManagerInternal.getPackageUid(packageName, flags, userId) >= 0;
1665         }
1666 
getRunningUserIds()1667         int[] getRunningUserIds() throws RemoteException {
1668             return ActivityManager.getService().getRunningUserIds();
1669         }
1670 
isDefaultDisplayOn()1671         boolean isDefaultDisplayOn() {
1672             return mDisplayManager
1673                     .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON;
1674         }
1675 
registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler)1676         void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) {
1677             mDisplayManager.registerDisplayListener(listener, handler);
1678         }
1679 
getActiveNetworkScorer()1680         String getActiveNetworkScorer() {
1681             NetworkScoreManager nsm = (NetworkScoreManager) mContext.getSystemService(
1682                     Context.NETWORK_SCORE_SERVICE);
1683             return nsm.getActiveScorerPackage();
1684         }
1685 
isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName, int userId)1686         public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName,
1687                 int userId) {
1688             return appWidgetManager.isBoundWidgetPackage(packageName, userId);
1689         }
1690 
getAppIdleSettings()1691         String getAppIdleSettings() {
1692             return Global.getString(mContext.getContentResolver(),
1693                     Global.APP_IDLE_CONSTANTS);
1694         }
1695 
1696         /** Whether the device is in doze or not. */
isDeviceIdleMode()1697         public boolean isDeviceIdleMode() {
1698             return mPowerManager.isDeviceIdleMode();
1699         }
1700     }
1701 
1702     class AppStandbyHandler extends Handler {
1703 
AppStandbyHandler(Looper looper)1704         AppStandbyHandler(Looper looper) {
1705             super(looper);
1706         }
1707 
1708         @Override
handleMessage(Message msg)1709         public void handleMessage(Message msg) {
1710             switch (msg.what) {
1711                 case MSG_INFORM_LISTENERS:
1712                     StandbyUpdateRecord r = (StandbyUpdateRecord) msg.obj;
1713                     informListeners(r.packageName, r.userId, r.bucket, r.reason,
1714                             r.isUserInteraction);
1715                     r.recycle();
1716                     break;
1717 
1718                 case MSG_FORCE_IDLE_STATE:
1719                     forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1);
1720                     break;
1721 
1722                 case MSG_CHECK_IDLE_STATES:
1723                     if (checkIdleStates(msg.arg1) && mAppIdleEnabled) {
1724                         mHandler.sendMessageDelayed(mHandler.obtainMessage(
1725                                 MSG_CHECK_IDLE_STATES, msg.arg1, 0),
1726                                 mCheckIdleIntervalMillis);
1727                     }
1728                     break;
1729 
1730                 case MSG_ONE_TIME_CHECK_IDLE_STATES:
1731                     mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
1732                     waitForAdminData();
1733                     checkIdleStates(UserHandle.USER_ALL);
1734                     break;
1735 
1736                 case MSG_CHECK_PAROLE_TIMEOUT:
1737                     checkParoleTimeout();
1738                     break;
1739 
1740                 case MSG_PAROLE_END_TIMEOUT:
1741                     if (DEBUG) Slog.d(TAG, "Ending parole");
1742                     setAppIdleParoled(false);
1743                     break;
1744 
1745                 case MSG_REPORT_CONTENT_PROVIDER_USAGE:
1746                     SomeArgs args = (SomeArgs) msg.obj;
1747                     reportContentProviderUsage((String) args.arg1, // authority name
1748                             (String) args.arg2, // package name
1749                             (int) args.arg3); // userId
1750                     args.recycle();
1751                     break;
1752 
1753                 case MSG_PAROLE_STATE_CHANGED:
1754                     if (DEBUG) Slog.d(TAG, "Parole state: " + mAppIdleTempParoled
1755                             + ", Charging state:" + mChargingStable);
1756                     informParoleStateChanged();
1757                     break;
1758                 case MSG_CHECK_PACKAGE_IDLE_STATE:
1759                     checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
1760                             mInjector.elapsedRealtime());
1761                     break;
1762 
1763                 case MSG_REPORT_SYNC_SCHEDULED:
1764                     final boolean exempted = msg.arg1 > 0 ? true : false;
1765                     if (exempted) {
1766                         reportExemptedSyncScheduled((String) msg.obj, msg.arg1);
1767                     } else {
1768                         reportUnexemptedSyncScheduled((String) msg.obj, msg.arg1);
1769                     }
1770                     break;
1771 
1772                 case MSG_REPORT_EXEMPTED_SYNC_START:
1773                     reportExemptedSyncStart((String) msg.obj, msg.arg1);
1774                     break;
1775 
1776                 case MSG_UPDATE_STABLE_CHARGING:
1777                     updateChargingStableState();
1778                     break;
1779 
1780                 default:
1781                     super.handleMessage(msg);
1782                     break;
1783 
1784             }
1785         }
1786     };
1787 
1788     private class DeviceStateReceiver extends BroadcastReceiver {
1789         @Override
onReceive(Context context, Intent intent)1790         public void onReceive(Context context, Intent intent) {
1791             switch (intent.getAction()) {
1792                 case BatteryManager.ACTION_CHARGING:
1793                     setChargingState(true);
1794                     break;
1795                 case BatteryManager.ACTION_DISCHARGING:
1796                     setChargingState(false);
1797                     break;
1798                 case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
1799                     onDeviceIdleModeChanged();
1800                     break;
1801             }
1802         }
1803     }
1804 
1805     private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder().build();
1806 
1807     private final ConnectivityManager.NetworkCallback mNetworkCallback
1808             = new ConnectivityManager.NetworkCallback() {
1809         @Override
1810         public void onAvailable(Network network) {
1811             mConnectivityManager.unregisterNetworkCallback(this);
1812             checkParoleTimeout();
1813         }
1814     };
1815 
1816     private final DisplayManager.DisplayListener mDisplayListener
1817             = new DisplayManager.DisplayListener() {
1818 
1819         @Override public void onDisplayAdded(int displayId) {
1820         }
1821 
1822         @Override public void onDisplayRemoved(int displayId) {
1823         }
1824 
1825         @Override public void onDisplayChanged(int displayId) {
1826             if (displayId == Display.DEFAULT_DISPLAY) {
1827                 final boolean displayOn = isDisplayOn();
1828                 synchronized (mAppIdleLock) {
1829                     mAppIdleHistory.updateDisplay(displayOn, mInjector.elapsedRealtime());
1830                 }
1831             }
1832         }
1833     };
1834 
1835     /**
1836      * Observe settings changes for {@link Global#APP_IDLE_CONSTANTS}.
1837      */
1838     private class SettingsObserver extends ContentObserver {
1839         /**
1840          * This flag has been used to disable app idle on older builds with bug b/26355386.
1841          */
1842         @Deprecated
1843         private static final String KEY_IDLE_DURATION_OLD = "idle_duration";
1844         @Deprecated
1845         private static final String KEY_IDLE_DURATION = "idle_duration2";
1846         @Deprecated
1847         private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold";
1848 
1849         private static final String KEY_PAROLE_INTERVAL = "parole_interval";
1850         private static final String KEY_PAROLE_WINDOW = "parole_window";
1851         private static final String KEY_PAROLE_DURATION = "parole_duration";
1852         private static final String KEY_SCREEN_TIME_THRESHOLDS = "screen_thresholds";
1853         private static final String KEY_ELAPSED_TIME_THRESHOLDS = "elapsed_thresholds";
1854         private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration";
1855         private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION =
1856                 "notification_seen_duration";
1857         private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION =
1858                 "system_update_usage_duration";
1859         private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout";
1860         private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration";
1861         private static final String KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION =
1862                 "exempted_sync_scheduled_nd_duration";
1863         private static final String KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION =
1864                 "exempted_sync_scheduled_d_duration";
1865         private static final String KEY_EXEMPTED_SYNC_START_HOLD_DURATION =
1866                 "exempted_sync_start_duration";
1867         private static final String KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION =
1868                 "unexempted_sync_scheduled_duration";
1869         private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
1870                 "system_interaction_duration";
1871         private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION =
1872                 "initial_foreground_service_start_duration";
1873         private static final String KEY_STABLE_CHARGING_THRESHOLD = "stable_charging_threshold";
1874         public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
1875         public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR;
1876         public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
1877         public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
1878         public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
1879         public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = 10 * ONE_MINUTE;
1880         public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 4 * ONE_HOUR;
1881         public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE;
1882         public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE;
1883         public static final long DEFAULT_STABLE_CHARGING_THRESHOLD = 10 * ONE_MINUTE;
1884         public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE;
1885 
1886         private final KeyValueListParser mParser = new KeyValueListParser(',');
1887 
SettingsObserver(Handler handler)1888         SettingsObserver(Handler handler) {
1889             super(handler);
1890         }
1891 
registerObserver()1892         void registerObserver() {
1893             final ContentResolver cr = mContext.getContentResolver();
1894             cr.registerContentObserver(Global.getUriFor(Global.APP_IDLE_CONSTANTS), false, this);
1895             cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this);
1896             cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED),
1897                     false, this);
1898         }
1899 
1900         @Override
onChange(boolean selfChange)1901         public void onChange(boolean selfChange) {
1902             updateSettings();
1903             postOneTimeCheckIdleStates();
1904         }
1905 
updateSettings()1906         void updateSettings() {
1907             if (DEBUG) {
1908                 Slog.d(TAG,
1909                         "appidle=" + Global.getString(mContext.getContentResolver(),
1910                                 Global.APP_STANDBY_ENABLED));
1911                 Slog.d(TAG,
1912                         "adaptivebat=" + Global.getString(mContext.getContentResolver(),
1913                                 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED));
1914                 Slog.d(TAG, "appidleconstants=" + Global.getString(
1915                         mContext.getContentResolver(),
1916                         Global.APP_IDLE_CONSTANTS));
1917             }
1918 
1919             // Look at global settings for this.
1920             // TODO: Maybe apply different thresholds for different users.
1921             try {
1922                 mParser.setString(mInjector.getAppIdleSettings());
1923             } catch (IllegalArgumentException e) {
1924                 Slog.e(TAG, "Bad value for app idle settings: " + e.getMessage());
1925                 // fallthrough, mParser is empty and all defaults will be returned.
1926             }
1927 
1928             synchronized (mAppIdleLock) {
1929 
1930                 // Default: 24 hours between paroles
1931                 mAppIdleParoleIntervalMillis = mParser.getDurationMillis(KEY_PAROLE_INTERVAL,
1932                         COMPRESS_TIME ? ONE_MINUTE * 10 : 24 * 60 * ONE_MINUTE);
1933 
1934                 // Default: 2 hours to wait on network
1935                 mAppIdleParoleWindowMillis = mParser.getDurationMillis(KEY_PAROLE_WINDOW,
1936                         COMPRESS_TIME ? ONE_MINUTE * 2 : 2 * 60 * ONE_MINUTE);
1937 
1938                 mAppIdleParoleDurationMillis = mParser.getDurationMillis(KEY_PAROLE_DURATION,
1939                         COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE); // 10 minutes
1940 
1941                 String screenThresholdsValue = mParser.getString(KEY_SCREEN_TIME_THRESHOLDS, null);
1942                 mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue,
1943                         SCREEN_TIME_THRESHOLDS);
1944 
1945                 String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS,
1946                         null);
1947                 mAppStandbyElapsedThresholds = parseLongArray(elapsedThresholdsValue,
1948                         ELAPSED_TIME_THRESHOLDS);
1949                 mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4,
1950                         COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours
1951                 mStrongUsageTimeoutMillis = mParser.getDurationMillis(
1952                         KEY_STRONG_USAGE_HOLD_DURATION,
1953                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STRONG_USAGE_TIMEOUT);
1954                 mNotificationSeenTimeoutMillis = mParser.getDurationMillis(
1955                         KEY_NOTIFICATION_SEEN_HOLD_DURATION,
1956                                 COMPRESS_TIME ? 12 * ONE_MINUTE : DEFAULT_NOTIFICATION_TIMEOUT);
1957                 mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis(
1958                         KEY_SYSTEM_UPDATE_HOLD_DURATION,
1959                                 COMPRESS_TIME ? 2 * ONE_MINUTE : DEFAULT_SYSTEM_UPDATE_TIMEOUT);
1960                 mPredictionTimeoutMillis = mParser.getDurationMillis(
1961                         KEY_PREDICTION_TIMEOUT,
1962                                 COMPRESS_TIME ? 10 * ONE_MINUTE : DEFAULT_PREDICTION_TIMEOUT);
1963                 mSyncAdapterTimeoutMillis = mParser.getDurationMillis(
1964                         KEY_SYNC_ADAPTER_HOLD_DURATION,
1965                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT);
1966 
1967                 mExemptedSyncScheduledNonDozeTimeoutMillis = mParser.getDurationMillis(
1968                         KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION,
1969                                 COMPRESS_TIME ? (ONE_MINUTE / 2)
1970                                         : DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT);
1971 
1972                 mExemptedSyncScheduledDozeTimeoutMillis = mParser.getDurationMillis(
1973                         KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION,
1974                                 COMPRESS_TIME ? ONE_MINUTE
1975                                         : DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT);
1976 
1977                 mExemptedSyncStartTimeoutMillis = mParser.getDurationMillis(
1978                         KEY_EXEMPTED_SYNC_START_HOLD_DURATION,
1979                                 COMPRESS_TIME ? ONE_MINUTE
1980                                         : DEFAULT_EXEMPTED_SYNC_START_TIMEOUT);
1981 
1982                 mUnexemptedSyncScheduledTimeoutMillis = mParser.getDurationMillis(
1983                         KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION,
1984                                 COMPRESS_TIME ? ONE_MINUTE
1985                                         : DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT); // TODO
1986 
1987                 mSystemInteractionTimeoutMillis = mParser.getDurationMillis(
1988                         KEY_SYSTEM_INTERACTION_HOLD_DURATION,
1989                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
1990 
1991                 mInitialForegroundServiceStartTimeoutMillis = mParser.getDurationMillis(
1992                         KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION,
1993                         COMPRESS_TIME ? ONE_MINUTE :
1994                                 DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT);
1995 
1996                 mStableChargingThresholdMillis = mParser.getDurationMillis(
1997                         KEY_STABLE_CHARGING_THRESHOLD,
1998                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD);
1999             }
2000 
2001             // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
2002             // in case we need to change something based on the new values.
2003             setAppIdleEnabled(mInjector.isAppIdleEnabled());
2004         }
2005 
parseLongArray(String values, long[] defaults)2006         long[] parseLongArray(String values, long[] defaults) {
2007             if (values == null) return defaults;
2008             if (values.isEmpty()) {
2009                 // Reset to defaults
2010                 return defaults;
2011             } else {
2012                 String[] thresholds = values.split("/");
2013                 if (thresholds.length == THRESHOLD_BUCKETS.length) {
2014                     long[] array = new long[THRESHOLD_BUCKETS.length];
2015                     for (int i = 0; i < THRESHOLD_BUCKETS.length; i++) {
2016                         try {
2017                             if (thresholds[i].startsWith("P") || thresholds[i].startsWith("p")) {
2018                                 array[i] = Duration.parse(thresholds[i]).toMillis();
2019                             } else {
2020                                 array[i] = Long.parseLong(thresholds[i]);
2021                             }
2022                         } catch (NumberFormatException|DateTimeParseException e) {
2023                             return defaults;
2024                         }
2025                     }
2026                     return array;
2027                 } else {
2028                     return defaults;
2029                 }
2030             }
2031         }
2032     }
2033 }
2034