Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 777b1537 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

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
parent faf85253
Loading
Loading
Loading
Loading
+26 −4
Original line number Diff line number Diff line
@@ -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;
    }
+3 −1
Original line number Diff line number Diff line
@@ -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;
+19 −9
Original line number Diff line number Diff line
@@ -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);
                    }
                }
            }
        }