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 import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
21 
22 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
23 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
24 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
26 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
27 
28 import static org.junit.Assert.assertEquals;
29 import static org.junit.Assert.fail;
30 import static org.mockito.ArgumentMatchers.any;
31 import static org.mockito.ArgumentMatchers.anyInt;
32 import static org.mockito.Mockito.eq;
33 import static org.mockito.Mockito.mock;
34 
35 import android.app.ActivityManager;
36 import android.app.IActivityManager;
37 import android.app.tare.EconomyManager;
38 import android.content.ContentResolver;
39 import android.content.Context;
40 import android.os.BatteryManager;
41 import android.os.Looper;
42 import android.os.PowerManager;
43 import android.os.RemoteException;
44 import android.provider.DeviceConfig;
45 
46 import androidx.annotation.NonNull;
47 import androidx.annotation.Nullable;
48 import androidx.test.runner.AndroidJUnit4;
49 
50 import org.junit.After;
51 import org.junit.Before;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 import org.mockito.ArgumentMatchers;
55 import org.mockito.Mock;
56 import org.mockito.MockitoSession;
57 import org.mockito.quality.Strictness;
58 import org.mockito.stubbing.Answer;
59 
60 @RunWith(AndroidJUnit4.class)
61 public class AlarmManagerEconomicPolicyTest {
62     private AlarmManagerEconomicPolicy mEconomicPolicy;
63     private DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
64     private EconomicPolicy.Injector mInjector = new InjectorForTest();
65 
66     private MockitoSession mMockingSession;
67     @Mock
68     private Context mContext;
69     @Mock
70     private InternalResourceService mIrs;
71 
72     private static class InjectorForTest extends EconomicPolicy.Injector {
73         public String settingsConstant;
74 
75         @Nullable
76         @Override
getSettingsGlobalString(@onNull ContentResolver resolver, @NonNull String name)77         String getSettingsGlobalString(@NonNull ContentResolver resolver, @NonNull String name) {
78             return TARE_ALARM_MANAGER_CONSTANTS.equals(name) ? settingsConstant : null;
79         }
80     }
81 
82     @Before
setUp()83     public void setUp() {
84         mMockingSession = mockitoSession()
85             .initMocks(this)
86             .strictness(Strictness.LENIENT)
87             .spyStatic(DeviceConfig.class)
88             .startMocking();
89 
90         when(mIrs.getContext()).thenReturn(mContext);
91         when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
92         when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
93         // Called by Modifiers.
94         when(mContext.getSystemService(BatteryManager.class))
95             .thenReturn(mock(BatteryManager.class));
96         when(mContext.getSystemService(PowerManager.class))
97             .thenReturn(mock(PowerManager.class));
98         IActivityManager activityManager = ActivityManager.getService();
99         spyOn(activityManager);
100         try {
101             doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
102         } catch (RemoteException e) {
103             fail("registerUidObserver threw exception: " + e.getMessage());
104         }
105 
106         mDeviceConfigPropertiesBuilder =
107                 new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_TARE);
108         doAnswer(
109                 (Answer<DeviceConfig.Properties>) invocationOnMock
110                         -> mDeviceConfigPropertiesBuilder.build())
111                 .when(() -> DeviceConfig.getProperties(
112                         eq(DeviceConfig.NAMESPACE_TARE), ArgumentMatchers.<String>any()));
113 
114         // Initialize real objects.
115         // Capture the listeners.
116         mEconomicPolicy = new AlarmManagerEconomicPolicy(mIrs, mInjector);
117     }
118 
119     @After
tearDown()120     public void tearDown() {
121         if (mMockingSession != null) {
122             mMockingSession.finishMocking();
123         }
124     }
125 
setDeviceConfigCakes(String key, long valCakes)126     private void setDeviceConfigCakes(String key, long valCakes) {
127         mDeviceConfigPropertiesBuilder.setString(key, valCakes + "c");
128         mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build());
129     }
130 
131     @Test
testDefaults()132     public void testDefaults() {
133         assertEquals(EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
134                 mEconomicPolicy.getInitialSatiatedConsumptionLimit());
135         assertEquals(EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES,
136                 mEconomicPolicy.getMinSatiatedConsumptionLimit());
137         assertEquals(EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES,
138                 mEconomicPolicy.getMaxSatiatedConsumptionLimit());
139 
140         final String pkgRestricted = "com.pkg.restricted";
141         when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
142         assertEquals(0, mEconomicPolicy.getMinSatiatedBalance(0, pkgRestricted));
143         assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
144 
145         final String pkgExempted = "com.pkg.exempted";
146         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
147         assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
148                 mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
149         assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
150                 mEconomicPolicy.getMaxSatiatedBalance(0, pkgExempted));
151 
152         final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
153         when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
154         assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES,
155                 mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
156         assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
157                 mEconomicPolicy.getMaxSatiatedBalance(0, pkgHeadlessSystemApp));
158 
159         assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
160                 mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
161         assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
162                 mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
163     }
164 
165     @Test
testConstantsUpdating_ValidValues()166     public void testConstantsUpdating_ValidValues() {
167         setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
168         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(3));
169         setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(25));
170         setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(10));
171         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(9));
172         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
173                 arcToCake(8));
174         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(7));
175 
176         assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
177         assertEquals(arcToCake(3), mEconomicPolicy.getMinSatiatedConsumptionLimit());
178         assertEquals(arcToCake(25), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
179         final String pkgRestricted = "com.pkg.restricted";
180         when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
181         assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
182         assertEquals(arcToCake(10), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
183         final String pkgExempted = "com.pkg.exempted";
184         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
185         assertEquals(arcToCake(9), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
186         final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
187         when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
188         assertEquals(arcToCake(8), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
189         assertEquals(arcToCake(7), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
190     }
191 
192     @Test
testConstantsUpdating_InvalidValues()193     public void testConstantsUpdating_InvalidValues() {
194         // Test negatives.
195         setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(-5));
196         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(-5));
197         setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(-5));
198         setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(-1));
199         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(-2));
200         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
201                 arcToCake(-3));
202         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(-3));
203 
204         assertEquals(arcToCake(1), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
205         assertEquals(arcToCake(1), mEconomicPolicy.getMinSatiatedConsumptionLimit());
206         assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
207         final String pkgRestricted = "com.pkg.restricted";
208         when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
209         assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
210         assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
211         final String pkgExempted = "com.pkg.exempted";
212         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
213         assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
214         final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
215         when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
216         assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
217         assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
218 
219         // Test min+max reversed.
220         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(5));
221         setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(4));
222         setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(3));
223         setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(10));
224         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(11));
225         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
226                 arcToCake(12));
227         setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(13));
228 
229         assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
230         assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedConsumptionLimit());
231         assertEquals(arcToCake(5), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
232         assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
233         assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
234         assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
235         assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
236         assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
237     }
238 }
239