From 777b1537c2d8afbd3a422bb64d6f5f2f101dc1c3 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Sun, 28 Jan 2018 23:20:07 +0000 Subject: [PATCH] Fix an issue with apps EXEMPTED after OTA 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 --- .../usage/AppStandbyControllerTests.java | 30 ++++++++++++++++--- .../android/server/usage/AppIdleHistory.java | 4 ++- .../server/usage/AppStandbyController.java | 28 +++++++++++------ 3 files changed, 48 insertions(+), 14 deletions(-) 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 40964c03db814..78b6077dc1bdf 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_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 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; } diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java index 2becdf230dbca..b654a66f7d30a 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 @@ 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; diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 8cb2eecc654a5..cc21199edfd9e 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 @@ 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 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); - } } } }