1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.tare; 18 19 import static android.app.tare.EconomyManager.arcToCake; 20 21 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 22 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 23 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 24 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; 26 27 import static org.junit.Assert.assertEquals; 28 import static org.junit.Assert.assertFalse; 29 import static org.junit.Assert.assertNotNull; 30 import static org.junit.Assert.assertNull; 31 import static org.junit.Assert.assertTrue; 32 import static org.junit.Assert.fail; 33 import static org.mockito.ArgumentMatchers.any; 34 import static org.mockito.ArgumentMatchers.anyInt; 35 import static org.mockito.Mockito.eq; 36 import static org.mockito.Mockito.mock; 37 38 import android.app.ActivityManager; 39 import android.app.IActivityManager; 40 import android.app.tare.EconomyManager; 41 import android.content.ContentResolver; 42 import android.content.Context; 43 import android.os.BatteryManager; 44 import android.os.Looper; 45 import android.os.PowerManager; 46 import android.os.RemoteException; 47 import android.provider.DeviceConfig; 48 49 import androidx.annotation.NonNull; 50 import androidx.annotation.Nullable; 51 import androidx.test.runner.AndroidJUnit4; 52 53 import org.junit.After; 54 import org.junit.Before; 55 import org.junit.Test; 56 import org.junit.runner.RunWith; 57 import org.mockito.ArgumentMatchers; 58 import org.mockito.Mock; 59 import org.mockito.MockitoSession; 60 import org.mockito.quality.Strictness; 61 import org.mockito.stubbing.Answer; 62 63 @RunWith(AndroidJUnit4.class) 64 public class CompleteEconomicPolicyTest { 65 private CompleteEconomicPolicy mEconomicPolicy; 66 private DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder; 67 private final CompleteEconomicPolicy.CompleteInjector mInjector = new InjectorForTest(); 68 69 private MockitoSession mMockingSession; 70 @Mock 71 private Context mContext; 72 @Mock 73 private InternalResourceService mIrs; 74 75 private static class InjectorForTest extends CompleteEconomicPolicy.CompleteInjector { 76 public String settingsConstant; 77 78 @Nullable 79 @Override getSettingsGlobalString(@onNull ContentResolver resolver, @NonNull String name)80 String getSettingsGlobalString(@NonNull ContentResolver resolver, @NonNull String name) { 81 return settingsConstant; 82 } 83 84 @Override isPolicyEnabled(int policy, @Nullable DeviceConfig.Properties properties)85 boolean isPolicyEnabled(int policy, @Nullable DeviceConfig.Properties properties) { 86 // Use a limited set of policies so that the test doesn't need to be updated whenever 87 // a policy is added or removed. 88 if (policy == EconomicPolicy.POLICY_ALARM || policy == EconomicPolicy.POLICY_JOB) { 89 return super.isPolicyEnabled(policy, properties); 90 } 91 return false; 92 } 93 } 94 95 @Before setUp()96 public void setUp() { 97 mMockingSession = mockitoSession() 98 .initMocks(this) 99 .strictness(Strictness.LENIENT) 100 .spyStatic(DeviceConfig.class) 101 .startMocking(); 102 103 when(mIrs.getContext()).thenReturn(mContext); 104 when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); 105 when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class)); 106 // Called by Modifiers. 107 when(mContext.getSystemService(BatteryManager.class)) 108 .thenReturn(mock(BatteryManager.class)); 109 when(mContext.getSystemService(PowerManager.class)) 110 .thenReturn(mock(PowerManager.class)); 111 IActivityManager activityManager = ActivityManager.getService(); 112 spyOn(activityManager); 113 try { 114 doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any()); 115 } catch (RemoteException e) { 116 fail("registerUidObserver threw exception: " + e.getMessage()); 117 } 118 119 mDeviceConfigPropertiesBuilder = 120 new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_TARE); 121 doAnswer( 122 (Answer<DeviceConfig.Properties>) invocationOnMock 123 -> mDeviceConfigPropertiesBuilder.build()) 124 .when(() -> DeviceConfig.getProperties( 125 eq(DeviceConfig.NAMESPACE_TARE), ArgumentMatchers.<String>any())); 126 mDeviceConfigPropertiesBuilder 127 .setBoolean(EconomyManager.KEY_ENABLE_POLICY_ALARM, true) 128 .setBoolean(EconomyManager.KEY_ENABLE_POLICY_JOB_SCHEDULER, true); 129 130 // Initialize real objects. 131 // Capture the listeners. 132 mEconomicPolicy = new CompleteEconomicPolicy(mIrs, mInjector); 133 mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build()); 134 } 135 136 @After tearDown()137 public void tearDown() { 138 if (mMockingSession != null) { 139 mMockingSession.finishMocking(); 140 } 141 } 142 setDeviceConfigBoolean(String key, boolean val)143 private void setDeviceConfigBoolean(String key, boolean val) { 144 mDeviceConfigPropertiesBuilder.setBoolean(key, val); 145 mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build()); 146 } 147 setDeviceConfigCakes(String key, long valCakes)148 private void setDeviceConfigCakes(String key, long valCakes) { 149 mDeviceConfigPropertiesBuilder.setString(key, valCakes + "c"); 150 mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build()); 151 } 152 153 @Test testDefaults()154 public void testDefaults() { 155 assertEquals(EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES 156 + EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES, 157 mEconomicPolicy.getInitialSatiatedConsumptionLimit()); 158 assertEquals(EconomyManager.DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES 159 + EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES, 160 mEconomicPolicy.getMinSatiatedConsumptionLimit()); 161 assertEquals(EconomyManager.DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES 162 + EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES, 163 mEconomicPolicy.getMaxSatiatedConsumptionLimit()); 164 final String pkgRestricted = "com.pkg.restricted"; 165 when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true); 166 assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted)); 167 assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES 168 + EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES, 169 mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app")); 170 final String pkgExempted = "com.pkg.exempted"; 171 when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true); 172 assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES 173 + EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES, 174 mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted)); 175 assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES 176 + EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES, 177 mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app")); 178 } 179 180 @Test testConstantsUpdated()181 public void testConstantsUpdated() { 182 setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(4)); 183 setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(6)); 184 setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT, arcToCake(2)); 185 setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(3)); 186 setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT, arcToCake(24)); 187 setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(26)); 188 setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(9)); 189 setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(11)); 190 setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(8)); 191 setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(5)); 192 setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP, 193 arcToCake(6)); 194 setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP, 195 arcToCake(4)); 196 setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(3)); 197 setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(2)); 198 199 assertEquals(arcToCake(10), mEconomicPolicy.getInitialSatiatedConsumptionLimit()); 200 assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedConsumptionLimit()); 201 assertEquals(arcToCake(50), mEconomicPolicy.getMaxSatiatedConsumptionLimit()); 202 final String pkgRestricted = "com.pkg.restricted"; 203 when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true); 204 assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted)); 205 assertEquals(arcToCake(20), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app")); 206 final String pkgExempted = "com.pkg.exempted"; 207 when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true); 208 assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted)); 209 final String pkgHeadlessSystemApp = "com.pkg.headless_system_app"; 210 when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true); 211 assertEquals(arcToCake(10), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp)); 212 assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app")); 213 } 214 215 216 @Test testPolicyToggling()217 public void testPolicyToggling() { 218 setDeviceConfigBoolean(EconomyManager.KEY_ENABLE_POLICY_ALARM, true); 219 setDeviceConfigBoolean(EconomyManager.KEY_ENABLE_POLICY_JOB_SCHEDULER, false); 220 assertEquals(EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES, 221 mEconomicPolicy.getInitialSatiatedConsumptionLimit()); 222 assertEquals(EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES, 223 mEconomicPolicy.getMinSatiatedConsumptionLimit()); 224 assertEquals(EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES, 225 mEconomicPolicy.getMaxSatiatedConsumptionLimit()); 226 final String pkgRestricted = "com.pkg.restricted"; 227 when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true); 228 assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted)); 229 assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES, 230 mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app")); 231 final String pkgExempted = "com.pkg.exempted"; 232 when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true); 233 assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES, 234 mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted)); 235 assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES, 236 mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app")); 237 assertNotNull(mEconomicPolicy.getAction(AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK)); 238 assertNull(mEconomicPolicy.getAction(JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START)); 239 assertEquals(EconomicPolicy.POLICY_ALARM, mEconomicPolicy.getEnabledPolicyIds()); 240 assertTrue(mEconomicPolicy.isPolicyEnabled(EconomicPolicy.POLICY_ALARM)); 241 assertFalse(mEconomicPolicy.isPolicyEnabled(EconomicPolicy.POLICY_JOB)); 242 243 setDeviceConfigBoolean(EconomyManager.KEY_ENABLE_POLICY_ALARM, false); 244 setDeviceConfigBoolean(EconomyManager.KEY_ENABLE_POLICY_JOB_SCHEDULER, true); 245 assertEquals(EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES, 246 mEconomicPolicy.getInitialSatiatedConsumptionLimit()); 247 assertEquals(EconomyManager.DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES, 248 mEconomicPolicy.getMinSatiatedConsumptionLimit()); 249 assertEquals(EconomyManager.DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES, 250 mEconomicPolicy.getMaxSatiatedConsumptionLimit()); 251 when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true); 252 assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted)); 253 assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES, 254 mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app")); 255 when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true); 256 assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES, 257 mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted)); 258 assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES, 259 mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app")); 260 assertNull(mEconomicPolicy.getAction(AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK)); 261 assertNotNull(mEconomicPolicy.getAction(JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START)); 262 assertEquals(EconomicPolicy.POLICY_JOB, mEconomicPolicy.getEnabledPolicyIds()); 263 assertFalse(mEconomicPolicy.isPolicyEnabled(EconomicPolicy.POLICY_ALARM)); 264 assertTrue(mEconomicPolicy.isPolicyEnabled(EconomicPolicy.POLICY_JOB)); 265 } 266 } 267