Add Chicken bit for the mDNS offload feature

Bug: 297482971
Test: TH
Change-Id: I6f2cdd066d9047b113ff80211cf6d4c6fa605104
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index b9acc48..6ac8ec0 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -26,7 +26,6 @@
 import static android.net.nsd.NsdManager.MDNS_SERVICE_EVENT;
 import static android.net.nsd.NsdManager.RESOLVE_SERVICE_SUCCEEDED;
 import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
-
 import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
 import static com.android.networkstack.apishim.ConstantsShim.REGISTER_NSD_OFFLOAD_ENGINE;
 import static com.android.server.connectivity.mdns.MdnsAdvertiser.AdvertiserMetrics;
@@ -89,6 +88,7 @@
 import com.android.server.connectivity.mdns.ExecutorProvider;
 import com.android.server.connectivity.mdns.MdnsAdvertiser;
 import com.android.server.connectivity.mdns.MdnsDiscoveryManager;
+import com.android.server.connectivity.mdns.MdnsFeatureFlags;
 import com.android.server.connectivity.mdns.MdnsInterfaceSocket;
 import com.android.server.connectivity.mdns.MdnsMultinetworkSocketClient;
 import com.android.server.connectivity.mdns.MdnsSearchOptions;
@@ -1695,8 +1695,11 @@
         mMdnsDiscoveryManager = deps.makeMdnsDiscoveryManager(new ExecutorProvider(),
                 mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager"));
         handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager));
+        MdnsFeatureFlags flags = new MdnsFeatureFlags.Builder().setIsMdnsOffloadFeatureEnabled(
+                mDeps.isTetheringFeatureNotChickenedOut(
+                        MdnsFeatureFlags.NSD_FORCE_DISABLE_MDNS_OFFLOAD)).build();
         mAdvertiser = deps.makeMdnsAdvertiser(handler.getLooper(), mMdnsSocketProvider,
-                new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser"));
+                new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser"), flags);
         mClock = deps.makeClock();
     }
 
@@ -1748,6 +1751,13 @@
         }
 
         /**
+         * @see DeviceConfigUtils#isTetheringFeatureNotChickenedOut
+         */
+        public boolean isTetheringFeatureNotChickenedOut(String feature) {
+            return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(feature);
+        }
+
+        /**
          * @see MdnsDiscoveryManager
          */
         public MdnsDiscoveryManager makeMdnsDiscoveryManager(
@@ -1761,8 +1771,9 @@
          */
         public MdnsAdvertiser makeMdnsAdvertiser(
                 @NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider,
-                @NonNull MdnsAdvertiser.AdvertiserCallback cb, @NonNull SharedLog sharedLog) {
-            return new MdnsAdvertiser(looper, socketProvider, cb, sharedLog);
+                @NonNull MdnsAdvertiser.AdvertiserCallback cb, @NonNull SharedLog sharedLog,
+                MdnsFeatureFlags featureFlags) {
+            return new MdnsAdvertiser(looper, socketProvider, cb, sharedLog, featureFlags);
         }
 
         /**
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
index 913d233..ce13747 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
@@ -78,6 +78,7 @@
     @NonNull private final SharedLog mSharedLog;
     private final Map<String, List<OffloadServiceInfoWrapper>> mInterfaceOffloadServices =
             new ArrayMap<>();
+    private final MdnsFeatureFlags mMdnsFeatureFlags;
 
     /**
      * Dependencies for {@link MdnsAdvertiser}, useful for testing.
@@ -140,22 +141,21 @@
                 mSharedLog.wtf("Register succeeded for unknown registration");
                 return;
             }
+            if (mMdnsFeatureFlags.mIsMdnsOffloadFeatureEnabled) {
+                final String interfaceName = advertiser.getSocketInterfaceName();
+                final List<OffloadServiceInfoWrapper> existingOffloadServiceInfoWrappers =
+                        mInterfaceOffloadServices.computeIfAbsent(interfaceName,
+                                k -> new ArrayList<>());
+                // Remove existing offload services from cache for update.
+                existingOffloadServiceInfoWrappers.removeIf(item -> item.mServiceId == serviceId);
 
-            final String interfaceName = advertiser.getSocketInterfaceName();
-            final List<OffloadServiceInfoWrapper> existingOffloadServiceInfoWrappers =
-                    mInterfaceOffloadServices.computeIfAbsent(
-                            interfaceName, k -> new ArrayList<>());
-            // Remove existing offload services from cache for update.
-            existingOffloadServiceInfoWrappers.removeIf(item -> item.mServiceId == serviceId);
-
-            byte[] rawOffloadPacket = advertiser.getRawOffloadPayload(serviceId);
-            final OffloadServiceInfoWrapper newOffloadServiceInfoWrapper = createOffloadService(
-                    serviceId,
-                    registration,
-                    rawOffloadPacket);
-            existingOffloadServiceInfoWrappers.add(newOffloadServiceInfoWrapper);
-            mCb.onOffloadStartOrUpdate(interfaceName,
-                    newOffloadServiceInfoWrapper.mOffloadServiceInfo);
+                byte[] rawOffloadPacket = advertiser.getRawOffloadPayload(serviceId);
+                final OffloadServiceInfoWrapper newOffloadServiceInfoWrapper = createOffloadService(
+                        serviceId, registration, rawOffloadPacket);
+                existingOffloadServiceInfoWrappers.add(newOffloadServiceInfoWrapper);
+                mCb.onOffloadStartOrUpdate(interfaceName,
+                        newOffloadServiceInfoWrapper.mOffloadServiceInfo);
+            }
 
             // Wait for all current interfaces to be done probing before notifying of success.
             if (any(mAllAdvertisers, (k, a) -> a.isProbing(serviceId))) return;
@@ -188,7 +188,9 @@
                     if (!a.maybeRestartProbingForConflict(serviceId)) {
                         return;
                     }
-                    maybeSendOffloadStop(a.getSocketInterfaceName(), serviceId);
+                    if (mMdnsFeatureFlags.mIsMdnsOffloadFeatureEnabled) {
+                        maybeSendOffloadStop(a.getSocketInterfaceName(), serviceId);
+                    }
                 });
                 return;
             }
@@ -280,12 +282,12 @@
          */
         boolean onAdvertiserDestroyed(@NonNull MdnsInterfaceSocket socket) {
             final MdnsInterfaceAdvertiser removedAdvertiser = mAdvertisers.remove(socket);
-            if (removedAdvertiser != null) {
+            if (mMdnsFeatureFlags.mIsMdnsOffloadFeatureEnabled && removedAdvertiser != null) {
                 final String interfaceName = removedAdvertiser.getSocketInterfaceName();
-                // If the interface is destroyed, stop all hardware offloading on that interface.
+                // If the interface is destroyed, stop all hardware offloading on that
+                // interface.
                 final List<OffloadServiceInfoWrapper> offloadServiceInfoWrappers =
-                        mInterfaceOffloadServices.remove(
-                                interfaceName);
+                        mInterfaceOffloadServices.remove(interfaceName);
                 if (offloadServiceInfoWrappers != null) {
                     for (OffloadServiceInfoWrapper offloadServiceInfoWrapper :
                             offloadServiceInfoWrappers) {
@@ -359,7 +361,9 @@
                 final MdnsInterfaceAdvertiser advertiser = mAdvertisers.valueAt(i);
                 advertiser.removeService(id);
 
-                maybeSendOffloadStop(advertiser.getSocketInterfaceName(), id);
+                if (mMdnsFeatureFlags.mIsMdnsOffloadFeatureEnabled) {
+                    maybeSendOffloadStop(advertiser.getSocketInterfaceName(), id);
+                }
             }
         }
 
@@ -419,25 +423,28 @@
                 return;
             }
             advertiser.updateAddresses(addresses);
-            // Update address should trigger offload packet update.
-            final String interfaceName = advertiser.getSocketInterfaceName();
-            final List<OffloadServiceInfoWrapper> existingOffloadServiceInfoWrappers =
-                    mInterfaceOffloadServices.get(interfaceName);
-            if (existingOffloadServiceInfoWrappers == null) {
-                return;
+
+            if (mMdnsFeatureFlags.mIsMdnsOffloadFeatureEnabled) {
+                // Update address should trigger offload packet update.
+                final String interfaceName = advertiser.getSocketInterfaceName();
+                final List<OffloadServiceInfoWrapper> existingOffloadServiceInfoWrappers =
+                        mInterfaceOffloadServices.get(interfaceName);
+                if (existingOffloadServiceInfoWrappers == null) {
+                    return;
+                }
+                final List<OffloadServiceInfoWrapper> updatedOffloadServiceInfoWrappers =
+                        new ArrayList<>(existingOffloadServiceInfoWrappers.size());
+                for (OffloadServiceInfoWrapper oldWrapper : existingOffloadServiceInfoWrappers) {
+                    OffloadServiceInfoWrapper newWrapper = new OffloadServiceInfoWrapper(
+                            oldWrapper.mServiceId,
+                            oldWrapper.mOffloadServiceInfo.withOffloadPayload(
+                                    advertiser.getRawOffloadPayload(oldWrapper.mServiceId))
+                    );
+                    updatedOffloadServiceInfoWrappers.add(newWrapper);
+                    mCb.onOffloadStartOrUpdate(interfaceName, newWrapper.mOffloadServiceInfo);
+                }
+                mInterfaceOffloadServices.put(interfaceName, updatedOffloadServiceInfoWrappers);
             }
-            final List<OffloadServiceInfoWrapper> updatedOffloadServiceInfoWrappers =
-                    new ArrayList<>(existingOffloadServiceInfoWrappers.size());
-            for (OffloadServiceInfoWrapper oldWrapper : existingOffloadServiceInfoWrappers) {
-                OffloadServiceInfoWrapper newWrapper = new OffloadServiceInfoWrapper(
-                        oldWrapper.mServiceId,
-                        oldWrapper.mOffloadServiceInfo.withOffloadPayload(
-                                advertiser.getRawOffloadPayload(oldWrapper.mServiceId))
-                );
-                updatedOffloadServiceInfoWrappers.add(newWrapper);
-                mCb.onOffloadStartOrUpdate(interfaceName, newWrapper.mOffloadServiceInfo);
-            }
-            mInterfaceOffloadServices.put(interfaceName, updatedOffloadServiceInfoWrappers);
         }
     }
 
@@ -595,20 +602,22 @@
     }
 
     public MdnsAdvertiser(@NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider,
-            @NonNull AdvertiserCallback cb, @NonNull SharedLog sharedLog) {
-        this(looper, socketProvider, cb, new Dependencies(), sharedLog);
+            @NonNull AdvertiserCallback cb, @NonNull SharedLog sharedLog,
+            @NonNull MdnsFeatureFlags mDnsFeatureFlags) {
+        this(looper, socketProvider, cb, new Dependencies(), sharedLog, mDnsFeatureFlags);
     }
 
     @VisibleForTesting
     MdnsAdvertiser(@NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider,
             @NonNull AdvertiserCallback cb, @NonNull Dependencies deps,
-            @NonNull SharedLog sharedLog) {
+            @NonNull SharedLog sharedLog, @NonNull MdnsFeatureFlags mDnsFeatureFlags) {
         mLooper = looper;
         mCb = cb;
         mSocketProvider = socketProvider;
         mDeps = deps;
         mDeviceHostName = deps.generateHostname();
         mSharedLog = sharedLog;
+        mMdnsFeatureFlags = mDnsFeatureFlags;
     }
 
     private void checkThread() {
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsFeatureFlags.java b/service-t/src/com/android/server/connectivity/mdns/MdnsFeatureFlags.java
new file mode 100644
index 0000000..9840409
--- /dev/null
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsFeatureFlags.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.connectivity.mdns;
+
+/**
+ * The class that contains mDNS feature flags;
+ */
+public class MdnsFeatureFlags {
+    /**
+     * The feature flag for control whether the  mDNS offload is enabled or not.
+     */
+    public static final String NSD_FORCE_DISABLE_MDNS_OFFLOAD = "nsd_force_disable_mdns_offload";
+
+    // Flag for offload feature
+    public final boolean mIsMdnsOffloadFeatureEnabled;
+
+    /**
+     * The constructor for {@link MdnsFeatureFlags}.
+     */
+    public MdnsFeatureFlags(boolean isOffloadFeatureEnabled) {
+        mIsMdnsOffloadFeatureEnabled = isOffloadFeatureEnabled;
+    }
+
+
+    /** Returns a {@link Builder} for {@link MdnsFeatureFlags}. */
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /** A builder to create {@link MdnsFeatureFlags}. */
+    public static final class Builder {
+
+        private boolean mIsMdnsOffloadFeatureEnabled;
+
+        /**
+         * The constructor for {@link Builder}.
+         */
+        public Builder() {
+            mIsMdnsOffloadFeatureEnabled = false;
+        }
+
+        /**
+         * Set if the mDNS offload  feature is enabled.
+         */
+        public Builder setIsMdnsOffloadFeatureEnabled(boolean isMdnsOffloadFeatureEnabled) {
+            mIsMdnsOffloadFeatureEnabled = isMdnsOffloadFeatureEnabled;
+            return this;
+        }
+
+        /**
+         * Builds a {@link MdnsFeatureFlags} with the arguments supplied to this builder.
+         */
+        public MdnsFeatureFlags build() {
+            return new MdnsFeatureFlags(mIsMdnsOffloadFeatureEnabled);
+        }
+
+    }
+}
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index 44ed02a..d32a9c0 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -35,17 +35,14 @@
 import static android.net.nsd.NsdManager.FAILURE_BAD_PARAMETERS;
 import static android.net.nsd.NsdManager.FAILURE_INTERNAL_ERROR;
 import static android.net.nsd.NsdManager.FAILURE_OPERATION_NOT_RUNNING;
-
 import static com.android.networkstack.apishim.api33.ConstantsShim.REGISTER_NSD_OFFLOAD_ENGINE;
 import static com.android.server.NsdService.DEFAULT_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF;
 import static com.android.server.NsdService.MdnsListener;
 import static com.android.server.NsdService.NO_TRANSACTION;
 import static com.android.server.NsdService.parseTypeAndSubtype;
 import static com.android.testutils.ContextUtils.mockService;
-
 import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
-
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -229,7 +226,7 @@
         doReturn(mSocketProvider).when(mDeps).makeMdnsSocketProvider(any(), any(), any(), any());
         doReturn(DEFAULT_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF).when(mDeps).getDeviceConfigInt(
                 eq(NsdService.MDNS_CONFIG_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF), anyInt());
-        doReturn(mAdvertiser).when(mDeps).makeMdnsAdvertiser(any(), any(), any(), any());
+        doReturn(mAdvertiser).when(mDeps).makeMdnsAdvertiser(any(), any(), any(), any(), any());
         doReturn(mMetrics).when(mDeps).makeNetworkNsdReportedMetrics(anyBoolean(), anyInt());
         doReturn(mClock).when(mDeps).makeClock();
         doReturn(TEST_TIME_MS).when(mClock).elapsedRealtime();
@@ -1289,7 +1286,7 @@
         // final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local";
         final ArgumentCaptor<MdnsAdvertiser.AdvertiserCallback> cbCaptor =
                 ArgumentCaptor.forClass(MdnsAdvertiser.AdvertiserCallback.class);
-        verify(mDeps).makeMdnsAdvertiser(any(), any(), cbCaptor.capture(), any());
+        verify(mDeps).makeMdnsAdvertiser(any(), any(), cbCaptor.capture(), any(), any());
 
         final NsdServiceInfo regInfo = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE);
         regInfo.setHost(parseNumericAddress("192.0.2.123"));
@@ -1339,7 +1336,7 @@
         // final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local";
         final ArgumentCaptor<MdnsAdvertiser.AdvertiserCallback> cbCaptor =
                 ArgumentCaptor.forClass(MdnsAdvertiser.AdvertiserCallback.class);
-        verify(mDeps).makeMdnsAdvertiser(any(), any(), cbCaptor.capture(), any());
+        verify(mDeps).makeMdnsAdvertiser(any(), any(), cbCaptor.capture(), any(), any());
 
         final NsdServiceInfo regInfo = new NsdServiceInfo(SERVICE_NAME, "invalid_type");
         regInfo.setHost(parseNumericAddress("192.0.2.123"));
@@ -1365,7 +1362,7 @@
         // final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local";
         final ArgumentCaptor<MdnsAdvertiser.AdvertiserCallback> cbCaptor =
                 ArgumentCaptor.forClass(MdnsAdvertiser.AdvertiserCallback.class);
-        verify(mDeps).makeMdnsAdvertiser(any(), any(), cbCaptor.capture(), any());
+        verify(mDeps).makeMdnsAdvertiser(any(), any(), cbCaptor.capture(), any(), any());
 
         final NsdServiceInfo regInfo = new NsdServiceInfo("a".repeat(70), SERVICE_TYPE);
         regInfo.setHost(parseNumericAddress("192.0.2.123"));
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
index 8b10e0b..8eace1c 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
@@ -146,6 +146,7 @@
     private val mockInterfaceAdvertiser1 = mock(MdnsInterfaceAdvertiser::class.java)
     private val mockInterfaceAdvertiser2 = mock(MdnsInterfaceAdvertiser::class.java)
     private val mockDeps = mock(MdnsAdvertiser.Dependencies::class.java)
+    private val flags = MdnsFeatureFlags.newBuilder().setIsMdnsOffloadFeatureEnabled(true).build()
 
     @Before
     fun setUp() {
@@ -183,7 +184,8 @@
 
     @Test
     fun testAddService_OneNetwork() {
-        val advertiser = MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog)
+        val advertiser =
+            MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags)
         postSync { advertiser.addService(SERVICE_ID_1, SERVICE_1, null /* subtype */) }
 
         val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
@@ -242,7 +244,8 @@
 
     @Test
     fun testAddService_AllNetworks() {
-        val advertiser = MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog)
+        val advertiser =
+            MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags)
         postSync { advertiser.addService(SERVICE_ID_1, ALL_NETWORKS_SERVICE, TEST_SUBTYPE) }
 
         val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
@@ -312,7 +315,8 @@
 
     @Test
     fun testAddService_Conflicts() {
-        val advertiser = MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog)
+        val advertiser =
+            MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags)
         postSync { advertiser.addService(SERVICE_ID_1, SERVICE_1, null /* subtype */) }
 
         val oneNetSocketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
@@ -396,7 +400,8 @@
 
     @Test
     fun testRemoveService_whenAllServiceRemoved_thenUpdateHostName() {
-        val advertiser = MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog)
+        val advertiser =
+            MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags)
         verify(mockDeps, times(1)).generateHostname()
         postSync { advertiser.addService(SERVICE_ID_1, SERVICE_1, null /* subtype */) }
         postSync { advertiser.removeService(SERVICE_ID_1) }