diff --git a/DnsResolver/DnsBpfHelper.cpp b/DnsResolver/DnsBpfHelper.cpp index de8bef5860..0719ade395 100644 --- a/DnsResolver/DnsBpfHelper.cpp +++ b/DnsResolver/DnsBpfHelper.cpp @@ -69,9 +69,10 @@ base::Result DnsBpfHelper::isUidNetworkingBlocked(uid_t uid, bool metered) // state, making it a trustworthy source. Since this library primarily serves DNS resolvers, // relying solely on V+ data prevents erroneous blocking of DNS queries. if (android::modules::sdklevel::IsAtLeastV() && metered) { - // The background data setting (PENALTY_BOX_MATCH) and unrestricted data usage setting - // (HAPPY_BOX_MATCH) for individual apps override the system wide Data Saver setting. - if (uidRules & PENALTY_BOX_MATCH) return true; + // The background data setting (PENALTY_BOX_USER_MATCH, PENALTY_BOX_ADMIN_MATCH) and + // unrestricted data usage setting (HAPPY_BOX_MATCH) for individual apps override the system + // wide Data Saver setting. + if (uidRules & (PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH)) return true; if (uidRules & HAPPY_BOX_MATCH) return false; auto dataSaverSetting = mDataSaverEnabledMap.readValue(DATA_SAVER_ENABLED_KEY); diff --git a/DnsResolver/DnsBpfHelperTest.cpp b/DnsResolver/DnsBpfHelperTest.cpp index 67b5b956c5..18a5df4bf4 100644 --- a/DnsResolver/DnsBpfHelperTest.cpp +++ b/DnsResolver/DnsBpfHelperTest.cpp @@ -158,23 +158,33 @@ TEST_F(DnsBpfHelperTest, IsUidNetworkingBlocked_metered) { } } testConfigs[]{ // clang-format off - // enabledRules, dataSaverEnabled, uidRules, blocked - {NO_MATCH, false, NO_MATCH, false}, - {NO_MATCH, false, PENALTY_BOX_MATCH, true}, - {NO_MATCH, false, HAPPY_BOX_MATCH, false}, - {NO_MATCH, false, PENALTY_BOX_MATCH|HAPPY_BOX_MATCH, true}, - {NO_MATCH, true, NO_MATCH, true}, - {NO_MATCH, true, PENALTY_BOX_MATCH, true}, - {NO_MATCH, true, HAPPY_BOX_MATCH, false}, - {NO_MATCH, true, PENALTY_BOX_MATCH|HAPPY_BOX_MATCH, true}, - {STANDBY_MATCH, false, STANDBY_MATCH, true}, - {STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_MATCH, true}, - {STANDBY_MATCH, false, STANDBY_MATCH|HAPPY_BOX_MATCH, true}, - {STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_MATCH|HAPPY_BOX_MATCH, true}, - {STANDBY_MATCH, true, STANDBY_MATCH, true}, - {STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_MATCH, true}, - {STANDBY_MATCH, true, STANDBY_MATCH|HAPPY_BOX_MATCH, true}, - {STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_MATCH|HAPPY_BOX_MATCH, true}, + // enabledRules, dataSaverEnabled, uidRules, blocked + {NO_MATCH, false, NO_MATCH, false}, + {NO_MATCH, false, PENALTY_BOX_USER_MATCH, true}, + {NO_MATCH, false, PENALTY_BOX_ADMIN_MATCH, true}, + {NO_MATCH, false, PENALTY_BOX_USER_MATCH|PENALTY_BOX_ADMIN_MATCH, true}, + {NO_MATCH, false, HAPPY_BOX_MATCH, false}, + {NO_MATCH, false, PENALTY_BOX_USER_MATCH|HAPPY_BOX_MATCH, true}, + {NO_MATCH, false, PENALTY_BOX_ADMIN_MATCH|HAPPY_BOX_MATCH, true}, + {NO_MATCH, true, NO_MATCH, true}, + {NO_MATCH, true, PENALTY_BOX_USER_MATCH, true}, + {NO_MATCH, true, PENALTY_BOX_ADMIN_MATCH, true}, + {NO_MATCH, true, PENALTY_BOX_USER_MATCH|PENALTY_BOX_ADMIN_MATCH, true}, + {NO_MATCH, true, HAPPY_BOX_MATCH, false}, + {NO_MATCH, true, PENALTY_BOX_USER_MATCH|HAPPY_BOX_MATCH, true}, + {NO_MATCH, true, PENALTY_BOX_ADMIN_MATCH|HAPPY_BOX_MATCH, true}, + {STANDBY_MATCH, false, STANDBY_MATCH, true}, + {STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_USER_MATCH, true}, + {STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_ADMIN_MATCH, true}, + {STANDBY_MATCH, false, STANDBY_MATCH|HAPPY_BOX_MATCH, true}, + {STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_USER_MATCH|HAPPY_BOX_MATCH, true}, + {STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_ADMIN_MATCH|HAPPY_BOX_MATCH, true}, + {STANDBY_MATCH, true, STANDBY_MATCH, true}, + {STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_USER_MATCH, true}, + {STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_ADMIN_MATCH, true}, + {STANDBY_MATCH, true, STANDBY_MATCH|HAPPY_BOX_MATCH, true}, + {STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_USER_MATCH|HAPPY_BOX_MATCH, true}, + {STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_ADMIN_MATCH|HAPPY_BOX_MATCH, true}, // clang-format on }; diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c index dfc769917a..2aff89c58c 100644 --- a/bpf_progs/netd.c +++ b/bpf_progs/netd.c @@ -644,7 +644,8 @@ DEFINE_XTBPF_PROG("skfilter/denylist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_den (struct __sk_buff* skb) { uint32_t sock_uid = bpf_get_socket_uid(skb); UidOwnerValue* denylistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid); - if (denylistMatch) return denylistMatch->rule & PENALTY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH; + uint32_t penalty_box = PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH; + if (denylistMatch) return denylistMatch->rule & penalty_box ? BPF_MATCH : BPF_NOMATCH; return BPF_NOMATCH; } diff --git a/bpf_progs/netd.h b/bpf_progs/netd.h index 098147f8f4..8a56b4a288 100644 --- a/bpf_progs/netd.h +++ b/bpf_progs/netd.h @@ -181,7 +181,7 @@ ASSERT_STRING_EQUAL(XT_BPF_DENYLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilte enum UidOwnerMatchType : uint32_t { NO_MATCH = 0, HAPPY_BOX_MATCH = (1 << 0), - PENALTY_BOX_MATCH = (1 << 1), + PENALTY_BOX_USER_MATCH = (1 << 1), DOZABLE_MATCH = (1 << 2), STANDBY_MATCH = (1 << 3), POWERSAVE_MATCH = (1 << 4), @@ -192,7 +192,8 @@ enum UidOwnerMatchType : uint32_t { OEM_DENY_1_MATCH = (1 << 9), OEM_DENY_2_MATCH = (1 << 10), OEM_DENY_3_MATCH = (1 << 11), - BACKGROUND_MATCH = (1 << 12) + BACKGROUND_MATCH = (1 << 12), + PENALTY_BOX_ADMIN_MATCH = (1 << 13), }; // LINT.ThenChange(../framework/src/android/net/BpfNetMapsConstants.java) diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt index 026d8a951c..b2aafa0e14 100644 --- a/framework/api/module-lib-current.txt +++ b/framework/api/module-lib-current.txt @@ -56,6 +56,9 @@ package android.net { 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 5d0fe73ca4..f3773de668 100644 --- a/framework/src/android/net/BpfNetMapsConstants.java +++ b/framework/src/android/net/BpfNetMapsConstants.java @@ -19,6 +19,9 @@ package android.net; 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 @@ public class BpfNetMapsConstants { // 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 class BpfNetMapsConstants { 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> 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 @@ public class BpfNetMapsConstants { 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 @@ public class BpfNetMapsConstants { ); /** - * 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 @@ public class BpfNetMapsConstants { 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 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 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 19ecafb15a..9cbf1478ef 100644 --- a/framework/src/android/net/BpfNetMapsUtils.java +++ b/framework/src/android/net/BpfNetMapsUtils.java @@ -25,11 +25,14 @@ import static android.net.BpfNetMapsConstants.DOZABLE_MATCH; 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.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY; 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 @@ public class BpfNetMapsUtils { 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 @@ public class BpfNetMapsUtils { * 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 @@ public class BpfNetMapsUtils { } 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 b1e636d0ad..782325809c 100644 --- a/framework/src/android/net/ConnectivityManager.java +++ b/framework/src/android/net/ConnectivityManager.java @@ -128,6 +128,8 @@ public class ConnectivityManager { "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 @@ public class ConnectivityManager { @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 @@ public class ConnectivityManager { 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 class ConnectivityManager { }) 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 class ConnectivityManager { }) 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 @@ public class ConnectivityManager { * 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 class ConnectivityManager { }) 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 @@ public class ConnectivityManager { * 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 class ConnectivityManager { }) 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 @@ public class ConnectivityManager { /** * 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 d3a02b9652..55c70856c7 100644 --- a/framework/src/android/net/IConnectivityManager.aidl +++ b/framework/src/android/net/IConnectivityManager.aidl @@ -242,10 +242,6 @@ interface IConnectivityManager 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); diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java index fc6d8c47bb..01bd71ec5b 100644 --- a/service/src/com/android/server/BpfNetMaps.java +++ b/service/src/com/android/server/BpfNetMaps.java @@ -23,11 +23,9 @@ import static android.net.BpfNetMapsConstants.DATA_SAVER_DISABLED; import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED; import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY; import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_MAP_PATH; -import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH; import static android.net.BpfNetMapsConstants.IIF_MATCH; import static android.net.BpfNetMapsConstants.INGRESS_DISCARD_MAP_PATH; 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; @@ -445,62 +443,6 @@ public class BpfNetMaps { addRule(uid, match, 0 /* iif */, caller); } - /** - * Add naughty app bandwidth rule for specific app - * - * @param uid uid of target app - * @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"); - - addRule(uid, PENALTY_BOX_MATCH, "addNaughtyApp"); - } - - /** - * Remove naughty app bandwidth rule for specific app - * - * @param uid uid of target app - * @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"); - - removeRule(uid, PENALTY_BOX_MATCH, "removeNaughtyApp"); - } - - /** - * Add nice app bandwidth rule for specific app - * - * @param uid uid of target app - * @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"); - - addRule(uid, HAPPY_BOX_MATCH, "addNiceApp"); - } - - /** - * Remove nice app bandwidth rule for specific app - * - * @param uid uid of target app - * @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"); - - removeRule(uid, HAPPY_BOX_MATCH, "removeNiceApp"); - } - /** * Set target firewall child chain * diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index a15a2bf412..0ea3366456 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -24,6 +24,8 @@ import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.FEATURE_WIFI; import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.BpfNetMapsConstants.METERED_ALLOW_CHAINS; +import static android.net.BpfNetMapsConstants.METERED_DENY_CHAINS; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT; @@ -13474,36 +13476,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - @Override - public void updateMeteredNetworkAllowList(final int uid, final boolean add) { - enforceNetworkStackOrSettingsPermission(); - - try { - if (add) { - mBpfNetMaps.addNiceApp(uid); - } else { - mBpfNetMaps.removeNiceApp(uid); - } - } catch (ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void updateMeteredNetworkDenyList(final int uid, final boolean add) { - enforceNetworkStackOrSettingsPermission(); - - try { - if (add) { - mBpfNetMaps.addNaughtyApp(uid); - } else { - mBpfNetMaps.removeNaughtyApp(uid); - } - } catch (ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - private int setPackageFirewallRule(final int chain, final String packageName, final int rule) throws PackageManager.NameNotFoundException { final PackageManager pm = mContext.getPackageManager(); @@ -13563,6 +13535,8 @@ public class ConnectivityService extends IConnectivityManager.Stub case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1: case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2: case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3: + case ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER: + case ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN: defaultRule = FIREWALL_RULE_ALLOW; break; case ConnectivityManager.FIREWALL_CHAIN_DOZABLE: @@ -13570,6 +13544,7 @@ public class ConnectivityService extends IConnectivityManager.Stub case ConnectivityManager.FIREWALL_CHAIN_RESTRICTED: case ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY: case ConnectivityManager.FIREWALL_CHAIN_BACKGROUND: + case ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW: defaultRule = FIREWALL_RULE_DENY; break; default: @@ -13606,6 +13581,12 @@ public class ConnectivityService extends IConnectivityManager.Stub + " the feature is disabled."); return; } + if (METERED_ALLOW_CHAINS.contains(chain) || METERED_DENY_CHAINS.contains(chain)) { + // Metered chains are used from a separate bpf program that is triggered by iptables + // and can not be controlled by setFirewallChainEnabled. + throw new UnsupportedOperationException( + "Chain (" + chain + ") can not be controlled by setFirewallChainEnabled"); + } try { mBpfNetMaps.setChildChain(chain, enable); @@ -13626,6 +13607,13 @@ public class ConnectivityService extends IConnectivityManager.Stub public boolean getFirewallChainEnabled(final int chain) { enforceNetworkStackOrSettingsPermission(); + if (METERED_ALLOW_CHAINS.contains(chain) || METERED_DENY_CHAINS.contains(chain)) { + // Metered chains are used from a separate bpf program that is triggered by iptables + // and can not be controlled by setFirewallChainEnabled. + throw new UnsupportedOperationException( + "getFirewallChainEnabled can not return status of chain (" + chain + ")"); + } + return mBpfNetMaps.isChainEnabled(chain); } diff --git a/tests/unit/java/android/net/NetworkStackBpfNetMapsTest.kt b/tests/unit/java/android/net/NetworkStackBpfNetMapsTest.kt index a9ccbddc0e..b5d78f33df 100644 --- a/tests/unit/java/android/net/NetworkStackBpfNetMapsTest.kt +++ b/tests/unit/java/android/net/NetworkStackBpfNetMapsTest.kt @@ -21,7 +21,8 @@ import android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED import android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY import android.net.BpfNetMapsConstants.DOZABLE_MATCH import android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH -import android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH +import android.net.BpfNetMapsConstants.PENALTY_BOX_ADMIN_MATCH +import android.net.BpfNetMapsConstants.PENALTY_BOX_USER_MATCH import android.net.BpfNetMapsConstants.STANDBY_MATCH import android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY import android.net.BpfNetMapsUtils.getMatchByFirewallChain @@ -48,9 +49,9 @@ private const val TEST_UID2 = TEST_UID1 + 1 private const val TEST_UID3 = TEST_UID2 + 1 private const val NO_IIF = 0 -// pre-T devices does not support Bpf. +// NetworkStack can not use this before U due to b/326143935 @RunWith(DevSdkIgnoreRunner::class) -@IgnoreUpTo(VERSION_CODES.S_V2) +@IgnoreUpTo(VERSION_CODES.TIRAMISU) class NetworkStackBpfNetMapsTest { @Rule @JvmField @@ -102,14 +103,18 @@ class NetworkStackBpfNetMapsTest { } // Verify the size matches, this also verifies no common item in allow and deny chains. assertEquals( - BpfNetMapsConstants.ALLOW_CHAINS.size + - BpfNetMapsConstants.DENY_CHAINS.size, + BpfNetMapsConstants.ALLOW_CHAINS.size + + BpfNetMapsConstants.DENY_CHAINS.size + + BpfNetMapsConstants.METERED_ALLOW_CHAINS.size + + BpfNetMapsConstants.METERED_DENY_CHAINS.size, declaredChains.size ) declaredChains.forEach { assertTrue( - BpfNetMapsConstants.ALLOW_CHAINS.contains(it.get(null)) || - BpfNetMapsConstants.DENY_CHAINS.contains(it.get(null)) + BpfNetMapsConstants.ALLOW_CHAINS.contains(it.get(null)) || + BpfNetMapsConstants.METERED_ALLOW_CHAINS.contains(it.get(null)) || + BpfNetMapsConstants.DENY_CHAINS.contains(it.get(null)) || + BpfNetMapsConstants.METERED_DENY_CHAINS.contains(it.get(null)) ) } } @@ -190,7 +195,16 @@ class NetworkStackBpfNetMapsTest { // Add uid1 to penalty box, verify the network is blocked for uid1, while uid2 is not // affected. - testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, PENALTY_BOX_MATCH)) + testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, PENALTY_BOX_USER_MATCH)) + assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true)) + assertFalse(isUidNetworkingBlocked(TEST_UID2, metered = true)) + testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, PENALTY_BOX_ADMIN_MATCH)) + assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true)) + assertFalse(isUidNetworkingBlocked(TEST_UID2, metered = true)) + testUidOwnerMap.updateEntry( + S32(TEST_UID1), + UidOwnerValue(NO_IIF, PENALTY_BOX_USER_MATCH or PENALTY_BOX_ADMIN_MATCH) + ) assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true)) assertFalse(isUidNetworkingBlocked(TEST_UID2, metered = true)) @@ -206,7 +220,14 @@ class NetworkStackBpfNetMapsTest { // priority. testUidOwnerMap.updateEntry( S32(TEST_UID1), - UidOwnerValue(NO_IIF, PENALTY_BOX_MATCH or HAPPY_BOX_MATCH) + UidOwnerValue(NO_IIF, PENALTY_BOX_USER_MATCH or HAPPY_BOX_MATCH) + ) + assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true)) + assertTrue(isUidNetworkingBlocked(TEST_UID2, metered = true)) + assertFalse(isUidNetworkingBlocked(TEST_UID3, metered = true)) + testUidOwnerMap.updateEntry( + S32(TEST_UID1), + UidOwnerValue(NO_IIF, PENALTY_BOX_ADMIN_MATCH or HAPPY_BOX_MATCH) ) assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true)) assertTrue(isUidNetworkingBlocked(TEST_UID2, metered = true)) @@ -240,7 +261,7 @@ class NetworkStackBpfNetMapsTest { for (uid in FIRST_APPLICATION_UID - 5..FIRST_APPLICATION_UID + 5) { // system uid is not blocked regardless of firewall chains val expectBlocked = uid >= FIRST_APPLICATION_UID - testUidOwnerMap.updateEntry(S32(uid), UidOwnerValue(NO_IIF, PENALTY_BOX_MATCH)) + testUidOwnerMap.updateEntry(S32(uid), UidOwnerValue(NO_IIF, PENALTY_BOX_USER_MATCH)) assertEquals( expectBlocked, isUidNetworkingBlocked(uid, metered = true), diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java index ea905d5828..fa79795105 100644 --- a/tests/unit/java/com/android/server/BpfNetMapsTest.java +++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java @@ -31,13 +31,17 @@ 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; 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_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; @@ -334,146 +338,6 @@ public final class BpfNetMapsTest { } } - private void doTestRemoveNaughtyApp(final int iif, final long match) throws Exception { - mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match)); - - mBpfNetMaps.removeNaughtyApp(TEST_UID); - - checkUidOwnerValue(TEST_UID, iif, match & ~PENALTY_BOX_MATCH); - } - - @Test - @IgnoreUpTo(Build.VERSION_CODES.S_V2) - public void testRemoveNaughtyApp() throws Exception { - doTestRemoveNaughtyApp(NO_IIF, PENALTY_BOX_MATCH); - - // PENALTY_BOX_MATCH with other matches - doTestRemoveNaughtyApp(NO_IIF, PENALTY_BOX_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH); - - // PENALTY_BOX_MATCH with IIF_MATCH - doTestRemoveNaughtyApp(TEST_IF_INDEX, PENALTY_BOX_MATCH | IIF_MATCH); - - // PENALTY_BOX_MATCH is not enabled - doTestRemoveNaughtyApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH); - } - - @Test - @IgnoreUpTo(Build.VERSION_CODES.S_V2) - public void testRemoveNaughtyAppMissingUid() { - // UidOwnerMap does not have entry for TEST_UID - assertThrows(ServiceSpecificException.class, - () -> mBpfNetMaps.removeNaughtyApp(TEST_UID)); - } - - @Test - @IgnoreAfter(Build.VERSION_CODES.S_V2) - public void testRemoveNaughtyAppBeforeT() { - assertThrows(UnsupportedOperationException.class, - () -> mBpfNetMaps.removeNaughtyApp(TEST_UID)); - } - - private void doTestAddNaughtyApp(final int iif, final long match) throws Exception { - if (match != NO_MATCH) { - mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match)); - } - - mBpfNetMaps.addNaughtyApp(TEST_UID); - - checkUidOwnerValue(TEST_UID, iif, match | PENALTY_BOX_MATCH); - } - - @Test - @IgnoreUpTo(Build.VERSION_CODES.S_V2) - public void testAddNaughtyApp() throws Exception { - doTestAddNaughtyApp(NO_IIF, NO_MATCH); - - // Other matches are enabled - doTestAddNaughtyApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH); - - // IIF_MATCH is enabled - doTestAddNaughtyApp(TEST_IF_INDEX, IIF_MATCH); - - // PENALTY_BOX_MATCH is already enabled - doTestAddNaughtyApp(NO_IIF, PENALTY_BOX_MATCH | DOZABLE_MATCH); - } - - @Test - @IgnoreAfter(Build.VERSION_CODES.S_V2) - public void testAddNaughtyAppBeforeT() { - assertThrows(UnsupportedOperationException.class, - () -> mBpfNetMaps.addNaughtyApp(TEST_UID)); - } - - private void doTestRemoveNiceApp(final int iif, final long match) throws Exception { - mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match)); - - mBpfNetMaps.removeNiceApp(TEST_UID); - - checkUidOwnerValue(TEST_UID, iif, match & ~HAPPY_BOX_MATCH); - } - - @Test - @IgnoreUpTo(Build.VERSION_CODES.S_V2) - public void testRemoveNiceApp() throws Exception { - doTestRemoveNiceApp(NO_IIF, HAPPY_BOX_MATCH); - - // HAPPY_BOX_MATCH with other matches - doTestRemoveNiceApp(NO_IIF, HAPPY_BOX_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH); - - // HAPPY_BOX_MATCH with IIF_MATCH - doTestRemoveNiceApp(TEST_IF_INDEX, HAPPY_BOX_MATCH | IIF_MATCH); - - // HAPPY_BOX_MATCH is not enabled - doTestRemoveNiceApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH); - } - - @Test - @IgnoreUpTo(Build.VERSION_CODES.S_V2) - public void testRemoveNiceAppMissingUid() { - // UidOwnerMap does not have entry for TEST_UID - assertThrows(ServiceSpecificException.class, - () -> mBpfNetMaps.removeNiceApp(TEST_UID)); - } - - @Test - @IgnoreAfter(Build.VERSION_CODES.S_V2) - public void testRemoveNiceAppBeforeT() { - assertThrows(UnsupportedOperationException.class, - () -> mBpfNetMaps.removeNiceApp(TEST_UID)); - } - - private void doTestAddNiceApp(final int iif, final long match) throws Exception { - if (match != NO_MATCH) { - mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match)); - } - - mBpfNetMaps.addNiceApp(TEST_UID); - - checkUidOwnerValue(TEST_UID, iif, match | HAPPY_BOX_MATCH); - } - - @Test - @IgnoreUpTo(Build.VERSION_CODES.S_V2) - public void testAddNiceApp() throws Exception { - doTestAddNiceApp(NO_IIF, NO_MATCH); - - // Other matches are enabled - doTestAddNiceApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH); - - // IIF_MATCH is enabled - doTestAddNiceApp(TEST_IF_INDEX, IIF_MATCH); - - // HAPPY_BOX_MATCH is already enabled - doTestAddNiceApp(NO_IIF, HAPPY_BOX_MATCH | DOZABLE_MATCH); - } - - @Test - @IgnoreAfter(Build.VERSION_CODES.S_V2) - public void testAddNiceAppBeforeT() { - assertThrows(UnsupportedOperationException.class, - () -> mBpfNetMaps.addNiceApp(TEST_UID)); - } - private void doTestUpdateUidLockdownRule(final int iif, final long match, final boolean add) throws Exception { if (match != NO_MATCH) { @@ -658,6 +522,9 @@ public final class BpfNetMapsTest { doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_1); doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_2); doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_3); + doTestSetUidRule(FIREWALL_CHAIN_METERED_ALLOW); + doTestSetUidRule(FIREWALL_CHAIN_METERED_DENY_USER); + doTestSetUidRule(FIREWALL_CHAIN_METERED_DENY_ADMIN); } @Test @@ -1079,7 +946,7 @@ public final class BpfNetMapsTest { @IgnoreUpTo(Build.VERSION_CODES.S_V2) public void testDumpUidOwnerMap() throws Exception { doTestDumpUidOwnerMap(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"); - doTestDumpUidOwnerMap(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"); + doTestDumpUidOwnerMap(PENALTY_BOX_USER_MATCH, "PENALTY_BOX_USER_MATCH"); doTestDumpUidOwnerMap(DOZABLE_MATCH, "DOZABLE_MATCH"); doTestDumpUidOwnerMap(STANDBY_MATCH, "STANDBY_MATCH"); doTestDumpUidOwnerMap(POWERSAVE_MATCH, "POWERSAVE_MATCH"); @@ -1089,6 +956,7 @@ public final class BpfNetMapsTest { doTestDumpUidOwnerMap(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH"); doTestDumpUidOwnerMap(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH"); doTestDumpUidOwnerMap(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH"); + doTestDumpUidOwnerMap(PENALTY_BOX_ADMIN_MATCH, "PENALTY_BOX_ADMIN_MATCH"); doTestDumpUidOwnerMap(HAPPY_BOX_MATCH | POWERSAVE_MATCH, "HAPPY_BOX_MATCH POWERSAVE_MATCH"); @@ -1137,7 +1005,6 @@ public final class BpfNetMapsTest { @IgnoreUpTo(Build.VERSION_CODES.S_V2) public void testDumpUidOwnerMapConfig() throws Exception { doTestDumpOwnerMatchConfig(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"); - doTestDumpOwnerMatchConfig(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"); doTestDumpOwnerMatchConfig(DOZABLE_MATCH, "DOZABLE_MATCH"); doTestDumpOwnerMatchConfig(STANDBY_MATCH, "STANDBY_MATCH"); doTestDumpOwnerMatchConfig(POWERSAVE_MATCH, "POWERSAVE_MATCH"); diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index ce495335b5..59e7d22dc6 100755 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -63,6 +63,9 @@ import static android.net.ConnectivityManager.EXTRA_REALTIME_NS; 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; @@ -10497,6 +10500,9 @@ public class ConnectivityServiceTest { doTestSetUidFirewallRule(FIREWALL_CHAIN_OEM_DENY_1, FIREWALL_RULE_ALLOW); doTestSetUidFirewallRule(FIREWALL_CHAIN_OEM_DENY_2, FIREWALL_RULE_ALLOW); doTestSetUidFirewallRule(FIREWALL_CHAIN_OEM_DENY_3, FIREWALL_RULE_ALLOW); + doTestSetUidFirewallRule(FIREWALL_CHAIN_METERED_ALLOW, FIREWALL_RULE_DENY); + doTestSetUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, FIREWALL_RULE_ALLOW); + doTestSetUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, FIREWALL_RULE_ALLOW); } @Test @IgnoreUpTo(SC_V2) diff --git a/tests/unit/java/com/android/server/connectivityservice/CSFirewallChainTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSFirewallChainTest.kt index 16de4dadea..83ccccd59c 100644 --- a/tests/unit/java/com/android/server/connectivityservice/CSFirewallChainTest.kt +++ b/tests/unit/java/com/android/server/connectivityservice/CSFirewallChainTest.kt @@ -16,7 +16,14 @@ package com.android.server -import android.net.ConnectivityManager +import android.net.BpfNetMapsConstants.METERED_ALLOW_CHAINS +import android.net.BpfNetMapsConstants.METERED_DENY_CHAINS +import android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND +import android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW +import android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER +import android.net.ConnectivityManager.FIREWALL_RULE_ALLOW +import android.net.ConnectivityManager.FIREWALL_RULE_DEFAULT +import android.net.ConnectivityManager.FIREWALL_RULE_DENY import android.os.Build import androidx.test.filters.SmallTest import com.android.server.connectivity.ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN @@ -24,6 +31,7 @@ import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.DevSdkIgnoreRunner +import com.android.testutils.assertThrows import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -52,13 +60,13 @@ class CSFirewallChainTest : CSTest() { @FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, true)]) @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) fun setFirewallChainEnabled_backgroundChainEnabled_afterU() { - cm.setFirewallChainEnabled(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, true) - verify(bpfNetMaps).setChildChain(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, true) + cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true) + verify(bpfNetMaps).setChildChain(FIREWALL_CHAIN_BACKGROUND, true) clearInvocations(bpfNetMaps) - cm.setFirewallChainEnabled(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, false) - verify(bpfNetMaps).setChildChain(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, false) + cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, false) + verify(bpfNetMaps).setChildChain(FIREWALL_CHAIN_BACKGROUND, false) } @Test @@ -69,10 +77,10 @@ class CSFirewallChainTest : CSTest() { } private fun verifySetFirewallChainEnabledOnBackgroundDoesNothing() { - cm.setFirewallChainEnabled(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, true) + cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true) verify(bpfNetMaps, never()).setChildChain(anyInt(), anyBoolean()) - cm.setFirewallChainEnabled(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, false) + cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, false) verify(bpfNetMaps, never()).setChildChain(anyInt(), anyBoolean()) } @@ -88,8 +96,8 @@ class CSFirewallChainTest : CSTest() { @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) fun replaceFirewallChain_backgroundChainEnabled_afterU() { val uids = intArrayOf(53, 42, 79) - cm.replaceFirewallChain(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uids) - verify(bpfNetMaps).replaceUidChain(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uids) + cm.replaceFirewallChain(FIREWALL_CHAIN_BACKGROUND, uids) + verify(bpfNetMaps).replaceUidChain(FIREWALL_CHAIN_BACKGROUND, uids) } @Test @@ -101,7 +109,7 @@ class CSFirewallChainTest : CSTest() { private fun verifyReplaceFirewallChainOnBackgroundDoesNothing() { val uids = intArrayOf(53, 42, 79) - cm.replaceFirewallChain(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uids) + cm.replaceFirewallChain(FIREWALL_CHAIN_BACKGROUND, uids) verify(bpfNetMaps, never()).replaceUidChain(anyInt(), any(IntArray::class.java)) } @@ -118,24 +126,18 @@ class CSFirewallChainTest : CSTest() { fun setUidFirewallRule_backgroundChainEnabled_afterU() { val uid = 2345 - cm.setUidFirewallRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid, - ConnectivityManager.FIREWALL_RULE_DEFAULT) - verify(bpfNetMaps).setUidRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid, - ConnectivityManager.FIREWALL_RULE_DENY) + cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DEFAULT) + verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DENY) clearInvocations(bpfNetMaps) - cm.setUidFirewallRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid, - ConnectivityManager.FIREWALL_RULE_DENY) - verify(bpfNetMaps).setUidRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid, - ConnectivityManager.FIREWALL_RULE_DENY) + cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DENY) + verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DENY) clearInvocations(bpfNetMaps) - cm.setUidFirewallRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid, - ConnectivityManager.FIREWALL_RULE_ALLOW) - verify(bpfNetMaps).setUidRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid, - ConnectivityManager.FIREWALL_RULE_ALLOW) + cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_ALLOW) + verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_ALLOW) } @Test @@ -148,10 +150,49 @@ class CSFirewallChainTest : CSTest() { private fun verifySetUidFirewallRuleOnBackgroundDoesNothing() { val uid = 2345 - listOf(ConnectivityManager.FIREWALL_RULE_DEFAULT, ConnectivityManager.FIREWALL_RULE_ALLOW, - ConnectivityManager.FIREWALL_RULE_DENY).forEach { rule -> - cm.setUidFirewallRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid, rule) + listOf(FIREWALL_RULE_DEFAULT, FIREWALL_RULE_ALLOW, FIREWALL_RULE_DENY).forEach { rule -> + cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, rule) verify(bpfNetMaps, never()).setUidRule(anyInt(), anyInt(), anyInt()) } } + + @Test + fun testSetFirewallChainEnabled_meteredChain() { + (METERED_ALLOW_CHAINS + METERED_DENY_CHAINS).forEach { + assertThrows(UnsupportedOperationException::class.java) { + cm.setFirewallChainEnabled(it, true) + } + assertThrows(UnsupportedOperationException::class.java) { + cm.setFirewallChainEnabled(it, false) + } + } + } + + @Test + fun testAddUidToMeteredNetworkAllowList() { + val uid = 1001 + cm.addUidToMeteredNetworkAllowList(uid) + verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_ALLOW) + } + + @Test + fun testRemoveUidFromMeteredNetworkAllowList() { + val uid = 1001 + cm.removeUidFromMeteredNetworkAllowList(uid) + verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_DENY) + } + + @Test + fun testAddUidToMeteredNetworkDenyList() { + val uid = 1001 + cm.addUidToMeteredNetworkDenyList(uid) + verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_DENY) + } + + @Test + fun testRemoveUidFromMeteredNetworkDenyList() { + val uid = 1001 + cm.removeUidFromMeteredNetworkDenyList(uid) + verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_ALLOW) + } }