Merge "Bugfix:com.android.server.nearby.fastpair.cache.FastPairCacheManagerTest#getAllInfo fail" into tm-mainline-prod
diff --git a/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl b/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
index 836761f..b4e3ba4 100644
--- a/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
+++ b/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
@@ -36,5 +36,4 @@
     void onTetherStatesChanged(in TetherStatesParcel states);
     void onTetherClientsChanged(in List<TetheredClient> clients);
     void onOffloadStatusChanged(int status);
-    void onSupportedTetheringTypes(long supportedBitmap);
 }
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl b/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
index f33f846..253eacb 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
@@ -26,7 +26,7 @@
  * @hide
  */
 parcelable TetheringCallbackStartedParcel {
-    long supportedTypes;
+    boolean tetheringSupported;
     Network upstreamNetwork;
     TetheringConfigurationParcel config;
     TetherStatesParcel states;
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index b3f0cf2..6f9b33e 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -183,12 +183,6 @@
      */
     public static final int TETHERING_WIGIG = 6;
 
-    /**
-     * The int value of last tethering type.
-     * @hide
-     */
-    public static final int MAX_TETHERING_TYPE = TETHERING_WIGIG;
-
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
@@ -526,9 +520,6 @@
         }
 
         @Override
-        public void onSupportedTetheringTypes(long supportedBitmap) { }
-
-        @Override
         public void onUpstreamChanged(Network network) { }
 
         @Override
@@ -1042,29 +1033,15 @@
         /**
          * Called when tethering supported status changed.
          *
-         * <p>This callback will be called immediately after the callback is
-         * registered, and never be called if there is changes afterward.
-         *
-         * <p>Tethering may be disabled via system properties, device configuration, or device
-         * policy restrictions.
-         *
-         * @param supported whether any tethering type is supported.
-         */
-        default void onTetheringSupported(boolean supported) {}
-
-        /**
-         * Called when tethering supported status changed.
-         *
          * <p>This will be called immediately after the callback is registered, and may be called
          * multiple times later upon changes.
          *
          * <p>Tethering may be disabled via system properties, device configuration, or device
          * policy restrictions.
          *
-         * @param supportedTypes a set of @TetheringType which is supported.
-         * @hide
+         * @param supported The new supported status
          */
-        default void onSupportedTetheringTypes(@NonNull Set<Integer> supportedTypes) {}
+        default void onTetheringSupported(boolean supported) {}
 
         /**
          * Called when tethering upstream changed.
@@ -1362,8 +1339,7 @@
                 @Override
                 public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
                     executor.execute(() -> {
-                        callback.onSupportedTetheringTypes(unpackBits(parcel.supportedTypes));
-                        callback.onTetheringSupported(parcel.supportedTypes != 0);
+                        callback.onTetheringSupported(parcel.tetheringSupported);
                         callback.onUpstreamChanged(parcel.upstreamNetwork);
                         sendErrorCallbacks(parcel.states);
                         sendRegexpsChanged(parcel.config);
@@ -1382,13 +1358,6 @@
                     });
                 }
 
-                @Override
-                public void onSupportedTetheringTypes(long supportedBitmap) {
-                    executor.execute(() -> {
-                        callback.onSupportedTetheringTypes(unpackBits(supportedBitmap));
-                    });
-                }
-
                 private void sendRegexpsChanged(TetheringConfigurationParcel parcel) {
                     callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps(
                             parcel.tetherableBluetoothRegexs,
@@ -1427,23 +1396,6 @@
     }
 
     /**
-     * Unpack bitmap to a set of bit position intergers.
-     * @hide
-     */
-    public static ArraySet<Integer> unpackBits(long val) {
-        final ArraySet<Integer> result = new ArraySet<>(Long.bitCount(val));
-        int bitPos = 0;
-        while (val != 0) {
-            if ((val & 1) == 1) result.add(bitPos);
-
-            val = val >>> 1;
-            bitPos++;
-        }
-
-        return result;
-    }
-
-    /**
      * Remove tethering event callback previously registered with
      * {@link #registerTetheringEventCallback}.
      *
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 47b1bd7..3f328db 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -281,11 +281,6 @@
     private BluetoothPan mBluetoothPan;
     private PanServiceListener mBluetoothPanListener;
     private ArrayList<Pair<Boolean, IIntResultListener>> mPendingPanRequests;
-    // AIDL doesn't support Set<Integer>. Maintain a int bitmap here. When the bitmap is passed to
-    // TetheringManager, TetheringManager would convert it to a set of Integer types.
-    // mSupportedTypeBitmap should always be updated inside tethering internal thread but it may be
-    // read from binder thread which called TetheringService directly.
-    private volatile long mSupportedTypeBitmap;
 
     public Tethering(TetheringDependencies deps) {
         mLog.mark("Tethering.constructed");
@@ -517,8 +512,6 @@
         mUpstreamNetworkMonitor.setUpstreamConfig(mConfig.chooseUpstreamAutomatically,
                 mConfig.isDunRequired);
         reportConfigurationChanged(mConfig.toStableParcelable());
-
-        updateSupportedDownstreams(mConfig);
     }
 
     private void maybeDunSettingChanged() {
@@ -1557,6 +1550,26 @@
         return mConfig;
     }
 
+    boolean hasAnySupportedDownstream() {
+        if ((mConfig.tetherableUsbRegexs.length != 0)
+                || (mConfig.tetherableWifiRegexs.length != 0)
+                || (mConfig.tetherableBluetoothRegexs.length != 0)) {
+            return true;
+        }
+
+        // Before T, isTetheringSupported would return true if wifi, usb and bluetooth tethering are
+        // disabled (whole tethering settings would be hidden). This means tethering would also not
+        // support wifi p2p, ethernet tethering and mirrorlink. This is wrong but probably there are
+        // some devices in the field rely on this to disable tethering entirely.
+        if (!SdkLevel.isAtLeastT()) return false;
+
+        return (mConfig.tetherableWifiP2pRegexs.length != 0)
+                || (mConfig.tetherableNcmRegexs.length != 0)
+                || isEthernetSupported();
+    }
+
+    // TODO: using EtherentManager new API to check whether ethernet is supported when the API is
+    // ready to use.
     private boolean isEthernetSupported() {
         return mContext.getSystemService(Context.ETHERNET_SERVICE) != null;
     }
@@ -2346,7 +2359,7 @@
         mHandler.post(() -> {
             mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission));
             final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
-            parcel.supportedTypes = mSupportedTypeBitmap;
+            parcel.tetheringSupported = isTetheringSupported();
             parcel.upstreamNetwork = mTetherUpstream;
             parcel.config = mConfig.toStableParcelable();
             parcel.states =
@@ -2385,22 +2398,6 @@
         });
     }
 
-    private void reportTetheringSupportedChange(final long supportedBitmap) {
-        final int length = mTetheringEventCallbacks.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mTetheringEventCallbacks.getBroadcastItem(i).onSupportedTetheringTypes(
-                            supportedBitmap);
-                } catch (RemoteException e) {
-                    // Not really very much to do here.
-                }
-            }
-        } finally {
-            mTetheringEventCallbacks.finishBroadcast();
-        }
-    }
-
     private void reportUpstreamChanged(UpstreamNetworkState ns) {
         final int length = mTetheringEventCallbacks.beginBroadcast();
         final Network network = (ns != null) ? ns.network : null;
@@ -2485,56 +2482,18 @@
         }
     }
 
-    private void updateSupportedDownstreams(final TetheringConfiguration config) {
-        final long preSupportedBitmap = mSupportedTypeBitmap;
-
-        if (!isTetheringAllowed() || mEntitlementMgr.isProvisioningNeededButUnavailable()) {
-            mSupportedTypeBitmap = 0;
-        } else {
-            mSupportedTypeBitmap = makeSupportedDownstreams(config);
-        }
-
-        if (preSupportedBitmap != mSupportedTypeBitmap) {
-            reportTetheringSupportedChange(mSupportedTypeBitmap);
-        }
-    }
-
-    private long makeSupportedDownstreams(final TetheringConfiguration config) {
-        long types = 0;
-        if (config.tetherableUsbRegexs.length != 0) types |= (1 << TETHERING_USB);
-
-        if (config.tetherableWifiRegexs.length != 0) types |= (1 << TETHERING_WIFI);
-
-        if (config.tetherableBluetoothRegexs.length != 0) types |= (1 << TETHERING_BLUETOOTH);
-
-        // Before T, isTetheringSupported would return true if wifi, usb and bluetooth tethering are
-        // disabled (whole tethering settings would be hidden). This means tethering would also not
-        // support wifi p2p, ethernet tethering and mirrorlink. This is wrong but probably there are
-        // some devices in the field rely on this to disable tethering entirely.
-        if (!SdkLevel.isAtLeastT() && types == 0) return types;
-
-        if (config.tetherableNcmRegexs.length != 0) types |= (1 << TETHERING_NCM);
-
-        if (config.tetherableWifiP2pRegexs.length != 0) types |= (1 << TETHERING_WIFI_P2P);
-
-        if (isEthernetSupported()) types |= (1 << TETHERING_ETHERNET);
-
-        return types;
-    }
-
     // if ro.tether.denied = true we default to no tethering
     // gservices could set the secure setting to 1 though to enable it on a build where it
     // had previously been turned off.
-    private boolean isTetheringAllowed() {
+    boolean isTetheringSupported() {
         final int defaultVal = mDeps.isTetheringDenied() ? 0 : 1;
         final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
-        return tetherSupported
+        final boolean tetherEnabledInSettings = tetherSupported
                 && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
-    }
 
-    boolean isTetheringSupported() {
-        return mSupportedTypeBitmap > 0;
+        return tetherEnabledInSettings && hasAnySupportedDownstream()
+                && !mEntitlementMgr.isProvisioningNeededButUnavailable();
     }
 
     private void dumpBpf(IndentingPrintWriter pw) {
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index ef4f052..86dca1c 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -192,13 +192,12 @@
         mUiAutomation.adoptShellPermissionIdentity(
                 MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED, ACCESS_NETWORK_STATE,
                 CONNECTIVITY_USE_RESTRICTED_NETWORKS, DUMP);
+        mRunTests = mTm.isTetheringSupported() && mEm != null;
+        assumeTrue(mRunTests);
+
         mHandlerThread = new HandlerThread(getClass().getSimpleName());
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
-
-        mRunTests = isEthernetTetheringSupported();
-        assumeTrue(mRunTests);
-
         mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm);
     }
 
@@ -226,6 +225,7 @@
             mHandler.post(() -> reader.stop());
             mDownstreamReader = null;
         }
+        mHandlerThread.quitSafely();
         mTetheredInterfaceRequester.release();
         mEm.setIncludeTestInterfaces(false);
         maybeDeleteTestInterface();
@@ -236,7 +236,6 @@
         try {
             if (mRunTests) cleanUp();
         } finally {
-            mHandlerThread.quitSafely();
             mUiAutomation.dropShellPermissionIdentity();
         }
     }
@@ -411,23 +410,6 @@
         // client, which is not possible in this test.
     }
 
-    private boolean isEthernetTetheringSupported() throws Exception {
-        final CompletableFuture<Boolean> future = new CompletableFuture<>();
-        final TetheringEventCallback callback = new TetheringEventCallback() {
-            @Override
-            public void onSupportedTetheringTypes(Set<Integer> supportedTypes) {
-                future.complete(supportedTypes.contains(TETHERING_ETHERNET));
-            }
-        };
-
-        try {
-            mTm.registerTetheringEventCallback(mHandler::post, callback);
-            return future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        } finally {
-            mTm.unregisterTetheringEventCallback(callback);
-        }
-    }
-
     private static final class MyTetheringEventCallback implements TetheringEventCallback {
         private final TetheringManager mTm;
         private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1);
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index cc80174..e90d27e 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -144,7 +144,6 @@
 import android.net.TetheringCallbackStartedParcel;
 import android.net.TetheringConfigurationParcel;
 import android.net.TetheringInterface;
-import android.net.TetheringManager;
 import android.net.TetheringRequestParcel;
 import android.net.dhcp.DhcpLeaseParcelable;
 import android.net.dhcp.DhcpServerCallbacks;
@@ -177,7 +176,6 @@
 import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyManager;
 import android.test.mock.MockContentResolver;
-import android.util.ArraySet;
 
 import androidx.annotation.NonNull;
 import androidx.test.filters.SmallTest;
@@ -219,7 +217,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 import java.util.Vector;
 
 @RunWith(AndroidJUnit4.class)
@@ -1732,7 +1729,6 @@
         private final ArrayList<TetherStatesParcel> mTetherStates = new ArrayList<>();
         private final ArrayList<Integer> mOffloadStatus = new ArrayList<>();
         private final ArrayList<List<TetheredClient>> mTetheredClients = new ArrayList<>();
-        private final ArrayList<Long> mSupportedBitmaps = new ArrayList<>();
 
         // This function will remove the recorded callbacks, so it must be called once for
         // each callback. If this is called after multiple callback, the order matters.
@@ -1785,10 +1781,6 @@
             assertTrue(leases.containsAll(result));
         }
 
-        public void expectSupportedTetheringTypes(Set<Integer> expectedTypes) {
-            assertEquals(expectedTypes, TetheringManager.unpackBits(mSupportedBitmaps.remove(0)));
-        }
-
         @Override
         public void onUpstreamChanged(Network network) {
             mActualUpstreams.add(network);
@@ -1821,17 +1813,11 @@
             mTetherStates.add(parcel.states);
             mOffloadStatus.add(parcel.offloadStatus);
             mTetheredClients.add(parcel.tetheredClients);
-            mSupportedBitmaps.add(parcel.supportedTypes);
         }
 
         @Override
         public void onCallbackStopped(int errorCode) { }
 
-        @Override
-        public void onSupportedTetheringTypes(long supportedBitmap) {
-            mSupportedBitmaps.add(supportedBitmap);
-        }
-
         public void assertNoUpstreamChangeCallback() {
             assertTrue(mActualUpstreams.isEmpty());
         }
@@ -2959,81 +2945,53 @@
         runStopUSBTethering();
     }
 
-    public static ArraySet<Integer> getAllSupportedTetheringTypes() {
-        return new ArraySet<>(new Integer[] { TETHERING_USB, TETHERING_NCM, TETHERING_WIFI,
-                TETHERING_WIFI_P2P, TETHERING_BLUETOOTH, TETHERING_ETHERNET });
-    }
-
     @Test
     public void testTetheringSupported() throws Exception {
-        final ArraySet<Integer> expectedTypes = getAllSupportedTetheringTypes();
-        // Check tethering is supported after initialization.
         setTetheringSupported(true /* supported */);
-        TestTetheringEventCallback callback = new TestTetheringEventCallback();
-        mTethering.registerTetheringEventCallback(callback);
-        mLooper.dispatchAll();
-        updateConfigAndVerifySupported(callback, expectedTypes);
+        updateConfigAndVerifySupported(true /* supported */);
 
         // Could disable tethering supported by settings.
         Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED, 0);
-        updateConfigAndVerifySupported(callback, new ArraySet<>());
+        updateConfigAndVerifySupported(false /* supported */);
 
         // Could disable tethering supported by user restriction.
         setTetheringSupported(true /* supported */);
-        updateConfigAndVerifySupported(callback, expectedTypes);
         when(mUserManager.hasUserRestriction(
                 UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(true);
-        updateConfigAndVerifySupported(callback, new ArraySet<>());
+        updateConfigAndVerifySupported(false /* supported */);
 
         // Tethering is supported if it has any supported downstream.
         setTetheringSupported(true /* supported */);
-        updateConfigAndVerifySupported(callback, expectedTypes);
-        // Usb tethering is not supported:
-        expectedTypes.remove(TETHERING_USB);
         when(mResources.getStringArray(R.array.config_tether_usb_regexs))
                 .thenReturn(new String[0]);
-        updateConfigAndVerifySupported(callback, expectedTypes);
-        // Wifi tethering is not supported:
-        expectedTypes.remove(TETHERING_WIFI);
+        updateConfigAndVerifySupported(true /* supported */);
         when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
                 .thenReturn(new String[0]);
-        updateConfigAndVerifySupported(callback, expectedTypes);
-        // Bluetooth tethering is not supported:
-        expectedTypes.remove(TETHERING_BLUETOOTH);
-        when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
-                .thenReturn(new String[0]);
+        updateConfigAndVerifySupported(true /* supported */);
+
 
         if (isAtLeastT()) {
-            updateConfigAndVerifySupported(callback, expectedTypes);
-
-            // P2p tethering is not supported:
-            expectedTypes.remove(TETHERING_WIFI_P2P);
+            when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
+                    .thenReturn(new String[0]);
+            updateConfigAndVerifySupported(true /* supported */);
             when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
                     .thenReturn(new String[0]);
-            updateConfigAndVerifySupported(callback, expectedTypes);
-            // Ncm tethering is not supported:
-            expectedTypes.remove(TETHERING_NCM);
+            updateConfigAndVerifySupported(true /* supported */);
             when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
                     .thenReturn(new String[0]);
-            updateConfigAndVerifySupported(callback, expectedTypes);
-            // Ethernet tethering (last supported type) is not supported:
-            expectedTypes.remove(TETHERING_ETHERNET);
+            updateConfigAndVerifySupported(true /* supported */);
             mForceEthernetServiceUnavailable = true;
-            updateConfigAndVerifySupported(callback, new ArraySet<>());
-
+            updateConfigAndVerifySupported(false /* supported */);
         } else {
-            // If wifi, usb and bluetooth are all not supported, all the types are not supported.
-            expectedTypes.clear();
-            updateConfigAndVerifySupported(callback, expectedTypes);
+            when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
+                    .thenReturn(new String[0]);
+            updateConfigAndVerifySupported(false /* supported */);
         }
     }
 
-    private void updateConfigAndVerifySupported(final TestTetheringEventCallback callback,
-            final ArraySet<Integer> expectedTypes) {
+    private void updateConfigAndVerifySupported(boolean supported) {
         sendConfigurationChanged();
-
-        assertEquals(expectedTypes.size() > 0, mTethering.isTetheringSupported());
-        callback.expectSupportedTetheringTypes(expectedTypes);
+        assertEquals(supported, mTethering.isTetheringSupported());
     }
     // TODO: Test that a request for hotspot mode doesn't interfere with an
     // already operating tethering mode interface.
diff --git a/bpf_progs/dscp_policy.c b/bpf_progs/dscp_policy.c
index 38e1050..92ea0e2 100644
--- a/bpf_progs/dscp_policy.c
+++ b/bpf_progs/dscp_policy.c
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-#include <linux/types.h>
 #include <linux/bpf.h>
+#include <linux/if_ether.h>
 #include <linux/if_packet.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
-#include <linux/if_ether.h>
 #include <linux/pkt_cls.h>
 #include <linux/tcp.h>
-#include <stdint.h>
+#include <linux/types.h>
 #include <netinet/in.h>
 #include <netinet/udp.h>
+#include <stdint.h>
 #include <string.h>
 
 // The resulting .o needs to load on the Android T beta 3 bpfloader
@@ -33,21 +33,25 @@
 #include "bpf_helpers.h"
 #include "dscp_policy.h"
 
+#define ECN_MASK 3
+#define IP4_OFFSET(field, header) (header + offsetof(struct iphdr, field))
+#define UPDATE_TOS(dscp, tos) (dscp << 2) | (tos & ECN_MASK)
+#define UPDATE_PRIORITY(dscp) ((dscp >> 2) + 0x60)
+#define UPDATE_FLOW_LABEL(dscp, flow_lbl) ((dscp & 0xf) << 6) + (flow_lbl >> 6)
+
 DEFINE_BPF_MAP_GRW(switch_comp_map, ARRAY, int, uint64_t, 1, AID_SYSTEM)
 
 DEFINE_BPF_MAP_GRW(ipv4_socket_to_policies_map_A, HASH, uint64_t, RuleEntry, MAX_POLICIES,
-        AID_SYSTEM)
+                   AID_SYSTEM)
 DEFINE_BPF_MAP_GRW(ipv4_socket_to_policies_map_B, HASH, uint64_t, RuleEntry, MAX_POLICIES,
-        AID_SYSTEM)
+                   AID_SYSTEM)
 DEFINE_BPF_MAP_GRW(ipv6_socket_to_policies_map_A, HASH, uint64_t, RuleEntry, MAX_POLICIES,
-        AID_SYSTEM)
+                   AID_SYSTEM)
 DEFINE_BPF_MAP_GRW(ipv6_socket_to_policies_map_B, HASH, uint64_t, RuleEntry, MAX_POLICIES,
-        AID_SYSTEM)
+                   AID_SYSTEM)
 
-DEFINE_BPF_MAP_GRW(ipv4_dscp_policies_map, ARRAY, uint32_t, DscpPolicy, MAX_POLICIES,
-        AID_SYSTEM)
-DEFINE_BPF_MAP_GRW(ipv6_dscp_policies_map, ARRAY, uint32_t, DscpPolicy, MAX_POLICIES,
-        AID_SYSTEM)
+DEFINE_BPF_MAP_GRW(ipv4_dscp_policies_map, ARRAY, uint32_t, DscpPolicy, MAX_POLICIES, AID_SYSTEM)
+DEFINE_BPF_MAP_GRW(ipv6_dscp_policies_map, ARRAY, uint32_t, DscpPolicy, MAX_POLICIES, AID_SYSTEM)
 
 static inline __always_inline void match_policy(struct __sk_buff* skb, bool ipv4, bool is_eth) {
     void* data = (void*)(long)skb->data;
@@ -69,21 +73,21 @@
 
     // used for map lookup
     uint64_t cookie = bpf_get_socket_cookie(skb);
-    if (!cookie)
-        return;
+    if (!cookie) return;
 
     uint16_t sport = 0;
     uint16_t dport = 0;
-    uint8_t protocol = 0; // TODO: Use are reserved value? Or int (-1) and cast to uint below?
+    uint8_t protocol = 0;  // TODO: Use are reserved value? Or int (-1) and cast to uint below?
     struct in6_addr srcIp = {};
     struct in6_addr dstIp = {};
-    uint8_t tos = 0; // Only used for IPv4
-    uint8_t priority = 0; // Only used for IPv6
-    uint8_t flow_lbl = 0; // Only used for IPv6
+    uint8_t tos = 0;       // Only used for IPv4
+    uint8_t priority = 0;  // Only used for IPv6
+    uint8_t flow_lbl = 0;  // Only used for IPv6
     if (ipv4) {
         const struct iphdr* const iph = is_eth ? (void*)(eth + 1) : data;
+        hdr_size = l2_header_size + sizeof(struct iphdr);
         // Must have ipv4 header
-        if (data + l2_header_size + sizeof(*iph) > data_end) return;
+        if (data + hdr_size > data_end) return;
 
         // IP version must be 4
         if (iph->version != 4) return;
@@ -100,11 +104,11 @@
         dstIp.s6_addr32[3] = iph->daddr;
         protocol = iph->protocol;
         tos = iph->tos;
-        hdr_size = sizeof(struct iphdr);
     } else {
         struct ipv6hdr* ip6h = is_eth ? (void*)(eth + 1) : data;
+        hdr_size = l2_header_size + sizeof(struct ipv6hdr);
         // Must have ipv6 header
-        if (data + l2_header_size + sizeof(*ip6h) > data_end) return;
+        if (data + hdr_size > data_end) return;
 
         if (ip6h->version != 6) return;
 
@@ -113,29 +117,24 @@
         protocol = ip6h->nexthdr;
         priority = ip6h->priority;
         flow_lbl = ip6h->flow_lbl[0];
-        hdr_size = sizeof(struct ipv6hdr);
     }
 
     switch (protocol) {
         case IPPROTO_UDP:
-        case IPPROTO_UDPLITE:
-        {
-            struct udphdr *udp;
+        case IPPROTO_UDPLITE: {
+            struct udphdr* udp;
             udp = data + hdr_size;
             if ((void*)(udp + 1) > data_end) return;
             sport = udp->source;
             dport = udp->dest;
-        }
-        break;
-        case IPPROTO_TCP:
-        {
-            struct tcphdr *tcp;
+        } break;
+        case IPPROTO_TCP: {
+            struct tcphdr* tcp;
             tcp = data + hdr_size;
             if ((void*)(tcp + 1) > data_end) return;
             sport = tcp->source;
             dport = tcp->dest;
-        }
-        break;
+        } break;
         default:
             return;
     }
@@ -156,22 +155,19 @@
     }
 
     if (existingRule && v6_equal(srcIp, existingRule->srcIp) &&
-                v6_equal(dstIp, existingRule->dstIp) &&
-                skb->ifindex == existingRule->ifindex &&
-                ntohs(sport) == htons(existingRule->srcPort) &&
-                ntohs(dport) == htons(existingRule->dstPort) &&
-                protocol == existingRule->proto) {
+        v6_equal(dstIp, existingRule->dstIp) && skb->ifindex == existingRule->ifindex &&
+        ntohs(sport) == htons(existingRule->srcPort) &&
+        ntohs(dport) == htons(existingRule->dstPort) && protocol == existingRule->proto) {
         if (ipv4) {
-            int ecn = tos & 3;
-            uint8_t newDscpVal = (existingRule->dscpVal << 2) + ecn;
-            int oldDscpVal = tos >> 2;
-            bpf_l3_csum_replace(skb, 1, oldDscpVal, newDscpVal, sizeof(uint8_t));
-            bpf_skb_store_bytes(skb, 1, &newDscpVal, sizeof(uint8_t), 0);
+            uint8_t newTos = UPDATE_TOS(existingRule->dscpVal, tos);
+            bpf_l3_csum_replace(skb, IP4_OFFSET(check, l2_header_size), htons(tos), htons(newTos),
+                                sizeof(uint16_t));
+            bpf_skb_store_bytes(skb, IP4_OFFSET(tos, l2_header_size), &newTos, sizeof(newTos), 0);
         } else {
-            uint8_t new_priority = (existingRule->dscpVal >> 2) + 0x60;
-            uint8_t new_flow_label = ((existingRule->dscpVal & 0xf) << 6) + (priority >> 6);
-            bpf_skb_store_bytes(skb, 0, &new_priority, sizeof(uint8_t), 0);
-            bpf_skb_store_bytes(skb, 1, &new_flow_label, sizeof(uint8_t), 0);
+            uint8_t new_priority = UPDATE_PRIORITY(existingRule->dscpVal);
+            uint8_t new_flow_label = UPDATE_FLOW_LABEL(existingRule->dscpVal, flow_lbl);
+            bpf_skb_store_bytes(skb, 0 + l2_header_size, &new_priority, sizeof(uint8_t), 0);
+            bpf_skb_store_bytes(skb, 1 + l2_header_size, &new_flow_label, sizeof(uint8_t), 0);
         }
         return;
     }
@@ -196,32 +192,31 @@
 
         // If the policy lookup failed, presentFields is 0, or iface index does not match
         // index on skb buff, then we can continue to next policy.
-        if (!policy || policy->presentFields == 0 || policy->ifindex != skb->ifindex)
-            continue;
+        if (!policy || policy->presentFields == 0 || policy->ifindex != skb->ifindex) continue;
 
         if ((policy->presentFields & SRC_IP_MASK_FLAG) == SRC_IP_MASK_FLAG &&
-                v6_equal(srcIp, policy->srcIp)) {
+            v6_equal(srcIp, policy->srcIp)) {
             score++;
             tempMask |= SRC_IP_MASK_FLAG;
         }
         if ((policy->presentFields & DST_IP_MASK_FLAG) == DST_IP_MASK_FLAG &&
-                v6_equal(dstIp, policy->dstIp)) {
+            v6_equal(dstIp, policy->dstIp)) {
             score++;
             tempMask |= DST_IP_MASK_FLAG;
         }
         if ((policy->presentFields & SRC_PORT_MASK_FLAG) == SRC_PORT_MASK_FLAG &&
-                ntohs(sport) == htons(policy->srcPort)) {
+            ntohs(sport) == htons(policy->srcPort)) {
             score++;
             tempMask |= SRC_PORT_MASK_FLAG;
         }
         if ((policy->presentFields & DST_PORT_MASK_FLAG) == DST_PORT_MASK_FLAG &&
-                ntohs(dport) >= htons(policy->dstPortStart) &&
-                ntohs(dport) <= htons(policy->dstPortEnd)) {
+            ntohs(dport) >= htons(policy->dstPortStart) &&
+            ntohs(dport) <= htons(policy->dstPortEnd)) {
             score++;
             tempMask |= DST_PORT_MASK_FLAG;
         }
         if ((policy->presentFields & PROTO_MASK_FLAG) == PROTO_MASK_FLAG &&
-                protocol == policy->proto) {
+            protocol == policy->proto) {
             score++;
             tempMask |= PROTO_MASK_FLAG;
         }
@@ -232,7 +227,8 @@
         }
     }
 
-    uint8_t new_tos= 0; // Can 0 be used as default forwarding value?
+    uint8_t new_tos = 0;  // Can 0 be used as default forwarding value?
+    uint8_t new_dscp = 0;
     uint8_t new_priority = 0;
     uint8_t new_flow_lbl = 0;
     if (bestScore > 0) {
@@ -244,20 +240,16 @@
         }
 
         if (policy) {
-            // TODO: if DSCP value is already set ignore?
+            new_dscp = policy->dscpVal;
             if (ipv4) {
-                int ecn = tos & 3;
-                new_tos = (policy->dscpVal << 2) + ecn;
+                new_tos = UPDATE_TOS(new_dscp, tos);
             } else {
-                new_priority = (policy->dscpVal >> 2) + 0x60;
-                new_flow_lbl = ((policy->dscpVal & 0xf) << 6) + (flow_lbl >> 6);
-
-                // Set IPv6 curDscp value to stored value and recalulate priority
-                // and flow label during next use.
-                new_tos = policy->dscpVal;
+                new_priority = UPDATE_PRIORITY(new_dscp);
+                new_flow_lbl = UPDATE_FLOW_LABEL(new_dscp, flow_lbl);
             }
         }
-    } else return;
+    } else
+        return;
 
     RuleEntry value = {
         .srcIp = srcIp,
@@ -266,10 +258,10 @@
         .srcPort = sport,
         .dstPort = dport,
         .proto = protocol,
-        .dscpVal = new_tos,
+        .dscpVal = new_dscp,
     };
 
-    //Update map with new policy.
+    // Update map with new policy.
     if (ipv4) {
         if (*selectedMap == MAP_A) {
             bpf_ipv4_socket_to_policies_map_A_update_elem(&cookie, &value, BPF_ANY);
@@ -286,12 +278,11 @@
 
     // Need to store bytes after updating map or program will not load.
     if (ipv4 && new_tos != (tos & 252)) {
-        int oldDscpVal = tos >> 2;
-        bpf_l3_csum_replace(skb, 1, oldDscpVal, new_tos, sizeof(uint8_t));
-        bpf_skb_store_bytes(skb, 1, &new_tos, sizeof(uint8_t), 0);
+        bpf_l3_csum_replace(skb, IP4_OFFSET(check, l2_header_size), htons(tos), htons(new_tos), 2);
+        bpf_skb_store_bytes(skb, IP4_OFFSET(tos, l2_header_size), &new_tos, sizeof(new_tos), 0);
     } else if (!ipv4 && (new_priority != priority || new_flow_lbl != flow_lbl)) {
-        bpf_skb_store_bytes(skb, 0, &new_priority, sizeof(uint8_t), 0);
-        bpf_skb_store_bytes(skb, 1, &new_flow_lbl, sizeof(uint8_t), 0);
+        bpf_skb_store_bytes(skb, l2_header_size, &new_priority, sizeof(new_priority), 0);
+        bpf_skb_store_bytes(skb, l2_header_size + 1, &new_flow_lbl, sizeof(new_flow_lbl), 0);
     }
     return;
 }
@@ -299,7 +290,6 @@
 DEFINE_BPF_PROG_KVER("schedcls/set_dscp_ether", AID_ROOT, AID_SYSTEM,
                      schedcls_set_dscp_ether, KVER(5, 15, 0))
 (struct __sk_buff* skb) {
-
     if (skb->pkt_type != PACKET_HOST) return TC_ACT_PIPE;
 
     if (skb->protocol == htons(ETH_P_IP)) {
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index be0eb5f..6599c7f 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -294,10 +294,8 @@
      *                                  cause of the failure.
      */
     public void addNiceApp(final int uid) {
-        synchronized (sUidOwnerMap) {
-            final int err = native_addNiceApp(uid);
-            maybeThrow(err, "Unable to add nice app");
-        }
+        throwIfPreT("addNiceApp is not available on pre-T devices");
+        addRule(uid, HAPPY_BOX_MATCH, "addNiceApp");
     }
 
     /**
@@ -308,10 +306,8 @@
      *                                  cause of the failure.
      */
     public void removeNiceApp(final int uid) {
-        synchronized (sUidOwnerMap) {
-            final int err = native_removeNiceApp(uid);
-            maybeThrow(err, "Unable to remove nice app");
-        }
+        throwIfPreT("removeNiceApp is not available on pre-T devices");
+        removeRule(uid, HAPPY_BOX_MATCH, "removeNiceApp");
     }
 
     /**
@@ -460,9 +456,11 @@
      *                                  cause of the failure.
      */
     public void updateUidLockdownRule(final int uid, final boolean add) {
-        synchronized (sUidOwnerMap) {
-            final int err = native_updateUidLockdownRule(uid, add);
-            maybeThrow(err, "Unable to update lockdown rule");
+        throwIfPreT("updateUidLockdownRule is not available on pre-T devices");
+        if (add) {
+            addRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
+        } else {
+            removeRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
         }
     }
 
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index e59fbc2..433b892 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -27,7 +27,9 @@
 import static android.net.INetd.PERMISSION_INTERNET;
 
 import static com.android.server.BpfNetMaps.DOZABLE_MATCH;
+import static com.android.server.BpfNetMaps.HAPPY_BOX_MATCH;
 import static com.android.server.BpfNetMaps.IIF_MATCH;
+import static com.android.server.BpfNetMaps.LOCKDOWN_VPN_MATCH;
 import static com.android.server.BpfNetMaps.NO_MATCH;
 import static com.android.server.BpfNetMaps.PENALTY_BOX_MATCH;
 import static com.android.server.BpfNetMaps.POWERSAVE_MATCH;
@@ -332,4 +334,128 @@
         assertThrows(UnsupportedOperationException.class,
                 () -> mBpfNetMaps.addNaughtyApp(TEST_UID));
     }
+
+    private void doTestRemoveNiceApp(final long iif, final long match) throws Exception {
+        mUidOwnerMap.updateEntry(new U32(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 long iif, final long match) throws Exception {
+        if (match != NO_MATCH) {
+            mUidOwnerMap.updateEntry(new U32(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 long iif, final long match, final boolean add)
+            throws Exception {
+        if (match != NO_MATCH) {
+            mUidOwnerMap.updateEntry(new U32(TEST_UID), new UidOwnerValue(iif, match));
+        }
+
+        mBpfNetMaps.updateUidLockdownRule(TEST_UID, add);
+
+        final long expectedMatch = add ? match | LOCKDOWN_VPN_MATCH : match & ~LOCKDOWN_VPN_MATCH;
+        checkUidOwnerValue(TEST_UID, iif, expectedMatch);
+    }
+
+    private static final boolean ADD = true;
+    private static final boolean REMOVE = false;
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testUpdateUidLockdownRuleAddLockdown() throws Exception {
+        doTestUpdateUidLockdownRule(NO_IIF, NO_MATCH, ADD);
+
+        // Other matches are enabled
+        doTestUpdateUidLockdownRule(
+                NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH, ADD);
+
+        // IIF_MATCH is enabled
+        doTestUpdateUidLockdownRule(TEST_IF_INDEX, DOZABLE_MATCH, ADD);
+
+        // LOCKDOWN_VPN_MATCH is already enabled
+        doTestUpdateUidLockdownRule(NO_IIF, LOCKDOWN_VPN_MATCH | DOZABLE_MATCH, ADD);
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testUpdateUidLockdownRuleRemoveLockdown() throws Exception {
+        doTestUpdateUidLockdownRule(NO_IIF, LOCKDOWN_VPN_MATCH, REMOVE);
+
+        // LOCKDOWN_VPN_MATCH with other matches
+        doTestUpdateUidLockdownRule(
+                NO_IIF, LOCKDOWN_VPN_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH, REMOVE);
+
+        // LOCKDOWN_VPN_MATCH with IIF_MATCH
+        doTestUpdateUidLockdownRule(TEST_IF_INDEX, LOCKDOWN_VPN_MATCH | IIF_MATCH, REMOVE);
+
+        // LOCKDOWN_VPN_MATCH is not enabled
+        doTestUpdateUidLockdownRule(NO_IIF, POWERSAVE_MATCH | RESTRICTED_MATCH, REMOVE);
+    }
+
+    @Test
+    @IgnoreAfter(Build.VERSION_CODES.S_V2)
+    public void testUpdateUidLockdownRuleBeforeT() {
+        assertThrows(UnsupportedOperationException.class,
+                () -> mBpfNetMaps.updateUidLockdownRule(TEST_UID, true /* add */));
+    }
 }