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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user