From 448eb43f28825b1a6f2de88af0928ea114e9ecf1 Mon Sep 17 00:00:00 2001 From: Sarup Dalwani Date: Thu, 23 Jan 2025 20:02:48 +0000 Subject: [PATCH] Adding access methods for local_net_access_map and local_net_blocked_uid_map Test: Manually tested this using dumpsys commands Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.server.BpfNetMapsTest Bug: 392855578 Change-Id: I61522f3282aa502f20641d3c2692a66638edf706 --- .../module/util/bpf/LocalNetAccessKey.java | 72 +++++++ .../src/android/net/BpfNetMapsConstants.java | 5 + .../src/com/android/server/BpfNetMaps.java | 197 ++++++++++++++++++ .../com/android/server/BpfNetMapsTest.java | 141 +++++++++++++ 4 files changed, 415 insertions(+) create mode 100644 common/src/com/android/net/module/util/bpf/LocalNetAccessKey.java diff --git a/common/src/com/android/net/module/util/bpf/LocalNetAccessKey.java b/common/src/com/android/net/module/util/bpf/LocalNetAccessKey.java new file mode 100644 index 0000000000..95265b9744 --- /dev/null +++ b/common/src/com/android/net/module/util/bpf/LocalNetAccessKey.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.net.module.util.bpf; + +import com.android.net.module.util.InetAddressUtils; +import com.android.net.module.util.Struct; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; + +public class LocalNetAccessKey extends Struct { + + @Field(order = 0, type = Type.U32) + public final long lpmBitlen; + @Field(order = 1, type = Type.U32) + public final long ifIndex; + @Field(order = 2, type = Type.Ipv6Address) + public final Inet6Address remoteAddress; + @Field(order = 3, type = Type.U16) + public final int protocol; + @Field(order = 4, type = Type.UBE16) + public final int remotePort; + + public LocalNetAccessKey(long lpmBitlen, long ifIndex, InetAddress remoteAddress, int protocol, + int remotePort) { + this.lpmBitlen = lpmBitlen; + this.ifIndex = ifIndex; + this.protocol = protocol; + this.remotePort = remotePort; + + if (remoteAddress instanceof Inet4Address) { + this.remoteAddress = InetAddressUtils.v4MappedV6Address((Inet4Address) remoteAddress); + } else { + this.remoteAddress = (Inet6Address) remoteAddress; + } + } + + public LocalNetAccessKey(long lpmBitlen, long ifIndex, Inet6Address remoteAddress, int protocol, + int remotePort) { + this.lpmBitlen = lpmBitlen; + this.ifIndex = ifIndex; + this.remoteAddress = remoteAddress; + this.protocol = protocol; + this.remotePort = remotePort; + } + + @Override + public String toString() { + return "LocalNetAccessKey{" + + "lpmBitlen=" + lpmBitlen + + ", ifIndex=" + ifIndex + + ", remoteAddress=" + remoteAddress + + ", protocol=" + protocol + + ", remotePort=" + remotePort + + "}"; + } +} diff --git a/framework/src/android/net/BpfNetMapsConstants.java b/framework/src/android/net/BpfNetMapsConstants.java index f3773de668..f1a6f00269 100644 --- a/framework/src/android/net/BpfNetMapsConstants.java +++ b/framework/src/android/net/BpfNetMapsConstants.java @@ -60,6 +60,11 @@ public class BpfNetMapsConstants { "/sys/fs/bpf/netd_shared/map_netd_data_saver_enabled_map"; public static final String INGRESS_DISCARD_MAP_PATH = "/sys/fs/bpf/netd_shared/map_netd_ingress_discard_map"; + public static final String LOCAL_NET_ACCESS_MAP_PATH = + "/sys/fs/bpf/netd_shared/map_netd_local_net_access_map"; + public static final String LOCAL_NET_BLOCKED_UID_MAP_PATH = + "/sys/fs/bpf/netd_shared/map_netd_local_net_blocked_uid_map"; + public static final Struct.S32 UID_RULES_CONFIGURATION_KEY = new Struct.S32(0); public static final Struct.S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new Struct.S32(1); public static final Struct.S32 DATA_SAVER_ENABLED_KEY = new Struct.S32(0); diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java index 44868b2db7..c743573f45 100644 --- a/service/src/com/android/server/BpfNetMaps.java +++ b/service/src/com/android/server/BpfNetMaps.java @@ -25,6 +25,8 @@ import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY; import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_MAP_PATH; import static android.net.BpfNetMapsConstants.IIF_MATCH; import static android.net.BpfNetMapsConstants.INGRESS_DISCARD_MAP_PATH; +import static android.net.BpfNetMapsConstants.LOCAL_NET_ACCESS_MAP_PATH; +import static android.net.BpfNetMapsConstants.LOCAL_NET_BLOCKED_UID_MAP_PATH; import static android.net.BpfNetMapsConstants.LOCKDOWN_VPN_MATCH; import static android.net.BpfNetMapsConstants.UID_OWNER_MAP_PATH; import static android.net.BpfNetMapsConstants.UID_PERMISSION_MAP_PATH; @@ -74,6 +76,7 @@ import com.android.net.module.util.BpfMap; import com.android.net.module.util.IBpfMap; import com.android.net.module.util.SingleWriterBpfMap; import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Bool; import com.android.net.module.util.Struct.S32; import com.android.net.module.util.Struct.U32; import com.android.net.module.util.Struct.U8; @@ -81,6 +84,7 @@ import com.android.net.module.util.bpf.CookieTagMapKey; import com.android.net.module.util.bpf.CookieTagMapValue; import com.android.net.module.util.bpf.IngressDiscardKey; import com.android.net.module.util.bpf.IngressDiscardValue; +import com.android.net.module.util.bpf.LocalNetAccessKey; import java.io.FileDescriptor; import java.io.IOException; @@ -131,6 +135,9 @@ public class BpfNetMaps { private static IBpfMap sDataSaverEnabledMap = null; private static IBpfMap sIngressDiscardMap = null; + private static IBpfMap sLocalNetAccessMap = null; + private static IBpfMap sLocalNetBlockedUidMap = null; + private static final List> PERMISSION_LIST = Arrays.asList( Pair.create(PERMISSION_INTERNET, "PERMISSION_INTERNET"), Pair.create(PERMISSION_UPDATE_DEVICE_STATS, "PERMISSION_UPDATE_DEVICE_STATS") @@ -186,6 +193,25 @@ public class BpfNetMaps { sIngressDiscardMap = ingressDiscardMap; } + /** + * Set localNetAccessMap for test. + */ + @VisibleForTesting + public static void setLocalNetAccessMapForTest( + IBpfMap localNetAccessMap) { + sLocalNetAccessMap = localNetAccessMap; + } + + /** + * Set localNetBlockedUidMap for test. + */ + @VisibleForTesting + public static void setLocalNetBlockedUidMapForTest( + IBpfMap localNetBlockedUidMap) { + sLocalNetBlockedUidMap = localNetBlockedUidMap; + } + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) private static IBpfMap getConfigurationMap() { try { @@ -247,6 +273,26 @@ public class BpfNetMaps { } } + @RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT) + private static IBpfMap getLocalNetBlockedUidMap() { + try { + return SingleWriterBpfMap.getSingleton(LOCAL_NET_BLOCKED_UID_MAP_PATH, + U32.class, Bool.class); + } catch (ErrnoException e) { + throw new IllegalStateException("Cannot open local_net_blocked_uid map", e); + } + } + + @RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT) + private static IBpfMap getLocalNetAccessMap() { + try { + return SingleWriterBpfMap.getSingleton(LOCAL_NET_ACCESS_MAP_PATH, + LocalNetAccessKey.class, Bool.class); + } catch (ErrnoException e) { + throw new IllegalStateException("Cannot open local_net_access map", e); + } + } + @RequiresApi(Build.VERSION_CODES.TIRAMISU) private static void initBpfMaps() { if (sConfigurationMap == null) { @@ -299,6 +345,27 @@ public class BpfNetMaps { } catch (ErrnoException e) { throw new IllegalStateException("Failed to initialize ingress discard map", e); } + + if (isAtLeast25Q2()) { + if (sLocalNetAccessMap == null) { + sLocalNetAccessMap = getLocalNetAccessMap(); + } + try { + sLocalNetAccessMap.clear(); + } catch (ErrnoException e) { + throw new IllegalStateException("Failed to initialize local_net_access map", e); + } + + if (sLocalNetBlockedUidMap == null) { + sLocalNetBlockedUidMap = getLocalNetBlockedUidMap(); + } + try { + sLocalNetBlockedUidMap.clear(); + } catch (ErrnoException e) { + throw new IllegalStateException("Failed to initialize local_net_blocked_uid map", + e); + } + } } /** @@ -387,6 +454,21 @@ public class BpfNetMaps { } } + private void throwIfPre25Q2(final String msg) { + if (!isAtLeast25Q2()) { + throw new UnsupportedOperationException(msg); + } + } + + /* + ToDo : Remove this method when SdkLevel.isAtLeastB() is fixed, aosp is at sdk level 36 or use + NetworkStackUtils.isAtLeast25Q2 when it is moved to a static lib. + */ + private static boolean isAtLeast25Q2() { + return SdkLevel.isAtLeastB() || (SdkLevel.isAtLeastV() + && "Baklava".equals(Build.VERSION.CODENAME)); + } + private void removeRule(final int uid, final long match, final String caller) { try { synchronized (sUidOwnerMap) { @@ -809,6 +891,113 @@ public class BpfNetMaps { } } + /** + * Add configuration to local_net_access trie map. + * @param lpmBitlen prefix length that will be used for longest matching + * @param iface interface name + * @param address remote address. ipv4 addresses would be mapped to v6 + * @param protocol required for longest match in special cases + * @param remotePort src/dst port for ingress/egress + * @param isAllowed is the local network call allowed or blocked. + */ + @RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT) + public void addLocalNetAccess(final int lpmBitlen, final String iface, + final InetAddress address, final int protocol, final int remotePort, + final boolean isAllowed) { + throwIfPre25Q2("addLocalNetAccess is not available on pre-B devices"); + final int ifIndex = mDeps.getIfIndex(iface); + if (ifIndex == 0) { + Log.e(TAG, "Failed to get if index, skip addLocalNetAccess for " + address + + "(" + iface + ")"); + return; + } + LocalNetAccessKey localNetAccessKey = new LocalNetAccessKey(lpmBitlen, ifIndex, + address, protocol, remotePort); + + try { + sLocalNetAccessMap.updateEntry(localNetAccessKey, new Bool(isAllowed)); + } catch (ErrnoException e) { + Log.e(TAG, "Failed to add local network access for localNetAccessKey : " + + localNetAccessKey + ", isAllowed : " + isAllowed); + } + } + + /** + * False if the configuration is disallowed. + * + * @param lpmBitlen prefix length that will be used for longest matching + * @param iface interface name + * @param address remote address. ipv4 addresses would be mapped to v6 + * @param protocol required for longest match in special cases + * @param remotePort src/dst port for ingress/egress + */ + @RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT) + public boolean getLocalNetAccess(final int lpmBitlen, final String iface, + final InetAddress address, final int protocol, final int remotePort) { + throwIfPre25Q2("getLocalNetAccess is not available on pre-B devices"); + final int ifIndex = mDeps.getIfIndex(iface); + if (ifIndex == 0) { + Log.e(TAG, "Failed to get if index, returning default from getLocalNetAccess for " + + address + "(" + iface + ")"); + return true; + } + LocalNetAccessKey localNetAccessKey = new LocalNetAccessKey(lpmBitlen, ifIndex, + address, protocol, remotePort); + try { + Bool value = sLocalNetAccessMap.getValue(localNetAccessKey); + return value == null ? true : value.val; + } catch (ErrnoException e) { + Log.e(TAG, "Failed to find local network access configuration for " + + "localNetAccessKey : " + localNetAccessKey); + } + return true; + } + + /** + * Add uid to local_net_blocked_uid map. + * @param uid application uid that needs to block local network calls. + */ + @RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT) + public void addUidToLocalNetBlockMap(final int uid) { + throwIfPre25Q2("addUidToLocalNetBlockMap is not available on pre-B devices"); + try { + sLocalNetBlockedUidMap.updateEntry(new U32(uid), new Bool(true)); + } catch (ErrnoException e) { + Log.e(TAG, "Failed to add local network blocked for uid : " + uid); + } + } + + /** + * True if local network calls are blocked for application. + * @param uid application uid that needs check if local network calls are blocked. + */ + @RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT) + public boolean getUidValueFromLocalNetBlockMap(final int uid) { + throwIfPre25Q2("getUidValueFromLocalNetBlockMap is not available on pre-B devices"); + try { + Bool value = sLocalNetBlockedUidMap.getValue(new U32(uid)); + return value == null ? false : value.val; + } catch (ErrnoException e) { + Log.e(TAG, "Failed to find uid(" + uid + + ") is present in local network blocked map"); + } + return false; + } + + /** + * Remove uid from local_net_blocked_uid map(if present). + * @param uid application uid that needs check if local network calls are blocked. + */ + @RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT) + public void removeUidFromLocalNetBlockMap(final int uid) { + throwIfPre25Q2("removeUidFromLocalNetBlockMap is not available on pre-B devices"); + try { + sLocalNetBlockedUidMap.deleteEntry(new U32(uid)); + } catch (ErrnoException e) { + Log.e(TAG, "Failed to remove uid(" + uid + ") from local network blocked map"); + } + } + /** * Get granted permissions for specified uid. If uid is not in the map, this method returns * {@link android.net.INetd.PERMISSION_INTERNET} since this is a default permission. @@ -1079,6 +1268,14 @@ public class BpfNetMaps { (key, value) -> "[" + key.dstAddr + "]: " + value.iif1 + "(" + mDeps.getIfName(value.iif1) + "), " + value.iif2 + "(" + mDeps.getIfName(value.iif2) + ")"); + if (sLocalNetBlockedUidMap != null) { + BpfDump.dumpMap(sLocalNetAccessMap, pw, "sLocalNetAccessMap", + (key, value) -> "[" + key + "]: " + value); + } + if (sLocalNetBlockedUidMap != null) { + BpfDump.dumpMap(sLocalNetBlockedUidMap, pw, "sLocalNetBlockedUidMap", + (key, value) -> "[" + key + "]: " + value); + } dumpDataSaverConfig(pw); pw.decreaseIndent(); } diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java index c1c15ca0aa..73eb24d3dc 100644 --- a/tests/unit/java/com/android/server/BpfNetMapsTest.java +++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java @@ -71,6 +71,7 @@ import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; @@ -99,6 +100,7 @@ import androidx.test.filters.SmallTest; import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.IBpfMap; +import com.android.net.module.util.Struct.Bool; import com.android.net.module.util.Struct.S32; import com.android.net.module.util.Struct.U32; import com.android.net.module.util.Struct.U8; @@ -106,6 +108,7 @@ import com.android.net.module.util.bpf.CookieTagMapKey; import com.android.net.module.util.bpf.CookieTagMapValue; import com.android.net.module.util.bpf.IngressDiscardKey; import com.android.net.module.util.bpf.IngressDiscardValue; +import com.android.net.module.util.bpf.LocalNetAccessKey; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; @@ -171,6 +174,10 @@ public final class BpfNetMapsTest { private final IBpfMap mUidOwnerMap = new TestBpfMap<>(S32.class, UidOwnerValue.class); private final IBpfMap mUidPermissionMap = new TestBpfMap<>(S32.class, U8.class); + private final IBpfMap mLocalNetBlockedUidMap = + new TestBpfMap<>(U32.class, Bool.class); + private final IBpfMap mLocalNetAccessMap = + new TestBpfMap<>(LocalNetAccessKey.class, Bool.class); private final IBpfMap mCookieTagMap = spy(new TestBpfMap<>(CookieTagMapKey.class, CookieTagMapValue.class)); private final IBpfMap mDataSaverEnabledMap = new TestBpfMap<>(S32.class, U8.class); @@ -189,6 +196,8 @@ public final class BpfNetMapsTest { CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A)); BpfNetMaps.setUidOwnerMapForTest(mUidOwnerMap); BpfNetMaps.setUidPermissionMapForTest(mUidPermissionMap); + BpfNetMaps.setLocalNetAccessMapForTest(mLocalNetAccessMap); + BpfNetMaps.setLocalNetBlockedUidMapForTest(mLocalNetBlockedUidMap); BpfNetMaps.setCookieTagMapForTest(mCookieTagMap); BpfNetMaps.setDataSaverEnabledMapForTest(mDataSaverEnabledMap); mDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(DATA_SAVER_DISABLED)); @@ -234,6 +243,138 @@ public final class BpfNetMapsTest { doTestIsChainEnabled(List.of(enableChain)); } + @Test + @IgnoreAfter(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testAddLocalNetAccessBeforeV() { + assertThrows(UnsupportedOperationException.class, () -> + mBpfNetMaps.addLocalNetAccess(0, TEST_IF_NAME, Inet6Address.ANY, 0, 0, true)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testAddLocalNetAccessAfterV() throws Exception { + assertTrue(mLocalNetAccessMap.isEmpty()); + + mBpfNetMaps.addLocalNetAccess(160, TEST_IF_NAME, + Inet4Address.getByName("196.68.0.0"), 0, 0, true); + + assertNotNull(mLocalNetAccessMap.getValue(new LocalNetAccessKey(160, TEST_IF_INDEX, + Inet4Address.getByName("196.68.0.0"), 0, 0))); + assertNull(mLocalNetAccessMap.getValue(new LocalNetAccessKey(160, TEST_IF_INDEX, + Inet4Address.getByName("100.68.0.0"), 0, 0))); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testAddLocalNetAccessAfterVWithIncorrectInterface() throws Exception { + assertTrue(mLocalNetAccessMap.isEmpty()); + + mBpfNetMaps.addLocalNetAccess(160, "wlan2", + Inet4Address.getByName("196.68.0.0"), 0, 0, true); + + assertTrue(mLocalNetAccessMap.isEmpty()); + } + + @Test + @IgnoreAfter(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testGetLocalNetAccessBeforeV() { + assertThrows(UnsupportedOperationException.class, () -> + mBpfNetMaps.getLocalNetAccess(0, TEST_IF_NAME, Inet6Address.ANY, 0, 0)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testGetLocalNetAccessAfterV() throws Exception { + assertTrue(mLocalNetAccessMap.isEmpty()); + + mLocalNetAccessMap.updateEntry(new LocalNetAccessKey(160, TEST_IF_INDEX, + Inet4Address.getByName("196.68.0.0"), 0, 0), + new Bool(false)); + + assertNotNull(mLocalNetAccessMap.getValue(new LocalNetAccessKey(160, TEST_IF_INDEX, + Inet4Address.getByName("196.68.0.0"), 0, 0))); + + assertFalse(mBpfNetMaps.getLocalNetAccess(160, TEST_IF_NAME, + Inet4Address.getByName("196.68.0.0"), 0, 0)); + assertTrue(mBpfNetMaps.getLocalNetAccess(160, TEST_IF_NAME, + Inet4Address.getByName("100.68.0.0"), 0, 0)); + } + + @Test + @IgnoreAfter(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testAddUidToLocalNetBlockMapBeforeV() { + assertThrows(UnsupportedOperationException.class, () -> + mBpfNetMaps.addUidToLocalNetBlockMap(0)); + } + + @Test + @IgnoreAfter(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testIsUidPresentInLocalNetBlockMapBeforeV() { + assertThrows(UnsupportedOperationException.class, () -> + mBpfNetMaps.getUidValueFromLocalNetBlockMap(0)); + } + + @Test + @IgnoreAfter(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testRemoveUidFromLocalNetBlockMapBeforeV() { + assertThrows(UnsupportedOperationException.class, () -> + mBpfNetMaps.removeUidFromLocalNetBlockMap(0)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testAddUidFromLocalNetBlockMapAfterV() throws Exception { + final int uid0 = TEST_UIDS[0]; + final int uid1 = TEST_UIDS[1]; + + assertTrue(mLocalNetAccessMap.isEmpty()); + + mBpfNetMaps.addUidToLocalNetBlockMap(uid0); + assertTrue(mLocalNetBlockedUidMap.getValue(new U32(uid0)).val); + assertNull(mLocalNetBlockedUidMap.getValue(new U32(uid1))); + + mBpfNetMaps.addUidToLocalNetBlockMap(uid1); + assertTrue(mLocalNetBlockedUidMap.getValue(new U32(uid1)).val); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testIsUidPresentInLocalNetBlockMapAfterV() throws Exception { + final int uid0 = TEST_UIDS[0]; + final int uid1 = TEST_UIDS[1]; + + assertTrue(mLocalNetAccessMap.isEmpty()); + + mLocalNetBlockedUidMap.updateEntry(new U32(uid0), new Bool(true)); + assertTrue(mBpfNetMaps.getUidValueFromLocalNetBlockMap(uid0)); + assertFalse(mBpfNetMaps.getUidValueFromLocalNetBlockMap(uid1)); + + mLocalNetBlockedUidMap.updateEntry(new U32(uid1), new Bool(true)); + assertTrue(mBpfNetMaps.getUidValueFromLocalNetBlockMap(uid1)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public void testRemoveUidFromLocalNetBlockMapAfterV() throws Exception { + final int uid0 = TEST_UIDS[0]; + final int uid1 = TEST_UIDS[1]; + + assertTrue(mLocalNetAccessMap.isEmpty()); + + mLocalNetBlockedUidMap.updateEntry(new U32(uid0), new Bool(true)); + mLocalNetBlockedUidMap.updateEntry(new U32(uid1), new Bool(true)); + + assertTrue(mLocalNetBlockedUidMap.getValue(new U32(uid0)).val); + assertTrue(mLocalNetBlockedUidMap.getValue(new U32(uid1)).val); + + mBpfNetMaps.removeUidFromLocalNetBlockMap(uid0); + assertNull(mLocalNetBlockedUidMap.getValue(new U32(uid0))); + assertTrue(mLocalNetBlockedUidMap.getValue(new U32(uid1)).val); + + mBpfNetMaps.removeUidFromLocalNetBlockMap(uid1); + assertNull(mLocalNetBlockedUidMap.getValue(new U32(uid1))); + } + @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2) public void testIsChainEnabled() throws Exception {