Merge "Integrate AlarmManager with TARE."
This commit is contained in:
@@ -43,7 +43,7 @@ import java.util.Date;
|
||||
*/
|
||||
class Alarm {
|
||||
@VisibleForTesting
|
||||
public static final int NUM_POLICIES = 4;
|
||||
public static final int NUM_POLICIES = 5;
|
||||
/**
|
||||
* Index used to store the time the alarm was requested to expire. To be used with
|
||||
* {@link #setPolicyElapsed(int, long)}.
|
||||
@@ -66,6 +66,12 @@ class Alarm {
|
||||
*/
|
||||
public static final int BATTERY_SAVER_POLICY_INDEX = 3;
|
||||
|
||||
/**
|
||||
* Index used to store the earliest time the alarm can expire based on TARE policy.
|
||||
* To be used with {@link #setPolicyElapsed(int, long)}.
|
||||
*/
|
||||
public static final int TARE_POLICY_INDEX = 4;
|
||||
|
||||
/**
|
||||
* Reason to use for inexact alarms.
|
||||
*/
|
||||
@@ -254,8 +260,10 @@ class Alarm {
|
||||
return "device_idle";
|
||||
case BATTERY_SAVER_POLICY_INDEX:
|
||||
return "battery_saver";
|
||||
case TARE_POLICY_INDEX:
|
||||
return "tare";
|
||||
default:
|
||||
return "--unknown--";
|
||||
return "--unknown(" + index + ")--";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_COMPAT;
|
||||
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE;
|
||||
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
|
||||
import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
|
||||
import static com.android.server.alarm.Alarm.TARE_POLICY_INDEX;
|
||||
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_ALARM_CANCELLED;
|
||||
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_DATA_CLEARED;
|
||||
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_EXACT_PERMISSION_REVOKED;
|
||||
@@ -73,6 +74,7 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Binder;
|
||||
@@ -112,6 +114,7 @@ import android.util.NtpTrustedTime;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseArrayMap;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.SparseLongArray;
|
||||
@@ -140,6 +143,8 @@ import com.android.server.SystemServiceManager;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
import com.android.server.pm.permission.PermissionManagerService;
|
||||
import com.android.server.pm.permission.PermissionManagerServiceInternal;
|
||||
import com.android.server.tare.AlarmManagerEconomicPolicy;
|
||||
import com.android.server.tare.EconomyManagerInternal;
|
||||
import com.android.server.usage.AppStandbyInternal;
|
||||
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
|
||||
|
||||
@@ -185,6 +190,7 @@ public class AlarmManagerService extends SystemService {
|
||||
static final boolean DEBUG_WAKELOCK = localLOGV || false;
|
||||
static final boolean DEBUG_BG_LIMIT = localLOGV || false;
|
||||
static final boolean DEBUG_STANDBY = localLOGV || false;
|
||||
static final boolean DEBUG_TARE = localLOGV || false;
|
||||
static final boolean RECORD_ALARMS_IN_HISTORY = true;
|
||||
static final boolean RECORD_DEVICE_IDLE_ALARMS = false;
|
||||
static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
|
||||
@@ -213,6 +219,7 @@ public class AlarmManagerService extends SystemService {
|
||||
DeviceIdleInternal mLocalDeviceIdleController;
|
||||
private UsageStatsManagerInternal mUsageStatsManagerInternal;
|
||||
private ActivityManagerInternal mActivityManagerInternal;
|
||||
private final EconomyManagerInternal mEconomyManagerInternal;
|
||||
private PackageManagerInternal mPackageManagerInternal;
|
||||
private volatile PermissionManagerServiceInternal mLocalPermissionManager;
|
||||
|
||||
@@ -230,6 +237,14 @@ public class AlarmManagerService extends SystemService {
|
||||
@GuardedBy("mLock")
|
||||
SparseIntArray mLastOpScheduleExactAlarm = new SparseIntArray();
|
||||
|
||||
/**
|
||||
* Local cache of the ability of each userId-pkg to afford the various bills we're tracking for
|
||||
* them.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private final SparseArrayMap<String, ArrayMap<EconomyManagerInternal.ActionBill, Boolean>>
|
||||
mAffordabilityCache = new SparseArrayMap<>();
|
||||
|
||||
// List of alarms per uid deferred due to user applied background restrictions on the source app
|
||||
SparseArray<ArrayList<Alarm>> mPendingBackgroundAlarms = new SparseArray<>();
|
||||
private long mNextWakeup;
|
||||
@@ -298,11 +313,13 @@ public class AlarmManagerService extends SystemService {
|
||||
interface Stats {
|
||||
int REORDER_ALARMS_FOR_STANDBY = 0;
|
||||
int HAS_SCHEDULE_EXACT_ALARM = 1;
|
||||
int REORDER_ALARMS_FOR_TARE = 2;
|
||||
}
|
||||
|
||||
private final StatLogger mStatLogger = new StatLogger("Alarm manager stats", new String[]{
|
||||
"REORDER_ALARMS_FOR_STANDBY",
|
||||
"HAS_SCHEDULE_EXACT_ALARM",
|
||||
"REORDER_ALARMS_FOR_TARE",
|
||||
});
|
||||
|
||||
BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic();
|
||||
@@ -472,7 +489,8 @@ public class AlarmManagerService extends SystemService {
|
||||
* holding the AlarmManagerService.mLock lock.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
final class Constants implements DeviceConfig.OnPropertiesChangedListener {
|
||||
final class Constants extends ContentObserver
|
||||
implements DeviceConfig.OnPropertiesChangedListener {
|
||||
@VisibleForTesting
|
||||
static final int MAX_EXACT_ALARM_DENY_LIST_SIZE = 250;
|
||||
|
||||
@@ -670,10 +688,13 @@ public class AlarmManagerService extends SystemService {
|
||||
public boolean KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
|
||||
DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED;
|
||||
|
||||
public boolean USE_TARE_POLICY = Settings.Global.DEFAULT_ENABLE_TARE == 1;
|
||||
|
||||
private long mLastAllowWhileIdleWhitelistDuration = -1;
|
||||
private int mVersion = 0;
|
||||
|
||||
Constants() {
|
||||
Constants(Handler handler) {
|
||||
super(handler);
|
||||
updateAllowWhileIdleWhitelistDurationLocked();
|
||||
for (int i = 0; i < APP_STANDBY_QUOTAS.length; i++) {
|
||||
APP_STANDBY_QUOTAS[i] = DEFAULT_APP_STANDBY_QUOTAS[i];
|
||||
@@ -687,8 +708,11 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
|
||||
public void start() {
|
||||
mInjector.registerContentObserver(this,
|
||||
Settings.Global.getUriFor(Settings.Global.ENABLE_TARE));
|
||||
mInjector.registerDeviceConfigListener(this);
|
||||
onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ALARM_MANAGER));
|
||||
updateTareSettings();
|
||||
}
|
||||
|
||||
public void updateAllowWhileIdleWhitelistDurationLocked() {
|
||||
@@ -860,6 +884,39 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
updateTareSettings();
|
||||
}
|
||||
|
||||
private void updateTareSettings() {
|
||||
synchronized (mLock) {
|
||||
final boolean isTareEnabled = Settings.Global.getInt(
|
||||
getContext().getContentResolver(),
|
||||
Settings.Global.ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE) == 1;
|
||||
if (USE_TARE_POLICY != isTareEnabled) {
|
||||
USE_TARE_POLICY = isTareEnabled;
|
||||
final boolean changed = mAlarmStore.updateAlarmDeliveries(alarm -> {
|
||||
final boolean standbyChanged = adjustDeliveryTimeBasedOnBucketLocked(alarm);
|
||||
final boolean tareChanged = adjustDeliveryTimeBasedOnTareLocked(alarm);
|
||||
if (USE_TARE_POLICY) {
|
||||
registerTareListener(alarm);
|
||||
} else {
|
||||
mEconomyManagerInternal.unregisterAffordabilityChangeListener(
|
||||
UserHandle.getUserId(alarm.uid), alarm.sourcePackage,
|
||||
mAffordabilityChangeListener,
|
||||
TareBill.getAppropriateBill(alarm));
|
||||
}
|
||||
return standbyChanged || tareChanged;
|
||||
});
|
||||
if (changed) {
|
||||
rescheduleKernelAlarmsLocked();
|
||||
updateNextAlarmClockLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateExactAlarmDenyList(String[] newDenyList) {
|
||||
final Set<String> newSet = Collections.unmodifiableSet(new ArraySet<>(newDenyList));
|
||||
final Set<String> removed = new ArraySet<>(EXACT_ALARM_DENY_LIST);
|
||||
@@ -1059,6 +1116,9 @@ public class AlarmManagerService extends SystemService {
|
||||
KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED);
|
||||
pw.println();
|
||||
|
||||
pw.print(Settings.Global.ENABLE_TARE, USE_TARE_POLICY);
|
||||
pw.println();
|
||||
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
@@ -1177,6 +1237,7 @@ public class AlarmManagerService extends SystemService {
|
||||
AlarmManagerService(Context context, Injector injector) {
|
||||
super(context);
|
||||
mInjector = injector;
|
||||
mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
|
||||
}
|
||||
|
||||
public AlarmManagerService(Context context) {
|
||||
@@ -1283,6 +1344,29 @@ public class AlarmManagerService extends SystemService {
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculates alarm send times based on TARE wealth.
|
||||
*
|
||||
* @param targetPackages [Package, User] pairs for which alarms need to be re-evaluated,
|
||||
* null indicates all
|
||||
* @return True if there was any reordering done to the current list.
|
||||
*/
|
||||
boolean reorderAlarmsBasedOnTare(ArraySet<Pair<String, Integer>> targetPackages) {
|
||||
final long start = mStatLogger.getTime();
|
||||
|
||||
final boolean changed = mAlarmStore.updateAlarmDeliveries(a -> {
|
||||
final Pair<String, Integer> packageUser =
|
||||
Pair.create(a.sourcePackage, UserHandle.getUserId(a.creatorUid));
|
||||
if (targetPackages != null && !targetPackages.contains(packageUser)) {
|
||||
return false;
|
||||
}
|
||||
return adjustDeliveryTimeBasedOnTareLocked(a);
|
||||
});
|
||||
|
||||
mStatLogger.logDurationStat(Stats.REORDER_ALARMS_FOR_TARE, start);
|
||||
return changed;
|
||||
}
|
||||
|
||||
private boolean restoreRequestedTime(Alarm a) {
|
||||
return a.setPolicyElapsed(REQUESTER_POLICY_INDEX, convertToElapsed(a.origWhen, a.type));
|
||||
}
|
||||
@@ -1632,7 +1716,7 @@ public class AlarmManagerService extends SystemService {
|
||||
|
||||
synchronized (mLock) {
|
||||
mHandler = new AlarmHandler();
|
||||
mConstants = new Constants();
|
||||
mConstants = new Constants(mHandler);
|
||||
|
||||
mAlarmStore = mConstants.LAZY_BATCHING ? new LazyAlarmStore()
|
||||
: new BatchingAlarmStore();
|
||||
@@ -2255,7 +2339,7 @@ public class AlarmManagerService extends SystemService {
|
||||
*/
|
||||
private boolean adjustDeliveryTimeBasedOnBucketLocked(Alarm alarm) {
|
||||
final long nowElapsed = mInjector.getElapsedRealtime();
|
||||
if (isExemptFromAppStandby(alarm) || mAppStandbyParole) {
|
||||
if (mConstants.USE_TARE_POLICY || isExemptFromAppStandby(alarm) || mAppStandbyParole) {
|
||||
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
|
||||
}
|
||||
|
||||
@@ -2299,6 +2383,50 @@ public class AlarmManagerService extends SystemService {
|
||||
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the alarm's policy time for TARE.
|
||||
*
|
||||
* @param alarm The alarm to update.
|
||||
* @return {@code true} if the actual delivery time of the given alarm was updated due to
|
||||
* adjustments made in this call.
|
||||
*/
|
||||
private boolean adjustDeliveryTimeBasedOnTareLocked(Alarm alarm) {
|
||||
final long nowElapsed = mInjector.getElapsedRealtime();
|
||||
if (!mConstants.USE_TARE_POLICY
|
||||
|| isExemptFromTare(alarm) || hasEnoughWealthLocked(alarm)) {
|
||||
return alarm.setPolicyElapsed(TARE_POLICY_INDEX, nowElapsed);
|
||||
}
|
||||
|
||||
// Not enough wealth. Just keep deferring indefinitely till the quota changes.
|
||||
return alarm.setPolicyElapsed(TARE_POLICY_INDEX, nowElapsed + INDEFINITE_DELAY);
|
||||
}
|
||||
|
||||
private void registerTareListener(Alarm alarm) {
|
||||
if (!mConstants.USE_TARE_POLICY) {
|
||||
return;
|
||||
}
|
||||
mEconomyManagerInternal.registerAffordabilityChangeListener(
|
||||
UserHandle.getUserId(alarm.uid), alarm.sourcePackage,
|
||||
mAffordabilityChangeListener, TareBill.getAppropriateBill(alarm));
|
||||
}
|
||||
|
||||
/** Unregister the TARE listener associated with the alarm if it's no longer needed. */
|
||||
private void maybeUnregisterTareListener(Alarm alarm) {
|
||||
if (!mConstants.USE_TARE_POLICY) {
|
||||
return;
|
||||
}
|
||||
final EconomyManagerInternal.ActionBill bill = TareBill.getAppropriateBill(alarm);
|
||||
final Predicate<Alarm> isSameAlarmTypeForSameApp = (a) ->
|
||||
alarm.creatorUid == a.creatorUid
|
||||
&& alarm.sourcePackage.equals(a.sourcePackage)
|
||||
&& bill.equals(TareBill.getAppropriateBill(a));
|
||||
if (mAlarmStore.getCount(isSameAlarmTypeForSameApp) == 0) {
|
||||
mEconomyManagerInternal.unregisterAffordabilityChangeListener(
|
||||
UserHandle.getUserId(alarm.uid), alarm.sourcePackage,
|
||||
mAffordabilityChangeListener, bill);
|
||||
}
|
||||
}
|
||||
|
||||
private void setImplLocked(Alarm a) {
|
||||
if ((a.flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
|
||||
adjustIdleUntilTime(a);
|
||||
@@ -2345,6 +2473,8 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
adjustDeliveryTimeBasedOnBatterySaver(a);
|
||||
adjustDeliveryTimeBasedOnBucketLocked(a);
|
||||
adjustDeliveryTimeBasedOnTareLocked(a);
|
||||
registerTareListener(a);
|
||||
mAlarmStore.add(a);
|
||||
rescheduleKernelAlarmsLocked();
|
||||
updateNextAlarmClockLocked();
|
||||
@@ -2711,14 +2841,43 @@ public class AlarmManagerService extends SystemService {
|
||||
mConstants.dump(pw);
|
||||
pw.println();
|
||||
|
||||
if (mAppStateTracker != null) {
|
||||
mAppStateTracker.dump(pw);
|
||||
if (mConstants.USE_TARE_POLICY) {
|
||||
pw.println("TARE details:");
|
||||
pw.increaseIndent();
|
||||
|
||||
pw.println("Affordability cache:");
|
||||
pw.increaseIndent();
|
||||
mAffordabilityCache.forEach((userId, pkgName, billMap) -> {
|
||||
final int numBills = billMap.size();
|
||||
if (numBills > 0) {
|
||||
pw.print(userId);
|
||||
pw.print(":");
|
||||
pw.print(pkgName);
|
||||
pw.println(":");
|
||||
|
||||
pw.increaseIndent();
|
||||
for (int i = 0; i < numBills; ++i) {
|
||||
pw.print(TareBill.getName(billMap.keyAt(i)));
|
||||
pw.print(": ");
|
||||
pw.println(billMap.valueAt(i));
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
});
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.decreaseIndent();
|
||||
pw.println();
|
||||
} else {
|
||||
if (mAppStateTracker != null) {
|
||||
mAppStateTracker.dump(pw);
|
||||
pw.println();
|
||||
}
|
||||
|
||||
pw.println("App Standby Parole: " + mAppStandbyParole);
|
||||
pw.println();
|
||||
}
|
||||
|
||||
pw.println("App Standby Parole: " + mAppStandbyParole);
|
||||
pw.println();
|
||||
|
||||
final long nowELAPSED = mInjector.getElapsedRealtime();
|
||||
final long nowUPTIME = SystemClock.uptimeMillis();
|
||||
final long nowRTC = mInjector.getCurrentTimeMillis();
|
||||
@@ -3673,6 +3832,7 @@ public class AlarmManagerService extends SystemService {
|
||||
mRemovalHistory.put(removed.uid, bufferForUid);
|
||||
}
|
||||
bufferForUid.append(new RemovedAlarm(removed, reason, nowRtc, nowElapsed));
|
||||
maybeUnregisterTareListener(removed);
|
||||
}
|
||||
|
||||
if (removedFromStore) {
|
||||
@@ -4010,6 +4170,11 @@ public class AlarmManagerService extends SystemService {
|
||||
alarm.uid, alarm.statsTag);
|
||||
}
|
||||
mDeliveryTracker.deliverLocked(alarm, nowELAPSED);
|
||||
reportAlarmEventToTare(alarm);
|
||||
if (alarm.repeatInterval <= 0) {
|
||||
// Don't bother trying to unregister for a repeating alarm.
|
||||
maybeUnregisterTareListener(alarm);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Slog.w(TAG, "Failure sending alarm.", e);
|
||||
}
|
||||
@@ -4018,12 +4183,60 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private void reportAlarmEventToTare(Alarm alarm) {
|
||||
final boolean allowWhileIdle =
|
||||
(alarm.flags & (FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_ALLOW_WHILE_IDLE)) != 0;
|
||||
final int action;
|
||||
if (alarm.alarmClock != null) {
|
||||
action = AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK;
|
||||
} else if (alarm.wakeup) {
|
||||
if (alarm.windowLength == 0) {
|
||||
if (allowWhileIdle) {
|
||||
action = AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE;
|
||||
} else {
|
||||
action = AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT;
|
||||
}
|
||||
} else {
|
||||
if (allowWhileIdle) {
|
||||
action =
|
||||
AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE;
|
||||
} else {
|
||||
action = AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (alarm.windowLength == 0) {
|
||||
if (allowWhileIdle) {
|
||||
action = AlarmManagerEconomicPolicy
|
||||
.ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE;
|
||||
} else {
|
||||
action = AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT;
|
||||
}
|
||||
} else {
|
||||
if (allowWhileIdle) {
|
||||
action = AlarmManagerEconomicPolicy
|
||||
.ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE;
|
||||
} else {
|
||||
action = AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT;
|
||||
}
|
||||
}
|
||||
}
|
||||
mEconomyManagerInternal.noteInstantaneousEvent(
|
||||
UserHandle.getUserId(alarm.uid), alarm.sourcePackage, action, null);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean isExemptFromAppStandby(Alarm a) {
|
||||
return a.alarmClock != null || UserHandle.isCore(a.creatorUid)
|
||||
|| (a.flags & (FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_ALLOW_WHILE_IDLE)) != 0;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean isExemptFromTare(Alarm a) {
|
||||
return a.alarmClock != null || UserHandle.isCore(a.creatorUid)
|
||||
|| (a.flags & (FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED)) != 0;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static class Injector {
|
||||
private long mNativeData;
|
||||
@@ -4117,6 +4330,10 @@ public class AlarmManagerService extends SystemService {
|
||||
return service.new ClockReceiver();
|
||||
}
|
||||
|
||||
void registerContentObserver(ContentObserver contentObserver, Uri uri) {
|
||||
mContext.getContentResolver().registerContentObserver(uri, false, contentObserver);
|
||||
}
|
||||
|
||||
void registerDeviceConfigListener(DeviceConfig.OnPropertiesChangedListener listener) {
|
||||
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ALARM_MANAGER,
|
||||
JobSchedulerBackgroundThread.getExecutor(), listener);
|
||||
@@ -4249,13 +4466,23 @@ public class AlarmManagerService extends SystemService {
|
||||
new ArraySet<>();
|
||||
for (int i = 0; i < triggerList.size(); i++) {
|
||||
final Alarm a = triggerList.get(i);
|
||||
if (!isExemptFromAppStandby(a)) {
|
||||
if (mConstants.USE_TARE_POLICY) {
|
||||
if (!isExemptFromTare(a)) {
|
||||
triggerPackages.add(Pair.create(
|
||||
a.sourcePackage,
|
||||
UserHandle.getUserId(a.creatorUid)));
|
||||
}
|
||||
} else if (!isExemptFromAppStandby(a)) {
|
||||
triggerPackages.add(Pair.create(
|
||||
a.sourcePackage, UserHandle.getUserId(a.creatorUid)));
|
||||
}
|
||||
}
|
||||
deliverAlarmsLocked(triggerList, nowELAPSED);
|
||||
reorderAlarmsBasedOnStandbyBuckets(triggerPackages);
|
||||
if (mConstants.USE_TARE_POLICY) {
|
||||
reorderAlarmsBasedOnTare(triggerPackages);
|
||||
} else {
|
||||
reorderAlarmsBasedOnStandbyBuckets(triggerPackages);
|
||||
}
|
||||
rescheduleKernelAlarmsLocked();
|
||||
updateNextAlarmClockLocked();
|
||||
MetricsHelper.pushAlarmBatchDelivered(triggerList.size(), wakeUps);
|
||||
@@ -4307,6 +4534,31 @@ public class AlarmManagerService extends SystemService {
|
||||
return alarm.creatorUid;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean canAffordBillLocked(@NonNull Alarm alarm,
|
||||
@NonNull EconomyManagerInternal.ActionBill bill) {
|
||||
final int userId = UserHandle.getUserId(alarm.uid);
|
||||
final String pkgName = alarm.sourcePackage;
|
||||
ArrayMap<EconomyManagerInternal.ActionBill, Boolean> actionAffordability =
|
||||
mAffordabilityCache.get(userId, pkgName);
|
||||
if (actionAffordability == null) {
|
||||
actionAffordability = new ArrayMap<>();
|
||||
mAffordabilityCache.add(userId, pkgName, actionAffordability);
|
||||
}
|
||||
|
||||
if (actionAffordability.containsKey(bill)) {
|
||||
return actionAffordability.get(bill);
|
||||
}
|
||||
|
||||
final boolean canAfford = mEconomyManagerInternal.canPayFor(userId, pkgName, bill);
|
||||
actionAffordability.put(bill, canAfford);
|
||||
return canAfford;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean hasEnoughWealthLocked(@NonNull Alarm alarm) {
|
||||
return canAffordBillLocked(alarm, TareBill.getAppropriateBill(alarm));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
class AlarmHandler extends Handler {
|
||||
@@ -4321,6 +4573,7 @@ public class AlarmManagerService extends SystemService {
|
||||
public static final int EXACT_ALARM_DENY_LIST_PACKAGES_ADDED = 9;
|
||||
public static final int EXACT_ALARM_DENY_LIST_PACKAGES_REMOVED = 10;
|
||||
public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11;
|
||||
public static final int TARE_AFFORDABILITY_CHANGED = 12;
|
||||
|
||||
AlarmHandler() {
|
||||
super(Looper.myLooper());
|
||||
@@ -4402,6 +4655,20 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
break;
|
||||
|
||||
case TARE_AFFORDABILITY_CHANGED:
|
||||
synchronized (mLock) {
|
||||
final int userId = msg.arg1;
|
||||
final String packageName = (String) msg.obj;
|
||||
|
||||
final ArraySet<Pair<String, Integer>> filterPackages = new ArraySet<>();
|
||||
filterPackages.add(Pair.create(packageName, userId));
|
||||
if (reorderAlarmsBasedOnTare(filterPackages)) {
|
||||
rescheduleKernelAlarmsLocked();
|
||||
updateNextAlarmClockLocked();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case REMOVE_FOR_CANCELED:
|
||||
final PendingIntent operation = (PendingIntent) msg.obj;
|
||||
synchronized (mLock) {
|
||||
@@ -4656,6 +4923,31 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private final EconomyManagerInternal.AffordabilityChangeListener mAffordabilityChangeListener =
|
||||
new EconomyManagerInternal.AffordabilityChangeListener() {
|
||||
@Override
|
||||
public void onAffordabilityChanged(int userId, @NonNull String packageName,
|
||||
@NonNull EconomyManagerInternal.ActionBill bill, boolean canAfford) {
|
||||
if (DEBUG_TARE) {
|
||||
Slog.d(TAG,
|
||||
userId + ":" + packageName + " affordability for "
|
||||
+ TareBill.getName(bill) + " changed to " + canAfford);
|
||||
}
|
||||
|
||||
ArrayMap<EconomyManagerInternal.ActionBill, Boolean> actionAffordability =
|
||||
mAffordabilityCache.get(userId, packageName);
|
||||
if (actionAffordability == null) {
|
||||
actionAffordability = new ArrayMap<>();
|
||||
mAffordabilityCache.add(userId, packageName, actionAffordability);
|
||||
}
|
||||
actionAffordability.put(bill, canAfford);
|
||||
|
||||
mHandler.obtainMessage(AlarmHandler.TARE_AFFORDABILITY_CHANGED, userId,
|
||||
canAfford ? 1 : 0, packageName)
|
||||
.sendToTarget();
|
||||
}
|
||||
};
|
||||
|
||||
private final Listener mForceAppStandbyListener = new Listener() {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.alarm;
|
||||
|
||||
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
|
||||
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
|
||||
|
||||
import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK;
|
||||
import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT;
|
||||
import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE;
|
||||
import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT;
|
||||
import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE;
|
||||
import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT;
|
||||
import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE;
|
||||
import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT;
|
||||
import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.server.tare.EconomyManagerInternal;
|
||||
import com.android.server.tare.EconomyManagerInternal.ActionBill;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Container to maintain alarm TARE {@link ActionBill}s and their related methods.
|
||||
*/
|
||||
final class TareBill {
|
||||
/**
|
||||
* Bill to use for AlarmClocks.
|
||||
*/
|
||||
static final ActionBill ALARM_CLOCK = new ActionBill(List.of(
|
||||
new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_CLOCK, 1, 0)));
|
||||
/**
|
||||
* Bills to use for various alarm types.
|
||||
*/
|
||||
static final ActionBill NONWAKEUP_INEXACT_ALARM = new ActionBill(List.of(
|
||||
new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_NONWAKEUP_INEXACT, 1, 0)));
|
||||
static final ActionBill NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
|
||||
new EconomyManagerInternal.AnticipatedAction(
|
||||
ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE, 1, 0)));
|
||||
static final ActionBill NONWAKEUP_EXACT_ALARM = new ActionBill(List.of(
|
||||
new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_NONWAKEUP_EXACT, 1, 0)));
|
||||
static final ActionBill NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
|
||||
new EconomyManagerInternal.AnticipatedAction(
|
||||
ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE, 1, 0)));
|
||||
static final ActionBill WAKEUP_INEXACT_ALARM = new ActionBill(List.of(
|
||||
new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_WAKEUP_INEXACT, 1, 0)));
|
||||
static final ActionBill WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
|
||||
new EconomyManagerInternal.AnticipatedAction(
|
||||
ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE, 1, 0)));
|
||||
static final ActionBill WAKEUP_EXACT_ALARM = new ActionBill(List.of(
|
||||
new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_WAKEUP_EXACT, 1, 0)));
|
||||
static final ActionBill WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
|
||||
new EconomyManagerInternal.AnticipatedAction(
|
||||
ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, 1, 0)));
|
||||
|
||||
@NonNull
|
||||
static ActionBill getAppropriateBill(@NonNull Alarm alarm) {
|
||||
if (alarm.alarmClock != null) {
|
||||
return ALARM_CLOCK;
|
||||
}
|
||||
|
||||
final boolean allowWhileIdle =
|
||||
(alarm.flags & (FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_ALLOW_WHILE_IDLE)) != 0;
|
||||
final boolean isExact = alarm.windowLength == 0;
|
||||
|
||||
if (alarm.wakeup) {
|
||||
if (isExact) {
|
||||
if (allowWhileIdle) {
|
||||
return WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM;
|
||||
}
|
||||
return WAKEUP_EXACT_ALARM;
|
||||
}
|
||||
// Inexact
|
||||
if (allowWhileIdle) {
|
||||
return WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM;
|
||||
}
|
||||
return WAKEUP_INEXACT_ALARM;
|
||||
}
|
||||
|
||||
// Nonwakeup
|
||||
if (isExact) {
|
||||
if (allowWhileIdle) {
|
||||
return NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM;
|
||||
}
|
||||
return NONWAKEUP_EXACT_ALARM;
|
||||
|
||||
}
|
||||
if (allowWhileIdle) {
|
||||
return NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM;
|
||||
}
|
||||
return NONWAKEUP_INEXACT_ALARM;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static String getName(@NonNull ActionBill bill) {
|
||||
if (bill.equals(ALARM_CLOCK)) {
|
||||
return "ALARM_CLOCK_BILL";
|
||||
}
|
||||
if (bill.equals(NONWAKEUP_INEXACT_ALARM)) {
|
||||
return "NONWAKEUP_INEXACT_ALARM_BILL";
|
||||
}
|
||||
if (bill.equals(NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM)) {
|
||||
return "NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
|
||||
}
|
||||
if (bill.equals(NONWAKEUP_EXACT_ALARM)) {
|
||||
return "NONWAKEUP_EXACT_ALARM_BILL";
|
||||
}
|
||||
if (bill.equals(NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM)) {
|
||||
return "NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
|
||||
}
|
||||
if (bill.equals(WAKEUP_INEXACT_ALARM)) {
|
||||
return "WAKEUP_INEXACT_ALARM_BILL";
|
||||
}
|
||||
if (bill.equals(WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM)) {
|
||||
return "WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
|
||||
}
|
||||
if (bill.equals(WAKEUP_EXACT_ALARM)) {
|
||||
return "WAKEUP_EXACT_ALARM_BILL";
|
||||
}
|
||||
if (bill.equals(WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM)) {
|
||||
return "WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
|
||||
}
|
||||
return "UNKNOWN_BILL (" + bill.toString() + ")";
|
||||
}
|
||||
|
||||
private TareBill() {
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,7 @@ import static com.android.server.alarm.AlarmManagerService.AlarmHandler.EXACT_AL
|
||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES;
|
||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS;
|
||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED;
|
||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.TARE_AFFORDABILITY_CHANGED;
|
||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA;
|
||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW;
|
||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_QUOTA;
|
||||
@@ -120,9 +121,12 @@ import android.app.IAlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.compat.CompatChanges;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -138,6 +142,7 @@ import android.os.UserHandle;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.provider.Settings;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
@@ -158,6 +163,7 @@ import com.android.server.SystemService;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
import com.android.server.pm.permission.PermissionManagerService;
|
||||
import com.android.server.pm.permission.PermissionManagerServiceInternal;
|
||||
import com.android.server.tare.EconomyManagerInternal;
|
||||
import com.android.server.usage.AppStandbyInternal;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
@@ -201,6 +207,8 @@ public class AlarmManagerServiceTest {
|
||||
@Mock
|
||||
private Context mMockContext;
|
||||
@Mock
|
||||
private ContentResolver mContentResolver;
|
||||
@Mock
|
||||
private IActivityManager mIActivityManager;
|
||||
@Mock
|
||||
private IAppOpsService mIAppOpsService;
|
||||
@@ -225,6 +233,8 @@ public class AlarmManagerServiceTest {
|
||||
@Mock
|
||||
private PowerManager.WakeLock mWakeLock;
|
||||
@Mock
|
||||
private EconomyManagerInternal mEconomyManagerInternal;
|
||||
@Mock
|
||||
DeviceConfig.Properties mDeviceConfigProperties;
|
||||
HashSet<String> mDeviceConfigKeys = new HashSet<>();
|
||||
|
||||
@@ -349,6 +359,11 @@ public class AlarmManagerServiceTest {
|
||||
return mWakeLock;
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerContentObserver(ContentObserver observer, Uri uri) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerDeviceConfigListener(DeviceConfig.OnPropertiesChangedListener listener) {
|
||||
// Do nothing.
|
||||
@@ -369,6 +384,7 @@ public class AlarmManagerServiceTest {
|
||||
.initMocks(this)
|
||||
.spyStatic(ActivityManager.class)
|
||||
.mockStatic(CompatChanges.class)
|
||||
.spyStatic(DateFormat.class)
|
||||
.spyStatic(DeviceConfig.class)
|
||||
.mockStatic(LocalServices.class)
|
||||
.spyStatic(Looper.class)
|
||||
@@ -384,6 +400,8 @@ public class AlarmManagerServiceTest {
|
||||
doReturn(mIActivityManager).when(ActivityManager::getService);
|
||||
doReturn(mDeviceIdleInternal).when(
|
||||
() -> LocalServices.getService(DeviceIdleInternal.class));
|
||||
doReturn(mEconomyManagerInternal).when(
|
||||
() -> LocalServices.getService(EconomyManagerInternal.class));
|
||||
doReturn(mPermissionManagerInternal).when(
|
||||
() -> LocalServices.getService(PermissionManagerServiceInternal.class));
|
||||
doReturn(mActivityManagerInternal).when(
|
||||
@@ -403,6 +421,8 @@ public class AlarmManagerServiceTest {
|
||||
eq(TEST_CALLING_USER), anyLong())).thenReturn(STANDBY_BUCKET_ACTIVE);
|
||||
doReturn(Looper.getMainLooper()).when(Looper::myLooper);
|
||||
|
||||
when(mMockContext.getContentResolver()).thenReturn(mContentResolver);
|
||||
|
||||
doReturn(mDeviceConfigKeys).when(mDeviceConfigProperties).getKeyset();
|
||||
when(mDeviceConfigProperties.getLong(anyString(), anyLong()))
|
||||
.thenAnswer((Answer<Long>) invocationOnMock -> {
|
||||
@@ -421,6 +441,9 @@ public class AlarmManagerServiceTest {
|
||||
doReturn(mDeviceConfigProperties).when(
|
||||
() -> DeviceConfig.getProperties(
|
||||
eq(DeviceConfig.NAMESPACE_ALARM_MANAGER), ArgumentMatchers.<String>any()));
|
||||
// Needed to ensure logging doesn't cause tests to fail.
|
||||
doReturn(true)
|
||||
.when(() -> DateFormat.is24HourFormat(eq(mMockContext), anyInt()));
|
||||
|
||||
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
|
||||
|
||||
@@ -447,6 +470,7 @@ public class AlarmManagerServiceTest {
|
||||
|
||||
// Other boot phases don't matter
|
||||
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
|
||||
setTareEnabled(false);
|
||||
mAppStandbyWindow = mService.mConstants.APP_STANDBY_WINDOW;
|
||||
mAllowWhileIdleWindow = mService.mConstants.ALLOW_WHILE_IDLE_WINDOW;
|
||||
ArgumentCaptor<AppStandbyInternal.AppIdleStateChangeListener> captor =
|
||||
@@ -596,6 +620,15 @@ public class AlarmManagerServiceTest {
|
||||
mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
|
||||
}
|
||||
|
||||
private void setTareEnabled(boolean enabled) {
|
||||
doReturn(enabled ? 1 : 0).when(
|
||||
() -> Settings.Global.getInt(mContentResolver, Settings.Global.ENABLE_TARE));
|
||||
doReturn(enabled ? 1 : 0).when(
|
||||
() -> Settings.Global.getInt(mContentResolver,
|
||||
Settings.Global.ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE));
|
||||
mService.mConstants.onChange(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lowers quotas to make testing feasible. Careful while calling as this will replace any
|
||||
* existing settings for the calling test.
|
||||
@@ -1987,6 +2020,44 @@ public class AlarmManagerServiceTest {
|
||||
assertEquals(idleUntil, mTestTimer.getElapsed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tareThrottling() {
|
||||
setTareEnabled(true);
|
||||
final ArgumentCaptor<EconomyManagerInternal.AffordabilityChangeListener> listenerCaptor =
|
||||
ArgumentCaptor.forClass(EconomyManagerInternal.AffordabilityChangeListener.class);
|
||||
final ArgumentCaptor<EconomyManagerInternal.ActionBill> billCaptor =
|
||||
ArgumentCaptor.forClass(EconomyManagerInternal.ActionBill.class);
|
||||
|
||||
when(mEconomyManagerInternal
|
||||
.canPayFor(eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), billCaptor.capture()))
|
||||
.thenReturn(false);
|
||||
|
||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||
setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 15, alarmPi);
|
||||
assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed());
|
||||
|
||||
final EconomyManagerInternal.ActionBill bill = billCaptor.getValue();
|
||||
verify(mEconomyManagerInternal).registerAffordabilityChangeListener(
|
||||
eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE),
|
||||
listenerCaptor.capture(), eq(bill));
|
||||
final EconomyManagerInternal.AffordabilityChangeListener listener =
|
||||
listenerCaptor.getValue();
|
||||
|
||||
when(mEconomyManagerInternal
|
||||
.canPayFor(eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), eq(bill)))
|
||||
.thenReturn(true);
|
||||
listener.onAffordabilityChanged(TEST_CALLING_USER, TEST_CALLING_PACKAGE, bill, true);
|
||||
assertAndHandleMessageSync(TARE_AFFORDABILITY_CHANGED);
|
||||
assertEquals(mNowElapsedTest + 15, mTestTimer.getElapsed());
|
||||
|
||||
when(mEconomyManagerInternal
|
||||
.canPayFor(eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), eq(bill)))
|
||||
.thenReturn(false);
|
||||
listener.onAffordabilityChanged(TEST_CALLING_USER, TEST_CALLING_PACKAGE, bill, false);
|
||||
assertAndHandleMessageSync(TARE_AFFORDABILITY_CHANGED);
|
||||
assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dispatchOrder() throws Exception {
|
||||
setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);
|
||||
@@ -3065,6 +3136,23 @@ public class AlarmManagerServiceTest {
|
||||
verify(() -> MetricsHelper.pushAlarmBatchDelivered(10, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tareEventPushed() throws Exception {
|
||||
setTareEnabled(true);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
final int type = (i % 2 == 1) ? ELAPSED_REALTIME : ELAPSED_REALTIME_WAKEUP;
|
||||
setTestAlarm(type, mNowElapsedTest + i, getNewMockPendingIntent());
|
||||
}
|
||||
|
||||
final ArrayList<Alarm> alarms = mService.mAlarmStore.remove((alarm) -> {
|
||||
return alarm.creatorUid == TEST_CALLING_UID;
|
||||
});
|
||||
mService.deliverAlarmsLocked(alarms, mNowElapsedTest);
|
||||
verify(mEconomyManagerInternal, times(10)).noteInstantaneousEvent(
|
||||
eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), anyInt(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setTimeZoneImpl() {
|
||||
final long durationMs = 20000L;
|
||||
|
||||
@@ -28,6 +28,7 @@ import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX;
|
||||
import static com.android.server.alarm.Alarm.NUM_POLICIES;
|
||||
import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
|
||||
import static com.android.server.alarm.AlarmManagerService.isExemptFromAppStandby;
|
||||
import static com.android.server.alarm.AlarmManagerService.isExemptFromTare;
|
||||
import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
|
||||
import static com.android.server.alarm.Constants.TEST_CALLING_UID;
|
||||
|
||||
@@ -193,4 +194,20 @@ public class AlarmTest {
|
||||
createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED)));
|
||||
assertTrue("Alarm clock not exempt", isExemptFromAppStandby(createAlarmClock(anything)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsExemptFromTare() {
|
||||
final long anything = 54321; // Arbitrary number, doesn't matter for this test.
|
||||
|
||||
assertFalse("Basic alarm exempt", isExemptFromTare(
|
||||
createDefaultAlarm(anything, anything, 0)));
|
||||
assertFalse("FLAG_ALLOW_WHILE_IDLE_COMPAT exempt", isExemptFromTare(
|
||||
createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE_COMPAT)));
|
||||
assertFalse("ALLOW_WHILE_IDLE exempt", isExemptFromTare(
|
||||
createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE)));
|
||||
|
||||
assertTrue("ALLOW_WHILE_IDLE_UNRESTRICTED not exempt", isExemptFromTare(
|
||||
createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED)));
|
||||
assertTrue("Alarm clock not exempt", isExemptFromTare(createAlarmClock(anything)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user