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