Exempt exact alarms from the stock limit.
Allow apps to set and use exact alarms even if the TARE system has run out of consumable stock. Since apps need to hold the SCHEDULE_EXACT_ALARM or USE_EXACT_ALARM permissions to use exact alarms, we can be a little more lenient with the check. Enforcing the stock limit check could result in some unexpected user journeys. We continue to apply the app balance check so apps can't runaway with exact alarms. Bug: 258032540 Test: atest frameworks/base/services/tests/mockingservicestests/src/com/android/server/tare Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/tare Change-Id: I307fe35370e0450d2248e4bbdbcf0c00839d3214
This commit is contained in:
@@ -164,8 +164,9 @@ class Agent {
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean isAffordableLocked(long balance, long price, long ctp) {
|
||||
return balance >= price && mScribe.getRemainingConsumableCakesLocked() >= ctp;
|
||||
private boolean isAffordableLocked(long balance, long price, long stockLimitHonoringCtp) {
|
||||
return balance >= price
|
||||
&& mScribe.getRemainingConsumableCakesLocked() >= stockLimitHonoringCtp;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@@ -303,7 +304,8 @@ class Agent {
|
||||
note.recalculateCosts(economicPolicy, userId, pkgName);
|
||||
final boolean isAffordable = isVip
|
||||
|| isAffordableLocked(newBalance,
|
||||
note.getCachedModifiedPrice(), note.getCtp());
|
||||
note.getCachedModifiedPrice(),
|
||||
note.getStockLimitHonoringCtp());
|
||||
if (note.isCurrentlyAffordable() != isAffordable) {
|
||||
note.setNewAffordability(isAffordable);
|
||||
mIrs.postAffordabilityChanged(userId, pkgName, note);
|
||||
@@ -339,7 +341,7 @@ class Agent {
|
||||
note.recalculateCosts(economicPolicy, userId, pkgName);
|
||||
final boolean isAffordable = isVip
|
||||
|| isAffordableLocked(newBalance,
|
||||
note.getCachedModifiedPrice(), note.getCtp());
|
||||
note.getCachedModifiedPrice(), note.getStockLimitHonoringCtp());
|
||||
if (note.isCurrentlyAffordable() != isAffordable) {
|
||||
note.setNewAffordability(isAffordable);
|
||||
mIrs.postAffordabilityChanged(userId, pkgName, note);
|
||||
@@ -403,7 +405,8 @@ class Agent {
|
||||
note.recalculateCosts(economicPolicy, userId, pkgName);
|
||||
final boolean isAffordable = isVip
|
||||
|| isAffordableLocked(newBalance,
|
||||
note.getCachedModifiedPrice(), note.getCtp());
|
||||
note.getCachedModifiedPrice(),
|
||||
note.getStockLimitHonoringCtp());
|
||||
if (note.isCurrentlyAffordable() != isAffordable) {
|
||||
note.setNewAffordability(isAffordable);
|
||||
mIrs.postAffordabilityChanged(userId, pkgName, note);
|
||||
@@ -541,7 +544,7 @@ class Agent {
|
||||
final ActionAffordabilityNote note = actionAffordabilityNotes.valueAt(i);
|
||||
final boolean isAffordable = isVip
|
||||
|| isAffordableLocked(newBalance,
|
||||
note.getCachedModifiedPrice(), note.getCtp());
|
||||
note.getCachedModifiedPrice(), note.getStockLimitHonoringCtp());
|
||||
if (note.isCurrentlyAffordable() != isAffordable) {
|
||||
note.setNewAffordability(isAffordable);
|
||||
mIrs.postAffordabilityChanged(userId, pkgName, note);
|
||||
@@ -882,7 +885,7 @@ class Agent {
|
||||
mUpperThreshold = (mUpperThreshold == Long.MIN_VALUE)
|
||||
? price : Math.min(mUpperThreshold, price);
|
||||
}
|
||||
final long ctp = note.getCtp();
|
||||
final long ctp = note.getStockLimitHonoringCtp();
|
||||
if (ctp <= mRemainingConsumableCredits) {
|
||||
mCtpThreshold = Math.max(mCtpThreshold, ctp);
|
||||
}
|
||||
@@ -1119,7 +1122,7 @@ class Agent {
|
||||
note.recalculateCosts(economicPolicy, userId, pkgName);
|
||||
note.setNewAffordability(isVip
|
||||
|| isAffordableLocked(getBalanceLocked(userId, pkgName),
|
||||
note.getCachedModifiedPrice(), note.getCtp()));
|
||||
note.getCachedModifiedPrice(), note.getStockLimitHonoringCtp()));
|
||||
mIrs.postAffordabilityChanged(userId, pkgName, note);
|
||||
// Update ongoing alarm
|
||||
scheduleBalanceCheckLocked(userId, pkgName);
|
||||
@@ -1146,7 +1149,7 @@ class Agent {
|
||||
static final class ActionAffordabilityNote {
|
||||
private final EconomyManagerInternal.ActionBill mActionBill;
|
||||
private final EconomyManagerInternal.AffordabilityChangeListener mListener;
|
||||
private long mCtp;
|
||||
private long mStockLimitHonoringCtp;
|
||||
private long mModifiedPrice;
|
||||
private boolean mIsAffordable;
|
||||
|
||||
@@ -1185,29 +1188,34 @@ class Agent {
|
||||
return mModifiedPrice;
|
||||
}
|
||||
|
||||
private long getCtp() {
|
||||
return mCtp;
|
||||
/** Returns the cumulative CTP of actions in this note that respect the stock limit. */
|
||||
private long getStockLimitHonoringCtp() {
|
||||
return mStockLimitHonoringCtp;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void recalculateCosts(@NonNull EconomicPolicy economicPolicy,
|
||||
int userId, @NonNull String pkgName) {
|
||||
long modifiedPrice = 0;
|
||||
long ctp = 0;
|
||||
long stockLimitHonoringCtp = 0;
|
||||
final List<EconomyManagerInternal.AnticipatedAction> anticipatedActions =
|
||||
mActionBill.getAnticipatedActions();
|
||||
for (int i = 0; i < anticipatedActions.size(); ++i) {
|
||||
final EconomyManagerInternal.AnticipatedAction aa = anticipatedActions.get(i);
|
||||
final EconomicPolicy.Action action = economicPolicy.getAction(aa.actionId);
|
||||
|
||||
final EconomicPolicy.Cost actionCost =
|
||||
economicPolicy.getCostOfAction(aa.actionId, userId, pkgName);
|
||||
modifiedPrice += actionCost.price * aa.numInstantaneousCalls
|
||||
+ actionCost.price * (aa.ongoingDurationMs / 1000);
|
||||
ctp += actionCost.costToProduce * aa.numInstantaneousCalls
|
||||
+ actionCost.costToProduce * (aa.ongoingDurationMs / 1000);
|
||||
if (action.respectsStockLimit) {
|
||||
stockLimitHonoringCtp +=
|
||||
actionCost.costToProduce * aa.numInstantaneousCalls
|
||||
+ actionCost.costToProduce * (aa.ongoingDurationMs / 1000);
|
||||
}
|
||||
}
|
||||
mModifiedPrice = modifiedPrice;
|
||||
mCtp = ctp;
|
||||
mStockLimitHonoringCtp = stockLimitHonoringCtp;
|
||||
}
|
||||
|
||||
boolean isCurrentlyAffordable() {
|
||||
@@ -1267,7 +1275,8 @@ class Agent {
|
||||
final ActionAffordabilityNote note =
|
||||
actionAffordabilityNotes.valueAt(i);
|
||||
final boolean isAffordable = isVip || isAffordableLocked(
|
||||
newBalance, note.getCachedModifiedPrice(), note.getCtp());
|
||||
newBalance, note.getCachedModifiedPrice(),
|
||||
note.getStockLimitHonoringCtp());
|
||||
if (note.isCurrentlyAffordable() != isAffordable) {
|
||||
note.setNewAffordability(isAffordable);
|
||||
mIrs.postAffordabilityChanged(userId, pkgName, note);
|
||||
|
||||
@@ -262,12 +262,17 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
|
||||
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE,
|
||||
DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE_CAKES);
|
||||
|
||||
// Apps must hold the SCHEDULE_EXACT_ALARM or USE_EXACT_ALARMS permission in order to use
|
||||
// exact alarms. Since the user has the option of granting/revoking the permission, we can
|
||||
// be a little lenient on the action cost checks and only stop the action if the app has
|
||||
// run out of credits, and not when the system has run out of stock.
|
||||
mActions.put(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
|
||||
new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
|
||||
getConstantAsCake(mParser, properties,
|
||||
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP,
|
||||
DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP_CAKES),
|
||||
exactAllowWhileIdleWakeupBasePrice));
|
||||
exactAllowWhileIdleWakeupBasePrice,
|
||||
/* respectsStockLimit */ false));
|
||||
mActions.put(ACTION_ALARM_WAKEUP_EXACT,
|
||||
new Action(ACTION_ALARM_WAKEUP_EXACT,
|
||||
getConstantAsCake(mParser, properties,
|
||||
@@ -275,7 +280,8 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
|
||||
DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP_CAKES),
|
||||
getConstantAsCake(mParser, properties,
|
||||
KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE,
|
||||
DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE_CAKES)));
|
||||
DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE_CAKES),
|
||||
/* respectsStockLimit */ false));
|
||||
|
||||
final long inexactAllowWhileIdleWakeupBasePrice =
|
||||
getConstantAsCake(mParser, properties,
|
||||
@@ -287,7 +293,8 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
|
||||
getConstantAsCake(mParser, properties,
|
||||
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP,
|
||||
DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP_CAKES),
|
||||
inexactAllowWhileIdleWakeupBasePrice));
|
||||
inexactAllowWhileIdleWakeupBasePrice,
|
||||
/* respectsStockLimit */ false));
|
||||
mActions.put(ACTION_ALARM_WAKEUP_INEXACT,
|
||||
new Action(ACTION_ALARM_WAKEUP_INEXACT,
|
||||
getConstantAsCake(mParser, properties,
|
||||
@@ -295,7 +302,8 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
|
||||
DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP_CAKES),
|
||||
getConstantAsCake(mParser, properties,
|
||||
KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE,
|
||||
DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES)));
|
||||
DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES),
|
||||
/* respectsStockLimit */ false));
|
||||
|
||||
final long exactAllowWhileIdleNonWakeupBasePrice = getConstantAsCake(mParser, properties,
|
||||
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE,
|
||||
@@ -305,7 +313,8 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
|
||||
getConstantAsCake(mParser, properties,
|
||||
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP,
|
||||
DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP_CAKES),
|
||||
exactAllowWhileIdleNonWakeupBasePrice));
|
||||
exactAllowWhileIdleNonWakeupBasePrice,
|
||||
/* respectsStockLimit */ false));
|
||||
|
||||
mActions.put(ACTION_ALARM_NONWAKEUP_EXACT,
|
||||
new Action(ACTION_ALARM_NONWAKEUP_EXACT,
|
||||
@@ -314,7 +323,8 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
|
||||
DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP_CAKES),
|
||||
getConstantAsCake(mParser, properties,
|
||||
KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE,
|
||||
DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE_CAKES)));
|
||||
DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE_CAKES),
|
||||
/* respectsStockLimit */ false));
|
||||
|
||||
final long inexactAllowWhileIdleNonWakeupBasePrice = getConstantAsCake(mParser, properties,
|
||||
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE,
|
||||
@@ -342,7 +352,8 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
|
||||
DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP_CAKES),
|
||||
getConstantAsCake(mParser, properties,
|
||||
KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE,
|
||||
DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE_CAKES)));
|
||||
DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE_CAKES),
|
||||
/* respectsStockLimit */ false));
|
||||
|
||||
mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
|
||||
getConstantAsCake(mParser, properties,
|
||||
|
||||
@@ -149,11 +149,22 @@ public abstract class EconomicPolicy {
|
||||
* the action unless a modifier lowers the cost to produce.
|
||||
*/
|
||||
public final long basePrice;
|
||||
/**
|
||||
* Whether the remaining stock limit affects an app's ability to perform this action.
|
||||
* If {@code false}, then the action can be performed, even if the cost is higher
|
||||
* than the remaining stock. This does not affect checking against an app's balance.
|
||||
*/
|
||||
public final boolean respectsStockLimit;
|
||||
|
||||
Action(int id, long costToProduce, long basePrice) {
|
||||
this(id, costToProduce, basePrice, true);
|
||||
}
|
||||
|
||||
Action(int id, long costToProduce, long basePrice, boolean respectsStockLimit) {
|
||||
this.id = id;
|
||||
this.costToProduce = costToProduce;
|
||||
this.basePrice = basePrice;
|
||||
this.respectsStockLimit = respectsStockLimit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user