Add firewall chains for HAPPY_BOX and user/admin PENALTY_BOX
Follow up CLs will update CS to generate blocked reason from bpf map
instead of asking NPMS.
However, one issue is NPMS set PENALTY_BOX for
BLOCKED_METERED_REASON_USER_RESTRICTED and
BLOCKED_METERED_REASON_ADMIN_DISABLED without telling the reason.
So, CS can not know the reason of PENALTY_BOX.
This CL add new firewall chain and match to distinguish reasons.
NPMS must call setUidFirewallRule with
FIREWALL_CHAIN_METERED_DENY_USER or FIREWALL_CHAIN_METERED_DENY_ADMIN
based on the reason so that CS can know the reason of restriction.
Bug: 332628891
Test: atest com.android.cts.net.HostsideRestrictBackgroundNetworkTests
Change-Id: Ia4ad4bdb345abc22c782630e828edfad2452db36
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 026d8a9..b2aafa0 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -56,6 +56,9 @@
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
field public static final int FIREWALL_CHAIN_LOW_POWER_STANDBY = 5; // 0x5
+ field @FlaggedApi("com.android.net.flags.metered_network_firewall_chains") public static final int FIREWALL_CHAIN_METERED_ALLOW = 10; // 0xa
+ field @FlaggedApi("com.android.net.flags.metered_network_firewall_chains") public static final int FIREWALL_CHAIN_METERED_DENY_ADMIN = 12; // 0xc
+ field @FlaggedApi("com.android.net.flags.metered_network_firewall_chains") public static final int FIREWALL_CHAIN_METERED_DENY_USER = 11; // 0xb
field public static final int FIREWALL_CHAIN_OEM_DENY_1 = 7; // 0x7
field public static final int FIREWALL_CHAIN_OEM_DENY_2 = 8; // 0x8
field public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9; // 0x9
diff --git a/framework/src/android/net/BpfNetMapsConstants.java b/framework/src/android/net/BpfNetMapsConstants.java
index 5d0fe73..f3773de 100644
--- a/framework/src/android/net/BpfNetMapsConstants.java
+++ b/framework/src/android/net/BpfNetMapsConstants.java
@@ -19,6 +19,9 @@
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;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
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;
@@ -67,7 +70,7 @@
// 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 PENALTY_BOX_USER_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);
@@ -79,10 +82,11 @@
public static final long OEM_DENY_2_MATCH = (1 << 10);
public static final long OEM_DENY_3_MATCH = (1 << 11);
public static final long BACKGROUND_MATCH = (1 << 12);
+ public static final long PENALTY_BOX_ADMIN_MATCH = (1 << 13);
public static final List<Pair<Long, String>> MATCH_LIST = Arrays.asList(
Pair.create(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"),
- Pair.create(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"),
+ Pair.create(PENALTY_BOX_USER_MATCH, "PENALTY_BOX_USER_MATCH"),
Pair.create(DOZABLE_MATCH, "DOZABLE_MATCH"),
Pair.create(STANDBY_MATCH, "STANDBY_MATCH"),
Pair.create(POWERSAVE_MATCH, "POWERSAVE_MATCH"),
@@ -93,11 +97,13 @@
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"),
- Pair.create(BACKGROUND_MATCH, "BACKGROUND_MATCH")
+ Pair.create(BACKGROUND_MATCH, "BACKGROUND_MATCH"),
+ Pair.create(PENALTY_BOX_ADMIN_MATCH, "PENALTY_BOX_ADMIN_MATCH")
);
/**
- * List of all firewall allow chains.
+ * List of all firewall allow chains that are applied to all networks regardless of meteredness
+ * See {@link #METERED_ALLOW_CHAINS} for allow chains that are only applied to metered networks.
*
* Allow chains mean the firewall denies all uids by default, uids must be explicitly allowed.
*/
@@ -110,7 +116,8 @@
);
/**
- * List of all firewall deny chains.
+ * List of all firewall deny chains that are applied to all networks regardless of meteredness
+ * See {@link #METERED_DENY_CHAINS} for deny chains that are only applied to metered networks.
*
* Deny chains mean the firewall allows all uids by default, uids must be explicitly denied.
*/
@@ -120,5 +127,24 @@
FIREWALL_CHAIN_OEM_DENY_2,
FIREWALL_CHAIN_OEM_DENY_3
);
+
+ /**
+ * List of all firewall allow chains that are only applied to metered networks.
+ * See {@link #ALLOW_CHAINS} for allow chains that are applied to all networks regardless of
+ * meteredness.
+ */
+ public static final List<Integer> METERED_ALLOW_CHAINS = List.of(
+ FIREWALL_CHAIN_METERED_ALLOW
+ );
+
+ /**
+ * List of all firewall deny chains that are only applied to metered networks.
+ * See {@link #DENY_CHAINS} for deny chains that are applied to all networks regardless of
+ * meteredness.
+ */
+ public static final List<Integer> METERED_DENY_CHAINS = List.of(
+ FIREWALL_CHAIN_METERED_DENY_USER,
+ FIREWALL_CHAIN_METERED_DENY_ADMIN
+ );
// LINT.ThenChange(../../../../bpf_progs/netd.h)
}
diff --git a/framework/src/android/net/BpfNetMapsUtils.java b/framework/src/android/net/BpfNetMapsUtils.java
index 19ecafb..9cbf147 100644
--- a/framework/src/android/net/BpfNetMapsUtils.java
+++ b/framework/src/android/net/BpfNetMapsUtils.java
@@ -25,11 +25,14 @@
import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.LOW_POWER_STANDBY_MATCH;
import static android.net.BpfNetMapsConstants.MATCH_LIST;
+import static android.net.BpfNetMapsConstants.METERED_ALLOW_CHAINS;
+import static android.net.BpfNetMapsConstants.METERED_DENY_CHAINS;
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.PENALTY_BOX_ADMIN_MATCH;
+import static android.net.BpfNetMapsConstants.PENALTY_BOX_USER_MATCH;
import static android.net.BpfNetMapsConstants.POWERSAVE_MATCH;
import static android.net.BpfNetMapsConstants.RESTRICTED_MATCH;
import static android.net.BpfNetMapsConstants.STANDBY_MATCH;
@@ -37,6 +40,9 @@
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;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
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;
@@ -117,6 +123,12 @@
return OEM_DENY_2_MATCH;
case FIREWALL_CHAIN_OEM_DENY_3:
return OEM_DENY_3_MATCH;
+ case FIREWALL_CHAIN_METERED_ALLOW:
+ return HAPPY_BOX_MATCH;
+ case FIREWALL_CHAIN_METERED_DENY_USER:
+ return PENALTY_BOX_USER_MATCH;
+ case FIREWALL_CHAIN_METERED_DENY_ADMIN:
+ return PENALTY_BOX_ADMIN_MATCH;
default:
throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
}
@@ -129,9 +141,9 @@
* DENYLIST means the firewall allows all by default, uids must be explicitly denied
*/
public static boolean isFirewallAllowList(final int chain) {
- if (ALLOW_CHAINS.contains(chain)) {
+ if (ALLOW_CHAINS.contains(chain) || METERED_ALLOW_CHAINS.contains(chain)) {
return true;
- } else if (DENY_CHAINS.contains(chain)) {
+ } else if (DENY_CHAINS.contains(chain) || METERED_DENY_CHAINS.contains(chain)) {
return false;
}
throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
@@ -264,7 +276,7 @@
}
if (!isNetworkMetered) return false;
- if ((uidMatch & PENALTY_BOX_MATCH) != 0) return true;
+ 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 b1e636d..7823258 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -128,6 +128,8 @@
"com.android.net.flags.support_is_uid_networking_blocked";
static final String BASIC_BACKGROUND_RESTRICTIONS_ENABLED =
"com.android.net.flags.basic_background_restrictions_enabled";
+ static final String METERED_NETWORK_FIREWALL_CHAINS =
+ "com.android.net.flags.metered_network_firewall_chains";
}
/**
@@ -1068,6 +1070,61 @@
@SystemApi(client = MODULE_LIBRARIES)
public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9;
+ /**
+ * Firewall chain for allow list on metered networks
+ *
+ * UIDs added to this chain have access to metered networks, unless they're also in one of the
+ * denylist, {@link #FIREWALL_CHAIN_METERED_DENY_USER},
+ * {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN}
+ *
+ * Note that this chain is used from a separate bpf program that is triggered by iptables and
+ * can not be controlled by {@link ConnectivityManager#setFirewallChainEnabled}.
+ *
+ * @hide
+ */
+ // TODO: Merge this chain with data saver and support setFirewallChainEnabled
+ @FlaggedApi(Flags.METERED_NETWORK_FIREWALL_CHAINS)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int FIREWALL_CHAIN_METERED_ALLOW = 10;
+
+ /**
+ * Firewall chain for user-set restrictions on metered networks
+ *
+ * UIDs added to this chain do not have access to metered networks.
+ * UIDs should be added to this chain based on user settings.
+ * To restrict metered network based on admin configuration (e.g. enterprise policies),
+ * {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN} should be used.
+ * This chain corresponds to {@link #BLOCKED_METERED_REASON_USER_RESTRICTED}
+ *
+ * Note that this chain is used from a separate bpf program that is triggered by iptables and
+ * can not be controlled by {@link ConnectivityManager#setFirewallChainEnabled}.
+ *
+ * @hide
+ */
+ // TODO: Support setFirewallChainEnabled to control this chain
+ @FlaggedApi(Flags.METERED_NETWORK_FIREWALL_CHAINS)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int FIREWALL_CHAIN_METERED_DENY_USER = 11;
+
+ /**
+ * Firewall chain for admin-set restrictions on metered networks
+ *
+ * UIDs added to this chain do not have access to metered networks.
+ * UIDs should be added to this chain based on admin configuration (e.g. enterprise policies).
+ * To restrict metered network based on user settings, {@link #FIREWALL_CHAIN_METERED_DENY_USER}
+ * should be used.
+ * This chain corresponds to {@link #BLOCKED_METERED_REASON_ADMIN_DISABLED}
+ *
+ * Note that this chain is used from a separate bpf program that is triggered by iptables and
+ * can not be controlled by {@link ConnectivityManager#setFirewallChainEnabled}.
+ *
+ * @hide
+ */
+ // TODO: Support setFirewallChainEnabled to control this chain
+ @FlaggedApi(Flags.METERED_NETWORK_FIREWALL_CHAINS)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int FIREWALL_CHAIN_METERED_DENY_ADMIN = 12;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = false, prefix = "FIREWALL_CHAIN_", value = {
@@ -1079,7 +1136,10 @@
FIREWALL_CHAIN_BACKGROUND,
FIREWALL_CHAIN_OEM_DENY_1,
FIREWALL_CHAIN_OEM_DENY_2,
- FIREWALL_CHAIN_OEM_DENY_3
+ FIREWALL_CHAIN_OEM_DENY_3,
+ FIREWALL_CHAIN_METERED_ALLOW,
+ FIREWALL_CHAIN_METERED_DENY_USER,
+ FIREWALL_CHAIN_METERED_DENY_ADMIN
})
public @interface FirewallChain {}
@@ -6065,7 +6125,7 @@
})
public void addUidToMeteredNetworkAllowList(final int uid) {
try {
- mService.updateMeteredNetworkAllowList(uid, true /* add */);
+ mService.setUidFirewallRule(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_ALLOW);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6088,7 +6148,7 @@
})
public void removeUidFromMeteredNetworkAllowList(final int uid) {
try {
- mService.updateMeteredNetworkAllowList(uid, false /* remove */);
+ mService.setUidFirewallRule(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_DENY);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6098,10 +6158,17 @@
* Adds the specified UID to the list of UIDs that are not allowed to use background data on
* metered networks. Takes precedence over {@link #addUidToMeteredNetworkAllowList}.
*
+ * On V+, {@link #setUidFirewallRule} should be used with
+ * {@link #FIREWALL_CHAIN_METERED_DENY_USER} or {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN}
+ * based on the reason so that users can receive {@link #BLOCKED_METERED_REASON_USER_RESTRICTED}
+ * or {@link #BLOCKED_METERED_REASON_ADMIN_DISABLED}, respectively.
+ * This API always uses {@link #FIREWALL_CHAIN_METERED_DENY_USER}.
+ *
* @param uid uid of target app
* @throws IllegalStateException if updating deny list failed.
* @hide
*/
+ // TODO(b/332649177): Deprecate this API after V
@SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_SETTINGS,
@@ -6110,7 +6177,7 @@
})
public void addUidToMeteredNetworkDenyList(final int uid) {
try {
- mService.updateMeteredNetworkDenyList(uid, true /* add */);
+ mService.setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_DENY);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6121,10 +6188,17 @@
* networks if background data is not restricted. The deny list takes precedence over the
* allow list.
*
+ * On V+, {@link #setUidFirewallRule} should be used with
+ * {@link #FIREWALL_CHAIN_METERED_DENY_USER} or {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN}
+ * based on the reason so that users can receive {@link #BLOCKED_METERED_REASON_USER_RESTRICTED}
+ * or {@link #BLOCKED_METERED_REASON_ADMIN_DISABLED}, respectively.
+ * This API always uses {@link #FIREWALL_CHAIN_METERED_DENY_USER}.
+ *
* @param uid uid of target app
* @throws IllegalStateException if updating deny list failed.
* @hide
*/
+ // TODO(b/332649177): Deprecate this API after V
@SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_SETTINGS,
@@ -6133,7 +6207,7 @@
})
public void removeUidFromMeteredNetworkDenyList(final int uid) {
try {
- mService.updateMeteredNetworkDenyList(uid, false /* remove */);
+ mService.setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_ALLOW);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6191,6 +6265,10 @@
/**
* Enables or disables the specified firewall chain.
*
+ * Note that metered firewall chains can not be controlled by this API.
+ * See {@link #FIREWALL_CHAIN_METERED_ALLOW}, {@link #FIREWALL_CHAIN_METERED_DENY_USER}, and
+ * {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN} for more detail.
+ *
* @param chain target chain.
* @param enable whether the chain should be enabled.
* @throws UnsupportedOperationException if called on pre-T devices.
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index d3a02b9..55c7085 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -242,10 +242,6 @@
void setDataSaverEnabled(boolean enable);
- void updateMeteredNetworkAllowList(int uid, boolean add);
-
- void updateMeteredNetworkDenyList(int uid, boolean add);
-
void setUidFirewallRule(int chain, int uid, int rule);
int getUidFirewallRule(int chain, int uid);