diff --git a/framework/Android.bp b/framework/Android.bp index 813e296377..e6637645aa 100644 --- a/framework/Android.bp +++ b/framework/Android.bp @@ -82,7 +82,6 @@ java_defaults { // framework-connectivity and framework-tethering are in the same APEX. "framework-tethering.impl", "framework-wifi.stubs.module_lib", - "net-utils-device-common", ], static_libs: [ "mdns_aidl_interface-lateststable-java", @@ -91,6 +90,9 @@ java_defaults { "modules-utils-preconditions", "framework-connectivity-javastream-protos", ], + impl_only_static_libs: [ + "net-utils-device-common-struct", + ], libs: [ "androidx.annotation_annotation", "app-compat-annotations", @@ -112,6 +114,13 @@ java_library { "httpclient_api", "httpclient_impl", "http_client_logging", + // Framework-connectivity-pre-jarjar is identical to framework-connectivity + // implementation, but without the jarjar rules. However, framework-connectivity + // is not based on framework-connectivity-pre-jarjar, it's rebuilt from source + // 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", ], libs: [ // This cannot be in the defaults clause above because if it were, it would be used diff --git a/framework/src/android/net/BpfNetMapsConstants.java b/framework/src/android/net/BpfNetMapsConstants.java new file mode 100644 index 0000000000..219168211a --- /dev/null +++ b/framework/src/android/net/BpfNetMapsConstants.java @@ -0,0 +1,79 @@ +/* + * 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.util.Pair; + +import com.android.net.module.util.Struct; + +import java.util.Arrays; +import java.util.List; + +/** + * BpfNetMaps related constants that can be shared among modules. + * + * @hide + */ +// Note that this class should be put into bootclasspath instead of static libraries. +// Because modules could have different copies of this class if this is statically linked, +// which would be problematic if the definitions in these modules are not synchronized. +public class BpfNetMapsConstants { + // Prevent this class from being accidental instantiated. + private BpfNetMapsConstants() {} + + public static final String CONFIGURATION_MAP_PATH = + "/sys/fs/bpf/netd_shared/map_netd_configuration_map"; + public static final String UID_OWNER_MAP_PATH = + "/sys/fs/bpf/netd_shared/map_netd_uid_owner_map"; + public static final String UID_PERMISSION_MAP_PATH = + "/sys/fs/bpf/netd_shared/map_netd_uid_permission_map"; + public static final String COOKIE_TAG_MAP_PATH = + "/sys/fs/bpf/netd_shared/map_netd_cookie_tag_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); + + // LINT.IfChange(match_type) + public static final long NO_MATCH = 0; + public static final long HAPPY_BOX_MATCH = (1 << 0); + public static final long PENALTY_BOX_MATCH = (1 << 1); + public static final long DOZABLE_MATCH = (1 << 2); + public static final long STANDBY_MATCH = (1 << 3); + public static final long POWERSAVE_MATCH = (1 << 4); + public static final long RESTRICTED_MATCH = (1 << 5); + public static final long LOW_POWER_STANDBY_MATCH = (1 << 6); + public static final long IIF_MATCH = (1 << 7); + public static final long LOCKDOWN_VPN_MATCH = (1 << 8); + public static final long OEM_DENY_1_MATCH = (1 << 9); + public static final long OEM_DENY_2_MATCH = (1 << 10); + public static final long OEM_DENY_3_MATCH = (1 << 11); + // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/netd.h) + + public static final List> MATCH_LIST = Arrays.asList( + Pair.create(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"), + Pair.create(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"), + Pair.create(DOZABLE_MATCH, "DOZABLE_MATCH"), + Pair.create(STANDBY_MATCH, "STANDBY_MATCH"), + Pair.create(POWERSAVE_MATCH, "POWERSAVE_MATCH"), + Pair.create(RESTRICTED_MATCH, "RESTRICTED_MATCH"), + Pair.create(LOW_POWER_STANDBY_MATCH, "LOW_POWER_STANDBY_MATCH"), + Pair.create(IIF_MATCH, "IIF_MATCH"), + Pair.create(LOCKDOWN_VPN_MATCH, "LOCKDOWN_VPN_MATCH"), + Pair.create(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH"), + Pair.create(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH"), + Pair.create(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH") + ); +} diff --git a/framework/src/android/net/BpfNetMapsUtils.java b/framework/src/android/net/BpfNetMapsUtils.java new file mode 100644 index 0000000000..d464e3df2c --- /dev/null +++ b/framework/src/android/net/BpfNetMapsUtils.java @@ -0,0 +1,127 @@ +/* + * 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.DOZABLE_MATCH; +import static android.net.BpfNetMapsConstants.LOW_POWER_STANDBY_MATCH; +import static android.net.BpfNetMapsConstants.MATCH_LIST; +import static android.net.BpfNetMapsConstants.NO_MATCH; +import static android.net.BpfNetMapsConstants.OEM_DENY_1_MATCH; +import static android.net.BpfNetMapsConstants.OEM_DENY_2_MATCH; +import static android.net.BpfNetMapsConstants.OEM_DENY_3_MATCH; +import static android.net.BpfNetMapsConstants.POWERSAVE_MATCH; +import static android.net.BpfNetMapsConstants.RESTRICTED_MATCH; +import static android.net.BpfNetMapsConstants.STANDBY_MATCH; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED; +import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY; +import static android.system.OsConstants.EINVAL; + +import android.os.ServiceSpecificException; +import android.util.Pair; + +import java.util.StringJoiner; + +/** + * The classes and the methods for BpfNetMaps utilization. + * + * @hide + */ +// Note that this class should be put into bootclasspath instead of static libraries. +// Because modules could have different copies of this class if this is statically linked, +// which would be problematic if the definitions in these modules are not synchronized. +public class BpfNetMapsUtils { + // Prevent this class from being accidental instantiated. + private BpfNetMapsUtils() {} + + /** + * Get corresponding match from firewall chain. + */ + public static long getMatchByFirewallChain(final int chain) { + switch (chain) { + case FIREWALL_CHAIN_DOZABLE: + return DOZABLE_MATCH; + case FIREWALL_CHAIN_STANDBY: + return STANDBY_MATCH; + case FIREWALL_CHAIN_POWERSAVE: + return POWERSAVE_MATCH; + case FIREWALL_CHAIN_RESTRICTED: + return RESTRICTED_MATCH; + case FIREWALL_CHAIN_LOW_POWER_STANDBY: + return LOW_POWER_STANDBY_MATCH; + case FIREWALL_CHAIN_OEM_DENY_1: + return OEM_DENY_1_MATCH; + case FIREWALL_CHAIN_OEM_DENY_2: + return OEM_DENY_2_MATCH; + case FIREWALL_CHAIN_OEM_DENY_3: + return OEM_DENY_3_MATCH; + default: + throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain); + } + } + + /** + * Get if the chain is allow list or not. + * + * ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed + * DENYLIST means the firewall allows all by default, uids must be explicitly denyed + */ + public static boolean isFirewallAllowList(final int chain) { + switch (chain) { + case FIREWALL_CHAIN_DOZABLE: + case FIREWALL_CHAIN_POWERSAVE: + case FIREWALL_CHAIN_RESTRICTED: + case FIREWALL_CHAIN_LOW_POWER_STANDBY: + return true; + case FIREWALL_CHAIN_STANDBY: + case FIREWALL_CHAIN_OEM_DENY_1: + case FIREWALL_CHAIN_OEM_DENY_2: + case FIREWALL_CHAIN_OEM_DENY_3: + return false; + default: + throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain); + } + } + + /** + * Get match string representation from the given match bitmap. + */ + public static String matchToString(long matchMask) { + if (matchMask == NO_MATCH) { + return "NO_MATCH"; + } + + final StringJoiner sj = new StringJoiner(" "); + for (final Pair match : MATCH_LIST) { + final long matchFlag = match.first; + final String matchName = match.second; + if ((matchMask & matchFlag) != 0) { + sj.add(matchName); + matchMask &= ~matchFlag; + } + } + if (matchMask != 0) { + sj.add("UNKNOWN_MATCH(" + matchMask + ")"); + } + return sj.toString(); + } +} diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java index 2842cc3963..62520dc797 100644 --- a/service/src/com/android/server/BpfNetMaps.java +++ b/service/src/com/android/server/BpfNetMaps.java @@ -16,6 +16,18 @@ package com.android.server; +import static android.net.BpfNetMapsConstants.CONFIGURATION_MAP_PATH; +import static android.net.BpfNetMapsConstants.COOKIE_TAG_MAP_PATH; +import static android.net.BpfNetMapsConstants.CURRENT_STATS_MAP_CONFIGURATION_KEY; +import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH; +import static android.net.BpfNetMapsConstants.IIF_MATCH; +import static android.net.BpfNetMapsConstants.LOCKDOWN_VPN_MATCH; +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.getMatchByFirewallChain; +import static android.net.BpfNetMapsUtils.matchToString; import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE; import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY; import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1; @@ -107,16 +119,6 @@ public class BpfNetMaps { // BpfNetMaps is an only writer of this entry. private static final Object sCurrentStatsMapConfigLock = new Object(); - private static final String CONFIGURATION_MAP_PATH = - "/sys/fs/bpf/netd_shared/map_netd_configuration_map"; - private static final String UID_OWNER_MAP_PATH = - "/sys/fs/bpf/netd_shared/map_netd_uid_owner_map"; - private static final String UID_PERMISSION_MAP_PATH = - "/sys/fs/bpf/netd_shared/map_netd_uid_permission_map"; - private static final String COOKIE_TAG_MAP_PATH = - "/sys/fs/bpf/netd_shared/map_netd_cookie_tag_map"; - private static final S32 UID_RULES_CONFIGURATION_KEY = new S32(0); - private static final S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new S32(1); private static final long UID_RULES_DEFAULT_CONFIGURATION = 0; private static final long STATS_SELECT_MAP_A = 0; private static final long STATS_SELECT_MAP_B = 1; @@ -127,40 +129,10 @@ public class BpfNetMaps { private static IBpfMap sUidPermissionMap = null; private static IBpfMap sCookieTagMap = null; - // LINT.IfChange(match_type) - @VisibleForTesting public static final long NO_MATCH = 0; - @VisibleForTesting public static final long HAPPY_BOX_MATCH = (1 << 0); - @VisibleForTesting public static final long PENALTY_BOX_MATCH = (1 << 1); - @VisibleForTesting public static final long DOZABLE_MATCH = (1 << 2); - @VisibleForTesting public static final long STANDBY_MATCH = (1 << 3); - @VisibleForTesting public static final long POWERSAVE_MATCH = (1 << 4); - @VisibleForTesting public static final long RESTRICTED_MATCH = (1 << 5); - @VisibleForTesting public static final long LOW_POWER_STANDBY_MATCH = (1 << 6); - @VisibleForTesting public static final long IIF_MATCH = (1 << 7); - @VisibleForTesting public static final long LOCKDOWN_VPN_MATCH = (1 << 8); - @VisibleForTesting public static final long OEM_DENY_1_MATCH = (1 << 9); - @VisibleForTesting public static final long OEM_DENY_2_MATCH = (1 << 10); - @VisibleForTesting public static final long OEM_DENY_3_MATCH = (1 << 11); - // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/netd.h) - private static final List> PERMISSION_LIST = Arrays.asList( Pair.create(PERMISSION_INTERNET, "PERMISSION_INTERNET"), Pair.create(PERMISSION_UPDATE_DEVICE_STATS, "PERMISSION_UPDATE_DEVICE_STATS") ); - private static final List> MATCH_LIST = Arrays.asList( - Pair.create(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"), - Pair.create(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"), - Pair.create(DOZABLE_MATCH, "DOZABLE_MATCH"), - Pair.create(STANDBY_MATCH, "STANDBY_MATCH"), - Pair.create(POWERSAVE_MATCH, "POWERSAVE_MATCH"), - Pair.create(RESTRICTED_MATCH, "RESTRICTED_MATCH"), - Pair.create(LOW_POWER_STANDBY_MATCH, "LOW_POWER_STANDBY_MATCH"), - Pair.create(IIF_MATCH, "IIF_MATCH"), - Pair.create(LOCKDOWN_VPN_MATCH, "LOCKDOWN_VPN_MATCH"), - Pair.create(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH"), - Pair.create(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH"), - Pair.create(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH") - ); /** * Set sEnableJavaBpfMap for test. @@ -352,33 +324,6 @@ public class BpfNetMaps { mDeps = deps; } - /** - * Get corresponding match from firewall chain. - */ - @VisibleForTesting - public long getMatchByFirewallChain(final int chain) { - switch (chain) { - case FIREWALL_CHAIN_DOZABLE: - return DOZABLE_MATCH; - case FIREWALL_CHAIN_STANDBY: - return STANDBY_MATCH; - case FIREWALL_CHAIN_POWERSAVE: - return POWERSAVE_MATCH; - case FIREWALL_CHAIN_RESTRICTED: - return RESTRICTED_MATCH; - case FIREWALL_CHAIN_LOW_POWER_STANDBY: - return LOW_POWER_STANDBY_MATCH; - case FIREWALL_CHAIN_OEM_DENY_1: - return OEM_DENY_1_MATCH; - case FIREWALL_CHAIN_OEM_DENY_2: - return OEM_DENY_2_MATCH; - case FIREWALL_CHAIN_OEM_DENY_3: - return OEM_DENY_3_MATCH; - default: - throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain); - } - } - /** * Get if the chain is allow list or not. * @@ -1049,26 +994,6 @@ public class BpfNetMaps { return sj.toString(); } - private String matchToString(long matchMask) { - if (matchMask == NO_MATCH) { - return "NO_MATCH"; - } - - final StringJoiner sj = new StringJoiner(" "); - for (Pair match: MATCH_LIST) { - final long matchFlag = match.first; - final String matchName = match.second; - if ((matchMask & matchFlag) != 0) { - sj.add(matchName); - matchMask &= ~matchFlag; - } - } - if (matchMask != 0) { - sj.add("UNKNOWN_MATCH(" + matchMask + ")"); - } - return sj.toString(); - } - private void dumpOwnerMatchConfig(final IndentingPrintWriter pw) { try { final long match = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val; diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java index 19fa41df32..5f280c637d 100644 --- a/tests/unit/java/com/android/server/BpfNetMapsTest.java +++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java @@ -16,6 +16,21 @@ package com.android.server; +import static android.net.BpfNetMapsConstants.CURRENT_STATS_MAP_CONFIGURATION_KEY; +import static android.net.BpfNetMapsConstants.DOZABLE_MATCH; +import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH; +import static android.net.BpfNetMapsConstants.IIF_MATCH; +import static android.net.BpfNetMapsConstants.LOCKDOWN_VPN_MATCH; +import static android.net.BpfNetMapsConstants.LOW_POWER_STANDBY_MATCH; +import static android.net.BpfNetMapsConstants.NO_MATCH; +import static android.net.BpfNetMapsConstants.OEM_DENY_1_MATCH; +import static android.net.BpfNetMapsConstants.OEM_DENY_2_MATCH; +import static android.net.BpfNetMapsConstants.OEM_DENY_3_MATCH; +import static android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH; +import static android.net.BpfNetMapsConstants.POWERSAVE_MATCH; +import static android.net.BpfNetMapsConstants.RESTRICTED_MATCH; +import static android.net.BpfNetMapsConstants.STANDBY_MATCH; +import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY; import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE; import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY; import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1; @@ -33,19 +48,6 @@ import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS; import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.EPERM; -import static com.android.server.BpfNetMaps.DOZABLE_MATCH; -import static com.android.server.BpfNetMaps.HAPPY_BOX_MATCH; -import static com.android.server.BpfNetMaps.IIF_MATCH; -import static com.android.server.BpfNetMaps.LOCKDOWN_VPN_MATCH; -import static com.android.server.BpfNetMaps.LOW_POWER_STANDBY_MATCH; -import static com.android.server.BpfNetMaps.NO_MATCH; -import static com.android.server.BpfNetMaps.OEM_DENY_1_MATCH; -import static com.android.server.BpfNetMaps.OEM_DENY_2_MATCH; -import static com.android.server.BpfNetMaps.OEM_DENY_3_MATCH; -import static com.android.server.BpfNetMaps.PENALTY_BOX_MATCH; -import static com.android.server.BpfNetMaps.POWERSAVE_MATCH; -import static com.android.server.BpfNetMaps.RESTRICTED_MATCH; -import static com.android.server.BpfNetMaps.STANDBY_MATCH; import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO; import static org.junit.Assert.assertEquals; @@ -62,6 +64,7 @@ import static org.mockito.Mockito.verify; import android.app.StatsManager; import android.content.Context; +import android.net.BpfNetMapsUtils; import android.net.INetd; import android.os.Build; import android.os.ServiceSpecificException; @@ -112,8 +115,6 @@ public final class BpfNetMapsTest { private static final int NO_IIF = 0; private static final int NULL_IIF = 0; private static final String CHAINNAME = "fw_dozable"; - private static final S32 UID_RULES_CONFIGURATION_KEY = new S32(0); - private static final S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new S32(1); private static final List FIREWALL_CHAINS = List.of( FIREWALL_CHAIN_DOZABLE, FIREWALL_CHAIN_STANDBY, @@ -170,7 +171,7 @@ public final class BpfNetMapsTest { private long getMatch(final List chains) { long match = 0; for (final int chain: chains) { - match |= mBpfNetMaps.getMatchByFirewallChain(chain); + match |= BpfNetMapsUtils.getMatchByFirewallChain(chain); } return match; } @@ -239,7 +240,7 @@ public final class BpfNetMapsTest { private void doTestSetChildChain(final List testChains) throws Exception { long expectedMatch = 0; for (final int chain: testChains) { - expectedMatch |= mBpfNetMaps.getMatchByFirewallChain(chain); + expectedMatch |= BpfNetMapsUtils.getMatchByFirewallChain(chain); } assertEquals(0, mConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);