Home | History | Annotate | Download | only in usage
      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 
    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 
    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 
    304         public void recycle() {
    305             synchronized (sStandbyUpdatePool) {
    306                 sStandbyUpdatePool.add(this);
    307             }
    308         }
    309     }
    310 
    311     AppStandbyController(Context context, Looper looper) {
    312         this(new Injector(context, looper));
    313     }
    314 
    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 
    342     void setAppIdleEnabled(boolean enabled) {
    343         mAppIdleEnabled = enabled;
    344     }
    345 
    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 
    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 
    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 
    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 
    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 
    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 */
    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 
    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 
    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 
    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 
    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 
    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      */
    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      */
    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. */
    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. */
    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 */
    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")
    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      */
    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 
    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 
    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 
    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 
    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      */
    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 
    933     public void setLastJobRunTime(String packageName, int userId, long elapsedRealtime) {
    934         synchronized (mAppIdleLock) {
    935             mAppIdleHistory.setLastJobRunTime(packageName, userId, elapsedRealtime);
    936         }
    937     }
    938 
    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 
    946     public void onUserRemoved(int userId) {
    947         synchronized (mAppIdleLock) {
    948             mAppIdleHistory.onUserRemoved(userId);
    949             synchronized (mActiveAdminApps) {
    950                 mActiveAdminApps.remove(userId);
    951             }
    952         }
    953     }
    954 
    955     private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
    956         synchronized (mAppIdleLock) {
    957             return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
    958         }
    959     }
    960 
    961     void addListener(AppIdleStateChangeListener listener) {
    962         synchronized (mPackageAccessListeners) {
    963             if (!mPackageAccessListeners.contains(listener)) {
    964                 mPackageAccessListeners.add(listener);
    965             }
    966         }
    967     }
    968 
    969     void removeListener(AppIdleStateChangeListener listener) {
    970         synchronized (mPackageAccessListeners) {
    971             mPackageAccessListeners.remove(listener);
    972         }
    973     }
    974 
    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 
    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 */
    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      */
   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 
   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 
   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 
   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 
   1150     public List<AppStandbyInfo> getAppStandbyBuckets(int userId) {
   1151         synchronized (mAppIdleLock) {
   1152             return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled);
   1153         }
   1154     }
   1155 
   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 
   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
   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 
   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 
   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 
   1246     public void onAdminDataAvailable() {
   1247         mAdminDataAvailableLatch.countDown();
   1248     }
   1249 
   1250     /**
   1251      * This will only ever be called once - during device boot.
   1252      */
   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 
   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      */
   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 
   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 
   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")
   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 
   1309     private boolean isActiveNetworkScorer(String packageName) {
   1310         String activeScorer = mInjector.getActiveNetworkScorer();
   1311         return packageName != null && packageName.equals(activeScorer);
   1312     }
   1313 
   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 
   1327     void informParoleStateChanged() {
   1328         final boolean paroled = isParoledOrCharging();
   1329         synchronized (mPackageAccessListeners) {
   1330             for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
   1331                 listener.onParoleStateChanged(paroled);
   1332             }
   1333         }
   1334     }
   1335 
   1336     void flushToDisk(int userId) {
   1337         synchronized (mAppIdleLock) {
   1338             mAppIdleHistory.writeAppIdleTimes(userId);
   1339         }
   1340     }
   1341 
   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 
   1350     boolean isDisplayOn() {
   1351         return mInjector.isDefaultDisplayOn();
   1352     }
   1353 
   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
   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 
   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 
   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 
   1414     void postReportExemptedSyncScheduled(String packageName, int userId) {
   1415         mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_SCHEDULED, userId, 0, packageName)
   1416                 .sendToTarget();
   1417     }
   1418 
   1419     void postReportExemptedSyncStart(String packageName, int userId) {
   1420         mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName)
   1421                 .sendToTarget();
   1422     }
   1423 
   1424     void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) {
   1425         synchronized (mAppIdleLock) {
   1426             mAppIdleHistory.dump(idpw, userId, pkg);
   1427         }
   1428     }
   1429 
   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 
   1496         Injector(Context context, Looper looper) {
   1497             mContext = context;
   1498             mLooper = looper;
   1499         }
   1500 
   1501         Context getContext() {
   1502             return mContext;
   1503         }
   1504 
   1505         Looper getLooper() {
   1506             return mLooper;
   1507         }
   1508 
   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 
   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          */
   1532         long elapsedRealtime() {
   1533             return SystemClock.elapsedRealtime();
   1534         }
   1535 
   1536         long currentTimeMillis() {
   1537             return System.currentTimeMillis();
   1538         }
   1539 
   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 
   1550         boolean isCharging() {
   1551             return mContext.getSystemService(BatteryManager.class).isCharging();
   1552         }
   1553 
   1554         boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
   1555             return mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName);
   1556         }
   1557 
   1558         File getDataSystemDirectory() {
   1559             return Environment.getDataSystemDirectory();
   1560         }
   1561 
   1562         void noteEvent(int event, String packageName, int uid) throws RemoteException {
   1563             mBatteryStats.noteEvent(event, packageName, uid);
   1564         }
   1565 
   1566         boolean isPackageEphemeral(int userId, String packageName) {
   1567             return mPackageManagerInternal.isPackageEphemeral(userId, packageName);
   1568         }
   1569 
   1570         int[] getRunningUserIds() throws RemoteException {
   1571             return ActivityManager.getService().getRunningUserIds();
   1572         }
   1573 
   1574         boolean isDefaultDisplayOn() {
   1575             return mDisplayManager
   1576                     .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON;
   1577         }
   1578 
   1579         void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) {
   1580             mDisplayManager.registerDisplayListener(listener, handler);
   1581         }
   1582 
   1583         String getActiveNetworkScorer() {
   1584             NetworkScoreManager nsm = (NetworkScoreManager) mContext.getSystemService(
   1585                     Context.NETWORK_SCORE_SERVICE);
   1586             return nsm.getActiveScorerPackage();
   1587         }
   1588 
   1589         public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName,
   1590                 int userId) {
   1591             return appWidgetManager.isBoundWidgetPackage(packageName, userId);
   1592         }
   1593 
   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. */
   1600         public boolean isDeviceIdleMode() {
   1601             return mPowerManager.isDeviceIdleMode();
   1602         }
   1603     }
   1604 
   1605     class AppStandbyHandler extends Handler {
   1606 
   1607         AppStandbyHandler(Looper looper) {
   1608             super(looper);
   1609         }
   1610 
   1611         @Override
   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
   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 
   1780         SettingsObserver(Handler handler) {
   1781             super(handler);
   1782         }
   1783 
   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
   1793         public void onChange(boolean selfChange) {
   1794             updateSettings();
   1795             postOneTimeCheckIdleStates();
   1796         }
   1797 
   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 
   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