Extreme battery saver: AlarmManager
- AlarmManagerService now uses ForceAppStandbyTracker.
- Now AlarmManagerService uses the system + user power-save whitelist,
rather than just the user whitelist.
Test: Manual test
Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
Bug 68769804
Change-Id: Ie2bd17fe0c3cb8b09ec4c4a78f9254277be16926
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 3904fc9..4330f5d 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -46,7 +46,6 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -55,7 +54,6 @@
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Slog;
@@ -81,6 +79,7 @@
import java.util.Random;
import java.util.TimeZone;
import java.util.TreeSet;
+import java.util.function.Predicate;
import static android.app.AlarmManager.RTC_WAKEUP;
import static android.app.AlarmManager.RTC;
@@ -88,11 +87,17 @@
import static android.app.AlarmManager.ELAPSED_REALTIME;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IAppOpsCallback;
-import com.android.internal.app.IAppOpsService;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.LocalLog;
+import com.android.server.ForceAppStandbyTracker.Listener;
+/**
+ * Alarm manager implementaion.
+ *
+ * Unit test:
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AlarmManagerServiceTest.java
+ */
class AlarmManagerService extends SystemService {
private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
private static final int RTC_MASK = 1 << RTC;
@@ -131,13 +136,10 @@
final LocalLog mLog = new LocalLog(TAG);
AppOpsManager mAppOps;
- IAppOpsService mAppOpsService;
DeviceIdleController.LocalService mLocalDeviceIdleController;
final Object mLock = new Object();
- ArraySet<String> mForcedAppStandbyPackages = new ArraySet<>();
- SparseBooleanArray mForegroundUids = new SparseBooleanArray();
// List of alarms per uid deferred due to user applied background restrictions on the source app
SparseArray<ArrayList<Alarm>> mPendingBackgroundAlarms = new SparseArray<>();
long mNativeData;
@@ -184,12 +186,6 @@
int mSystemUiUid;
/**
- * The current set of user whitelisted apps for device idle mode, meaning these are allowed
- * to freely schedule alarms.
- */
- int[] mDeviceIdleUserWhitelist = new int[0];
-
- /**
* For each uid, this is the last time we dispatched an "allow while idle" alarm,
* used to determine the earliest we can dispatch the next such alarm. Times are in the
* 'elapsed' timebase.
@@ -223,6 +219,8 @@
private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
new SparseArray<>();
+ private final ForceAppStandbyTracker mForceAppStandbyTracker;
+
/**
* All times are in milliseconds. These constants are kept synchronized with the system
* global Settings. Any access to this class or its fields should be done while
@@ -757,6 +755,9 @@
public AlarmManagerService(Context context) {
super(context);
mConstants = new Constants(mHandler);
+
+ mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
+ mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
}
static long convertToElapsed(long when, int type) {
@@ -894,17 +895,48 @@
deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, SystemClock.elapsedRealtime());
}
- void sendPendingBackgroundAlarmsForAppIdLocked(int appId) {
+ /**
+ * Check all alarms in {@link #mPendingBackgroundAlarms} and send the ones that are not
+ * restricted.
+ *
+ * This is only called when the global "force all apps-standby" flag changes or when the
+ * power save whitelist changes, so it's okay to be slow.
+ */
+ void sendAllUnrestrictedPendingBackgroundAlarmsLocked() {
final ArrayList<Alarm> alarmsToDeliver = new ArrayList<>();
- for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
- final int uid = mPendingBackgroundAlarms.keyAt(i);
- final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
- if (UserHandle.getAppId(uid) == appId) {
- alarmsToDeliver.addAll(alarmsForUid);
- mPendingBackgroundAlarms.removeAt(i);
+
+ findAllUnrestrictedPendingBackgroundAlarmsLockedInner(
+ mPendingBackgroundAlarms, alarmsToDeliver, this::isBackgroundRestricted);
+
+ if (alarmsToDeliver.size() > 0) {
+ deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, SystemClock.elapsedRealtime());
+ }
+ }
+
+ @VisibleForTesting
+ static void findAllUnrestrictedPendingBackgroundAlarmsLockedInner(
+ SparseArray<ArrayList<Alarm>> pendingAlarms, ArrayList<Alarm> unrestrictedAlarms,
+ Predicate<Alarm> isBackgroundRestricted) {
+
+ for (int uidIndex = pendingAlarms.size() - 1; uidIndex >= 0; uidIndex--) {
+ final int uid = pendingAlarms.keyAt(uidIndex);
+ final ArrayList<Alarm> alarmsForUid = pendingAlarms.valueAt(uidIndex);
+
+ for (int alarmIndex = alarmsForUid.size() - 1; alarmIndex >= 0; alarmIndex--) {
+ final Alarm alarm = alarmsForUid.get(alarmIndex);
+
+ if (isBackgroundRestricted.test(alarm)) {
+ continue;
+ }
+
+ unrestrictedAlarms.add(alarm);
+ alarmsForUid.remove(alarmIndex);
+ }
+
+ if (alarmsForUid.size() == 0) {
+ pendingAlarms.removeAt(uidIndex);
}
}
- deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, SystemClock.elapsedRealtime());
}
private void deliverPendingBackgroundAlarmsLocked(ArrayList<Alarm> alarms, long nowELAPSED) {
@@ -1234,10 +1266,8 @@
} catch (RemoteException e) {
// ignored; both services live in system_server
}
- mAppOpsService = IAppOpsService.Stub.asInterface(
- ServiceManager.getService(Context.APP_OPS_SERVICE));
publishBinderService(Context.ALARM_SERVICE, mService);
- publishLocalService(LocalService.class, new LocalService());
+ mForceAppStandbyTracker.start();
}
@Override
@@ -1247,13 +1277,6 @@
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mLocalDeviceIdleController
= LocalServices.getService(DeviceIdleController.LocalService.class);
- try {
- mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
- new AppOpsWatcher());
- } catch (RemoteException rexc) {
- // Shouldn't happen as they are in the same process.
- Slog.e(TAG, "AppOps service not reachable", rexc);
- }
}
}
@@ -1582,8 +1605,7 @@
// timing restrictions.
} else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
|| callingUid == mSystemUiUid
- || Arrays.binarySearch(mDeviceIdleUserWhitelist,
- UserHandle.getAppId(callingUid)) >= 0)) {
+ || mForceAppStandbyTracker.isUidPowerSaveWhitelisted(callingUid))) {
flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
}
@@ -1660,24 +1682,14 @@
}
};
- public final class LocalService {
- public void setDeviceIdleUserWhitelist(int[] appids) {
- setDeviceIdleUserWhitelistImpl(appids);
- }
- }
-
void dumpImpl(PrintWriter pw) {
synchronized (mLock) {
pw.println("Current Alarm Manager state:");
mConstants.dump(pw);
pw.println();
- pw.print(" Foreground uids: [");
- for (int i = 0; i < mForegroundUids.size(); i++) {
- if (mForegroundUids.valueAt(i)) pw.print(mForegroundUids.keyAt(i) + " ");
- }
- pw.println("]");
- pw.println(" Forced app standby packages: " + mForcedAppStandbyPackages);
+ mForceAppStandbyTracker.dump(pw, " ");
+
final long nowRTC = System.currentTimeMillis();
final long nowELAPSED = SystemClock.elapsedRealtime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -1717,7 +1729,6 @@
pw.print(" set at "); TimeUtils.formatDuration(mLastWakeupSet, nowELAPSED, pw);
pw.println();
pw.print(" Num time change events: "); pw.println(mNumTimeChanged);
- pw.println(" mDeviceIdleUserWhitelist=" + Arrays.toString(mDeviceIdleUserWhitelist));
pw.println();
pw.println(" Next alarm clock information: ");
@@ -1990,15 +2001,8 @@
mConstants.dumpProto(proto, AlarmManagerServiceProto.SETTINGS);
- final int foregroundUidsSize = mForegroundUids.size();
- for (int i = 0; i < foregroundUidsSize; i++) {
- if (mForegroundUids.valueAt(i)) {
- proto.write(AlarmManagerServiceProto.FOREGROUND_UIDS, mForegroundUids.keyAt(i));
- }
- }
- for (String pkg : mForcedAppStandbyPackages) {
- proto.write(AlarmManagerServiceProto.FORCED_APP_STANDBY_PACKAGES, pkg);
- }
+ mForceAppStandbyTracker.dumpProto(proto,
+ AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER);
proto.write(AlarmManagerServiceProto.IS_INTERACTIVE, mInteractive);
if (!mInteractive) {
@@ -2022,9 +2026,6 @@
proto.write(AlarmManagerServiceProto.TIME_SINCE_LAST_WAKEUP_SET_MS,
nowElapsed - mLastWakeupSet);
proto.write(AlarmManagerServiceProto.TIME_CHANGE_EVENT_COUNT, mNumTimeChanged);
- for (int i : mDeviceIdleUserWhitelist) {
- proto.write(AlarmManagerServiceProto.DEVICE_IDLE_USER_WHITELIST_APP_IDS, i);
- }
final TreeSet<Integer> users = new TreeSet<>();
final int nextAlarmClockForUserSize = mNextAlarmClockForUser.size();
@@ -2266,28 +2267,6 @@
}
}
- void setDeviceIdleUserWhitelistImpl(int[] appids) {
- synchronized (mLock) {
- // appids are sorted, just send pending alarms for any new appids added to the whitelist
- int i = 0, j = 0;
- while (i < appids.length) {
- while (j < mDeviceIdleUserWhitelist.length
- && mDeviceIdleUserWhitelist[j] < appids[i]) {
- j++;
- }
- if (j < mDeviceIdleUserWhitelist.length
- && appids[i] != mDeviceIdleUserWhitelist[j]) {
- if (DEBUG_BG_LIMIT) {
- Slog.d(TAG, "Sending blocked alarms for whitelisted appid " + appids[j]);
- }
- sendPendingBackgroundAlarmsForAppIdLocked(appids[j]);
- }
- i++;
- }
- mDeviceIdleUserWhitelist = appids;
- }
- }
-
AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
synchronized (mLock) {
return mNextAlarmClockForUser.get(userId);
@@ -2710,9 +2689,7 @@
final String sourcePackage =
(alarm.operation != null) ? alarm.operation.getCreatorPackage() : alarm.packageName;
final int sourceUid = alarm.creatorUid;
- return mForcedAppStandbyPackages.contains(sourcePackage) && !mForegroundUids.get(sourceUid)
- && Arrays.binarySearch(mDeviceIdleUserWhitelist, UserHandle.getAppId(sourceUid))
- < 0;
+ return mForceAppStandbyTracker.areAlarmsRestricted(sourceUid, sourcePackage);
}
private native long init();
@@ -2859,7 +2836,8 @@
}
}
- private static class Alarm {
+ @VisibleForTesting
+ static class Alarm {
public final int type;
public final long origWhen;
public final boolean wakeup;
@@ -3476,17 +3454,10 @@
if (disabled) {
removeForStoppedLocked(uid);
}
- mForegroundUids.delete(uid);
}
}
@Override public void onUidActive(int uid) {
- synchronized (mLock) {
- if (!mForegroundUids.get(uid)) {
- mForegroundUids.put(uid, true);
- sendPendingBackgroundAlarmsLocked(uid, null);
- }
- }
}
@Override public void onUidIdle(int uid, boolean disabled) {
@@ -3494,7 +3465,6 @@
if (disabled) {
removeForStoppedLocked(uid);
}
- mForegroundUids.delete(uid);
}
}
@@ -3502,27 +3472,29 @@
}
};
- private final class AppOpsWatcher extends IAppOpsCallback.Stub {
+
+ private final Listener mForceAppStandbyListener = new Listener() {
@Override
- public void opChanged(int op, int uid, String packageName) throws RemoteException {
+ public void unblockAllUnrestrictedAlarms() {
synchronized (mLock) {
- final int mode = mAppOpsService.checkOperation(op, uid, packageName);
- if (DEBUG_BG_LIMIT) {
- Slog.d(TAG,
- "Appop changed for " + uid + ", " + packageName + " to " + mode);
- }
- final boolean changed;
- if (mode != AppOpsManager.MODE_ALLOWED) {
- changed = mForcedAppStandbyPackages.add(packageName);
- } else {
- changed = mForcedAppStandbyPackages.remove(packageName);
- }
- if (changed && mode == AppOpsManager.MODE_ALLOWED) {
- sendPendingBackgroundAlarmsLocked(uid, packageName);
- }
+ sendAllUnrestrictedPendingBackgroundAlarmsLocked();
}
}
- }
+
+ @Override
+ public void unblockAlarmsForUid(int uid) {
+ synchronized (mLock) {
+ sendPendingBackgroundAlarmsLocked(uid, null);
+ }
+ }
+
+ @Override
+ public void unblockAlarmsForUidPackage(int uid, String packageName) {
+ synchronized (mLock) {
+ sendPendingBackgroundAlarmsLocked(uid, packageName);
+ }
+ }
+ };
private final BroadcastStats getStatsLocked(PendingIntent pi) {
String pkg = pi.getCreatorPackage();
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 0921a00..d7aeb8c 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -119,7 +119,6 @@
private PowerManagerInternal mLocalPowerManager;
private PowerManager mPowerManager;
private ConnectivityService mConnectivityService;
- private AlarmManagerService.LocalService mLocalAlarmManager;
private INetworkPolicyManager mNetworkPolicyManager;
private SensorManager mSensorManager;
private Sensor mMotionSensor;
@@ -1435,7 +1434,6 @@
mGoingIdleWakeLock.setReferenceCounted(true);
mConnectivityService = (ConnectivityService)ServiceManager.getService(
Context.CONNECTIVITY_SERVICE);
- mLocalAlarmManager = getLocalService(AlarmManagerService.LocalService.class);
mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
mNetworkPolicyManagerInternal = getLocalService(NetworkPolicyManagerInternal.class);
@@ -1500,8 +1498,8 @@
mLocalActivityManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
- mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
+ passWhiteListToForceAppStandbyTrackerLocked();
updateInteractivityLocked();
}
updateConnectivityState(null);
@@ -2477,13 +2475,7 @@
}
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
}
- if (mLocalAlarmManager != null) {
- if (DEBUG) {
- Slog.d(TAG, "Setting alarm whitelist to "
- + Arrays.toString(mPowerSaveWhitelistUserAppIdArray));
- }
- mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
- }
+ passWhiteListToForceAppStandbyTrackerLocked();
}
private void updateTempWhitelistAppIdsLocked(int appId, boolean adding) {
@@ -2509,6 +2501,7 @@
}
mLocalPowerManager.setDeviceIdleTempWhitelist(mTempWhitelistAppIdArray);
}
+ passWhiteListToForceAppStandbyTrackerLocked();
}
private void reportPowerSaveWhitelistChangedLocked() {
@@ -2523,6 +2516,12 @@
getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
}
+ private void passWhiteListToForceAppStandbyTrackerLocked() {
+ ForceAppStandbyTracker.getInstance(getContext()).setPowerSaveWhitelistAppIds(
+ mPowerSaveWhitelistAllAppIdArray,
+ mTempWhitelistAppIdArray);
+ }
+
void readConfigFileLocked() {
if (DEBUG) Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile());
mPowerSaveWhitelistUserApps.clear();
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index 5dd3ee0..61d3833 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -16,13 +16,18 @@
package com.android.server;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.AppOpsManager.PackageOps;
+import android.app.IActivityManager;
import android.app.IUidObserver;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.RemoteException;
@@ -30,21 +35,36 @@
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Pair;
-import android.util.Slog;
import android.util.SparseBooleanArray;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
+import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.List;
/**
- * Class to track OP_RUN_ANY_IN_BACKGROUND, UID foreground state and "force all app standby".
+ * Class to keep track of the information related to "force app standby", which includes:
+ * - OP_RUN_ANY_IN_BACKGROUND for each package
+ * - UID foreground state
+ * - User+system power save whitelist
+ * - Temporary power save whitelist
+ * - Global "force all apps standby" mode enforced by battery saver.
*
- * TODO Clean up cache when a user is deleted.
- * TODO Add unit tests. b/68769804.
+ * TODO: In general, we can reduce the number of callbacks by checking all signals before sending
+ * each callback. For example, even when an UID comes into the foreground, if it wasn't
+ * originally restricted, then there's no need to send an event.
+ * Doing this would be error-prone, so we punt it for now, but we should revisit it later.
+ *
+ * Test:
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
*/
public class ForceAppStandbyTracker {
private static final String TAG = "ForceAppStandbyTracker";
@@ -55,22 +75,32 @@
private final Object mLock = new Object();
private final Context mContext;
+ @VisibleForTesting
+ static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
+
+ IActivityManager mIActivityManager;
AppOpsManager mAppOpsManager;
IAppOpsService mAppOpsService;
PowerManagerInternal mPowerManagerInternal;
- private final Handler mCallbackHandler;
+ private final MyHandler mHandler;
/**
* Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
*/
@GuardedBy("mLock")
- final ArraySet<Pair<Integer, String>> mForcedAppStandbyUidPackages = new ArraySet<>();
+ final ArraySet<Pair<Integer, String>> mRunAnyRestrictedPackages = new ArraySet<>();
@GuardedBy("mLock")
final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
@GuardedBy("mLock")
+ private int[] mPowerWhitelistedAllAppIds = new int[0];
+
+ @GuardedBy("mLock")
+ private int[] mTempWhitelistedAppIds = mPowerWhitelistedAllAppIds;
+
+ @GuardedBy("mLock")
final ArraySet<Listener> mListeners = new ArraySet<>();
@GuardedBy("mLock")
@@ -80,16 +110,116 @@
boolean mForceAllAppsStandby;
public static abstract class Listener {
- public void onRestrictionChanged(int uid, @Nullable String packageName) {
+ /**
+ * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package.
+ */
+ private void onRunAnyAppOpsChanged(ForceAppStandbyTracker sender,
+ int uid, @NonNull String packageName) {
+ updateJobsForUidPackage(uid, packageName);
+
+ if (!sender.areAlarmsRestricted(uid, packageName)) {
+ unblockAlarmsForUidPackage(uid, packageName);
+ }
}
- public void onGlobalRestrictionChanged() {
+ /**
+ * This is called when the foreground state changed for a UID.
+ */
+ private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) {
+ updateJobsForUid(uid);
+
+ if (sender.isInForeground(uid)) {
+ unblockAlarmsForUid(uid);
+ }
+ }
+
+ /**
+ * This is called when an app-id(s) is removed from the power save whitelist.
+ */
+ private void onPowerSaveUnwhitelisted(ForceAppStandbyTracker sender) {
+ updateAllJobs();
+ unblockAllUnrestrictedAlarms();
+ }
+
+ /**
+ * This is called when the power save whitelist changes, excluding the
+ * {@link #onPowerSaveUnwhitelisted} case.
+ */
+ private void onPowerSaveWhitelistedChanged(ForceAppStandbyTracker sender) {
+ updateAllJobs();
+ }
+
+ /**
+ * This is called when the temp whitelist changes.
+ */
+ private void onTempPowerSaveWhitelistChanged(ForceAppStandbyTracker sender) {
+
+ // TODO This case happens rather frequently; consider optimizing and update jobs
+ // only for affected app-ids.
+
+ updateAllJobs();
+ }
+
+ /**
+ * This is called when the global "force all apps standby" flag changes.
+ */
+ private void onForceAllAppsStandbyChanged(ForceAppStandbyTracker sender) {
+ updateAllJobs();
+
+ if (!sender.isForceAllAppsStandbyEnabled()) {
+ unblockAllUnrestrictedAlarms();
+ }
+ }
+
+ /**
+ * Called when the job restrictions for multiple UIDs might have changed, so the job
+ * scheduler should re-evaluate all restrictions for all jobs.
+ */
+ public void updateAllJobs() {
+ }
+
+ /**
+ * Called when the job restrictions for a UID might have changed, so the job
+ * scheduler should re-evaluate all restrictions for all jobs.
+ */
+ public void updateJobsForUid(int uid) {
+ }
+
+ /**
+ * Called when the job restrictions for a UID - package might have changed, so the job
+ * scheduler should re-evaluate all restrictions for all jobs.
+ */
+ public void updateJobsForUidPackage(int uid, String packageName) {
+ }
+
+ /**
+ * Called when the job restrictions for multiple UIDs might have changed, so the alarm
+ * manager should re-evaluate all restrictions for all blocked jobs.
+ */
+ public void unblockAllUnrestrictedAlarms() {
+ }
+
+ /**
+ * Called when all jobs for a specific UID are unblocked.
+ */
+ public void unblockAlarmsForUid(int uid) {
+ }
+
+ /**
+ * Called when all alarms for a specific UID - package are unblocked.
+ */
+ public void unblockAlarmsForUidPackage(int uid, String packageName) {
}
}
- private ForceAppStandbyTracker(Context context) {
+ @VisibleForTesting
+ ForceAppStandbyTracker(Context context, Looper looper) {
mContext = context;
- mCallbackHandler = FgThread.getHandler();
+ mHandler = new MyHandler(looper);
+ }
+
+ private ForceAppStandbyTracker(Context context) {
+ this(context, FgThread.get().getLooper());
}
/**
@@ -112,45 +242,65 @@
}
mStarted = true;
- mAppOpsManager = Preconditions.checkNotNull(
- mContext.getSystemService(AppOpsManager.class));
- mAppOpsService = Preconditions.checkNotNull(
- IAppOpsService.Stub.asInterface(
- ServiceManager.getService(Context.APP_OPS_SERVICE)));
- mPowerManagerInternal = Preconditions.checkNotNull(
- LocalServices.getService(PowerManagerInternal.class));
+ mIActivityManager = Preconditions.checkNotNull(injectIActivityManager());
+ mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
+ mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
+ mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
try {
- ActivityManager.getService().registerUidObserver(new UidObserver(),
+ mIActivityManager.registerUidObserver(new UidObserver(),
ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
| ActivityManager.UID_OBSERVER_ACTIVE,
ActivityManager.PROCESS_STATE_UNKNOWN, null);
- mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
+ mAppOpsService.startWatchingMode(TARGET_OP, null,
new AppOpsWatcher());
} catch (RemoteException e) {
// shouldn't happen.
}
- mPowerManagerInternal.registerLowPowerModeObserver(
- ServiceType.FORCE_ALL_APPS_STANDBY,
- state -> updateForceAllAppsStandby(state.batterySaverEnabled));
-
- updateForceAllAppsStandby(
- mPowerManagerInternal.getLowPowerState(ServiceType.FORCE_ALL_APPS_STANDBY)
- .batterySaverEnabled);
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiver(new MyReceiver(), filter);
refreshForcedAppStandbyUidPackagesLocked();
+
+ mPowerManagerInternal.registerLowPowerModeObserver(
+ ServiceType.FORCE_ALL_APPS_STANDBY,
+ (state) -> updateForceAllAppsStandby(state.batterySaverEnabled));
+
+ updateForceAllAppsStandby(mPowerManagerInternal.getLowPowerState(
+ ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled);
}
}
+ @VisibleForTesting
+ AppOpsManager injectAppOpsManager() {
+ return mContext.getSystemService(AppOpsManager.class);
+ }
+
+ @VisibleForTesting
+ IAppOpsService injectIAppOpsService() {
+ return IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
+ }
+
+ @VisibleForTesting
+ IActivityManager injectIActivityManager() {
+ return ActivityManager.getService();
+ }
+
+ @VisibleForTesting
+ PowerManagerInternal injectPowerManagerInternal() {
+ return LocalServices.getService(PowerManagerInternal.class);
+ }
+
/**
- * Update {@link #mForcedAppStandbyUidPackages} with the current app ops state.
+ * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
*/
private void refreshForcedAppStandbyUidPackagesLocked() {
- final int op = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
-
- mForcedAppStandbyUidPackages.clear();
- final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(new int[] {op});
+ mRunAnyRestrictedPackages.clear();
+ final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(
+ new int[] {TARGET_OP});
if (ops == null) {
return;
@@ -162,31 +312,38 @@
for (int j = 0; j < entries.size(); j++) {
AppOpsManager.OpEntry ent = entries.get(j);
- if (ent.getOp() != op) {
+ if (ent.getOp() != TARGET_OP) {
continue;
}
if (ent.getMode() != AppOpsManager.MODE_ALLOWED) {
- mForcedAppStandbyUidPackages.add(Pair.create(
+ mRunAnyRestrictedPackages.add(Pair.create(
pkg.getUid(), pkg.getPackageName()));
}
}
}
}
- boolean isRunAnyInBackgroundAppOpRestricted(int uid, @NonNull String packageName) {
- try {
- return mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
- uid, packageName) != AppOpsManager.MODE_ALLOWED;
- } catch (RemoteException e) {
- return false; // shouldn't happen.
+ /**
+ * Update {@link #mForceAllAppsStandby} and notifies the listeners.
+ */
+ void updateForceAllAppsStandby(boolean enable) {
+ synchronized (mLock) {
+ if (enable == mForceAllAppsStandby) {
+ return;
+ }
+ mForceAllAppsStandby = enable;
+
+ mHandler.notifyForceAllAppsStandbyChanged();
}
}
private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
- // TODO Maybe we should switch to indexOf(Pair.create()) if the array size is too big.
- final int size = mForcedAppStandbyUidPackages.size();
+ final int size = mRunAnyRestrictedPackages.size();
+ if (size > 8) {
+ return mRunAnyRestrictedPackages.indexOf(Pair.create(uid, packageName));
+ }
for (int i = 0; i < size; i++) {
- final Pair<Integer, String> pair = mForcedAppStandbyUidPackages.valueAt(i);
+ final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
if ((pair.first == uid) && packageName.equals(pair.second)) {
return i;
@@ -196,13 +353,16 @@
}
/**
- * @return whether a uid package-name pair is in mForcedAppStandbyUidPackages.
+ * @return whether a uid package-name pair is in mRunAnyRestrictedPackages.
*/
- boolean isUidPackageRestrictedLocked(int uid, @NonNull String packageName) {
+ boolean isRunAnyRestrictedLocked(int uid, @NonNull String packageName) {
return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
}
- boolean updateRestrictedUidPackageLocked(int uid, @NonNull String packageName,
+ /**
+ * Add to / remove from {@link #mRunAnyRestrictedPackages}.
+ */
+ boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName,
boolean restricted) {
final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
final boolean wasRestricted = index >= 0;
@@ -210,13 +370,16 @@
return false;
}
if (restricted) {
- mForcedAppStandbyUidPackages.add(Pair.create(uid, packageName));
+ mRunAnyRestrictedPackages.add(Pair.create(uid, packageName));
} else {
- mForcedAppStandbyUidPackages.removeAt(index);
+ mRunAnyRestrictedPackages.removeAt(index);
}
return true;
}
+ /**
+ * Puts a UID to {@link #mForegroundUids}.
+ */
void uidToForeground(int uid) {
synchronized (mLock) {
if (!UserHandle.isApp(uid)) {
@@ -228,10 +391,13 @@
return;
}
mForegroundUids.put(uid, true);
- notifyForUidPackage(uid, null);
+ mHandler.notifyUidForegroundStateChanged(uid);
}
}
+ /**
+ * Sets false for a UID {@link #mForegroundUids}, or remove it when {@code remove} is true.
+ */
void uidToBackground(int uid, boolean remove) {
synchronized (mLock) {
if (!UserHandle.isApp(uid)) {
@@ -247,13 +413,11 @@
} else {
mForegroundUids.put(uid, false);
}
- notifyForUidPackage(uid, null);
+ mHandler.notifyUidForegroundStateChanged(uid);
}
}
- // Event handlers
-
- final class UidObserver extends IUidObserver.Stub {
+ private final class UidObserver extends IUidObserver.Stub {
@Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
}
@@ -277,11 +441,28 @@
private final class AppOpsWatcher extends IAppOpsCallback.Stub {
@Override
public void opChanged(int op, int uid, String packageName) throws RemoteException {
+ boolean restricted = false;
+ try {
+ restricted = mAppOpsService.checkOperation(TARGET_OP,
+ uid, packageName) != AppOpsManager.MODE_ALLOWED;
+ } catch (RemoteException e) {
+ // Shouldn't happen
+ }
synchronized (mLock) {
- final boolean restricted = isRunAnyInBackgroundAppOpRestricted(uid, packageName);
+ if (updateForcedAppStandbyUidPackageLocked(uid, packageName, restricted)) {
+ mHandler.notifyRunAnyAppOpsChanged(uid, packageName);
+ }
+ }
+ }
+ }
- if (updateRestrictedUidPackageLocked(uid, packageName, restricted)) {
- notifyForUidPackage(uid, packageName);
+ private final class MyReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (userId > 0) {
+ mHandler.doUserRemoved(userId);
}
}
}
@@ -293,31 +474,183 @@
}
}
- void notifyForUidPackage(int uid, String packageName) {
- mCallbackHandler.post(() -> {
- for (Listener l : cloneListeners()) {
- l.onRestrictionChanged(uid, packageName);
- }
- });
- }
+ private class MyHandler extends Handler {
+ private static final int MSG_UID_STATE_CHANGED = 1;
+ private static final int MSG_RUN_ANY_CHANGED = 2;
+ private static final int MSG_ALL_UNWHITELISTED = 3;
+ private static final int MSG_ALL_WHITELIST_CHANGED = 4;
+ private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
+ private static final int MSG_FORCE_ALL_CHANGED = 6;
- void notifyGlobal() {
- mCallbackHandler.post(() -> {
- for (Listener l : cloneListeners()) {
- l.onGlobalRestrictionChanged();
- }
- });
- }
+ private static final int MSG_USER_REMOVED = 7;
- void updateForceAllAppsStandby(boolean forceAllAppsStandby) {
- synchronized (mLock) {
- if (mForceAllAppsStandby == forceAllAppsStandby) {
- return;
- }
- mForceAllAppsStandby = forceAllAppsStandby;
- Slog.i(TAG, "Force all app standby: " + mForceAllAppsStandby);
- notifyGlobal();
+ public MyHandler(Looper looper) {
+ super(looper);
}
+
+ public void notifyUidForegroundStateChanged(int uid) {
+ obtainMessage(MSG_UID_STATE_CHANGED, uid, 0).sendToTarget();
+ }
+ public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
+ obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
+ }
+
+ public void notifyAllUnwhitelisted() {
+ obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
+ }
+
+ public void notifyAllWhitelistChanged() {
+ obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
+ }
+
+ public void notifyTempWhitelistChanged() {
+ obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
+ }
+
+ public void notifyForceAllAppsStandbyChanged() {
+ obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
+ }
+
+ public void doUserRemoved(int userId) {
+ obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
+ }
+
+ @Override
+ public void dispatchMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_USER_REMOVED:
+ handleUserRemoved(msg.arg1);
+ return;
+ }
+
+ // Only notify the listeners when started.
+ synchronized (mLock) {
+ if (!mStarted) {
+ return;
+ }
+ }
+ final ForceAppStandbyTracker sender = ForceAppStandbyTracker.this;
+
+ switch (msg.what) {
+ case MSG_UID_STATE_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onUidForegroundStateChanged(sender, msg.arg1);
+ }
+ return;
+ case MSG_RUN_ANY_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onRunAnyAppOpsChanged(sender, msg.arg1, (String) msg.obj);
+ }
+ return;
+ case MSG_ALL_UNWHITELISTED:
+ for (Listener l : cloneListeners()) {
+ l.onPowerSaveUnwhitelisted(sender);
+ }
+ return;
+ case MSG_ALL_WHITELIST_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onPowerSaveWhitelistedChanged(sender);
+ }
+ return;
+ case MSG_TEMP_WHITELIST_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onTempPowerSaveWhitelistChanged(sender);
+ }
+ return;
+ case MSG_FORCE_ALL_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onForceAllAppsStandbyChanged(sender);
+ }
+ return;
+ case MSG_USER_REMOVED:
+ handleUserRemoved(msg.arg1);
+ return;
+ }
+ }
+ }
+
+ void handleUserRemoved(int removedUserId) {
+ synchronized (mLock) {
+ for (int i = mRunAnyRestrictedPackages.size() - 1; i >= 0; i--) {
+ final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
+ final int uid = pair.first;
+ final int userId = UserHandle.getUserId(uid);
+
+ if (userId == removedUserId) {
+ mRunAnyRestrictedPackages.removeAt(i);
+ }
+ }
+ for (int i = mForegroundUids.size() - 1; i >= 0; i--) {
+ final int uid = mForegroundUids.keyAt(i);
+ final int userId = UserHandle.getUserId(uid);
+
+ if (userId == removedUserId) {
+ mForegroundUids.removeAt(i);
+ }
+ }
+ }
+ }
+
+ /**
+ * Called by device idle controller to update the power save whitelists.
+ */
+ public void setPowerSaveWhitelistAppIds(
+ int[] powerSaveWhitelistAllAppIdArray, int[] tempWhitelistAppIdArray) {
+ synchronized (mLock) {
+ final int[] previousWhitelist = mPowerWhitelistedAllAppIds;
+ final int[] previousTempWhitelist = mTempWhitelistedAppIds;
+
+ mPowerWhitelistedAllAppIds = powerSaveWhitelistAllAppIdArray;
+ mTempWhitelistedAppIds = tempWhitelistAppIdArray;
+
+ if (isAnyAppIdUnwhitelisted(previousWhitelist, mPowerWhitelistedAllAppIds)) {
+ mHandler.notifyAllUnwhitelisted();
+ } else if (!Arrays.equals(previousWhitelist, mPowerWhitelistedAllAppIds)) {
+ mHandler.notifyAllWhitelistChanged();
+ }
+
+ if (!Arrays.equals(previousTempWhitelist, mTempWhitelistedAppIds)) {
+ mHandler.notifyTempWhitelistChanged();
+ }
+
+ }
+ }
+
+ /**
+ * @retunr true if a sorted app-id array {@code prevArray} has at least one element
+ * that's not in a sorted app-id array {@code newArray}.
+ */
+ @VisibleForTesting
+ static boolean isAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray) {
+ int i1 = 0;
+ int i2 = 0;
+ boolean prevFinished;
+ boolean newFinished;
+
+ for (;;) {
+ prevFinished = i1 >= prevArray.length;
+ newFinished = i2 >= newArray.length;
+ if (prevFinished || newFinished) {
+ break;
+ }
+ int a1 = prevArray[i1];
+ int a2 = newArray[i2];
+
+ if (a1 == a2) {
+ i1++;
+ i2++;
+ continue;
+ }
+ if (a1 < a2) {
+ // prevArray has an element that's not in a2.
+ return true;
+ }
+ i2++;
+ }
+ if (prevFinished) {
+ return false;
+ }
+ return newFinished;
}
// Public interface.
@@ -332,21 +665,51 @@
}
/**
- * Whether force-app-standby is effective for a UID package-name.
+ * @return whether alarms should be restricted for a UID package-name.
*/
- public boolean isRestricted(int uid, @NonNull String packageName) {
+ public boolean areAlarmsRestricted(int uid, @NonNull String packageName) {
+ return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false);
+ }
+
+ /**
+ * @return whether jobs should be restricted for a UID package-name.
+ */
+ public boolean areJobsRestricted(int uid, @NonNull String packageName) {
+ return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true);
+ }
+
+ /**
+ * @return whether force-app-standby is effective for a UID package-name.
+ */
+ private boolean isRestricted(int uid, @NonNull String packageName,
+ boolean useTempWhitelistToo) {
if (isInForeground(uid)) {
return false;
}
synchronized (mLock) {
+ // Whitelisted?
+ final int appId = UserHandle.getAppId(uid);
+ if (ArrayUtils.contains(mPowerWhitelistedAllAppIds, appId)) {
+ return false;
+ }
+ if (useTempWhitelistToo &&
+ ArrayUtils.contains(mTempWhitelistedAppIds, appId)) {
+ return false;
+ }
+
if (mForceAllAppsStandby) {
return true;
}
- return isUidPackageRestrictedLocked(uid, packageName);
+
+ return isRunAnyRestrictedLocked(uid, packageName);
}
}
- /** For dumpsys -- otherwise the callers don't need to know it. */
+ /**
+ * @return whether a UID is in the foreground or not.
+ *
+ * Note clients normally shouldn't need to access it. It's only for dumpsys.
+ */
public boolean isInForeground(int uid) {
if (!UserHandle.isApp(uid)) {
return true;
@@ -356,31 +719,120 @@
}
}
- /** For dumpsys -- otherwise the callers don't need to know it. */
- public boolean isForceAllAppsStandbyEnabled() {
+ /**
+ * @return whether force all apps standby is enabled or not.
+ *
+ * Note clients normally shouldn't need to access it.
+ */
+ boolean isForceAllAppsStandbyEnabled() {
synchronized (mLock) {
return mForceAllAppsStandby;
}
}
- /** For dumpsys -- otherwise the callers don't need to know it. */
+ /**
+ * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not.
+ *
+ * Note clients normally shouldn't need to access it. It's only for dumpsys.
+ */
public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
synchronized (mLock) {
- return !isUidPackageRestrictedLocked(uid, packageName);
+ return !isRunAnyRestrictedLocked(uid, packageName);
}
}
- /** For dumpsys -- otherwise the callers don't need to know it. */
- public SparseBooleanArray getForegroudUids() {
+ /**
+ * @return whether a UID is in the user / system defined power-save whitelist or not.
+ *
+ * Note clients normally shouldn't need to access it. It's only for dumpsys.
+ */
+ public boolean isUidPowerSaveWhitelisted(int uid) {
synchronized (mLock) {
- return mForegroundUids.clone();
+ return ArrayUtils.contains(mPowerWhitelistedAllAppIds, UserHandle.getAppId(uid));
}
}
- /** For dumpsys -- otherwise the callers don't need to know it. */
- public ArraySet<Pair<Integer, String>> getRestrictedUidPackages() {
+ /**
+ * @return whether a UID is in the temp power-save whitelist or not.
+ *
+ * Note clients normally shouldn't need to access it. It's only for dumpsys.
+ */
+ public boolean isUidTempPowerSaveWhitelisted(int uid) {
synchronized (mLock) {
- return new ArraySet(mForcedAppStandbyUidPackages);
+ return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid));
+ }
+ }
+
+ public void dump(PrintWriter pw, String indent) {
+ synchronized (mLock) {
+ pw.print(indent);
+ pw.print("Force all apps standby: ");
+ pw.println(isForceAllAppsStandbyEnabled());
+
+ pw.print(indent);
+ pw.print("Foreground uids: [");
+
+ String sep = "";
+ for (int i = 0; i < mForegroundUids.size(); i++) {
+ if (mForegroundUids.valueAt(i)) {
+ pw.print(sep);
+ pw.print(UserHandle.formatUid(mForegroundUids.keyAt(i)));
+ sep = " ";
+ }
+ }
+ pw.println("]");
+
+ pw.print(indent);
+ pw.print("Whitelist appids: ");
+ pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
+
+ pw.print(indent);
+ pw.print("Temp whitelist appids: ");
+ pw.println(Arrays.toString(mTempWhitelistedAppIds));
+
+ pw.print(indent);
+ pw.println("Restricted packages:");
+ for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
+ pw.print(indent);
+ pw.print(" ");
+ pw.print(UserHandle.formatUid(uidAndPackage.first));
+ pw.print(" ");
+ pw.print(uidAndPackage.second);
+ pw.println();
+ }
+ }
+ }
+
+ public void dumpProto(ProtoOutputStream proto, long fieldId) {
+ synchronized (mLock) {
+ final long token = proto.start(fieldId);
+
+ proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
+
+ for (int i = 0; i < mForegroundUids.size(); i++) {
+ if (mForegroundUids.valueAt(i)) {
+ proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS,
+ mForegroundUids.keyAt(i));
+ }
+ }
+
+ for (int appId : mPowerWhitelistedAllAppIds) {
+ proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
+ }
+
+ for (int appId : mTempWhitelistedAppIds) {
+ proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
+ }
+
+ for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
+ final long token2 = proto.start(
+ ForceAppStandbyTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
+ proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
+ proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
+ uidAndPackage.second);
+ proto.end(token2);
+ }
+ proto.end(token);
}
}
}
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index f67bd04..fc4015d 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -16,19 +16,12 @@
package com.android.server.job.controllers;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.IDeviceIdleController;
-import android.os.PowerManager;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.util.Pair;
import android.util.Slog;
-import android.util.SparseBooleanArray;
import com.android.internal.util.ArrayUtils;
import com.android.server.ForceAppStandbyTracker;
@@ -37,7 +30,6 @@
import com.android.server.job.JobStore;
import java.io.PrintWriter;
-import java.util.function.Predicate;
public final class BackgroundJobsController extends StateController {
@@ -51,9 +43,6 @@
private final JobSchedulerService mJobSchedulerService;
private final IDeviceIdleController mDeviceIdleController;
- private int[] mPowerWhitelistedUserAppIds;
- private int[] mTempWhitelistedAppIds;
-
private final ForceAppStandbyTracker mForceAppStandbyTracker;
@@ -67,28 +56,6 @@
}
}
- private BroadcastReceiver mDozeWhitelistReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (mLock) {
- try {
- switch (intent.getAction()) {
- case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
- mPowerWhitelistedUserAppIds =
- mDeviceIdleController.getAppIdUserWhitelist();
- break;
- case PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED:
- mTempWhitelistedAppIds = mDeviceIdleController.getAppIdTempWhitelist();
- break;
- }
- } catch (RemoteException rexc) {
- Slog.e(LOG_TAG, "Device idle controller not reachable");
- }
- updateAllJobRestrictionsLocked();
- }
- }
- };
-
private BackgroundJobsController(JobSchedulerService service, Context context, Object lock) {
super(service, context, lock);
mJobSchedulerService = service;
@@ -97,19 +64,6 @@
mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
- try {
- mPowerWhitelistedUserAppIds = mDeviceIdleController.getAppIdUserWhitelist();
- mTempWhitelistedAppIds = mDeviceIdleController.getAppIdTempWhitelist();
- } catch (RemoteException rexc) {
- // Shouldn't happen as they are in the same process.
- Slog.e(LOG_TAG, "AppOps or DeviceIdle service not reachable", rexc);
- }
- IntentFilter powerWhitelistFilter = new IntentFilter();
- powerWhitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
- powerWhitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
- context.registerReceiverAsUser(mDozeWhitelistReceiver, UserHandle.ALL, powerWhitelistFilter,
- null, null);
-
mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
mForceAppStandbyTracker.start();
}
@@ -128,31 +82,7 @@
public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
pw.println("BackgroundJobsController");
- pw.print("Force all apps standby: ");
- pw.println(mForceAppStandbyTracker.isForceAllAppsStandbyEnabled());
-
- pw.print("Foreground uids: [");
- final SparseBooleanArray foregroundUids = mForceAppStandbyTracker.getForegroudUids();
-
- String sep = "";
- for (int i = 0; i < foregroundUids.size(); i++) {
- if (foregroundUids.valueAt(i)) {
- pw.print(sep);
- pw.print(UserHandle.formatUid(foregroundUids.keyAt(i)));
- sep = " ";
- }
- }
- pw.println("]");
-
- pw.println("Restricted packages:");
- for (Pair<Integer, String> uidAndPackage
- : mForceAppStandbyTracker.getRestrictedUidPackages()) {
- pw.print(" ");
- pw.print(UserHandle.formatUid(uidAndPackage.first));
- pw.print(" ");
- pw.print(uidAndPackage.second);
- pw.println();
- }
+ mForceAppStandbyTracker.dump(pw, "");
pw.println("Job state:");
mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
@@ -165,15 +95,17 @@
pw.print(" from ");
UserHandle.formatUid(pw, uid);
pw.print(mForceAppStandbyTracker.isInForeground(uid) ? " foreground" : " background");
- if (isWhitelistedLocked(uid)) {
+ if (mForceAppStandbyTracker.isUidPowerSaveWhitelisted(uid) ||
+ mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(uid)) {
pw.print(", whitelisted");
}
pw.print(": ");
pw.print(jobStatus.getSourcePackageName());
- pw.print(" [background restrictions ");
+ pw.print(" [RUN_ANY_IN_BACKGROUND ");
pw.print(mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(
- jobStatus.getSourceUid(), jobStatus.getSourcePackageName()) ? "off]" : "on]");
+ jobStatus.getSourceUid(), jobStatus.getSourcePackageName())
+ ? "allowed]" : "disallowed]");
if ((jobStatus.satisfiedConstraints
& JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
@@ -218,19 +150,12 @@
}
}
- private boolean isWhitelistedLocked(int uid) {
- final int appId = UserHandle.getAppId(uid);
- return ArrayUtils.contains(mTempWhitelistedAppIds, appId)
- || ArrayUtils.contains(mPowerWhitelistedUserAppIds, appId);
- }
-
boolean updateSingleJobRestrictionLocked(JobStatus jobStatus) {
final int uid = jobStatus.getSourceUid();
final String packageName = jobStatus.getSourcePackageName();
- final boolean canRun = isWhitelistedLocked(uid)
- || !mForceAppStandbyTracker.isRestricted(uid, packageName);
+ final boolean canRun = !mForceAppStandbyTracker.areJobsRestricted(uid, packageName);
return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
}
@@ -261,13 +186,18 @@
private final Listener mForceAppStandbyListener = new Listener() {
@Override
- public void onRestrictionChanged(int uid, String packageName) {
+ public void updateAllJobs() {
+ updateAllJobRestrictionsLocked();
+ }
+
+ @Override
+ public void updateJobsForUid(int uid) {
updateJobRestrictionsForUidLocked(uid);
}
@Override
- public void onGlobalRestrictionChanged() {
- updateAllJobRestrictionsLocked();
+ public void updateJobsForUidPackage(int uid, String packageName) {
+ updateJobRestrictionsForUidLocked(uid);
}
};
}