Merge "Fix an issue with apps EXEMPTED after OTA"
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 40964c0..78b6077 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -24,6 +24,7 @@
 import static android.app.usage.UsageStatsManager.REASON_TIMEOUT;
 import static android.app.usage.UsageStatsManager.REASON_USAGE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
@@ -35,6 +36,7 @@
 import static org.junit.Assert.assertTrue;
 
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
@@ -80,6 +82,8 @@
 
     private static final String PACKAGE_1 = "com.example.foo";
     private static final int UID_1 = 10000;
+    private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
+    private static final int UID_EXEMPTED_1 = 10001;
     private static final int USER_ID = 0;
     private static final int USER_ID2 = 10;
 
@@ -116,7 +120,7 @@
         List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
         boolean mDisplayOn;
         DisplayManager.DisplayListener mDisplayListener;
-        String mBoundWidgetPackage;
+        String mBoundWidgetPackage = PACKAGE_EXEMPTED_1;
 
         MyInjector(Context context, Looper looper) {
             super(context, looper);
@@ -223,10 +227,21 @@
         pi.packageName = PACKAGE_1;
         packages.add(pi);
 
+        PackageInfo pie = new PackageInfo();
+        pie.applicationInfo = new ApplicationInfo();
+        pie.applicationInfo.uid = UID_EXEMPTED_1;
+        pie.packageName = PACKAGE_EXEMPTED_1;
+        packages.add(pie);
+
         doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt());
         try {
-            doReturn(UID_1).when(mockPm).getPackageUidAsUser(anyString(), anyInt(), anyInt());
-            doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(anyString(), anyInt());
+            doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt(), anyInt());
+            doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1),
+                    anyInt(), anyInt());
+            doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(eq(pi.packageName),
+                    anyInt());
+            doReturn(pie.applicationInfo).when(mockPm).getApplicationInfo(eq(pie.packageName),
+                    anyInt());
         } catch (PackageManager.NameNotFoundException nnfe) {}
     }
 
@@ -239,14 +254,21 @@
 
     private AppStandbyController setupController() throws Exception {
         mInjector.mElapsedRealtime = 0;
+        setupPm(mInjector.getContext().getPackageManager());
         AppStandbyController controller = new AppStandbyController(mInjector);
+        controller.initializeDefaultsForSystemApps(USER_ID);
         controller.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
         controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
         mInjector.setDisplayOn(false);
         mInjector.setDisplayOn(true);
         setChargingState(controller, false);
-        setupPm(mInjector.getContext().getPackageManager());
         controller.checkIdleStates(USER_ID);
+        assertEquals(STANDBY_BUCKET_EXEMPTED,
+                controller.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
+                        mInjector.mElapsedRealtime, false));
+        assertNotEquals(STANDBY_BUCKET_EXEMPTED,
+                controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
+                        mInjector.mElapsedRealtime, false));
 
         return controller;
     }
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 2becdf2..b654a66 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -228,7 +228,9 @@
             }
             if (timeout > elapsedRealtime) {
                 // Convert to elapsed timebase
-                appUsageHistory.bucketTimeoutTime = mElapsedDuration + (timeout - mElapsedSnapshot);
+                appUsageHistory.bucketTimeoutTime =
+                        Math.max(appUsageHistory.bucketTimeoutTime,
+                                mElapsedDuration + (timeout - mElapsedSnapshot));
             }
         }
         appUsageHistory.bucketingReason = REASON_USAGE;
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 8cb2eec..cc21199 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -183,6 +183,8 @@
     boolean mCharging;
     private long mLastAppIdleParoledTime;
     private boolean mSystemServicesReady = false;
+    // There was a system update, defaults need to be initialized after services are ready
+    private boolean mPendingInitializeDefaults;
 
     private final DeviceStateReceiver mDeviceStateReceiver;
 
@@ -279,6 +281,7 @@
     public void onBootPhase(int phase) {
         mInjector.onBootPhase(phase);
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
+            Slog.d(TAG, "Setting app idle enabled state");
             setAppIdleEnabled(mInjector.isAppIdleEnabled());
             // Observe changes to the threshold
             SettingsObserver settingsObserver = new SettingsObserver(mHandler);
@@ -293,11 +296,15 @@
                 mAppIdleHistory.updateDisplay(isDisplayOn(), mInjector.elapsedRealtime());
             }
 
+            mSystemServicesReady = true;
+
+            if (mPendingInitializeDefaults) {
+                initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM);
+            }
+
             if (mPendingOneTimeCheckIdleStates) {
                 postOneTimeCheckIdleStates();
             }
-
-            mSystemServicesReady = true;
         } else if (phase == PHASE_BOOT_COMPLETED) {
             setChargingState(mInjector.isCharging());
         }
@@ -451,7 +458,8 @@
                         UserHandle.getAppId(pi.applicationInfo.uid),
                         userId);
                 if (DEBUG) {
-                    Slog.d(TAG, "   Checking idle state for " + packageName);
+                    Slog.d(TAG, "   Checking idle state for " + packageName + " special=" +
+                            isSpecial);
                 }
                 if (isSpecial) {
                     synchronized (mAppIdleLock) {
@@ -523,6 +531,7 @@
                     elapsedRealtime, bucket)) {
                 StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId,
                         bucket, userStartedInteracting);
+                if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket);
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
                         StandbyUpdateRecord.obtain(packageName, userId,
                                 bucket, userStartedInteracting)));
@@ -1087,7 +1096,13 @@
     }
 
     void initializeDefaultsForSystemApps(int userId) {
-        Slog.d(TAG, "Initializing defaults for system apps on user " + userId);
+        if (!mSystemServicesReady) {
+            // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled
+            mPendingInitializeDefaults = true;
+            return;
+        }
+        Slog.d(TAG, "Initializing defaults for system apps on user " + userId + ", "
+                + "appIdleEnabled=" + mAppIdleEnabled);
         final long elapsedRealtime = mInjector.elapsedRealtime();
         List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
                 PackageManager.MATCH_DISABLED_COMPONENTS,
@@ -1102,11 +1117,6 @@
                     // past usage pattern was.
                     mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, 0,
                             elapsedRealtime + 4 * ONE_HOUR);
-                    if (isAppSpecial(packageName, UserHandle.getAppId(pi.applicationInfo.uid),
-                            userId)) {
-                        mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
-                                STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
-                    }
                 }
             }
         }