OSDN Git Service

Fix an issue with apps EXEMPTED after OTA
authorAmith Yamasani <yamasani@google.com>
Sun, 28 Jan 2018 23:20:07 +0000 (23:20 +0000)
committerAmith Yamasani <yamasani@google.com>
Fri, 2 Feb 2018 15:46:31 +0000 (15:46 +0000)
After an OTA, all system apps were being
pushed into EXEMPTED for 4 hours because
of a race with the boot phase resulting in
it appearing as if app standby was disabled.

Another bug in updating the state out of EXEMPTED
was preventing checkIdleStates() from fixing
the issue soon after.

Bug: 72835804
Test: Manual:
        Manually delete /data/system/usagestats/version
        Reboot
        Verify that correct apps are EXEMPTED
      Automated:
        atest FrameworksServicesTests:AppStandbyControllerTests
Change-Id: Ib53f0c45e5c2e2456442f6782ad5ca9b9d0c3d72

services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
services/usage/java/com/android/server/usage/AppIdleHistory.java
services/usage/java/com/android/server/usage/AppStandbyController.java

index 40964c0..78b6077 100644 (file)
@@ -24,6 +24,7 @@ import static android.app.usage.UsageStatsManager.REASON_PREDICTED;
 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.assertNotEquals;
 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 @@ public class AppStandbyControllerTests {
 
     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 @@ public class AppStandbyControllerTests {
         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 @@ public class AppStandbyControllerTests {
         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 @@ public class AppStandbyControllerTests {
 
     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;
     }
index 2becdf2..b654a66 100644 (file)
@@ -228,7 +228,9 @@ public class AppIdleHistory {
             }
             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;
index 8cb2eec..cc21199 100644 (file)
@@ -183,6 +183,8 @@ public class AppStandbyController {
     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 class AppStandbyController {
     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 @@ public class AppStandbyController {
                 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 @@ public class AppStandbyController {
                         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 @@ public class AppStandbyController {
                     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 @@ public class AppStandbyController {
     }
 
     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 @@ public class AppStandbyController {
                     // 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);
-                    }
                 }
             }
         }