summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java1
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java53
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java54
4 files changed, 101 insertions, 10 deletions
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index d2d942a4a7e5..dc72d6d9c4b3 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -85,6 +85,7 @@ public interface AppStandbyInternal {
/**
* Checks if an app has been idle for a while and filters out apps that are excluded.
* It returns false if the current system state allows all apps to be considered active.
+ * This happens if the device is plugged in or otherwise temporarily allowed to make exceptions.
* Called by interface impls.
*/
boolean isAppIdleFiltered(String packageName, int appId, int userId,
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index f1bfa0411978..e343478ec61f 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -48,6 +48,7 @@ import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
+import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
import android.annotation.NonNull;
@@ -71,9 +72,8 @@ import android.content.pm.ParceledListSlice;
import android.database.ContentObserver;
import android.hardware.display.DisplayManager;
import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkRequest;
import android.net.NetworkScoreManager;
+import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Build;
import android.os.Environment;
@@ -285,6 +285,7 @@ public class AppStandbyController implements AppStandbyInternal {
long mInitialForegroundServiceStartTimeoutMillis;
private volatile boolean mAppIdleEnabled;
+ private boolean mIsCharging;
private boolean mSystemServicesReady = false;
// There was a system update, defaults need to be initialized after services are ready
private boolean mPendingInitializeDefaults;
@@ -360,6 +361,11 @@ public class AppStandbyController implements AppStandbyInternal {
mHandler = new AppStandbyHandler(mInjector.getLooper());
mPackageManager = mContext.getPackageManager();
+ DeviceStateReceiver deviceStateReceiver = new DeviceStateReceiver();
+ IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
+ deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
+ mContext.registerReceiver(deviceStateReceiver, deviceStates);
+
synchronized (mAppIdleLock) {
mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(),
mInjector.elapsedRealtime());
@@ -417,6 +423,8 @@ public class AppStandbyController implements AppStandbyInternal {
if (mPendingOneTimeCheckIdleStates) {
postOneTimeCheckIdleStates();
}
+ } else if (phase == PHASE_BOOT_COMPLETED) {
+ setChargingState(mInjector.isCharging());
}
}
@@ -515,6 +523,16 @@ public class AppStandbyController implements AppStandbyInternal {
appUsage.bucketingReason, false);
}
+ @VisibleForTesting
+ void setChargingState(boolean isCharging) {
+ synchronized (mAppIdleLock) {
+ if (mIsCharging != isCharging) {
+ if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging);
+ mIsCharging = isCharging;
+ }
+ }
+ }
+
@Override
public void postCheckIdleStates(int userId) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
@@ -977,6 +995,11 @@ public class AppStandbyController implements AppStandbyInternal {
if (isAppSpecial(packageName, appId, userId)) {
return false;
} else {
+ synchronized (mAppIdleLock) {
+ if (!mAppIdleEnabled || mIsCharging) {
+ return false;
+ }
+ }
return isAppIdleUnfiltered(packageName, userId, elapsedRealtime);
}
}
@@ -1543,6 +1566,8 @@ public class AppStandbyController implements AppStandbyInternal {
pw.println();
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
+ pw.print(" mIsCharging=");
+ pw.print(mIsCharging);
pw.println();
pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds));
pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds));
@@ -1560,6 +1585,7 @@ public class AppStandbyController implements AppStandbyInternal {
private final Looper mLooper;
private IDeviceIdleController mDeviceIdleController;
private IBatteryStats mBatteryStats;
+ private BatteryManager mBatteryManager;
private PackageManagerInternal mPackageManagerInternal;
private DisplayManager mDisplayManager;
private PowerManager mPowerManager;
@@ -1593,6 +1619,7 @@ public class AppStandbyController implements AppStandbyInternal {
mDisplayManager = (DisplayManager) mContext.getSystemService(
Context.DISPLAY_SERVICE);
mPowerManager = mContext.getSystemService(PowerManager.class);
+ mBatteryManager = mContext.getSystemService(BatteryManager.class);
final ActivityManager activityManager =
(ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -1630,6 +1657,10 @@ public class AppStandbyController implements AppStandbyInternal {
return buildFlag && runtimeFlag;
}
+ boolean isCharging() {
+ return mBatteryManager.isCharging();
+ }
+
boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
return mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName);
}
@@ -1766,15 +1797,19 @@ public class AppStandbyController implements AppStandbyInternal {
}
};
- private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder().build();
-
- private final ConnectivityManager.NetworkCallback mNetworkCallback
- = new ConnectivityManager.NetworkCallback() {
+ private class DeviceStateReceiver extends BroadcastReceiver {
@Override
- public void onAvailable(Network network) {
- mConnectivityManager.unregisterNetworkCallback(this);
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case BatteryManager.ACTION_CHARGING:
+ setChargingState(true);
+ break;
+ case BatteryManager.ACTION_DISCHARGING:
+ setChargingState(false);
+ break;
+ }
}
- };
+ }
private final DisplayManager.DisplayListener mDisplayListener
= new DisplayManager.DisplayListener() {
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 5668944dfd4e..2c701b48455c 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -599,7 +599,8 @@ public final class UsageStatsManager {
/**
* Returns whether the specified app is currently considered inactive. This will be true if the
* app hasn't been used directly or indirectly for a period of time defined by the system. This
- * could be of the order of several hours or days.
+ * could be of the order of several hours or days. Apps are not considered inactive when the
+ * device is charging.
* @param packageName The package name of the app to query
* @return whether the app is currently considered inactive
*/
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 e768205c2cf4..9e577636c1b3 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -145,6 +145,7 @@ public class AppStandbyControllerTests {
static class MyInjector extends AppStandbyController.Injector {
long mElapsedRealtime;
boolean mIsAppIdleEnabled = true;
+ boolean mIsCharging;
List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
boolean mDisplayOn;
DisplayManager.DisplayListener mDisplayListener;
@@ -179,6 +180,11 @@ public class AppStandbyControllerTests {
}
@Override
+ boolean isCharging() {
+ return mIsCharging;
+ }
+
+ @Override
boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
return mPowerSaveWhitelistExceptIdle.contains(packageName);
}
@@ -281,6 +287,13 @@ public class AppStandbyControllerTests {
} catch (PackageManager.NameNotFoundException nnfe) {}
}
+ private void setChargingState(AppStandbyController controller, boolean charging) {
+ mInjector.mIsCharging = charging;
+ if (controller != null) {
+ controller.setChargingState(charging);
+ }
+ }
+
private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
mInjector.mIsAppIdleEnabled = enabled;
if (controller != null) {
@@ -297,6 +310,7 @@ public class AppStandbyControllerTests {
controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
mInjector.setDisplayOn(false);
mInjector.setDisplayOn(true);
+ setChargingState(controller, false);
controller.checkIdleStates(USER_ID);
assertNotEquals(STANDBY_BUCKET_EXEMPTED,
controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
@@ -324,6 +338,46 @@ public class AppStandbyControllerTests {
mInjector.mElapsedRealtime, false));
}
+ @Test
+ public void testIsAppIdle_Charging() throws Exception {
+ setChargingState(mController, false);
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_MAIN_FORCED_BY_SYSTEM);
+ assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+ assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+ assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+
+ setChargingState(mController, true);
+ assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+ assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+ assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+
+ setChargingState(mController, false);
+ assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+ assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+ assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ }
+
+ @Test
+ public void testIsAppIdle_Enabled() throws Exception {
+ setChargingState(mController, false);
+ setAppIdleEnabled(mController, true);
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_MAIN_FORCED_BY_SYSTEM);
+ assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+ assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+ assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+
+ setAppIdleEnabled(mController, false);
+ assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+ assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+
+ setAppIdleEnabled(mController, true);
+ assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+ assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+ assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ }
+
private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
mInjector.mElapsedRealtime = elapsedTime;
controller.checkIdleStates(USER_ID);