• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
18 
19 import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
20 import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
21 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
22 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
23 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
24 import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
25 import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
26 import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
27 import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
28 import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
29 import static android.net.INetd.PERMISSION_INTERNET;
30 import static android.net.INetd.PERMISSION_NONE;
31 import static android.net.INetd.PERMISSION_UNINSTALLED;
32 import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
33 import static android.system.OsConstants.EINVAL;
34 import static android.system.OsConstants.EPERM;
35 
36 import static com.android.server.BpfNetMaps.DOZABLE_MATCH;
37 import static com.android.server.BpfNetMaps.HAPPY_BOX_MATCH;
38 import static com.android.server.BpfNetMaps.IIF_MATCH;
39 import static com.android.server.BpfNetMaps.LOCKDOWN_VPN_MATCH;
40 import static com.android.server.BpfNetMaps.LOW_POWER_STANDBY_MATCH;
41 import static com.android.server.BpfNetMaps.NO_MATCH;
42 import static com.android.server.BpfNetMaps.OEM_DENY_1_MATCH;
43 import static com.android.server.BpfNetMaps.OEM_DENY_2_MATCH;
44 import static com.android.server.BpfNetMaps.OEM_DENY_3_MATCH;
45 import static com.android.server.BpfNetMaps.PENALTY_BOX_MATCH;
46 import static com.android.server.BpfNetMaps.POWERSAVE_MATCH;
47 import static com.android.server.BpfNetMaps.RESTRICTED_MATCH;
48 import static com.android.server.BpfNetMaps.STANDBY_MATCH;
49 import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO;
50 
51 import static org.junit.Assert.assertEquals;
52 import static org.junit.Assert.assertFalse;
53 import static org.junit.Assert.assertNull;
54 import static org.junit.Assert.assertThrows;
55 import static org.junit.Assert.assertTrue;
56 import static org.junit.Assume.assumeFalse;
57 import static org.mockito.Mockito.any;
58 import static org.mockito.Mockito.doReturn;
59 import static org.mockito.Mockito.doThrow;
60 import static org.mockito.Mockito.spy;
61 import static org.mockito.Mockito.verify;
62 
63 import android.app.StatsManager;
64 import android.content.Context;
65 import android.net.INetd;
66 import android.os.Build;
67 import android.os.ServiceSpecificException;
68 import android.system.ErrnoException;
69 import android.util.ArraySet;
70 import android.util.IndentingPrintWriter;
71 
72 import androidx.test.filters.SmallTest;
73 
74 import com.android.modules.utils.build.SdkLevel;
75 import com.android.net.module.util.IBpfMap;
76 import com.android.net.module.util.Struct.S32;
77 import com.android.net.module.util.Struct.U32;
78 import com.android.net.module.util.Struct.U8;
79 import com.android.net.module.util.bpf.CookieTagMapKey;
80 import com.android.net.module.util.bpf.CookieTagMapValue;
81 import com.android.testutils.DevSdkIgnoreRule;
82 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
83 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
84 import com.android.testutils.DevSdkIgnoreRunner;
85 import com.android.testutils.TestBpfMap;
86 
87 import org.junit.Before;
88 import org.junit.Rule;
89 import org.junit.Test;
90 import org.junit.runner.RunWith;
91 import org.mockito.Mock;
92 import org.mockito.MockitoAnnotations;
93 
94 import java.io.FileDescriptor;
95 import java.io.StringWriter;
96 import java.util.ArrayList;
97 import java.util.List;
98 
99 @RunWith(DevSdkIgnoreRunner.class)
100 @SmallTest
101 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
102 public final class BpfNetMapsTest {
103     private static final String TAG = "BpfNetMapsTest";
104 
105     @Rule
106     public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
107 
108     private static final int TEST_UID = 10086;
109     private static final int[] TEST_UIDS = {10002, 10003};
110     private static final String TEST_IF_NAME = "wlan0";
111     private static final int TEST_IF_INDEX = 7;
112     private static final int NO_IIF = 0;
113     private static final int NULL_IIF = 0;
114     private static final String CHAINNAME = "fw_dozable";
115     private static final S32 UID_RULES_CONFIGURATION_KEY = new S32(0);
116     private static final S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new S32(1);
117     private static final List<Integer> FIREWALL_CHAINS = List.of(
118             FIREWALL_CHAIN_DOZABLE,
119             FIREWALL_CHAIN_STANDBY,
120             FIREWALL_CHAIN_POWERSAVE,
121             FIREWALL_CHAIN_RESTRICTED,
122             FIREWALL_CHAIN_LOW_POWER_STANDBY,
123             FIREWALL_CHAIN_OEM_DENY_1,
124             FIREWALL_CHAIN_OEM_DENY_2,
125             FIREWALL_CHAIN_OEM_DENY_3
126     );
127 
128     private static final long STATS_SELECT_MAP_A = 0;
129     private static final long STATS_SELECT_MAP_B = 1;
130 
131     private BpfNetMaps mBpfNetMaps;
132 
133     @Mock INetd mNetd;
134     @Mock BpfNetMaps.Dependencies mDeps;
135     @Mock Context mContext;
136     private final IBpfMap<S32, U32> mConfigurationMap = new TestBpfMap<>(S32.class, U32.class);
137     private final IBpfMap<S32, UidOwnerValue> mUidOwnerMap =
138             new TestBpfMap<>(S32.class, UidOwnerValue.class);
139     private final IBpfMap<S32, U8> mUidPermissionMap = new TestBpfMap<>(S32.class, U8.class);
140     private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap =
141             spy(new TestBpfMap<>(CookieTagMapKey.class, CookieTagMapValue.class));
142 
143     @Before
setUp()144     public void setUp() throws Exception {
145         MockitoAnnotations.initMocks(this);
146         doReturn(TEST_IF_INDEX).when(mDeps).getIfIndex(TEST_IF_NAME);
147         doReturn(0).when(mDeps).synchronizeKernelRCU();
148         BpfNetMaps.setEnableJavaBpfMapForTest(true /* enable */);
149         BpfNetMaps.setConfigurationMapForTest(mConfigurationMap);
150         mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(0));
151         mConfigurationMap.updateEntry(
152                 CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A));
153         BpfNetMaps.setUidOwnerMapForTest(mUidOwnerMap);
154         BpfNetMaps.setUidPermissionMapForTest(mUidPermissionMap);
155         BpfNetMaps.setCookieTagMapForTest(mCookieTagMap);
156         mBpfNetMaps = new BpfNetMaps(mContext, mNetd, mDeps);
157     }
158 
159     @Test
testBpfNetMapsBeforeT()160     public void testBpfNetMapsBeforeT() throws Exception {
161         assumeFalse(SdkLevel.isAtLeastT());
162         mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS);
163         verify(mNetd).firewallAddUidInterfaceRules(TEST_IF_NAME, TEST_UIDS);
164         mBpfNetMaps.removeUidInterfaceRules(TEST_UIDS);
165         verify(mNetd).firewallRemoveUidInterfaceRules(TEST_UIDS);
166         mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
167         verify(mNetd).trafficSetNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
168     }
169 
getMatch(final List<Integer> chains)170     private long getMatch(final List<Integer> chains) {
171         long match = 0;
172         for (final int chain: chains) {
173             match |= mBpfNetMaps.getMatchByFirewallChain(chain);
174         }
175         return match;
176     }
177 
doTestIsChainEnabled(final List<Integer> enableChains)178     private void doTestIsChainEnabled(final List<Integer> enableChains) throws Exception {
179         mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(getMatch(enableChains)));
180 
181         for (final int chain: FIREWALL_CHAINS) {
182             final String testCase = "EnabledChains: " + enableChains + " CheckedChain: " + chain;
183             if (enableChains.contains(chain)) {
184                 assertTrue("Expected isChainEnabled returns True, " + testCase,
185                         mBpfNetMaps.isChainEnabled(chain));
186             } else {
187                 assertFalse("Expected isChainEnabled returns False, " + testCase,
188                         mBpfNetMaps.isChainEnabled(chain));
189             }
190         }
191     }
192 
doTestIsChainEnabled(final int enableChain)193     private void doTestIsChainEnabled(final int enableChain) throws Exception {
194         doTestIsChainEnabled(List.of(enableChain));
195     }
196 
197     @Test
198     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testIsChainEnabled()199     public void testIsChainEnabled() throws Exception {
200         doTestIsChainEnabled(FIREWALL_CHAIN_DOZABLE);
201         doTestIsChainEnabled(FIREWALL_CHAIN_STANDBY);
202         doTestIsChainEnabled(FIREWALL_CHAIN_POWERSAVE);
203         doTestIsChainEnabled(FIREWALL_CHAIN_RESTRICTED);
204         doTestIsChainEnabled(FIREWALL_CHAIN_LOW_POWER_STANDBY);
205         doTestIsChainEnabled(FIREWALL_CHAIN_OEM_DENY_1);
206         doTestIsChainEnabled(FIREWALL_CHAIN_OEM_DENY_2);
207         doTestIsChainEnabled(FIREWALL_CHAIN_OEM_DENY_3);
208     }
209 
210     @Test
211     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testIsChainEnabledMultipleChainEnabled()212     public void testIsChainEnabledMultipleChainEnabled() throws Exception {
213         doTestIsChainEnabled(List.of(
214                 FIREWALL_CHAIN_DOZABLE,
215                 FIREWALL_CHAIN_STANDBY));
216         doTestIsChainEnabled(List.of(
217                 FIREWALL_CHAIN_DOZABLE,
218                 FIREWALL_CHAIN_STANDBY,
219                 FIREWALL_CHAIN_POWERSAVE,
220                 FIREWALL_CHAIN_RESTRICTED));
221         doTestIsChainEnabled(FIREWALL_CHAINS);
222     }
223 
224     @Test
225     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testIsChainEnabledInvalidChain()226     public void testIsChainEnabledInvalidChain() {
227         final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
228         assertThrows(expected, () -> mBpfNetMaps.isChainEnabled(-1 /* childChain */));
229         assertThrows(expected, () -> mBpfNetMaps.isChainEnabled(1000 /* childChain */));
230     }
231 
232     @Test
233     @IgnoreAfter(Build.VERSION_CODES.S_V2)
testIsChainEnabledBeforeT()234     public void testIsChainEnabledBeforeT() {
235         assertThrows(UnsupportedOperationException.class,
236                 () -> mBpfNetMaps.isChainEnabled(FIREWALL_CHAIN_DOZABLE));
237     }
238 
doTestSetChildChain(final List<Integer> testChains)239     private void doTestSetChildChain(final List<Integer> testChains) throws Exception {
240         long expectedMatch = 0;
241         for (final int chain: testChains) {
242             expectedMatch |= mBpfNetMaps.getMatchByFirewallChain(chain);
243         }
244 
245         assertEquals(0, mConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);
246 
247         for (final int chain: testChains) {
248             mBpfNetMaps.setChildChain(chain, true /* enable */);
249         }
250         assertEquals(expectedMatch, mConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);
251 
252         for (final int chain: testChains) {
253             mBpfNetMaps.setChildChain(chain, false /* enable */);
254         }
255         assertEquals(0, mConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);
256     }
257 
doTestSetChildChain(final int testChain)258     private void doTestSetChildChain(final int testChain) throws Exception {
259         doTestSetChildChain(List.of(testChain));
260     }
261 
262     @Test
263     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetChildChain()264     public void testSetChildChain() throws Exception {
265         mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(0));
266         doTestSetChildChain(FIREWALL_CHAIN_DOZABLE);
267         doTestSetChildChain(FIREWALL_CHAIN_STANDBY);
268         doTestSetChildChain(FIREWALL_CHAIN_POWERSAVE);
269         doTestSetChildChain(FIREWALL_CHAIN_RESTRICTED);
270         doTestSetChildChain(FIREWALL_CHAIN_LOW_POWER_STANDBY);
271         doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_1);
272         doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_2);
273         doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_3);
274     }
275 
276     @Test
277     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetChildChainMultipleChain()278     public void testSetChildChainMultipleChain() throws Exception {
279         mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(0));
280         doTestSetChildChain(List.of(
281                 FIREWALL_CHAIN_DOZABLE,
282                 FIREWALL_CHAIN_STANDBY));
283         doTestSetChildChain(List.of(
284                 FIREWALL_CHAIN_DOZABLE,
285                 FIREWALL_CHAIN_STANDBY,
286                 FIREWALL_CHAIN_POWERSAVE,
287                 FIREWALL_CHAIN_RESTRICTED));
288         doTestSetChildChain(FIREWALL_CHAINS);
289     }
290 
291     @Test
292     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetChildChainInvalidChain()293     public void testSetChildChainInvalidChain() {
294         final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
295         assertThrows(expected,
296                 () -> mBpfNetMaps.setChildChain(-1 /* childChain */, true /* enable */));
297         assertThrows(expected,
298                 () -> mBpfNetMaps.setChildChain(1000 /* childChain */, true /* enable */));
299     }
300 
301     @Test
302     @IgnoreAfter(Build.VERSION_CODES.S_V2)
testSetChildChainBeforeT()303     public void testSetChildChainBeforeT() {
304         assertThrows(UnsupportedOperationException.class,
305                 () -> mBpfNetMaps.setChildChain(FIREWALL_CHAIN_DOZABLE, true /* enable */));
306     }
307 
checkUidOwnerValue(final int uid, final int expectedIif, final long expectedMatch)308     private void checkUidOwnerValue(final int uid, final int expectedIif,
309             final long expectedMatch) throws Exception {
310         final UidOwnerValue config = mUidOwnerMap.getValue(new S32(uid));
311         if (expectedMatch == 0) {
312             assertNull(config);
313         } else {
314             assertEquals(expectedIif, config.iif);
315             assertEquals(expectedMatch, config.rule);
316         }
317     }
318 
doTestRemoveNaughtyApp(final int iif, final long match)319     private void doTestRemoveNaughtyApp(final int iif, final long match) throws Exception {
320         mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match));
321 
322         mBpfNetMaps.removeNaughtyApp(TEST_UID);
323 
324         checkUidOwnerValue(TEST_UID, iif, match & ~PENALTY_BOX_MATCH);
325     }
326 
327     @Test
328     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testRemoveNaughtyApp()329     public void testRemoveNaughtyApp() throws Exception {
330         doTestRemoveNaughtyApp(NO_IIF, PENALTY_BOX_MATCH);
331 
332         // PENALTY_BOX_MATCH with other matches
333         doTestRemoveNaughtyApp(NO_IIF, PENALTY_BOX_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH);
334 
335         // PENALTY_BOX_MATCH with IIF_MATCH
336         doTestRemoveNaughtyApp(TEST_IF_INDEX, PENALTY_BOX_MATCH | IIF_MATCH);
337 
338         // PENALTY_BOX_MATCH is not enabled
339         doTestRemoveNaughtyApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH);
340     }
341 
342     @Test
343     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testRemoveNaughtyAppMissingUid()344     public void testRemoveNaughtyAppMissingUid() {
345         // UidOwnerMap does not have entry for TEST_UID
346         assertThrows(ServiceSpecificException.class,
347                 () -> mBpfNetMaps.removeNaughtyApp(TEST_UID));
348     }
349 
350     @Test
351     @IgnoreAfter(Build.VERSION_CODES.S_V2)
testRemoveNaughtyAppBeforeT()352     public void testRemoveNaughtyAppBeforeT() {
353         assertThrows(UnsupportedOperationException.class,
354                 () -> mBpfNetMaps.removeNaughtyApp(TEST_UID));
355     }
356 
doTestAddNaughtyApp(final int iif, final long match)357     private void doTestAddNaughtyApp(final int iif, final long match) throws Exception {
358         if (match != NO_MATCH) {
359             mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match));
360         }
361 
362         mBpfNetMaps.addNaughtyApp(TEST_UID);
363 
364         checkUidOwnerValue(TEST_UID, iif, match | PENALTY_BOX_MATCH);
365     }
366 
367     @Test
368     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testAddNaughtyApp()369     public void testAddNaughtyApp() throws Exception {
370         doTestAddNaughtyApp(NO_IIF, NO_MATCH);
371 
372         // Other matches are enabled
373         doTestAddNaughtyApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH);
374 
375         // IIF_MATCH is enabled
376         doTestAddNaughtyApp(TEST_IF_INDEX, IIF_MATCH);
377 
378         // PENALTY_BOX_MATCH is already enabled
379         doTestAddNaughtyApp(NO_IIF, PENALTY_BOX_MATCH | DOZABLE_MATCH);
380     }
381 
382     @Test
383     @IgnoreAfter(Build.VERSION_CODES.S_V2)
testAddNaughtyAppBeforeT()384     public void testAddNaughtyAppBeforeT() {
385         assertThrows(UnsupportedOperationException.class,
386                 () -> mBpfNetMaps.addNaughtyApp(TEST_UID));
387     }
388 
doTestRemoveNiceApp(final int iif, final long match)389     private void doTestRemoveNiceApp(final int iif, final long match) throws Exception {
390         mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match));
391 
392         mBpfNetMaps.removeNiceApp(TEST_UID);
393 
394         checkUidOwnerValue(TEST_UID, iif, match & ~HAPPY_BOX_MATCH);
395     }
396 
397     @Test
398     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testRemoveNiceApp()399     public void testRemoveNiceApp() throws Exception {
400         doTestRemoveNiceApp(NO_IIF, HAPPY_BOX_MATCH);
401 
402         // HAPPY_BOX_MATCH with other matches
403         doTestRemoveNiceApp(NO_IIF, HAPPY_BOX_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH);
404 
405         // HAPPY_BOX_MATCH with IIF_MATCH
406         doTestRemoveNiceApp(TEST_IF_INDEX, HAPPY_BOX_MATCH | IIF_MATCH);
407 
408         // HAPPY_BOX_MATCH is not enabled
409         doTestRemoveNiceApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH);
410     }
411 
412     @Test
413     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testRemoveNiceAppMissingUid()414     public void testRemoveNiceAppMissingUid() {
415         // UidOwnerMap does not have entry for TEST_UID
416         assertThrows(ServiceSpecificException.class,
417                 () -> mBpfNetMaps.removeNiceApp(TEST_UID));
418     }
419 
420     @Test
421     @IgnoreAfter(Build.VERSION_CODES.S_V2)
testRemoveNiceAppBeforeT()422     public void testRemoveNiceAppBeforeT() {
423         assertThrows(UnsupportedOperationException.class,
424                 () -> mBpfNetMaps.removeNiceApp(TEST_UID));
425     }
426 
doTestAddNiceApp(final int iif, final long match)427     private void doTestAddNiceApp(final int iif, final long match) throws Exception {
428         if (match != NO_MATCH) {
429             mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match));
430         }
431 
432         mBpfNetMaps.addNiceApp(TEST_UID);
433 
434         checkUidOwnerValue(TEST_UID, iif, match | HAPPY_BOX_MATCH);
435     }
436 
437     @Test
438     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testAddNiceApp()439     public void testAddNiceApp() throws Exception {
440         doTestAddNiceApp(NO_IIF, NO_MATCH);
441 
442         // Other matches are enabled
443         doTestAddNiceApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH);
444 
445         // IIF_MATCH is enabled
446         doTestAddNiceApp(TEST_IF_INDEX, IIF_MATCH);
447 
448         // HAPPY_BOX_MATCH is already enabled
449         doTestAddNiceApp(NO_IIF, HAPPY_BOX_MATCH | DOZABLE_MATCH);
450     }
451 
452     @Test
453     @IgnoreAfter(Build.VERSION_CODES.S_V2)
testAddNiceAppBeforeT()454     public void testAddNiceAppBeforeT() {
455         assertThrows(UnsupportedOperationException.class,
456                 () -> mBpfNetMaps.addNiceApp(TEST_UID));
457     }
458 
doTestUpdateUidLockdownRule(final int iif, final long match, final boolean add)459     private void doTestUpdateUidLockdownRule(final int iif, final long match, final boolean add)
460             throws Exception {
461         if (match != NO_MATCH) {
462             mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match));
463         }
464 
465         mBpfNetMaps.updateUidLockdownRule(TEST_UID, add);
466 
467         final long expectedMatch = add ? match | LOCKDOWN_VPN_MATCH : match & ~LOCKDOWN_VPN_MATCH;
468         checkUidOwnerValue(TEST_UID, iif, expectedMatch);
469     }
470 
471     private static final boolean ADD = true;
472     private static final boolean REMOVE = false;
473 
474     @Test
475     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testUpdateUidLockdownRuleAddLockdown()476     public void testUpdateUidLockdownRuleAddLockdown() throws Exception {
477         doTestUpdateUidLockdownRule(NO_IIF, NO_MATCH, ADD);
478 
479         // Other matches are enabled
480         doTestUpdateUidLockdownRule(
481                 NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH, ADD);
482 
483         // IIF_MATCH is enabled
484         doTestUpdateUidLockdownRule(TEST_IF_INDEX, DOZABLE_MATCH, ADD);
485 
486         // LOCKDOWN_VPN_MATCH is already enabled
487         doTestUpdateUidLockdownRule(NO_IIF, LOCKDOWN_VPN_MATCH | DOZABLE_MATCH, ADD);
488     }
489 
490     @Test
491     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testUpdateUidLockdownRuleRemoveLockdown()492     public void testUpdateUidLockdownRuleRemoveLockdown() throws Exception {
493         doTestUpdateUidLockdownRule(NO_IIF, LOCKDOWN_VPN_MATCH, REMOVE);
494 
495         // LOCKDOWN_VPN_MATCH with other matches
496         doTestUpdateUidLockdownRule(
497                 NO_IIF, LOCKDOWN_VPN_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH, REMOVE);
498 
499         // LOCKDOWN_VPN_MATCH with IIF_MATCH
500         doTestUpdateUidLockdownRule(TEST_IF_INDEX, LOCKDOWN_VPN_MATCH | IIF_MATCH, REMOVE);
501 
502         // LOCKDOWN_VPN_MATCH is not enabled
503         doTestUpdateUidLockdownRule(NO_IIF, POWERSAVE_MATCH | RESTRICTED_MATCH, REMOVE);
504     }
505 
506     @Test
507     @IgnoreAfter(Build.VERSION_CODES.S_V2)
testUpdateUidLockdownRuleBeforeT()508     public void testUpdateUidLockdownRuleBeforeT() {
509         assertThrows(UnsupportedOperationException.class,
510                 () -> mBpfNetMaps.updateUidLockdownRule(TEST_UID, true /* add */));
511     }
512 
513     @Test
514     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testAddUidInterfaceRules()515     public void testAddUidInterfaceRules() throws Exception {
516         final int uid0 = TEST_UIDS[0];
517         final int uid1 = TEST_UIDS[1];
518 
519         mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS);
520 
521         checkUidOwnerValue(uid0, TEST_IF_INDEX, IIF_MATCH);
522         checkUidOwnerValue(uid1, TEST_IF_INDEX, IIF_MATCH);
523     }
524 
525     @Test
526     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testAddUidInterfaceRulesWithOtherMatch()527     public void testAddUidInterfaceRulesWithOtherMatch() throws Exception {
528         final int uid0 = TEST_UIDS[0];
529         final int uid1 = TEST_UIDS[1];
530         final long match0 = DOZABLE_MATCH;
531         final long match1 = DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH;
532         mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(NO_IIF, match0));
533         mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NO_IIF, match1));
534 
535         mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS);
536 
537         checkUidOwnerValue(uid0, TEST_IF_INDEX, match0 | IIF_MATCH);
538         checkUidOwnerValue(uid1, TEST_IF_INDEX, match1 | IIF_MATCH);
539     }
540 
541     @Test
542     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testAddUidInterfaceRulesWithExistingIifMatch()543     public void testAddUidInterfaceRulesWithExistingIifMatch() throws Exception {
544         final int uid0 = TEST_UIDS[0];
545         final int uid1 = TEST_UIDS[1];
546         final long match0 = IIF_MATCH;
547         final long match1 = IIF_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH;
548         mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(TEST_IF_INDEX + 1, match0));
549         mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1));
550 
551         mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS);
552 
553         checkUidOwnerValue(uid0, TEST_IF_INDEX, match0);
554         checkUidOwnerValue(uid1, TEST_IF_INDEX, match1);
555     }
556 
557     @Test
558     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testAddUidInterfaceRulesGetIfIndexFail()559     public void testAddUidInterfaceRulesGetIfIndexFail() {
560         doReturn(0).when(mDeps).getIfIndex(TEST_IF_NAME);
561         assertThrows(ServiceSpecificException.class,
562                 () -> mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS));
563     }
564 
565     @Test
566     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testAddUidInterfaceRulesWithNullInterface()567     public void testAddUidInterfaceRulesWithNullInterface() throws Exception {
568         final int uid0 = TEST_UIDS[0];
569         final int uid1 = TEST_UIDS[1];
570         final long match0 = IIF_MATCH;
571         final long match1 = IIF_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH;
572         mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(TEST_IF_INDEX, match0));
573         mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1));
574 
575         mBpfNetMaps.addUidInterfaceRules(null /* ifName */, TEST_UIDS);
576 
577         checkUidOwnerValue(uid0, NULL_IIF, match0);
578         checkUidOwnerValue(uid1, NULL_IIF, match1);
579     }
580 
doTestRemoveUidInterfaceRules(final int iif0, final long match0, final int iif1, final long match1)581     private void doTestRemoveUidInterfaceRules(final int iif0, final long match0,
582             final int iif1, final long match1) throws Exception {
583         final int uid0 = TEST_UIDS[0];
584         final int uid1 = TEST_UIDS[1];
585         mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(iif0, match0));
586         mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(iif1, match1));
587 
588         mBpfNetMaps.removeUidInterfaceRules(TEST_UIDS);
589 
590         checkUidOwnerValue(uid0, NO_IIF, match0 & ~IIF_MATCH);
591         checkUidOwnerValue(uid1, NO_IIF, match1 & ~IIF_MATCH);
592     }
593 
594     @Test
595     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testRemoveUidInterfaceRules()596     public void testRemoveUidInterfaceRules() throws Exception {
597         doTestRemoveUidInterfaceRules(TEST_IF_INDEX, IIF_MATCH, NULL_IIF, IIF_MATCH);
598 
599         // IIF_MATCH and other matches are enabled
600         doTestRemoveUidInterfaceRules(TEST_IF_INDEX, IIF_MATCH | DOZABLE_MATCH,
601                 NULL_IIF, IIF_MATCH | DOZABLE_MATCH | RESTRICTED_MATCH);
602 
603         // IIF_MATCH is not enabled
604         doTestRemoveUidInterfaceRules(NO_IIF, DOZABLE_MATCH,
605                 NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH);
606     }
607 
doTestSetUidRule(final List<Integer> testChains)608     private void doTestSetUidRule(final List<Integer> testChains) throws Exception {
609         mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(TEST_IF_INDEX, IIF_MATCH));
610 
611         for (final int chain: testChains) {
612             final int ruleToAddMatch = mBpfNetMaps.isFirewallAllowList(chain)
613                     ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY;
614             mBpfNetMaps.setUidRule(chain, TEST_UID, ruleToAddMatch);
615         }
616 
617         checkUidOwnerValue(TEST_UID, TEST_IF_INDEX, IIF_MATCH | getMatch(testChains));
618 
619         for (final int chain: testChains) {
620             final int ruleToRemoveMatch = mBpfNetMaps.isFirewallAllowList(chain)
621                     ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW;
622             mBpfNetMaps.setUidRule(chain, TEST_UID, ruleToRemoveMatch);
623         }
624 
625         checkUidOwnerValue(TEST_UID, TEST_IF_INDEX, IIF_MATCH);
626     }
627 
doTestSetUidRule(final int testChain)628     private void doTestSetUidRule(final int testChain) throws Exception {
629         doTestSetUidRule(List.of(testChain));
630     }
631 
632     @Test
633     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetUidRule()634     public void testSetUidRule() throws Exception {
635         doTestSetUidRule(FIREWALL_CHAIN_DOZABLE);
636         doTestSetUidRule(FIREWALL_CHAIN_STANDBY);
637         doTestSetUidRule(FIREWALL_CHAIN_POWERSAVE);
638         doTestSetUidRule(FIREWALL_CHAIN_RESTRICTED);
639         doTestSetUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY);
640         doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_1);
641         doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_2);
642         doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_3);
643     }
644 
645     @Test
646     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetUidRuleMultipleChain()647     public void testSetUidRuleMultipleChain() throws Exception {
648         doTestSetUidRule(List.of(
649                 FIREWALL_CHAIN_DOZABLE,
650                 FIREWALL_CHAIN_STANDBY));
651         doTestSetUidRule(List.of(
652                 FIREWALL_CHAIN_DOZABLE,
653                 FIREWALL_CHAIN_STANDBY,
654                 FIREWALL_CHAIN_POWERSAVE,
655                 FIREWALL_CHAIN_RESTRICTED));
656         doTestSetUidRule(FIREWALL_CHAINS);
657     }
658 
659     @Test
660     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetUidRuleRemoveRuleFromUidWithNoRule()661     public void testSetUidRuleRemoveRuleFromUidWithNoRule() {
662         final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
663         assertThrows(expected,
664                 () -> mBpfNetMaps.setUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID, FIREWALL_RULE_DENY));
665     }
666 
667     @Test
668     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetUidRuleInvalidChain()669     public void testSetUidRuleInvalidChain() {
670         final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
671         assertThrows(expected,
672                 () -> mBpfNetMaps.setUidRule(-1 /* childChain */, TEST_UID, FIREWALL_RULE_ALLOW));
673         assertThrows(expected,
674                 () -> mBpfNetMaps.setUidRule(1000 /* childChain */, TEST_UID, FIREWALL_RULE_ALLOW));
675     }
676 
677     @Test
678     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetUidRuleInvalidRule()679     public void testSetUidRuleInvalidRule() {
680         final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
681         assertThrows(expected, () ->
682                 mBpfNetMaps.setUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID, -1 /* firewallRule */));
683         assertThrows(expected, () ->
684                 mBpfNetMaps.setUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID, 1000 /* firewallRule */));
685     }
686 
687     @Test
688     @IgnoreAfter(Build.VERSION_CODES.S_V2)
testSetUidRuleBeforeT()689     public void testSetUidRuleBeforeT() {
690         assertThrows(UnsupportedOperationException.class, () ->
691                 mBpfNetMaps.setUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID, FIREWALL_RULE_ALLOW));
692     }
693 
doTestGetUidRule(final List<Integer> enableChains)694     private void doTestGetUidRule(final List<Integer> enableChains) throws Exception {
695         mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(0, getMatch(enableChains)));
696 
697         for (final int chain: FIREWALL_CHAINS) {
698             final String testCase = "EnabledChains: " + enableChains + " CheckedChain: " + chain;
699             if (enableChains.contains(chain)) {
700                 final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain)
701                         ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY;
702                 assertEquals(testCase, expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID));
703             } else {
704                 final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain)
705                         ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW;
706                 assertEquals(testCase, expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID));
707             }
708         }
709     }
710 
doTestGetUidRule(final int enableChain)711     private void doTestGetUidRule(final int enableChain) throws Exception {
712         doTestGetUidRule(List.of(enableChain));
713     }
714 
715     @Test
716     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testGetUidRule()717     public void testGetUidRule() throws Exception {
718         doTestGetUidRule(FIREWALL_CHAIN_DOZABLE);
719         doTestGetUidRule(FIREWALL_CHAIN_STANDBY);
720         doTestGetUidRule(FIREWALL_CHAIN_POWERSAVE);
721         doTestGetUidRule(FIREWALL_CHAIN_RESTRICTED);
722         doTestGetUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY);
723         doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_1);
724         doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_2);
725         doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_3);
726     }
727 
728     @Test
729     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testGetUidRuleMultipleChainEnabled()730     public void testGetUidRuleMultipleChainEnabled() throws Exception {
731         doTestGetUidRule(List.of(
732                 FIREWALL_CHAIN_DOZABLE,
733                 FIREWALL_CHAIN_STANDBY));
734         doTestGetUidRule(List.of(
735                 FIREWALL_CHAIN_DOZABLE,
736                 FIREWALL_CHAIN_STANDBY,
737                 FIREWALL_CHAIN_POWERSAVE,
738                 FIREWALL_CHAIN_RESTRICTED));
739         doTestGetUidRule(FIREWALL_CHAINS);
740     }
741 
742     @Test
743     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testGetUidRuleNoEntry()744     public void testGetUidRuleNoEntry() throws Exception {
745         mUidOwnerMap.clear();
746         for (final int chain: FIREWALL_CHAINS) {
747             final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain)
748                     ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW;
749             assertEquals(expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID));
750         }
751     }
752 
753     @Test
754     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testGetUidRuleInvalidChain()755     public void testGetUidRuleInvalidChain() {
756         final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
757         assertThrows(expected, () -> mBpfNetMaps.getUidRule(-1 /* childChain */, TEST_UID));
758         assertThrows(expected, () -> mBpfNetMaps.getUidRule(1000 /* childChain */, TEST_UID));
759     }
760 
761     @Test
762     @IgnoreAfter(Build.VERSION_CODES.S_V2)
testGetUidRuleBeforeT()763     public void testGetUidRuleBeforeT() {
764         assertThrows(UnsupportedOperationException.class,
765                 () -> mBpfNetMaps.getUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID));
766     }
767 
768     @Test
769     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testReplaceUidChain()770     public void testReplaceUidChain() throws Exception {
771         final int uid0 = TEST_UIDS[0];
772         final int uid1 = TEST_UIDS[1];
773 
774         mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, TEST_UIDS);
775 
776         checkUidOwnerValue(uid0, NO_IIF, DOZABLE_MATCH);
777         checkUidOwnerValue(uid1, NO_IIF, DOZABLE_MATCH);
778     }
779 
780     @Test
781     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testReplaceUidChainWithOtherMatch()782     public void testReplaceUidChainWithOtherMatch() throws Exception {
783         final int uid0 = TEST_UIDS[0];
784         final int uid1 = TEST_UIDS[1];
785         final long match0 = POWERSAVE_MATCH;
786         final long match1 = POWERSAVE_MATCH | RESTRICTED_MATCH;
787         mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(NO_IIF, match0));
788         mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NO_IIF, match1));
789 
790         mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, new int[]{uid1});
791 
792         checkUidOwnerValue(uid0, NO_IIF, match0);
793         checkUidOwnerValue(uid1, NO_IIF, match1 | DOZABLE_MATCH);
794     }
795 
796     @Test
797     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testReplaceUidChainWithExistingIifMatch()798     public void testReplaceUidChainWithExistingIifMatch() throws Exception {
799         final int uid0 = TEST_UIDS[0];
800         final int uid1 = TEST_UIDS[1];
801         final long match0 = IIF_MATCH;
802         final long match1 = IIF_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH;
803         mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(TEST_IF_INDEX, match0));
804         mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1));
805 
806         mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, TEST_UIDS);
807 
808         checkUidOwnerValue(uid0, TEST_IF_INDEX, match0 | DOZABLE_MATCH);
809         checkUidOwnerValue(uid1, NULL_IIF, match1 | DOZABLE_MATCH);
810     }
811 
812     @Test
813     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testReplaceUidChainRemoveExistingMatch()814     public void testReplaceUidChainRemoveExistingMatch() throws Exception {
815         final int uid0 = TEST_UIDS[0];
816         final int uid1 = TEST_UIDS[1];
817         final long match0 = IIF_MATCH | DOZABLE_MATCH;
818         final long match1 = IIF_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH;
819         mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(TEST_IF_INDEX, match0));
820         mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1));
821 
822         mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, new int[]{uid1});
823 
824         checkUidOwnerValue(uid0, TEST_IF_INDEX, match0 & ~DOZABLE_MATCH);
825         checkUidOwnerValue(uid1, NULL_IIF, match1 | DOZABLE_MATCH);
826     }
827 
828     @Test
829     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testReplaceUidChainInvalidChain()830     public void testReplaceUidChainInvalidChain() {
831         final Class<IllegalArgumentException> expected = IllegalArgumentException.class;
832         assertThrows(expected, () -> mBpfNetMaps.replaceUidChain(-1 /* chain */, TEST_UIDS));
833         assertThrows(expected, () -> mBpfNetMaps.replaceUidChain(1000 /* chain */, TEST_UIDS));
834     }
835 
836     @Test
837     @IgnoreAfter(Build.VERSION_CODES.S_V2)
testReplaceUidChainBeforeT()838     public void testReplaceUidChainBeforeT() {
839         assertThrows(UnsupportedOperationException.class,
840                 () -> mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, TEST_UIDS));
841     }
842 
843     @Test
844     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetNetPermForUidsGrantInternetPermission()845     public void testSetNetPermForUidsGrantInternetPermission() throws Exception {
846         mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
847 
848         assertTrue(mUidPermissionMap.isEmpty());
849     }
850 
851     @Test
852     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetNetPermForUidsGrantUpdateStatsPermission()853     public void testSetNetPermForUidsGrantUpdateStatsPermission() throws Exception {
854         mBpfNetMaps.setNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS, TEST_UIDS);
855 
856         final int uid0 = TEST_UIDS[0];
857         final int uid1 = TEST_UIDS[1];
858         assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new S32(uid0)).val);
859         assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new S32(uid1)).val);
860     }
861 
862     @Test
863     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetNetPermForUidsGrantMultiplePermissions()864     public void testSetNetPermForUidsGrantMultiplePermissions() throws Exception {
865         final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
866         mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
867 
868         final int uid0 = TEST_UIDS[0];
869         final int uid1 = TEST_UIDS[1];
870         assertEquals(permission, mUidPermissionMap.getValue(new S32(uid0)).val);
871         assertEquals(permission, mUidPermissionMap.getValue(new S32(uid1)).val);
872     }
873 
874     @Test
875     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetNetPermForUidsRevokeInternetPermission()876     public void testSetNetPermForUidsRevokeInternetPermission() throws Exception {
877         final int uid0 = TEST_UIDS[0];
878         final int uid1 = TEST_UIDS[1];
879         mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
880         mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0});
881 
882         assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid0)).val);
883         assertNull(mUidPermissionMap.getValue(new S32(uid1)));
884     }
885 
886     @Test
887     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetNetPermForUidsRevokeUpdateDeviceStatsPermission()888     public void testSetNetPermForUidsRevokeUpdateDeviceStatsPermission() throws Exception {
889         final int uid0 = TEST_UIDS[0];
890         final int uid1 = TEST_UIDS[1];
891         mBpfNetMaps.setNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS, TEST_UIDS);
892         mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0});
893 
894         assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid0)).val);
895         assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new S32(uid1)).val);
896     }
897 
898     @Test
899     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetNetPermForUidsRevokeMultiplePermissions()900     public void testSetNetPermForUidsRevokeMultiplePermissions() throws Exception {
901         final int uid0 = TEST_UIDS[0];
902         final int uid1 = TEST_UIDS[1];
903         final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
904         mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
905         mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0});
906 
907         assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid0)).val);
908         assertEquals(permission, mUidPermissionMap.getValue(new S32(uid1)).val);
909     }
910 
911     @Test
912     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetNetPermForUidsPermissionUninstalled()913     public void testSetNetPermForUidsPermissionUninstalled() throws Exception {
914         final int uid0 = TEST_UIDS[0];
915         final int uid1 = TEST_UIDS[1];
916         final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
917         mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
918         mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, new int[]{uid0});
919 
920         assertNull(mUidPermissionMap.getValue(new S32(uid0)));
921         assertEquals(permission, mUidPermissionMap.getValue(new S32(uid1)).val);
922     }
923 
924     @Test
925     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSetNetPermForUidsDuplicatedRequestSilentlyIgnored()926     public void testSetNetPermForUidsDuplicatedRequestSilentlyIgnored() throws Exception {
927         final int uid0 = TEST_UIDS[0];
928         final int uid1 = TEST_UIDS[1];
929         final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
930 
931         mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
932         assertEquals(permission, mUidPermissionMap.getValue(new S32(uid0)).val);
933         assertEquals(permission, mUidPermissionMap.getValue(new S32(uid1)).val);
934 
935         mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
936         assertEquals(permission, mUidPermissionMap.getValue(new S32(uid0)).val);
937         assertEquals(permission, mUidPermissionMap.getValue(new S32(uid1)).val);
938 
939         mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, TEST_UIDS);
940         assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid0)).val);
941         assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid1)).val);
942 
943         mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, TEST_UIDS);
944         assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid0)).val);
945         assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid1)).val);
946 
947         mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, TEST_UIDS);
948         assertNull(mUidPermissionMap.getValue(new S32(uid0)));
949         assertNull(mUidPermissionMap.getValue(new S32(uid1)));
950 
951         mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, TEST_UIDS);
952         assertNull(mUidPermissionMap.getValue(new S32(uid0)));
953         assertNull(mUidPermissionMap.getValue(new S32(uid1)));
954     }
955 
956     @Test
957     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSwapActiveStatsMap()958     public void testSwapActiveStatsMap() throws Exception {
959         mConfigurationMap.updateEntry(
960                 CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A));
961 
962         mBpfNetMaps.swapActiveStatsMap();
963         assertEquals(STATS_SELECT_MAP_B,
964                 mConfigurationMap.getValue(CURRENT_STATS_MAP_CONFIGURATION_KEY).val);
965 
966         mBpfNetMaps.swapActiveStatsMap();
967         assertEquals(STATS_SELECT_MAP_A,
968                 mConfigurationMap.getValue(CURRENT_STATS_MAP_CONFIGURATION_KEY).val);
969     }
970 
971     @Test
972     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testSwapActiveStatsMapSynchronizeKernelRCUFail()973     public void testSwapActiveStatsMapSynchronizeKernelRCUFail() throws Exception {
974         doReturn(EPERM).when(mDeps).synchronizeKernelRCU();
975         mConfigurationMap.updateEntry(
976                 CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A));
977 
978         assertThrows(ServiceSpecificException.class, () -> mBpfNetMaps.swapActiveStatsMap());
979     }
980 
981     @Test
982     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testPullBpfMapInfo()983     public void testPullBpfMapInfo() throws Exception {
984         // mCookieTagMap has 1 entry
985         mCookieTagMap.updateEntry(new CookieTagMapKey(0), new CookieTagMapValue(0, 0));
986 
987         // mUidOwnerMap has 2 entries
988         mUidOwnerMap.updateEntry(new S32(0), new UidOwnerValue(0, 0));
989         mUidOwnerMap.updateEntry(new S32(1), new UidOwnerValue(0, 0));
990 
991         // mUidPermissionMap has 3 entries
992         mUidPermissionMap.updateEntry(new S32(0), new U8((short) 0));
993         mUidPermissionMap.updateEntry(new S32(1), new U8((short) 0));
994         mUidPermissionMap.updateEntry(new S32(2), new U8((short) 0));
995 
996         final int ret = mBpfNetMaps.pullBpfMapInfoAtom(NETWORK_BPF_MAP_INFO, new ArrayList<>());
997         assertEquals(StatsManager.PULL_SUCCESS, ret);
998         verify(mDeps).buildStatsEvent(
999                 1 /* cookieTagMapSize */, 2 /* uidOwnerMapSize */, 3 /* uidPermissionMapSize */);
1000     }
1001 
1002     @Test
1003     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testPullBpfMapInfoGetMapSizeFailure()1004     public void testPullBpfMapInfoGetMapSizeFailure() throws Exception {
1005         doThrow(new ErrnoException("", EINVAL)).when(mCookieTagMap).forEach(any());
1006         final int ret = mBpfNetMaps.pullBpfMapInfoAtom(NETWORK_BPF_MAP_INFO, new ArrayList<>());
1007         assertEquals(StatsManager.PULL_SKIP, ret);
1008     }
1009 
1010     @Test
1011     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testPullBpfMapInfoUnexpectedAtomTag()1012     public void testPullBpfMapInfoUnexpectedAtomTag() {
1013         final int ret = mBpfNetMaps.pullBpfMapInfoAtom(-1 /* atomTag */, new ArrayList<>());
1014         assertEquals(StatsManager.PULL_SKIP, ret);
1015     }
1016 
assertDumpContains(final String dump, final String message)1017     private void assertDumpContains(final String dump, final String message) {
1018         assertTrue(String.format("dump(%s) does not contain '%s'", dump, message),
1019                 dump.contains(message));
1020     }
1021 
getDump()1022     private String getDump() throws Exception {
1023         final StringWriter sw = new StringWriter();
1024         mBpfNetMaps.dump(new IndentingPrintWriter(sw), new FileDescriptor(), true /* verbose */);
1025         return sw.toString();
1026     }
1027 
doTestDumpUidPermissionMap(final int permission, final String permissionString)1028     private void doTestDumpUidPermissionMap(final int permission, final String permissionString)
1029             throws Exception {
1030         mUidPermissionMap.updateEntry(new S32(TEST_UID), new U8((short) permission));
1031         assertDumpContains(getDump(), TEST_UID + " " + permissionString);
1032     }
1033 
1034     @Test
1035     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testDumpUidPermissionMap()1036     public void testDumpUidPermissionMap() throws Exception {
1037         doTestDumpUidPermissionMap(PERMISSION_NONE, "PERMISSION_NONE");
1038         doTestDumpUidPermissionMap(PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS,
1039                 "PERMISSION_INTERNET PERMISSION_UPDATE_DEVICE_STATS");
1040     }
1041 
1042     @Test
1043     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testDumpUidPermissionMapInvalidPermission()1044     public void testDumpUidPermissionMapInvalidPermission() throws Exception {
1045         doTestDumpUidPermissionMap(PERMISSION_UNINSTALLED, "PERMISSION_UNINSTALLED error!");
1046         doTestDumpUidPermissionMap(PERMISSION_INTERNET | 1 << 6,
1047                 "PERMISSION_INTERNET PERMISSION_UNKNOWN(64)");
1048     }
1049 
doTestDumpUidOwnerMap(final int iif, final long match, final String matchString)1050     void doTestDumpUidOwnerMap(final int iif, final long match, final String matchString)
1051             throws Exception {
1052         mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match));
1053         assertDumpContains(getDump(), TEST_UID + " " + matchString);
1054     }
1055 
doTestDumpUidOwnerMap(final long match, final String matchString)1056     void doTestDumpUidOwnerMap(final long match, final String matchString) throws Exception {
1057         doTestDumpUidOwnerMap(0 /* iif */, match, matchString);
1058     }
1059 
1060     @Test
1061     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testDumpUidOwnerMap()1062     public void testDumpUidOwnerMap() throws Exception {
1063         doTestDumpUidOwnerMap(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH");
1064         doTestDumpUidOwnerMap(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH");
1065         doTestDumpUidOwnerMap(DOZABLE_MATCH, "DOZABLE_MATCH");
1066         doTestDumpUidOwnerMap(STANDBY_MATCH, "STANDBY_MATCH");
1067         doTestDumpUidOwnerMap(POWERSAVE_MATCH, "POWERSAVE_MATCH");
1068         doTestDumpUidOwnerMap(RESTRICTED_MATCH, "RESTRICTED_MATCH");
1069         doTestDumpUidOwnerMap(LOW_POWER_STANDBY_MATCH, "LOW_POWER_STANDBY_MATCH");
1070         doTestDumpUidOwnerMap(LOCKDOWN_VPN_MATCH, "LOCKDOWN_VPN_MATCH");
1071         doTestDumpUidOwnerMap(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH");
1072         doTestDumpUidOwnerMap(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH");
1073         doTestDumpUidOwnerMap(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH");
1074 
1075         doTestDumpUidOwnerMap(HAPPY_BOX_MATCH | POWERSAVE_MATCH,
1076                 "HAPPY_BOX_MATCH POWERSAVE_MATCH");
1077         doTestDumpUidOwnerMap(DOZABLE_MATCH | LOCKDOWN_VPN_MATCH | OEM_DENY_1_MATCH,
1078                 "DOZABLE_MATCH LOCKDOWN_VPN_MATCH OEM_DENY_1_MATCH");
1079     }
1080 
1081     @Test
1082     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testDumpUidOwnerMapWithIifMatch()1083     public void testDumpUidOwnerMapWithIifMatch() throws Exception {
1084         doTestDumpUidOwnerMap(TEST_IF_INDEX, IIF_MATCH, "IIF_MATCH " + TEST_IF_INDEX);
1085         doTestDumpUidOwnerMap(TEST_IF_INDEX,
1086                 IIF_MATCH | DOZABLE_MATCH | LOCKDOWN_VPN_MATCH | OEM_DENY_1_MATCH,
1087                 "DOZABLE_MATCH IIF_MATCH LOCKDOWN_VPN_MATCH OEM_DENY_1_MATCH " + TEST_IF_INDEX);
1088     }
1089 
1090     @Test
1091     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testDumpUidOwnerMapWithInvalidMatch()1092     public void testDumpUidOwnerMapWithInvalidMatch() throws Exception {
1093         final long invalid_match = 1L << 31;
1094         doTestDumpUidOwnerMap(invalid_match, "UNKNOWN_MATCH(" + invalid_match + ")");
1095         doTestDumpUidOwnerMap(DOZABLE_MATCH | invalid_match,
1096                 "DOZABLE_MATCH UNKNOWN_MATCH(" + invalid_match + ")");
1097     }
1098 
1099     @Test
1100     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testDumpCurrentStatsMapConfig()1101     public void testDumpCurrentStatsMapConfig() throws Exception {
1102         mConfigurationMap.updateEntry(
1103                 CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A));
1104         assertDumpContains(getDump(), "current statsMap configuration: 0 SELECT_MAP_A");
1105 
1106         mConfigurationMap.updateEntry(
1107                 CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_B));
1108         assertDumpContains(getDump(), "current statsMap configuration: 1 SELECT_MAP_B");
1109     }
1110 
doTestDumpOwnerMatchConfig(final long match, final String matchString)1111     private void doTestDumpOwnerMatchConfig(final long match, final String matchString)
1112             throws Exception {
1113         mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(match));
1114         assertDumpContains(getDump(),
1115                 "current ownerMatch configuration: " + match + " " + matchString);
1116     }
1117 
1118     @Test
1119     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testDumpUidOwnerMapConfig()1120     public void testDumpUidOwnerMapConfig() throws Exception {
1121         doTestDumpOwnerMatchConfig(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH");
1122         doTestDumpOwnerMatchConfig(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH");
1123         doTestDumpOwnerMatchConfig(DOZABLE_MATCH, "DOZABLE_MATCH");
1124         doTestDumpOwnerMatchConfig(STANDBY_MATCH, "STANDBY_MATCH");
1125         doTestDumpOwnerMatchConfig(POWERSAVE_MATCH, "POWERSAVE_MATCH");
1126         doTestDumpOwnerMatchConfig(RESTRICTED_MATCH, "RESTRICTED_MATCH");
1127         doTestDumpOwnerMatchConfig(LOW_POWER_STANDBY_MATCH, "LOW_POWER_STANDBY_MATCH");
1128         doTestDumpOwnerMatchConfig(IIF_MATCH, "IIF_MATCH");
1129         doTestDumpOwnerMatchConfig(LOCKDOWN_VPN_MATCH, "LOCKDOWN_VPN_MATCH");
1130         doTestDumpOwnerMatchConfig(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH");
1131         doTestDumpOwnerMatchConfig(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH");
1132         doTestDumpOwnerMatchConfig(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH");
1133 
1134         doTestDumpOwnerMatchConfig(HAPPY_BOX_MATCH | POWERSAVE_MATCH,
1135                 "HAPPY_BOX_MATCH POWERSAVE_MATCH");
1136         doTestDumpOwnerMatchConfig(DOZABLE_MATCH | LOCKDOWN_VPN_MATCH | OEM_DENY_1_MATCH,
1137                 "DOZABLE_MATCH LOCKDOWN_VPN_MATCH OEM_DENY_1_MATCH");
1138     }
1139 
1140     @Test
1141     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testDumpUidOwnerMapConfigWithInvalidMatch()1142     public void testDumpUidOwnerMapConfigWithInvalidMatch() throws Exception {
1143         final long invalid_match = 1L << 31;
1144         doTestDumpOwnerMatchConfig(invalid_match, "UNKNOWN_MATCH(" + invalid_match + ")");
1145         doTestDumpOwnerMatchConfig(DOZABLE_MATCH | invalid_match,
1146                 "DOZABLE_MATCH UNKNOWN_MATCH(" + invalid_match + ")");
1147     }
1148 
1149     @Test
1150     @IgnoreUpTo(Build.VERSION_CODES.S_V2)
testDumpCookieTagMap()1151     public void testDumpCookieTagMap() throws Exception {
1152         mCookieTagMap.updateEntry(new CookieTagMapKey(123), new CookieTagMapValue(456, 0x789));
1153         assertDumpContains(getDump(), "cookie=123 tag=0x789 uid=456");
1154     }
1155 
1156     @Test
testGetUids()1157     public void testGetUids() throws ErrnoException {
1158         final int uid0 = TEST_UIDS[0];
1159         final int uid1 = TEST_UIDS[1];
1160         final long match0 = DOZABLE_MATCH | POWERSAVE_MATCH;
1161         final long match1 = DOZABLE_MATCH | STANDBY_MATCH;
1162         mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(NULL_IIF, match0));
1163         mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1));
1164 
1165         assertEquals(new ArraySet<>(List.of(uid0, uid1)),
1166                 mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_DOZABLE));
1167         assertEquals(new ArraySet<>(List.of(uid0)),
1168                 mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_POWERSAVE));
1169 
1170         assertEquals(new ArraySet<>(List.of(uid1)),
1171                 mBpfNetMaps.getUidsWithDenyRuleOnDenyListChain(FIREWALL_CHAIN_STANDBY));
1172         assertEquals(new ArraySet<>(),
1173                 mBpfNetMaps.getUidsWithDenyRuleOnDenyListChain(FIREWALL_CHAIN_OEM_DENY_1));
1174     }
1175 
1176     @Test
testGetUidsIllegalArgument()1177     public void testGetUidsIllegalArgument() {
1178         final Class<IllegalArgumentException> expected = IllegalArgumentException.class;
1179         assertThrows(expected,
1180                 () -> mBpfNetMaps.getUidsWithDenyRuleOnDenyListChain(FIREWALL_CHAIN_DOZABLE));
1181         assertThrows(expected,
1182                 () -> mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_OEM_DENY_1));
1183     }
1184 }
1185