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);