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