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