From 626045a60133c24b83324ae857adf1f884dba209 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 28 Aug 2023 18:49:44 +0800 Subject: [PATCH] [BR01.1] Support BpfNetMapsReader A helper class to *read* java BpfMaps. This is designed to provide direct bpf access in the caller process through ConnectivityManager APIs. The change also removes any statical link to net-utils-device-common-struct from service-connectivity. This is because net-utils-device-common-struct is already included in framework-connectivity. Including it again in service-connectivity would create a r8 build fail by circular dependency. Test: atest FrameworksNetTests:android.net.connectivity.com.android.server.BpfNetMapsTest Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.net.module.util.StructTest Test: atest FrameworksNetTests:android.net.connectivity.android.net.BpfNetMapsReaderTest Bug: 297836825 Change-Id: I7a6d2eb816d0dc7343167bddd672806b199f44fe --- Tethering/Android.bp | 2 + common/Android.bp | 6 +- framework/Android.bp | 4 +- .../src/android/net/BpfNetMapsReader.java | 179 ++++++++++++++++++ .../src/android/net/BpfNetMapsUtils.java | 13 ++ .../src/android/net}/UidOwnerValue.java | 10 +- service/Android.bp | 1 - .../src/com/android/server/BpfNetMaps.java | 48 ++--- staticlibs/Android.bp | 11 +- staticlibs/testutils/Android.bp | 1 + .../com/android/testutils/TestBpfMap.java | 2 + .../java/android/net/BpfNetMapsReaderTest.kt | 69 +++++++ .../com/android/server/BpfNetMapsTest.java | 1 + 13 files changed, 313 insertions(+), 34 deletions(-) create mode 100644 framework/src/android/net/BpfNetMapsReader.java rename {service/src/com/android/server => framework/src/android/net}/UidOwnerValue.java (86%) create mode 100644 tests/unit/java/android/net/BpfNetMapsReaderTest.kt diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 4478b1e92a..e69b872ce1 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -95,6 +95,7 @@ android_library { ], static_libs: [ "NetworkStackApiCurrentShims", + "net-utils-device-common-struct", ], apex_available: ["com.android.tethering"], lint: { strict_updatability_linting: true }, @@ -109,6 +110,7 @@ android_library { ], static_libs: [ "NetworkStackApiStableShims", + "net-utils-device-common-struct", ], apex_available: ["com.android.tethering"], lint: { strict_updatability_linting: true }, diff --git a/common/Android.bp b/common/Android.bp index c9824312a0..1d73a46af5 100644 --- a/common/Android.bp +++ b/common/Android.bp @@ -25,6 +25,7 @@ build = ["TrunkStable.bp"] // as the above target may not exist // depending on the branch +// The library requires the final artifact to contain net-utils-device-common-struct. java_library { name: "connectivity-net-module-utils-bpf", srcs: [ @@ -40,8 +41,9 @@ java_library { libs: [ "androidx.annotation_annotation", "framework-connectivity.stubs.module_lib", - ], - static_libs: [ + // For libraries which are statically linked in framework-connectivity, do not + // statically link here because callers of this library might already have a static + // version linked. "net-utils-device-common-struct", ], apex_available: [ diff --git a/framework/Android.bp b/framework/Android.bp index 182c558b37..449e652783 100644 --- a/framework/Android.bp +++ b/framework/Android.bp @@ -101,7 +101,7 @@ java_defaults { "framework-connectivity-javastream-protos", ], impl_only_static_libs: [ - "net-utils-device-common-struct", + "net-utils-device-common-bpf", ], libs: [ "androidx.annotation_annotation", @@ -130,7 +130,7 @@ java_library { // to generate the SDK stubs. // Even if the library is included in "impl_only_static_libs" of defaults. This is still // needed because java_library which doesn't understand "impl_only_static_libs". - "net-utils-device-common-struct", + "net-utils-device-common-bpf", ], libs: [ // This cannot be in the defaults clause above because if it were, it would be used diff --git a/framework/src/android/net/BpfNetMapsReader.java b/framework/src/android/net/BpfNetMapsReader.java new file mode 100644 index 0000000000..49e874ad9e --- /dev/null +++ b/framework/src/android/net/BpfNetMapsReader.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2023 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 android.net; + +import static android.net.BpfNetMapsConstants.CONFIGURATION_MAP_PATH; +import static android.net.BpfNetMapsConstants.UID_OWNER_MAP_PATH; +import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY; +import static android.net.BpfNetMapsUtils.getMatchByFirewallChain; +import static android.net.BpfNetMapsUtils.isFirewallAllowList; +import static android.net.BpfNetMapsUtils.throwIfPreT; +import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW; +import static android.net.ConnectivityManager.FIREWALL_RULE_DENY; + +import android.annotation.NonNull; +import android.annotation.RequiresApi; +import android.os.Build; +import android.os.ServiceSpecificException; +import android.system.ErrnoException; +import android.system.Os; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.modules.utils.build.SdkLevel; +import com.android.net.module.util.BpfMap; +import com.android.net.module.util.IBpfMap; +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.S32; +import com.android.net.module.util.Struct.U32; + +/** + * A helper class to *read* java BpfMaps. + * @hide + */ +@RequiresApi(Build.VERSION_CODES.TIRAMISU) // BPF maps were only mainlined in T +public class BpfNetMapsReader { + // Locally store the handle of bpf maps. The FileDescriptors are statically cached inside the + // BpfMap implementation. + + // Bpf map to store various networking configurations, the format of the value is different + // for different keys. See BpfNetMapsConstants#*_CONFIGURATION_KEY for keys. + private final IBpfMap mConfigurationMap; + // Bpf map to store per uid traffic control configurations. + // See {@link UidOwnerValue} for more detail. + private final IBpfMap mUidOwnerMap; + private final Dependencies mDeps; + + public BpfNetMapsReader() { + this(new Dependencies()); + } + + @VisibleForTesting + public BpfNetMapsReader(@NonNull Dependencies deps) { + if (!SdkLevel.isAtLeastT()) { + throw new UnsupportedOperationException( + BpfNetMapsReader.class.getSimpleName() + " is not supported below Android T"); + } + mDeps = deps; + mConfigurationMap = mDeps.getConfigurationMap(); + mUidOwnerMap = mDeps.getUidOwnerMap(); + } + + /** + * Dependencies of BpfNetMapReader, for injection in tests. + */ + @VisibleForTesting + public static class Dependencies { + /** Get the configuration map. */ + public IBpfMap getConfigurationMap() { + try { + return new BpfMap<>(CONFIGURATION_MAP_PATH, BpfMap.BPF_F_RDONLY, + S32.class, U32.class); + } catch (ErrnoException e) { + throw new IllegalStateException("Cannot open configuration map", e); + } + } + + /** Get the uid owner map. */ + public IBpfMap getUidOwnerMap() { + try { + return new BpfMap<>(UID_OWNER_MAP_PATH, BpfMap.BPF_F_RDONLY, + S32.class, UidOwnerValue.class); + } catch (ErrnoException e) { + throw new IllegalStateException("Cannot open uid owner map", e); + } + } + } + + /** + * Get the specified firewall chain's status. + * + * @param chain target chain + * @return {@code true} if chain is enabled, {@code false} if chain is not enabled. + * @throws UnsupportedOperationException if called on pre-T devices. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + public boolean isChainEnabled(final int chain) { + return isChainEnabled(mConfigurationMap, chain); + } + + /** + * Get firewall rule of specified firewall chain on specified uid. + * + * @param chain target chain + * @param uid target uid + * @return either {@link ConnectivityManager#FIREWALL_RULE_ALLOW} or + * {@link ConnectivityManager#FIREWALL_RULE_DENY}. + * @throws UnsupportedOperationException if called on pre-T devices. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + public int getUidRule(final int chain, final int uid) { + return getUidRule(mUidOwnerMap, chain, uid); + } + + /** + * Get the specified firewall chain's status. + * + * @param configurationMap target configurationMap + * @param chain target chain + * @return {@code true} if chain is enabled, {@code false} if chain is not enabled. + * @throws UnsupportedOperationException if called on pre-T devices. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + public static boolean isChainEnabled( + final IBpfMap configurationMap, final int chain) { + throwIfPreT("isChainEnabled is not available on pre-T devices"); + + final long match = getMatchByFirewallChain(chain); + try { + final Struct.U32 config = configurationMap.getValue(UID_RULES_CONFIGURATION_KEY); + return (config.val & match) != 0; + } catch (ErrnoException e) { + throw new ServiceSpecificException(e.errno, + "Unable to get firewall chain status: " + Os.strerror(e.errno)); + } + } + + /** + * Get firewall rule of specified firewall chain on specified uid. + * + * @param uidOwnerMap target uidOwnerMap. + * @param chain target chain. + * @param uid target uid. + * @return either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY + * @throws UnsupportedOperationException if called on pre-T devices. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + public static int getUidRule(final IBpfMap uidOwnerMap, + final int chain, final int uid) { + throwIfPreT("getUidRule is not available on pre-T devices"); + + final long match = getMatchByFirewallChain(chain); + final boolean isAllowList = isFirewallAllowList(chain); + try { + final UidOwnerValue uidMatch = uidOwnerMap.getValue(new Struct.S32(uid)); + final boolean isMatchEnabled = uidMatch != null && (uidMatch.rule & match) != 0; + return isMatchEnabled == isAllowList ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY; + } catch (ErrnoException e) { + throw new ServiceSpecificException(e.errno, + "Unable to get uid rule status: " + Os.strerror(e.errno)); + } + } +} diff --git a/framework/src/android/net/BpfNetMapsUtils.java b/framework/src/android/net/BpfNetMapsUtils.java index d464e3df2c..28d5891fe7 100644 --- a/framework/src/android/net/BpfNetMapsUtils.java +++ b/framework/src/android/net/BpfNetMapsUtils.java @@ -39,6 +39,8 @@ import static android.system.OsConstants.EINVAL; import android.os.ServiceSpecificException; import android.util.Pair; +import com.android.modules.utils.build.SdkLevel; + import java.util.StringJoiner; /** @@ -124,4 +126,15 @@ public class BpfNetMapsUtils { } return sj.toString(); } + + public static final boolean PRE_T = !SdkLevel.isAtLeastT(); + + /** + * Throw UnsupportedOperationException if SdkLevel is before T. + */ + public static void throwIfPreT(final String msg) { + if (PRE_T) { + throw new UnsupportedOperationException(msg); + } + } } diff --git a/service/src/com/android/server/UidOwnerValue.java b/framework/src/android/net/UidOwnerValue.java similarity index 86% rename from service/src/com/android/server/UidOwnerValue.java rename to framework/src/android/net/UidOwnerValue.java index d6c0e0ddf4..e8ae604b63 100644 --- a/service/src/com/android/server/UidOwnerValue.java +++ b/framework/src/android/net/UidOwnerValue.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 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. @@ -14,11 +14,15 @@ * limitations under the License. */ -package com.android.server; +package android.net; import com.android.net.module.util.Struct; -/** Value type for per uid traffic control configuration map */ +/** + * Value type for per uid traffic control configuration map. + * + * @hide + */ public class UidOwnerValue extends Struct { // Allowed interface index. Only applicable if IIF_MATCH is set in the rule bitmask below. @Field(order = 0, type = Type.S32) diff --git a/service/Android.bp b/service/Android.bp index 8e59e8615e..250693f7f3 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -188,7 +188,6 @@ java_library { "dnsresolver_aidl_interface-V11-java", "modules-utils-shell-command-handler", "net-utils-device-common", - "net-utils-device-common-bpf", "net-utils-device-common-ip", "net-utils-device-common-netlink", "net-utils-services-common", diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java index 6a34a242ad..671c4ac3ab 100644 --- a/service/src/com/android/server/BpfNetMaps.java +++ b/service/src/com/android/server/BpfNetMaps.java @@ -26,6 +26,7 @@ import static android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH; import static android.net.BpfNetMapsConstants.UID_OWNER_MAP_PATH; import static android.net.BpfNetMapsConstants.UID_PERMISSION_MAP_PATH; import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY; +import static android.net.BpfNetMapsUtils.PRE_T; import static android.net.BpfNetMapsUtils.getMatchByFirewallChain; import static android.net.BpfNetMapsUtils.matchToString; import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE; @@ -51,7 +52,9 @@ import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO; import android.app.StatsManager; import android.content.Context; +import android.net.BpfNetMapsReader; import android.net.INetd; +import android.net.UidOwnerValue; import android.os.Build; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -92,7 +95,6 @@ import java.util.StringJoiner; * {@hide} */ public class BpfNetMaps { - private static final boolean PRE_T = !SdkLevel.isAtLeastT(); static { if (!PRE_T) { System.loadLibrary("service-connectivity"); @@ -298,6 +300,7 @@ public class BpfNetMaps { } /** Constructor used after T that doesn't need to use netd anymore. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public BpfNetMaps(final Context context) { this(context, null); @@ -420,6 +423,7 @@ public class BpfNetMaps { * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void addNaughtyApp(final int uid) { throwIfPreT("addNaughtyApp is not available on pre-T devices"); @@ -438,6 +442,7 @@ public class BpfNetMaps { * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void removeNaughtyApp(final int uid) { throwIfPreT("removeNaughtyApp is not available on pre-T devices"); @@ -456,6 +461,7 @@ public class BpfNetMaps { * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void addNiceApp(final int uid) { throwIfPreT("addNiceApp is not available on pre-T devices"); @@ -474,6 +480,7 @@ public class BpfNetMaps { * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void removeNiceApp(final int uid) { throwIfPreT("removeNiceApp is not available on pre-T devices"); @@ -494,6 +501,7 @@ public class BpfNetMaps { * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void setChildChain(final int childChain, final boolean enable) { throwIfPreT("setChildChain is not available on pre-T devices"); @@ -523,18 +531,14 @@ public class BpfNetMaps { * @throws UnsupportedOperationException if called on pre-T devices. * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. + * + * @deprecated Use {@link BpfNetMapsReader#isChainEnabled} instead. */ + // TODO: Migrate the callers to use {@link BpfNetMapsReader#isChainEnabled} instead. + @Deprecated + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public boolean isChainEnabled(final int childChain) { - throwIfPreT("isChainEnabled is not available on pre-T devices"); - - final long match = getMatchByFirewallChain(childChain); - try { - final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY); - return (config.val & match) != 0; - } catch (ErrnoException e) { - throw new ServiceSpecificException(e.errno, - "Unable to get firewall chain status: " + Os.strerror(e.errno)); - } + return BpfNetMapsReader.isChainEnabled(sConfigurationMap, childChain); } private Set asSet(final int[] uids) { @@ -554,6 +558,7 @@ public class BpfNetMaps { * @throws UnsupportedOperationException if called on pre-T devices. * @throws IllegalArgumentException if {@code chain} is not a valid chain. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void replaceUidChain(final int chain, final int[] uids) { throwIfPreT("replaceUidChain is not available on pre-T devices"); @@ -638,6 +643,7 @@ public class BpfNetMaps { * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void setUidRule(final int childChain, final int uid, final int firewallRule) { throwIfPreT("setUidRule is not available on pre-T devices"); @@ -667,20 +673,12 @@ public class BpfNetMaps { * @throws UnsupportedOperationException if called on pre-T devices. * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. + * + * @deprecated use {@link BpfNetMapsReader#getUidRule} instead. */ + // TODO: Migrate the callers to use {@link BpfNetMapsReader#getUidRule} instead. public int getUidRule(final int childChain, final int uid) { - throwIfPreT("isUidChainEnabled is not available on pre-T devices"); - - final long match = getMatchByFirewallChain(childChain); - final boolean isAllowList = isFirewallAllowList(childChain); - try { - final UidOwnerValue uidMatch = sUidOwnerMap.getValue(new S32(uid)); - final boolean isMatchEnabled = uidMatch != null && (uidMatch.rule & match) != 0; - return isMatchEnabled == isAllowList ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY; - } catch (ErrnoException e) { - throw new ServiceSpecificException(e.errno, - "Unable to get uid rule status: " + Os.strerror(e.errno)); - } + return BpfNetMapsReader.getUidRule(sUidOwnerMap, childChain, uid); } private Set getUidsMatchEnabled(final int childChain) throws ErrnoException { @@ -830,6 +828,7 @@ public class BpfNetMaps { * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void updateUidLockdownRule(final int uid, final boolean add) { throwIfPreT("updateUidLockdownRule is not available on pre-T devices"); @@ -852,6 +851,7 @@ public class BpfNetMaps { * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void swapActiveStatsMap() { throwIfPreT("swapActiveStatsMap is not available on pre-T devices"); @@ -927,6 +927,7 @@ public class BpfNetMaps { } /** Register callback for statsd to pull atom. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void setPullAtomCallback(final Context context) { throwIfPreT("setPullAtomCallback is not available on pre-T devices"); @@ -1016,6 +1017,7 @@ public class BpfNetMaps { * @throws IOException when file descriptor is invalid. * @throws ServiceSpecificException when the method is called on an unsupported device. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) public void dump(final IndentingPrintWriter pw, final FileDescriptor fd, boolean verbose) throws IOException, ServiceSpecificException { if (PRE_T) { diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 621759e932..0bcb757a0f 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -181,6 +181,8 @@ java_library { }, } +// The net-utils-device-common-netlink library requires the callers to contain +// net-utils-device-common-struct. java_library { name: "net-utils-device-common-netlink", srcs: [ @@ -192,12 +194,13 @@ java_library { "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", ], - static_libs: [ - "net-utils-device-common-struct", - ], libs: [ "androidx.annotation_annotation", "framework-connectivity.stubs.module_lib", + // For libraries which are statically linked in framework-connectivity, do not + // statically link here because callers of this library might already have a static + // version linked. + "net-utils-device-common-struct", ], apex_available: [ "com.android.tethering", @@ -209,6 +212,8 @@ java_library { }, } +// The net-utils-device-common-ip library requires the callers to contain +// net-utils-device-common-struct. java_library { // TODO : this target should probably be folded into net-utils-device-common name: "net-utils-device-common-ip", diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 5fe7ac3a96..a5e5afb886 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -38,6 +38,7 @@ java_library { "net-utils-device-common", "net-utils-device-common-async", "net-utils-device-common-netlink", + "net-utils-device-common-struct", "net-utils-device-common-wear", "modules-utils-build_system", ], diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java b/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java index 733bd9807b..70f20d6e27 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java @@ -43,6 +43,8 @@ import java.util.concurrent.ConcurrentHashMap; public class TestBpfMap implements IBpfMap { private final ConcurrentHashMap mMap = new ConcurrentHashMap<>(); + public TestBpfMap() {} + // TODO: Remove this constructor public TestBpfMap(final Class key, final Class value) { } diff --git a/tests/unit/java/android/net/BpfNetMapsReaderTest.kt b/tests/unit/java/android/net/BpfNetMapsReaderTest.kt new file mode 100644 index 0000000000..facb932e6c --- /dev/null +++ b/tests/unit/java/android/net/BpfNetMapsReaderTest.kt @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2023 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 android.net + +import android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY +import android.net.BpfNetMapsUtils.getMatchByFirewallChain +import android.os.Build +import com.android.net.module.util.IBpfMap +import com.android.net.module.util.Struct.S32 +import com.android.net.module.util.Struct.U32 +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.DevSdkIgnoreRunner +import com.android.testutils.TestBpfMap +import kotlin.test.assertFalse +import kotlin.test.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +// pre-T devices does not support Bpf. +@RunWith(DevSdkIgnoreRunner::class) +@IgnoreUpTo(Build.VERSION_CODES.S_V2) +class BpfNetMapsReaderTest { + private val testConfigurationMap: IBpfMap = TestBpfMap() + private val testUidOwnerMap: IBpfMap = TestBpfMap() + private val bpfNetMapsReader = BpfNetMapsReader( + TestDependencies(testConfigurationMap, testUidOwnerMap)) + + class TestDependencies( + private val configMap: IBpfMap, + private val uidOwnerMap: IBpfMap + ) : BpfNetMapsReader.Dependencies() { + override fun getConfigurationMap() = configMap + override fun getUidOwnerMap() = uidOwnerMap + } + + private fun doTestIsChainEnabled(chain: Int) { + testConfigurationMap.updateEntry( + UID_RULES_CONFIGURATION_KEY, + U32(getMatchByFirewallChain(chain)) + ) + assertTrue(bpfNetMapsReader.isChainEnabled(chain)) + testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0)) + assertFalse(bpfNetMapsReader.isChainEnabled(chain)) + } + + @Test + @Throws(Exception::class) + fun testIsChainEnabled() { + doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE) + doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_STANDBY) + doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_POWERSAVE) + doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_RESTRICTED) + doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY) + } +} diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java index 5f280c637d..da5f7e13c9 100644 --- a/tests/unit/java/com/android/server/BpfNetMapsTest.java +++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java @@ -66,6 +66,7 @@ import android.app.StatsManager; import android.content.Context; import android.net.BpfNetMapsUtils; import android.net.INetd; +import android.net.UidOwnerValue; import android.os.Build; import android.os.ServiceSpecificException; import android.system.ErrnoException;