1 /*
2  * Copyright (C) 2023 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.settings.fuelgauge.datasaver;
18 
19 import static android.net.NetworkPolicyManager.POLICY_NONE;
20 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
21 
22 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
23 import static com.android.settings.fuelgauge.datasaver.DynamicDenylistManager.PREF_KEY_MANUAL_DENYLIST_SYNCED;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import static org.junit.Assert.assertFalse;
28 import static org.junit.Assert.assertTrue;
29 import static org.mockito.ArgumentMatchers.anyInt;
30 import static org.mockito.ArgumentMatchers.eq;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.spy;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.verify;
35 import static org.mockito.Mockito.when;
36 
37 import android.content.Context;
38 import android.content.SharedPreferences;
39 import android.content.pm.PackageManager;
40 import android.net.NetworkPolicyManager;
41 import android.util.ArraySet;
42 
43 import org.junit.After;
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.mockito.Mock;
48 import org.mockito.MockitoAnnotations;
49 import org.robolectric.RobolectricTestRunner;
50 import org.robolectric.RuntimeEnvironment;
51 
52 import java.io.PrintWriter;
53 import java.io.StringWriter;
54 import java.util.Collections;
55 import java.util.List;
56 import java.util.Set;
57 
58 @RunWith(RobolectricTestRunner.class)
59 public class DynamicDenylistManagerTest {
60 
61     private static final int[] EMPTY_ARRAY = new int[] {};
62     private static final String FAKE_UID_1 = "1001";
63     private static final String FAKE_UID_2 = "1002";
64     private static final int FAKE_UID_1_INT = Integer.parseInt(FAKE_UID_1);
65     private static final int FAKE_UID_2_INT = Integer.parseInt(FAKE_UID_2);
66 
67     private SharedPreferences mManualDenyListPref;
68     private SharedPreferences mDynamicDenyListPref;
69     private DynamicDenylistManager mDynamicDenylistManager;
70 
71     @Mock
72     private NetworkPolicyManager mNetworkPolicyManager;
73     @Mock
74     private PackageManager mPackageManager;
75 
76     @Before
setUp()77     public void setUp() {
78         MockitoAnnotations.initMocks(this);
79     }
80 
81     @After
tearDown()82     public void tearDown() {
83         mDynamicDenylistManager.clearSharedPreferences();
84     }
85 
86     @Test
init_withoutExistedRejectPolicy_createWithExpectedValue()87     public void init_withoutExistedRejectPolicy_createWithExpectedValue() {
88         initDynamicDenylistManager(EMPTY_ARRAY);
89 
90         assertThat(mManualDenyListPref.getAll()).hasSize(1);
91         assertTrue(mManualDenyListPref.contains(PREF_KEY_MANUAL_DENYLIST_SYNCED));
92     }
93 
94     @Test
init_withExistedRejectPolicy_createWithExpectedValue()95     public void init_withExistedRejectPolicy_createWithExpectedValue() {
96         initDynamicDenylistManager(new int[] {FAKE_UID_1_INT, FAKE_UID_2_INT});
97 
98         assertThat(mManualDenyListPref.getAll()).hasSize(3);
99         assertTrue(mManualDenyListPref.contains(PREF_KEY_MANUAL_DENYLIST_SYNCED));
100         assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
101         assertTrue(mManualDenyListPref.contains(FAKE_UID_2));
102     }
103 
104     @Test
getManualDenylistPref_initiated_containsExpectedValue()105     public void getManualDenylistPref_initiated_containsExpectedValue() {
106         initDynamicDenylistManager(EMPTY_ARRAY);
107 
108         setupPreference(mManualDenyListPref, FAKE_UID_1);
109 
110         assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
111     }
112 
113     @Test
getDynamicDenylistPref_initiated_containsExpectedValue()114     public void getDynamicDenylistPref_initiated_containsExpectedValue() {
115         initDynamicDenylistManager(EMPTY_ARRAY);
116 
117         setupPreference(mDynamicDenyListPref, FAKE_UID_1);
118 
119         assertTrue(mDynamicDenyListPref.contains(FAKE_UID_1));
120     }
121 
122     @Test
updateManualDenylist_policyReject_addsUid()123     public void updateManualDenylist_policyReject_addsUid() {
124         initDynamicDenylistManager(EMPTY_ARRAY);
125 
126         mDynamicDenylistManager.updateDenylistPref(FAKE_UID_1_INT,
127                 POLICY_REJECT_METERED_BACKGROUND);
128 
129         assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
130     }
131 
132     @Test
updateManualDenylist_policyNone_removesUid()133     public void updateManualDenylist_policyNone_removesUid() {
134         initDynamicDenylistManager(EMPTY_ARRAY);
135         setupPreference(mManualDenyListPref, FAKE_UID_1);
136         assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
137 
138         mDynamicDenylistManager.updateDenylistPref(FAKE_UID_1_INT, POLICY_NONE);
139 
140         assertFalse(mManualDenyListPref.contains(FAKE_UID_1));
141     }
142 
143     @Test
updateManualDenylist_samePolicy_doNothing()144     public void updateManualDenylist_samePolicy_doNothing() {
145         initDynamicDenylistManager(EMPTY_ARRAY);
146         setupPreference(mManualDenyListPref, FAKE_UID_1);
147         assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
148         assertThat(mManualDenyListPref.getAll()).hasSize(2);
149 
150         mDynamicDenylistManager.updateDenylistPref(FAKE_UID_1_INT,
151                 POLICY_REJECT_METERED_BACKGROUND);
152 
153         assertThat(mManualDenyListPref.getAll()).hasSize(2);
154     }
155 
156     @Test
setUidPolicyLocked_invokeSetUidPolicy()157     public void setUidPolicyLocked_invokeSetUidPolicy() {
158         initDynamicDenylistManager(EMPTY_ARRAY);
159 
160         mDynamicDenylistManager.setUidPolicyLocked(FAKE_UID_1_INT,
161                 POLICY_REJECT_METERED_BACKGROUND);
162 
163         assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
164         verify(mNetworkPolicyManager).setUidPolicy(eq(FAKE_UID_1_INT),
165                 eq(POLICY_REJECT_METERED_BACKGROUND));
166     }
167 
168     @Test
setDenylist_emptyListAndNoData_doNothing()169     public void setDenylist_emptyListAndNoData_doNothing() {
170         initDynamicDenylistManager(EMPTY_ARRAY);
171 
172         setDenylist(Collections.emptySet());
173 
174         verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), anyInt());
175     }
176 
177     @Test
setDenylist_uidDeniedAlready_doNothing()178     public void setDenylist_uidDeniedAlready_doNothing() {
179         initDynamicDenylistManager(new int[] {FAKE_UID_1_INT});
180         final ArraySet uids = new ArraySet<>();
181         uids.add(FAKE_UID_1_INT);
182         uids.add(null);
183 
184         setDenylist(uids);
185 
186         verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), anyInt());
187     }
188 
189     @Test
setDenylist_sameList_doNothing()190     public void setDenylist_sameList_doNothing() {
191         initDynamicDenylistManager(EMPTY_ARRAY);
192         setupPreference(mDynamicDenyListPref, FAKE_UID_2, FAKE_UID_1);
193 
194         setDenylist(new ArraySet<>(List.of(FAKE_UID_1_INT, FAKE_UID_2_INT)));
195 
196         verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), anyInt());
197     }
198 
199     @Test
setDenylist_newListWithOldData_modifyPolicyNoneAndReject()200     public void setDenylist_newListWithOldData_modifyPolicyNoneAndReject() {
201         initDynamicDenylistManager(EMPTY_ARRAY);
202         setupPreference(mDynamicDenyListPref, FAKE_UID_2);
203 
204         setDenylist(new ArraySet<>(List.of(FAKE_UID_1_INT)));
205 
206         verify(mNetworkPolicyManager).setUidPolicy(FAKE_UID_2_INT, POLICY_NONE);
207         verify(mNetworkPolicyManager).setUidPolicy(FAKE_UID_1_INT,
208                 POLICY_REJECT_METERED_BACKGROUND);
209         assertThat(mDynamicDenyListPref.getAll()).hasSize(1);
210         assertTrue(mDynamicDenyListPref.contains(FAKE_UID_1));
211     }
212 
213     @Test
setDenylist_newListWithoutOldData_modifyPolicyReject()214     public void setDenylist_newListWithoutOldData_modifyPolicyReject() {
215         initDynamicDenylistManager(EMPTY_ARRAY);
216 
217         setDenylist(new ArraySet<>(List.of(FAKE_UID_1_INT)));
218 
219         verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), eq(POLICY_NONE));
220         verify(mNetworkPolicyManager).setUidPolicy(FAKE_UID_1_INT,
221                 POLICY_REJECT_METERED_BACKGROUND);
222         assertThat(mDynamicDenyListPref.getAll()).hasSize(1);
223         assertTrue(mDynamicDenyListPref.contains(FAKE_UID_1));
224     }
225 
226     @Test
setDenylist_emptyListWithOldData_modifyPolicyNone()227     public void setDenylist_emptyListWithOldData_modifyPolicyNone() {
228         initDynamicDenylistManager(EMPTY_ARRAY);
229         setupPreference(mDynamicDenyListPref, FAKE_UID_2);
230 
231         setDenylist(Collections.emptySet());
232 
233         verify(mNetworkPolicyManager).setUidPolicy(FAKE_UID_2_INT, POLICY_NONE);
234         verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(),
235                 eq(POLICY_REJECT_METERED_BACKGROUND));
236         assertThat(mDynamicDenyListPref.getAll()).isEmpty();
237     }
238 
239     @Test
isInManualDenylist_returnsFalse()240     public void isInManualDenylist_returnsFalse() {
241         initDynamicDenylistManager(EMPTY_ARRAY);
242 
243         assertFalse(mDynamicDenylistManager.isInManualDenylist(FAKE_UID_1_INT));
244     }
245 
246     @Test
isInManualDenylist_incorrectUid_returnsFalse()247     public void isInManualDenylist_incorrectUid_returnsFalse() {
248         initDynamicDenylistManager(EMPTY_ARRAY);
249 
250         mManualDenyListPref.edit().putInt(FAKE_UID_2, POLICY_REJECT_METERED_BACKGROUND).apply();
251 
252         assertFalse(mDynamicDenylistManager.isInManualDenylist(FAKE_UID_1_INT));
253     }
254 
255     @Test
isInManualDenylist_initiated_returnsTrue()256     public void isInManualDenylist_initiated_returnsTrue() {
257         initDynamicDenylistManager(EMPTY_ARRAY);
258 
259         mManualDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
260 
261         assertTrue(mDynamicDenylistManager.isInManualDenylist(FAKE_UID_1_INT));
262     }
263 
264     @Test
resetDenylistIfNeeded_nullPackageName_doNothing()265     public void resetDenylistIfNeeded_nullPackageName_doNothing() {
266         initDynamicDenylistManager(new int[0], new int[] {FAKE_UID_1_INT, FAKE_UID_2_INT});
267 
268         mDynamicDenylistManager.resetDenylistIfNeeded(null, false);
269 
270         assertThat(mManualDenyListPref.getAll()).hasSize(1);
271         verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), eq(POLICY_NONE));
272     }
273 
274     @Test
resetDenylistIfNeeded_invalidPackageName_doNothing()275     public void resetDenylistIfNeeded_invalidPackageName_doNothing() {
276         initDynamicDenylistManager(new int[0], new int[] {FAKE_UID_1_INT, FAKE_UID_2_INT});
277 
278         mDynamicDenylistManager.resetDenylistIfNeeded("invalid_package_name", false);
279 
280         assertThat(mManualDenyListPref.getAll()).hasSize(1);
281         verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), eq(POLICY_NONE));
282     }
283 
284     @Test
resetDenylistIfNeeded_denylistUnchanged_doNothingWithPolicy()285     public void resetDenylistIfNeeded_denylistUnchanged_doNothingWithPolicy() {
286         initDynamicDenylistManager(new int[] {FAKE_UID_1_INT, FAKE_UID_2_INT});
287 
288         mDynamicDenylistManager.resetDenylistIfNeeded(SETTINGS_PACKAGE_NAME, false);
289 
290         verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), eq(POLICY_NONE));
291     }
292 
293     @Test
resetDenylistIfNeeded_denylistChanged_resetAndClear()294     public void resetDenylistIfNeeded_denylistChanged_resetAndClear() {
295         initDynamicDenylistManager(new int[0], new int[] {FAKE_UID_1_INT, FAKE_UID_2_INT});
296 
297         mDynamicDenylistManager.resetDenylistIfNeeded(SETTINGS_PACKAGE_NAME, false);
298 
299         assertThat(mManualDenyListPref.getAll()).isEmpty();
300         verify(mNetworkPolicyManager, times(2)).setUidPolicy(anyInt(), eq(POLICY_NONE));
301     }
302 
303     @Test
resetDenylistIfNeeded_forceResetWithNullPackageName_resetAndClear()304     public void resetDenylistIfNeeded_forceResetWithNullPackageName_resetAndClear() {
305         initDynamicDenylistManager(new int[0], new int[] {FAKE_UID_2_INT});
306 
307         mDynamicDenylistManager.resetDenylistIfNeeded(null, true);
308 
309         assertThat(mManualDenyListPref.getAll()).isEmpty();
310         verify(mNetworkPolicyManager).setUidPolicy(eq(FAKE_UID_2_INT), eq(POLICY_NONE));
311     }
312 
313     @Test
resetDenylistIfNeeded_forceResetWithInvalidPackageName_resetAndClear()314     public void resetDenylistIfNeeded_forceResetWithInvalidPackageName_resetAndClear() {
315         initDynamicDenylistManager(new int[0], new int[] {FAKE_UID_1_INT, FAKE_UID_2_INT});
316 
317         mDynamicDenylistManager.resetDenylistIfNeeded("invalid_package_name", true);
318 
319         assertThat(mManualDenyListPref.getAll()).isEmpty();
320         verify(mNetworkPolicyManager, times(2)).setUidPolicy(anyInt(), eq(POLICY_NONE));
321     }
322 
323     @Test
resetDenylistIfNeeded_forceResetButDenylistUnchanged_doNothingWithPolicy()324     public void resetDenylistIfNeeded_forceResetButDenylistUnchanged_doNothingWithPolicy() {
325         initDynamicDenylistManager(new int[] {FAKE_UID_1_INT});
326 
327         mDynamicDenylistManager.resetDenylistIfNeeded(SETTINGS_PACKAGE_NAME, true);
328 
329         assertThat(mManualDenyListPref.getAll()).isEmpty();
330         verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), eq(POLICY_NONE));
331     }
332 
333     @Test
resetDenylistIfNeeded_forceResetWithDenylistChanged_resetAndClear()334     public void resetDenylistIfNeeded_forceResetWithDenylistChanged_resetAndClear() {
335         initDynamicDenylistManager(new int[0], new int[] {FAKE_UID_1_INT, FAKE_UID_2_INT});
336 
337         mDynamicDenylistManager.resetDenylistIfNeeded(SETTINGS_PACKAGE_NAME, true);
338 
339         assertThat(mManualDenyListPref.getAll()).isEmpty();
340         verify(mNetworkPolicyManager, times(2)).setUidPolicy(anyInt(), eq(POLICY_NONE));
341     }
342 
343     @Test
clearSharedPreferences_manualDenyListPrefIsEmpty()344     public void clearSharedPreferences_manualDenyListPrefIsEmpty() {
345         initDynamicDenylistManager(EMPTY_ARRAY);
346         mManualDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
347         assertThat(mManualDenyListPref.getAll()).hasSize(2);
348         assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
349         assertTrue(mManualDenyListPref.contains(PREF_KEY_MANUAL_DENYLIST_SYNCED));
350 
351         mDynamicDenylistManager.clearSharedPreferences();
352 
353         assertThat(mManualDenyListPref.getAll()).isEmpty();
354     }
355 
356     @Test
clearSharedPreferences_dynamicDenyListPrefIsEmpty()357     public void clearSharedPreferences_dynamicDenyListPrefIsEmpty() {
358         initDynamicDenylistManager(EMPTY_ARRAY);
359         mDynamicDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
360         assertThat(mDynamicDenyListPref.getAll()).hasSize(1);
361         assertTrue(mDynamicDenyListPref.contains(FAKE_UID_1));
362 
363         mDynamicDenylistManager.clearSharedPreferences();
364 
365         assertThat(mDynamicDenyListPref.getAll()).isEmpty();
366     }
367 
368     @Test
dump_dumpExpectedResult()369     public void dump_dumpExpectedResult() {
370         initDynamicDenylistManager(EMPTY_ARRAY);
371         setupPreference(mManualDenyListPref, FAKE_UID_1);
372         setupPreference(mDynamicDenyListPref, FAKE_UID_2);
373         final StringWriter stringWriter = new StringWriter();
374         final PrintWriter printWriter = new PrintWriter(stringWriter);
375         when(mPackageManager.getNameForUid(FAKE_UID_1_INT)).thenReturn("app1");
376         when(mPackageManager.getNameForUid(FAKE_UID_2_INT)).thenReturn("app2");
377 
378         mDynamicDenylistManager.dump(printWriter);
379 
380         final String dumpResults = stringWriter.toString();
381         assertThat(dumpResults.contains("\tManualDenylist:\n\t\tapp1")).isTrue();
382         assertThat(dumpResults.contains("\tDynamicDenylist:\n\t\tapp2")).isTrue();
383     }
384 
385     @Test
dump_withEmptySharedPreferences_dumpExpectedResult()386     public void dump_withEmptySharedPreferences_dumpExpectedResult() {
387         initDynamicDenylistManager(EMPTY_ARRAY, EMPTY_ARRAY);
388         mDynamicDenylistManager.clearSharedPreferences();
389         final StringWriter stringWriter = new StringWriter();
390         final PrintWriter printWriter = new PrintWriter(stringWriter);
391 
392         mDynamicDenylistManager.dump(printWriter);
393 
394         final String dumpResults = stringWriter.toString();
395         assertThat(dumpResults.contains("Dump of DynamicDenylistManager:")).isTrue();
396         assertThat(dumpResults.contains("\tManualDenylist:\n\tDynamicDenylist:")).isTrue();
397     }
398 
399     @Test
onBootComplete_resetIntoManualMode()400     public void onBootComplete_resetIntoManualMode() {
401         initDynamicDenylistManager(new int[] {FAKE_UID_1_INT});
402         setDenylist(new ArraySet<>(List.of(FAKE_UID_2_INT)));
403         // Ensure the testing environment for manual denylist.
404         assertThat(mManualDenyListPref.getAll()).hasSize(2);
405         assertTrue(mManualDenyListPref.contains(PREF_KEY_MANUAL_DENYLIST_SYNCED));
406         assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
407         // Ensure the testing environment for dynamic denylist.
408         assertThat(mDynamicDenyListPref.getAll()).hasSize(1);
409 
410         mDynamicDenylistManager.onBootComplete();
411 
412         // Keep the users set uids in the manual denylist.
413         assertThat(mManualDenyListPref.getAll()).hasSize(2);
414         assertTrue(mManualDenyListPref.contains(PREF_KEY_MANUAL_DENYLIST_SYNCED));
415         assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
416         // Clear the uids in the dynamic denylist.
417         assertThat(mDynamicDenyListPref.getAll()).isEmpty();
418     }
419 
initDynamicDenylistManager(int[] preload)420     private void initDynamicDenylistManager(int[] preload) {
421         initDynamicDenylistManager(preload, preload);
422     }
423 
initDynamicDenylistManager(int[] preload1, int[] preload2)424     private void initDynamicDenylistManager(int[] preload1, int[] preload2) {
425         final Context context = spy(RuntimeEnvironment.application.getApplicationContext());
426         when(context.getApplicationContext()).thenReturn(context);
427         when(context.getPackageManager()).thenReturn(mPackageManager);
428         when(mNetworkPolicyManager.getUidsWithPolicy(anyInt()))
429                 .thenReturn(preload1).thenReturn(preload2);
430         mDynamicDenylistManager = new DynamicDenylistManager(context, mNetworkPolicyManager);
431         mManualDenyListPref = mDynamicDenylistManager.getManualDenylistPref();
432         mDynamicDenyListPref = mDynamicDenylistManager.getDynamicDenylistPref();
433     }
434 
setDenylist(Set<Integer> packageNameList)435     private void setDenylist(Set<Integer> packageNameList) {
436         mDynamicDenylistManager.setDenylist(packageNameList);
437     }
438 
setupPreference(SharedPreferences sharedPreferences, String... uids)439     private void setupPreference(SharedPreferences sharedPreferences, String... uids) {
440         final SharedPreferences.Editor editor = sharedPreferences.edit();
441         for (String uid : uids) {
442             editor.putInt(uid, POLICY_REJECT_METERED_BACKGROUND);
443         }
444         editor.apply();
445     }
446 }
447