Merge changes I2d3820bf,Ie802b3d1,I3793aa0e into main
* changes:
Use Bpf map based isUidRestrictedOnMeteredNetworks on V+
Add bpf map based getUidNetworkingBlockedReasons
Add blocked reason for OEM deny firewall chains
diff --git a/common/flags.aconfig b/common/flags.aconfig
index 40e6cd8..55a96ac 100644
--- a/common/flags.aconfig
+++ b/common/flags.aconfig
@@ -91,3 +91,11 @@
description: "Flag for metered network firewall chain API"
bug: "332628891"
}
+
+flag {
+ name: "blocked_reason_oem_deny_chains"
+ is_exported: true
+ namespace: "android_core_networking"
+ description: "Flag for oem deny chains blocked reasons API"
+ bug: "328732146"
+}
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index b2aafa0..d233f3e 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -52,6 +52,7 @@
field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
field public static final int BLOCKED_REASON_LOW_POWER_STANDBY = 32; // 0x20
field public static final int BLOCKED_REASON_NONE = 0; // 0x0
+ field @FlaggedApi("com.android.net.flags.blocked_reason_oem_deny_chains") public static final int BLOCKED_REASON_OEM_DENY = 128; // 0x80
field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
field @FlaggedApi("com.android.net.flags.basic_background_restrictions_enabled") public static final int FIREWALL_CHAIN_BACKGROUND = 6; // 0x6
field public static final int FIREWALL_CHAIN_DOZABLE = 1; // 0x1
diff --git a/framework/src/android/net/BpfNetMapsUtils.java b/framework/src/android/net/BpfNetMapsUtils.java
index 4e01fee..4099e2a 100644
--- a/framework/src/android/net/BpfNetMapsUtils.java
+++ b/framework/src/android/net/BpfNetMapsUtils.java
@@ -37,6 +37,18 @@
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.BLOCKED_METERED_REASON_ADMIN_DISABLED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_BACKGROUND;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_OEM_DENY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_RESTRICTED_MODE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
@@ -238,6 +250,67 @@
}
/**
+ * Get blocked reasons for specified uid
+ *
+ * @param uid Target Uid
+ * @return Reasons of network access blocking for an UID
+ */
+ public static int getUidNetworkingBlockedReasons(final int uid,
+ IBpfMap<S32, U32> configurationMap,
+ IBpfMap<S32, UidOwnerValue> uidOwnerMap,
+ IBpfMap<S32, U8> dataSaverEnabledMap
+ ) {
+ final long uidRuleConfig;
+ final long uidMatch;
+ try {
+ uidRuleConfig = configurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val;
+ final UidOwnerValue value = uidOwnerMap.getValue(new Struct.S32(uid));
+ uidMatch = (value != null) ? value.rule : 0L;
+ } catch (ErrnoException e) {
+ throw new ServiceSpecificException(e.errno,
+ "Unable to get firewall chain status: " + Os.strerror(e.errno));
+ }
+ final long blockingMatches = (uidRuleConfig & ~uidMatch & sMaskDropIfUnset)
+ | (uidRuleConfig & uidMatch & sMaskDropIfSet);
+
+ int blockedReasons = BLOCKED_REASON_NONE;
+ if ((blockingMatches & POWERSAVE_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_BATTERY_SAVER;
+ }
+ if ((blockingMatches & DOZABLE_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_DOZE;
+ }
+ if ((blockingMatches & STANDBY_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_APP_STANDBY;
+ }
+ if ((blockingMatches & RESTRICTED_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
+ }
+ if ((blockingMatches & LOW_POWER_STANDBY_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_LOW_POWER_STANDBY;
+ }
+ if ((blockingMatches & BACKGROUND_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_APP_BACKGROUND;
+ }
+ if ((blockingMatches & (OEM_DENY_1_MATCH | OEM_DENY_2_MATCH | OEM_DENY_3_MATCH)) != 0) {
+ blockedReasons |= BLOCKED_REASON_OEM_DENY;
+ }
+
+ // Metered chains are not enabled by configuration map currently.
+ if ((uidMatch & PENALTY_BOX_USER_MATCH) != 0) {
+ blockedReasons |= BLOCKED_METERED_REASON_USER_RESTRICTED;
+ }
+ if ((uidMatch & PENALTY_BOX_ADMIN_MATCH) != 0) {
+ blockedReasons |= BLOCKED_METERED_REASON_ADMIN_DISABLED;
+ }
+ if ((uidMatch & HAPPY_BOX_MATCH) == 0 && getDataSaverEnabled(dataSaverEnabledMap)) {
+ blockedReasons |= BLOCKED_METERED_REASON_DATA_SAVER;
+ }
+
+ return blockedReasons;
+ }
+
+ /**
* Return whether the network is blocked by firewall chains for the given uid.
*
* Note that {@link #getDataSaverEnabled(IBpfMap)} has a latency before V.
@@ -263,27 +336,16 @@
return false;
}
- final long uidRuleConfig;
- final long uidMatch;
- try {
- uidRuleConfig = configurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val;
- final UidOwnerValue value = uidOwnerMap.getValue(new Struct.S32(uid));
- uidMatch = (value != null) ? value.rule : 0L;
- } catch (ErrnoException e) {
- throw new ServiceSpecificException(e.errno,
- "Unable to get firewall chain status: " + Os.strerror(e.errno));
+ final int blockedReasons = getUidNetworkingBlockedReasons(
+ uid,
+ configurationMap,
+ uidOwnerMap,
+ dataSaverEnabledMap);
+ if (isNetworkMetered) {
+ return blockedReasons != BLOCKED_REASON_NONE;
+ } else {
+ return (blockedReasons & ~BLOCKED_METERED_REASON_MASK) != BLOCKED_REASON_NONE;
}
-
- final boolean blockedByAllowChains = 0 != (uidRuleConfig & ~uidMatch & sMaskDropIfUnset);
- final boolean blockedByDenyChains = 0 != (uidRuleConfig & uidMatch & sMaskDropIfSet);
- if (blockedByAllowChains || blockedByDenyChains) {
- return true;
- }
-
- if (!isNetworkMetered) return false;
- if ((uidMatch & (PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH)) != 0) return true;
- if ((uidMatch & HAPPY_BOX_MATCH) != 0) return false;
- return getDataSaverEnabled(dataSaverEnabledMap);
}
/**
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 7823258..48ed732 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -130,6 +130,8 @@
"com.android.net.flags.basic_background_restrictions_enabled";
static final String METERED_NETWORK_FIREWALL_CHAINS =
"com.android.net.flags.metered_network_firewall_chains";
+ static final String BLOCKED_REASON_OEM_DENY_CHAINS =
+ "com.android.net.flags.blocked_reason_oem_deny_chains";
}
/**
@@ -913,6 +915,19 @@
public static final int BLOCKED_REASON_APP_BACKGROUND = 1 << 6;
/**
+ * Flag to indicate that an app is subject to OEM-specific application restrictions that would
+ * result in its network access being blocked.
+ *
+ * @see #FIREWALL_CHAIN_OEM_DENY_1
+ * @see #FIREWALL_CHAIN_OEM_DENY_2
+ * @see #FIREWALL_CHAIN_OEM_DENY_3
+ * @hide
+ */
+ @FlaggedApi(Flags.BLOCKED_REASON_OEM_DENY_CHAINS)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_OEM_DENY = 1 << 7;
+
+ /**
* Flag to indicate that an app is subject to Data saver restrictions that would
* result in its metered network access being blocked.
*
@@ -952,6 +967,7 @@
BLOCKED_REASON_LOCKDOWN_VPN,
BLOCKED_REASON_LOW_POWER_STANDBY,
BLOCKED_REASON_APP_BACKGROUND,
+ BLOCKED_REASON_OEM_DENY,
BLOCKED_METERED_REASON_DATA_SAVER,
BLOCKED_METERED_REASON_USER_RESTRICTED,
BLOCKED_METERED_REASON_ADMIN_DISABLED,
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 04d8ea4..2a4eafd 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -32,6 +32,8 @@
import static android.net.BpfNetMapsUtils.getMatchByFirewallChain;
import static android.net.BpfNetMapsUtils.isFirewallAllowList;
import static android.net.BpfNetMapsUtils.matchToString;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
import static android.net.INetd.PERMISSION_INTERNET;
@@ -863,6 +865,30 @@
}
}
+ /**
+ * Get blocked reasons for specified uid
+ *
+ * @param uid Target Uid
+ * @return Reasons of network access blocking for an UID
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public int getUidNetworkingBlockedReasons(final int uid) {
+ return BpfNetMapsUtils.getUidNetworkingBlockedReasons(uid,
+ sConfigurationMap, sUidOwnerMap, sDataSaverEnabledMap);
+ }
+
+ /**
+ * Return whether the network access of specified uid is blocked on metered networks
+ *
+ * @param uid The target uid.
+ * @return True if the network access is blocked on metered networks. Otherwise, false
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public boolean isUidRestrictedOnMeteredNetworks(final int uid) {
+ final int blockedReasons = getUidNetworkingBlockedReasons(uid);
+ return (blockedReasons & BLOCKED_METERED_REASON_MASK) != BLOCKED_REASON_NONE;
+ }
+
/** Register callback for statsd to pull atom. */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public void setPullAtomCallback(final Context context) {
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index b99d0de..5b68a24 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -7951,6 +7951,13 @@
// Policy already enforced.
return;
}
+ if (mDeps.isAtLeastV()) {
+ if (mBpfNetMaps.isUidRestrictedOnMeteredNetworks(uid)) {
+ // If UID is restricted, don't allow them to bring up metered APNs.
+ networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ }
+ return;
+ }
final long ident = Binder.clearCallingIdentity();
try {
if (mPolicyManager.isUidRestrictedOnMeteredNetworks(uid)) {
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index fa79795..62e55d5 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.net.BpfNetMapsConstants.ALLOW_CHAINS;
+import static android.net.BpfNetMapsConstants.BACKGROUND_MATCH;
import static android.net.BpfNetMapsConstants.CURRENT_STATS_MAP_CONFIGURATION_KEY;
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY;
import static android.net.BpfNetMapsConstants.DATA_SAVER_DISABLED;
@@ -37,6 +38,14 @@
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.BLOCKED_METERED_REASON_ADMIN_DISABLED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_OEM_DENY;
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_METERED_ALLOW;
@@ -1150,4 +1159,138 @@
assertDumpContains(dump, TEST_V6_ADDRESS.getHostAddress());
assertDumpContains(dump, TEST_IF_INDEX + "(" + TEST_IF_NAME + ")");
}
+
+ private void doTestGetUidNetworkingBlockedReasons(
+ final long configurationMatches,
+ final long uidRules,
+ final short dataSaverStatus,
+ final int expectedBlockedReasons
+ ) throws Exception {
+ mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(configurationMatches));
+ mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(NULL_IIF, uidRules));
+ mDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(dataSaverStatus));
+
+ assertEquals(expectedBlockedReasons, mBpfNetMaps.getUidNetworkingBlockedReasons(TEST_UID));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testGetUidNetworkingBlockedReasons() throws Exception {
+ doTestGetUidNetworkingBlockedReasons(
+ NO_MATCH,
+ NO_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_REASON_NONE
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ DOZABLE_MATCH,
+ NO_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_REASON_DOZE
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ DOZABLE_MATCH | POWERSAVE_MATCH | STANDBY_MATCH,
+ DOZABLE_MATCH | STANDBY_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_APP_STANDBY
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ OEM_DENY_1_MATCH | OEM_DENY_2_MATCH | OEM_DENY_3_MATCH,
+ OEM_DENY_1_MATCH | OEM_DENY_3_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_REASON_OEM_DENY
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ DOZABLE_MATCH,
+ DOZABLE_MATCH | BACKGROUND_MATCH | STANDBY_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_REASON_NONE
+ );
+
+ // Note that HAPPY_BOX and PENALTY_BOX are not disabled by configuration map
+ doTestGetUidNetworkingBlockedReasons(
+ NO_MATCH,
+ PENALTY_BOX_USER_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_METERED_REASON_USER_RESTRICTED
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ NO_MATCH,
+ PENALTY_BOX_ADMIN_MATCH,
+ DATA_SAVER_ENABLED,
+ BLOCKED_METERED_REASON_ADMIN_DISABLED | BLOCKED_METERED_REASON_DATA_SAVER
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ NO_MATCH,
+ PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH | HAPPY_BOX_MATCH,
+ DATA_SAVER_ENABLED,
+ BLOCKED_METERED_REASON_USER_RESTRICTED | BLOCKED_METERED_REASON_ADMIN_DISABLED
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ STANDBY_MATCH,
+ STANDBY_MATCH | PENALTY_BOX_USER_MATCH | HAPPY_BOX_MATCH,
+ DATA_SAVER_ENABLED,
+ BLOCKED_REASON_APP_STANDBY | BLOCKED_METERED_REASON_USER_RESTRICTED
+ );
+ }
+
+ private void doTestIsUidRestrictedOnMeteredNetworks(
+ final long enabledMatches,
+ final long uidRules,
+ final short dataSaver,
+ final boolean expectedRestricted
+ ) throws Exception {
+ mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(enabledMatches));
+ mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(NULL_IIF, uidRules));
+ mDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(dataSaver));
+
+ assertEquals(expectedRestricted, mBpfNetMaps.isUidRestrictedOnMeteredNetworks(TEST_UID));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testIsUidRestrictedOnMeteredNetworks() throws Exception {
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ NO_MATCH,
+ DATA_SAVER_DISABLED,
+ false /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ DOZABLE_MATCH | POWERSAVE_MATCH | STANDBY_MATCH,
+ DOZABLE_MATCH | STANDBY_MATCH ,
+ DATA_SAVER_DISABLED,
+ false /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ PENALTY_BOX_USER_MATCH,
+ DATA_SAVER_DISABLED,
+ true /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ PENALTY_BOX_ADMIN_MATCH,
+ DATA_SAVER_DISABLED,
+ true /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH | HAPPY_BOX_MATCH,
+ DATA_SAVER_DISABLED,
+ true /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ NO_MATCH,
+ DATA_SAVER_ENABLED,
+ true /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ HAPPY_BOX_MATCH,
+ DATA_SAVER_ENABLED,
+ false /* expectRestricted */
+ );
+ }
}