summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kweku Adams <kwekua@google.com> 2022-07-25 17:50:47 +0000
committer Kweku Adams <kwekua@google.com> 2022-07-25 18:06:49 +0000
commite56b39071698a7146e6d93b384970111a2e21a60 (patch)
tree80352160098d6b11200439fae119d266053264af
parent84ce5affa7161f765f6c1b7bceb52589930c3a12 (diff)
Update EconomicPolicy loading.
1. Fix bug in CompleteEconomicPolicy that returned the incorrect hard consumption limit. 2. Add lower limits on the policy values to ensure valid values that allow for reasonable operation. Bug: 240162678 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: I89bae508930564ee3a082027dfb97ec517101dd0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java30
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java58
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java26
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java32
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java194
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java179
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java194
7 files changed, 662 insertions, 51 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
index d0f719b13b89..a46430feb688 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -91,6 +91,7 @@ import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_ONGOING
import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT;
import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_MAX;
import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.arcToCake;
import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
@@ -103,7 +104,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.provider.DeviceConfig;
-import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
import android.util.Slog;
@@ -150,13 +150,15 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
private final KeyValueListParser mParser = new KeyValueListParser(',');
private final InternalResourceService mInternalResourceService;
+ private final Injector mInjector;
private final SparseArray<Action> mActions = new SparseArray<>();
private final SparseArray<Reward> mRewards = new SparseArray<>();
- AlarmManagerEconomicPolicy(InternalResourceService irs) {
+ AlarmManagerEconomicPolicy(InternalResourceService irs, Injector injector) {
super(irs);
mInternalResourceService = irs;
+ mInjector = injector;
loadConstants("", null);
}
@@ -164,7 +166,7 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
void setup(@NonNull DeviceConfig.Properties properties) {
super.setup(properties);
ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
- loadConstants(Settings.Global.getString(resolver, TARE_ALARM_MANAGER_CONSTANTS),
+ loadConstants(mInjector.getSettingsGlobalString(resolver, TARE_ALARM_MANAGER_CONSTANTS),
properties);
}
@@ -226,20 +228,20 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
Slog.e(TAG, "Global setting key incorrect: ", e);
}
- mMinSatiatedBalanceExempted = getConstantAsCake(mParser, properties,
- KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED,
- DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES);
mMinSatiatedBalanceOther = getConstantAsCake(mParser, properties,
- KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP,
- DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES);
+ KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES);
+ mMinSatiatedBalanceExempted = getConstantAsCake(mParser, properties,
+ KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
+ mMinSatiatedBalanceOther);
mMaxSatiatedBalance = getConstantAsCake(mParser, properties,
- KEY_AM_MAX_SATIATED_BALANCE,
- DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES);
+ KEY_AM_MAX_SATIATED_BALANCE, DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
+ Math.max(arcToCake(1), mMinSatiatedBalanceExempted));
mInitialSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
- KEY_AM_INITIAL_CONSUMPTION_LIMIT, DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES);
- mHardSatiatedConsumptionLimit = Math.max(mInitialSatiatedConsumptionLimit,
- getConstantAsCake(mParser, properties,
- KEY_AM_HARD_CONSUMPTION_LIMIT, DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES));
+ KEY_AM_INITIAL_CONSUMPTION_LIMIT, DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
+ arcToCake(1));
+ mHardSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
+ KEY_AM_HARD_CONSUMPTION_LIMIT, DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES,
+ mInitialSatiatedConsumptionLimit);
final long exactAllowWhileIdleWakeupBasePrice = getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE,
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
index c3eb5bf51161..5d9cce84a7ac 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
@@ -23,11 +23,13 @@ import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.SparseArray;
-import libcore.util.EmptyArray;
+import com.android.internal.annotations.VisibleForTesting;
+import libcore.util.EmptyArray;
/** Combines all enabled policies into one. */
public class CompleteEconomicPolicy extends EconomicPolicy {
+
private final ArraySet<EconomicPolicy> mEnabledEconomicPolicies = new ArraySet<>();
/** Lazily populated set of actions covered by this policy. */
private final SparseArray<Action> mActions = new SparseArray<>();
@@ -35,12 +37,23 @@ public class CompleteEconomicPolicy extends EconomicPolicy {
private final SparseArray<Reward> mRewards = new SparseArray<>();
private final int[] mCostModifiers;
private long mMaxSatiatedBalance;
- private long mConsumptionLimit;
+ private long mInitialConsumptionLimit;
+ private long mHardConsumptionLimit;
CompleteEconomicPolicy(@NonNull InternalResourceService irs) {
+ this(irs, new CompleteInjector());
+ }
+
+ @VisibleForTesting
+ CompleteEconomicPolicy(@NonNull InternalResourceService irs,
+ @NonNull CompleteInjector injector) {
super(irs);
- mEnabledEconomicPolicies.add(new AlarmManagerEconomicPolicy(irs));
- mEnabledEconomicPolicies.add(new JobSchedulerEconomicPolicy(irs));
+ if (injector.isPolicyEnabled(POLICY_AM)) {
+ mEnabledEconomicPolicies.add(new AlarmManagerEconomicPolicy(irs, injector));
+ }
+ if (injector.isPolicyEnabled(POLICY_JS)) {
+ mEnabledEconomicPolicies.add(new JobSchedulerEconomicPolicy(irs, injector));
+ }
ArraySet<Integer> costModifiers = new ArraySet<>();
for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
@@ -54,7 +67,7 @@ public class CompleteEconomicPolicy extends EconomicPolicy {
mCostModifiers[i] = costModifiers.valueAt(i);
}
- updateMaxBalances();
+ updateLimits();
}
@Override
@@ -63,21 +76,22 @@ public class CompleteEconomicPolicy extends EconomicPolicy {
for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
mEnabledEconomicPolicies.valueAt(i).setup(properties);
}
- updateMaxBalances();
+ updateLimits();
}
- private void updateMaxBalances() {
- long max = 0;
+ private void updateLimits() {
+ long maxSatiatedBalance = 0;
+ long initialConsumptionLimit = 0;
+ long hardConsumptionLimit = 0;
for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
- max += mEnabledEconomicPolicies.valueAt(i).getMaxSatiatedBalance();
- }
- mMaxSatiatedBalance = max;
-
- max = 0;
- for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
- max += mEnabledEconomicPolicies.valueAt(i).getInitialSatiatedConsumptionLimit();
+ final EconomicPolicy economicPolicy = mEnabledEconomicPolicies.valueAt(i);
+ maxSatiatedBalance += economicPolicy.getMaxSatiatedBalance();
+ initialConsumptionLimit += economicPolicy.getInitialSatiatedConsumptionLimit();
+ hardConsumptionLimit += economicPolicy.getHardSatiatedConsumptionLimit();
}
- mConsumptionLimit = max;
+ mMaxSatiatedBalance = maxSatiatedBalance;
+ mInitialConsumptionLimit = initialConsumptionLimit;
+ mHardConsumptionLimit = hardConsumptionLimit;
}
@Override
@@ -96,12 +110,12 @@ public class CompleteEconomicPolicy extends EconomicPolicy {
@Override
long getInitialSatiatedConsumptionLimit() {
- return mConsumptionLimit;
+ return mInitialConsumptionLimit;
}
@Override
long getHardSatiatedConsumptionLimit() {
- return mConsumptionLimit;
+ return mHardConsumptionLimit;
}
@NonNull
@@ -156,6 +170,14 @@ public class CompleteEconomicPolicy extends EconomicPolicy {
return reward;
}
+ @VisibleForTesting
+ static class CompleteInjector extends Injector {
+
+ boolean isPolicyEnabled(int policy) {
+ return true;
+ }
+ }
+
@Override
void dump(IndentingPrintWriter pw) {
dumpActiveModifiers(pw);
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
index d401373c0066..c3855f0c71f0 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -29,10 +29,14 @@ import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ContentResolver;
import android.provider.DeviceConfig;
+import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -415,18 +419,34 @@ public abstract class EconomicPolicy {
protected long getConstantAsCake(@NonNull KeyValueListParser parser,
@Nullable DeviceConfig.Properties properties, String key, long defaultValCake) {
+ return getConstantAsCake(parser, properties, key, defaultValCake, 0);
+ }
+
+ protected long getConstantAsCake(@NonNull KeyValueListParser parser,
+ @Nullable DeviceConfig.Properties properties, String key, long defaultValCake,
+ long minValCake) {
// Don't cross the streams! Mixing Settings/local user config changes with DeviceConfig
// config can cause issues since the scales may be different, so use one or the other.
if (parser.size() > 0) {
// User settings take precedence. Just stick with the Settings constants, even if there
// are invalid values. It's not worth the time to evaluate all the key/value pairs to
// make sure there are valid ones before deciding.
- return parseCreditValue(parser.getString(key, null), defaultValCake);
+ return Math.max(minValCake,
+ parseCreditValue(parser.getString(key, null), defaultValCake));
}
if (properties != null) {
- return parseCreditValue(properties.getString(key, null), defaultValCake);
+ return Math.max(minValCake,
+ parseCreditValue(properties.getString(key, null), defaultValCake));
+ }
+ return Math.max(minValCake, defaultValCake);
+ }
+
+ @VisibleForTesting
+ static class Injector {
+ @Nullable
+ String getSettingsGlobalString(@NonNull ContentResolver resolver, @NonNull String name) {
+ return Settings.Global.getString(resolver, name);
}
- return defaultValCake;
}
protected static void dumpActiveModifiers(IndentingPrintWriter pw) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index 948f0a71510c..e7db1adc859e 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -100,6 +100,7 @@ import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_ONGOING
import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT;
import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_MAX;
import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.arcToCake;
import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
@@ -112,7 +113,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.provider.DeviceConfig;
-import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
import android.util.Slog;
@@ -152,13 +152,15 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
private final KeyValueListParser mParser = new KeyValueListParser(',');
private final InternalResourceService mInternalResourceService;
+ private final Injector mInjector;
private final SparseArray<Action> mActions = new SparseArray<>();
private final SparseArray<Reward> mRewards = new SparseArray<>();
- JobSchedulerEconomicPolicy(InternalResourceService irs) {
+ JobSchedulerEconomicPolicy(InternalResourceService irs, Injector injector) {
super(irs);
mInternalResourceService = irs;
+ mInjector = injector;
loadConstants("", null);
}
@@ -166,7 +168,7 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
void setup(@NonNull DeviceConfig.Properties properties) {
super.setup(properties);
ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
- loadConstants(Settings.Global.getString(resolver, TARE_JOB_SCHEDULER_CONSTANTS),
+ loadConstants(mInjector.getSettingsGlobalString(resolver, TARE_JOB_SCHEDULER_CONSTANTS),
properties);
}
@@ -223,22 +225,20 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
Slog.e(TAG, "Global setting key incorrect: ", e);
}
- mMinSatiatedBalanceExempted = getConstantAsCake(mParser, properties,
- KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED,
- DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES);
mMinSatiatedBalanceOther = getConstantAsCake(mParser, properties,
- KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP,
- DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES);
+ KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES);
+ mMinSatiatedBalanceExempted = getConstantAsCake(mParser, properties,
+ KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
+ mMinSatiatedBalanceOther);
mMaxSatiatedBalance = getConstantAsCake(mParser, properties,
- KEY_JS_MAX_SATIATED_BALANCE,
- DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES);
+ KEY_JS_MAX_SATIATED_BALANCE, DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
+ Math.max(arcToCake(1), mMinSatiatedBalanceExempted));
mInitialSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
- KEY_JS_INITIAL_CONSUMPTION_LIMIT,
- DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES);
- mHardSatiatedConsumptionLimit = Math.max(mInitialSatiatedConsumptionLimit,
- getConstantAsCake(mParser, properties,
- KEY_JS_HARD_CONSUMPTION_LIMIT,
- DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES));
+ KEY_JS_INITIAL_CONSUMPTION_LIMIT, DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES,
+ arcToCake(1));
+ mHardSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
+ KEY_JS_HARD_CONSUMPTION_LIMIT, DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES,
+ mInitialSatiatedConsumptionLimit);
mActions.put(ACTION_JOB_MAX_START, new Action(ACTION_JOB_MAX_START,
getConstantAsCake(mParser, properties,
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
new file mode 100644
index 000000000000..2e200c395e9d
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 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.tare;
+
+import static android.app.tare.EconomyManager.arcToCake;
+import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.app.tare.EconomyManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.provider.DeviceConfig;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+
+@RunWith(AndroidJUnit4.class)
+public class AlarmManagerEconomicPolicyTest {
+ private AlarmManagerEconomicPolicy mEconomicPolicy;
+ private DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
+ private EconomicPolicy.Injector mInjector = new InjectorForTest();
+
+ private MockitoSession mMockingSession;
+ @Mock
+ private Context mContext;
+ @Mock
+ private InternalResourceService mIrs;
+
+ private static class InjectorForTest extends EconomicPolicy.Injector {
+ public String settingsConstant;
+
+ @Nullable
+ @Override
+ String getSettingsGlobalString(@NonNull ContentResolver resolver, @NonNull String name) {
+ return TARE_ALARM_MANAGER_CONSTANTS.equals(name) ? settingsConstant : null;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .spyStatic(DeviceConfig.class)
+ .startMocking();
+
+ when(mIrs.getContext()).thenReturn(mContext);
+ when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+ when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
+ // Called by Modifiers.
+ when(mContext.getSystemService(BatteryManager.class))
+ .thenReturn(mock(BatteryManager.class));
+ when(mContext.getSystemService(PowerManager.class))
+ .thenReturn(mock(PowerManager.class));
+ IActivityManager activityManager = ActivityManager.getService();
+ spyOn(activityManager);
+ try {
+ doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
+ } catch (RemoteException e) {
+ fail("registerUidObserver threw exception: " + e.getMessage());
+ }
+
+ mDeviceConfigPropertiesBuilder =
+ new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_TARE);
+ doAnswer(
+ (Answer<DeviceConfig.Properties>) invocationOnMock
+ -> mDeviceConfigPropertiesBuilder.build())
+ .when(() -> DeviceConfig.getProperties(
+ eq(DeviceConfig.NAMESPACE_TARE), ArgumentMatchers.<String>any()));
+
+ // Initialize real objects.
+ // Capture the listeners.
+ mEconomicPolicy = new AlarmManagerEconomicPolicy(mIrs, mInjector);
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ private void setDeviceConfigCakes(String key, long valCakes) {
+ mDeviceConfigPropertiesBuilder.setString(key, valCakes + "c");
+ mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build());
+ }
+
+ @Test
+ public void testDefaults() {
+ assertEquals(EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
+ mEconomicPolicy.getMaxSatiatedBalance());
+ final String pkgExempted = "com.pkg.exempted";
+ when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
+ assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
+ mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
+ assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
+ mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
+ }
+
+ @Test
+ public void testConstantsUpdating_ValidValues() {
+ setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_HARD_CONSUMPTION_LIMIT, arcToCake(25));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(10));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(9));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(7));
+
+ assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ assertEquals(arcToCake(25), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(10), mEconomicPolicy.getMaxSatiatedBalance());
+ final String pkgExempted = "com.pkg.exempted";
+ when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
+ assertEquals(arcToCake(9), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
+ assertEquals(arcToCake(7), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
+ }
+
+ @Test
+ public void testConstantsUpdating_InvalidValues() {
+ // Test negatives.
+ setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(-5));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_HARD_CONSUMPTION_LIMIT, arcToCake(-5));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(-1));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(-2));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(-3));
+
+ assertEquals(arcToCake(1), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ assertEquals(arcToCake(1), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedBalance());
+ final String pkgExempted = "com.pkg.exempted";
+ when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
+ assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
+ assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
+
+ // Test min+max reversed.
+ setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_HARD_CONSUMPTION_LIMIT, arcToCake(3));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(10));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(11));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(13));
+
+ assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ assertEquals(arcToCake(5), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance());
+ assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
+ assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
new file mode 100644
index 000000000000..45c97e4c5d80
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2022 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.tare;
+
+import static android.app.tare.EconomyManager.arcToCake;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.app.tare.EconomyManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.provider.DeviceConfig;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+
+@RunWith(AndroidJUnit4.class)
+public class CompleteEconomicPolicyTest {
+ private CompleteEconomicPolicy mEconomicPolicy;
+ private DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
+ private final CompleteEconomicPolicy.CompleteInjector mInjector = new InjectorForTest();
+
+ private MockitoSession mMockingSession;
+ @Mock
+ private Context mContext;
+ @Mock
+ private InternalResourceService mIrs;
+
+ private static class InjectorForTest extends CompleteEconomicPolicy.CompleteInjector {
+ public String settingsConstant;
+
+ @Nullable
+ @Override
+ String getSettingsGlobalString(@NonNull ContentResolver resolver, @NonNull String name) {
+ return settingsConstant;
+ }
+
+ @Override
+ boolean isPolicyEnabled(int policy) {
+ // Use a limited set of policies so that the test doesn't need to be updated whenever
+ // a policy is added or removed.
+ return policy == EconomicPolicy.POLICY_AM || policy == EconomicPolicy.POLICY_JS;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .spyStatic(DeviceConfig.class)
+ .startMocking();
+
+ when(mIrs.getContext()).thenReturn(mContext);
+ when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+ when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
+ // Called by Modifiers.
+ when(mContext.getSystemService(BatteryManager.class))
+ .thenReturn(mock(BatteryManager.class));
+ when(mContext.getSystemService(PowerManager.class))
+ .thenReturn(mock(PowerManager.class));
+ IActivityManager activityManager = ActivityManager.getService();
+ spyOn(activityManager);
+ try {
+ doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
+ } catch (RemoteException e) {
+ fail("registerUidObserver threw exception: " + e.getMessage());
+ }
+
+ mDeviceConfigPropertiesBuilder =
+ new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_TARE);
+ doAnswer(
+ (Answer<DeviceConfig.Properties>) invocationOnMock
+ -> mDeviceConfigPropertiesBuilder.build())
+ .when(() -> DeviceConfig.getProperties(
+ eq(DeviceConfig.NAMESPACE_TARE), ArgumentMatchers.<String>any()));
+
+ // Initialize real objects.
+ // Capture the listeners.
+ mEconomicPolicy = new CompleteEconomicPolicy(mIrs, mInjector);
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ private void setDeviceConfigCakes(String key, long valCakes) {
+ mDeviceConfigPropertiesBuilder.setString(key, valCakes + "c");
+ mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build());
+ }
+
+ @Test
+ public void testDefaults() {
+ assertEquals(EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES
+ + EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES
+ + EconomyManager.DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES
+ + EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
+ mEconomicPolicy.getMaxSatiatedBalance());
+ final String pkgExempted = "com.pkg.exempted";
+ when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
+ assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES
+ + EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
+ mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
+ assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES
+ + EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
+ mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
+ }
+
+ @Test
+ public void testConstantsUpdated() {
+ setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(4));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(6));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT, arcToCake(24));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_HARD_CONSUMPTION_LIMIT, arcToCake(26));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(9));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(11));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(8));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(5));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(3));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(2));
+
+ assertEquals(arcToCake(10), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ assertEquals(arcToCake(50), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(20), mEconomicPolicy.getMaxSatiatedBalance());
+ final String pkgExempted = "com.pkg.exempted";
+ when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
+ assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
+ assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
new file mode 100644
index 000000000000..03ce91aea58b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 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.tare;
+
+import static android.app.tare.EconomyManager.arcToCake;
+import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.app.tare.EconomyManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.provider.DeviceConfig;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+
+@RunWith(AndroidJUnit4.class)
+public class JobSchedulerEconomicPolicyTest {
+ private JobSchedulerEconomicPolicy mEconomicPolicy;
+ private DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
+ private final EconomicPolicy.Injector mInjector = new InjectorForTest();
+
+ private MockitoSession mMockingSession;
+ @Mock
+ private Context mContext;
+ @Mock
+ private InternalResourceService mIrs;
+
+ private static class InjectorForTest extends EconomicPolicy.Injector {
+ public String settingsConstant;
+
+ @Nullable
+ @Override
+ String getSettingsGlobalString(@NonNull ContentResolver resolver, @NonNull String name) {
+ return TARE_JOB_SCHEDULER_CONSTANTS.equals(name) ? settingsConstant : null;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .spyStatic(DeviceConfig.class)
+ .startMocking();
+
+ when(mIrs.getContext()).thenReturn(mContext);
+ when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+ when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
+ // Called by Modifiers.
+ when(mContext.getSystemService(BatteryManager.class))
+ .thenReturn(mock(BatteryManager.class));
+ when(mContext.getSystemService(PowerManager.class))
+ .thenReturn(mock(PowerManager.class));
+ IActivityManager activityManager = ActivityManager.getService();
+ spyOn(activityManager);
+ try {
+ doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
+ } catch (RemoteException e) {
+ fail("registerUidObserver threw exception: " + e.getMessage());
+ }
+
+ mDeviceConfigPropertiesBuilder =
+ new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_TARE);
+ doAnswer(
+ (Answer<DeviceConfig.Properties>) invocationOnMock
+ -> mDeviceConfigPropertiesBuilder.build())
+ .when(() -> DeviceConfig.getProperties(
+ eq(DeviceConfig.NAMESPACE_TARE), ArgumentMatchers.<String>any()));
+
+ // Initialize real objects.
+ // Capture the listeners.
+ mEconomicPolicy = new JobSchedulerEconomicPolicy(mIrs, mInjector);
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ private void setDeviceConfigCakes(String key, long valCakes) {
+ mDeviceConfigPropertiesBuilder.setString(key, valCakes + "c");
+ mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build());
+ }
+
+ @Test
+ public void testDefaults() {
+ assertEquals(EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
+ mEconomicPolicy.getMaxSatiatedBalance());
+ final String pkgExempted = "com.pkg.exempted";
+ when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
+ assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
+ mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
+ assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
+ mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
+ }
+
+ @Test
+ public void testConstantsUpdating_ValidValues() {
+ setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT, arcToCake(25));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(10));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(9));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(7));
+
+ assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ assertEquals(arcToCake(25), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(10), mEconomicPolicy.getMaxSatiatedBalance());
+ final String pkgExempted = "com.pkg.exempted";
+ when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
+ assertEquals(arcToCake(9), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
+ assertEquals(arcToCake(7), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
+ }
+
+ @Test
+ public void testConstantsUpdating_InvalidValues() {
+ // Test negatives.
+ setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(-5));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT, arcToCake(-5));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(-1));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(-2));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(-3));
+
+ assertEquals(arcToCake(1), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ assertEquals(arcToCake(1), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedBalance());
+ final String pkgExempted = "com.pkg.exempted";
+ when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
+ assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
+ assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
+
+ // Test min+max reversed.
+ setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT, arcToCake(3));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(10));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(11));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(13));
+
+ assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ assertEquals(arcToCake(5), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance());
+ assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
+ assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
+ }
+}