Create the MdnsDiscoveryManager

Create the MdnsDiscoveryManager for mdns discovery and resolution
if the feature is enable.

Bug: 254166302
Test: atest FrameworksNetTests CtsNetTestCases
Change-Id: I4d7591b50cb06f0efcc0dde9834b775c513cceff
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 1226eea..b5a10e2 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -18,7 +18,9 @@
 
 import static android.net.ConnectivityManager.NETID_UNSET;
 import static android.net.nsd.NsdManager.MDNS_SERVICE_EVENT;
+import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
@@ -39,6 +41,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -50,7 +53,13 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.net.module.util.DeviceConfigUtils;
 import com.android.net.module.util.PermissionUtils;
+import com.android.server.connectivity.mdns.ExecutorProvider;
+import com.android.server.connectivity.mdns.MdnsDiscoveryManager;
+import com.android.server.connectivity.mdns.MdnsMultinetworkSocketClient;
+import com.android.server.connectivity.mdns.MdnsSocketClientBase;
+import com.android.server.connectivity.mdns.MdnsSocketProvider;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -69,6 +78,7 @@
 public class NsdService extends INsdManager.Stub {
     private static final String TAG = "NsdService";
     private static final String MDNS_TAG = "mDnsConnector";
+    private static final String MDNS_DISCOVERY_MANAGER_VERSION = "mdns_discovery_manager_version";
 
     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     private static final long CLEANUP_DELAY_MS = 10000;
@@ -78,6 +88,12 @@
     private final NsdStateMachine mNsdStateMachine;
     private final MDnsManager mMDnsManager;
     private final MDnsEventCallback mMDnsEventCallback;
+    @Nullable
+    private final MdnsMultinetworkSocketClient mMdnsSocketClient;
+    @Nullable
+    private final MdnsDiscoveryManager mMdnsDiscoveryManager;
+    @Nullable
+    private final MdnsSocketProvider mMdnsSocketProvider;
     // WARNING : Accessing this value in any thread is not safe, it must only be changed in the
     // state machine thread. If change this outside state machine, it will need to introduce
     // synchronization.
@@ -650,12 +666,61 @@
 
     @VisibleForTesting
     NsdService(Context ctx, Handler handler, long cleanupDelayMs) {
+        this(ctx, handler, cleanupDelayMs, new Dependencies());
+    }
+
+    @VisibleForTesting
+    NsdService(Context ctx, Handler handler, long cleanupDelayMs, Dependencies deps) {
         mCleanupDelayMs = cleanupDelayMs;
         mContext = ctx;
         mNsdStateMachine = new NsdStateMachine(TAG, handler);
         mNsdStateMachine.start();
         mMDnsManager = ctx.getSystemService(MDnsManager.class);
         mMDnsEventCallback = new MDnsEventCallback(mNsdStateMachine);
+        if (deps.isMdnsDiscoveryManagerEnabled(ctx)) {
+            mMdnsSocketProvider = deps.makeMdnsSocketProvider(ctx, handler.getLooper());
+            mMdnsSocketClient =
+                    new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider);
+            mMdnsDiscoveryManager =
+                    deps.makeMdnsDiscoveryManager(new ExecutorProvider(), mMdnsSocketClient);
+            handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager));
+        } else {
+            mMdnsSocketProvider = null;
+            mMdnsSocketClient = null;
+            mMdnsDiscoveryManager = null;
+        }
+    }
+
+    /**
+     * Dependencies of NsdService, for injection in tests.
+     */
+    @VisibleForTesting
+    public static class Dependencies {
+        /**
+         * Check whether or not MdnsDiscoveryManager feature is enabled.
+         *
+         * @param context The global context information about an app environment.
+         * @return true if MdnsDiscoveryManager feature is enabled.
+         */
+        public boolean isMdnsDiscoveryManagerEnabled(Context context) {
+            return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY,
+                    MDNS_DISCOVERY_MANAGER_VERSION, false /* defaultEnabled */);
+        }
+
+        /**
+         * @see MdnsDiscoveryManager
+         */
+        public MdnsDiscoveryManager makeMdnsDiscoveryManager(
+                ExecutorProvider executorProvider, MdnsSocketClientBase socketClient) {
+            return new MdnsDiscoveryManager(executorProvider, socketClient);
+        }
+
+        /**
+         * @see MdnsSocketProvider
+         */
+        public MdnsSocketProvider makeMdnsSocketProvider(Context context, Looper looper) {
+            return new MdnsSocketProvider(context, looper);
+        }
     }
 
     public static NsdService create(Context context) {
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index 5808beb..58a1a4f 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -18,6 +18,8 @@
 
 import static android.net.nsd.NsdManager.FAILURE_INTERNAL_ERROR;
 
+import static com.android.testutils.ContextUtils.mockService;
+
 import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
 
@@ -67,6 +69,7 @@
 import androidx.annotation.NonNull;
 import androidx.test.filters.SmallTest;
 
+import com.android.server.NsdService.Dependencies;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
 import com.android.testutils.HandlerUtils;
@@ -112,6 +115,7 @@
     @Mock Context mContext;
     @Mock ContentResolver mResolver;
     @Mock MDnsManager mMockMDnsM;
+    @Mock Dependencies mDeps;
     HandlerThread mThread;
     TestHandler mHandler;
     NsdService mService;
@@ -133,9 +137,7 @@
         mThread.start();
         mHandler = new TestHandler(mThread.getLooper());
         when(mContext.getContentResolver()).thenReturn(mResolver);
-        doReturn(MDnsManager.MDNS_SERVICE).when(mContext)
-                .getSystemServiceName(MDnsManager.class);
-        doReturn(mMockMDnsM).when(mContext).getSystemService(MDnsManager.MDNS_SERVICE);
+        mockService(mContext, MDnsManager.class, MDnsManager.MDNS_SERVICE, mMockMDnsM);
         if (mContext.getSystemService(MDnsManager.class) == null) {
             // Test is using mockito-extended
             doCallRealMethod().when(mContext).getSystemService(MDnsManager.class);
@@ -146,6 +148,7 @@
         doReturn(true).when(mMockMDnsM).discover(anyInt(), anyString(), anyInt());
         doReturn(true).when(mMockMDnsM).resolve(
                 anyInt(), anyString(), anyString(), anyString(), anyInt());
+        doReturn(false).when(mDeps).isMdnsDiscoveryManagerEnabled(any(Context.class));
 
         mService = makeService();
     }
@@ -555,12 +558,27 @@
                 anyInt()/* interfaceIdx */);
     }
 
+    @Test
+    public void testMdnsDiscoveryManagerFeature() {
+        // Create NsdService w/o feature enabled.
+        connectClient(mService);
+        verify(mDeps, never()).makeMdnsDiscoveryManager(any(), any());
+        verify(mDeps, never()).makeMdnsSocketProvider(any(), any());
+
+        // Create NsdService again w/ feature enabled.
+        doReturn(true).when(mDeps).isMdnsDiscoveryManagerEnabled(any(Context.class));
+        makeService();
+        verify(mDeps).makeMdnsDiscoveryManager(any(), any());
+        verify(mDeps).makeMdnsSocketProvider(any(), any());
+    }
+
+
     private void waitForIdle() {
         HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
     }
 
     NsdService makeService() {
-        final NsdService service = new NsdService(mContext, mHandler, CLEANUP_DELAY_MS) {
+        final NsdService service = new NsdService(mContext, mHandler, CLEANUP_DELAY_MS, mDeps) {
             @Override
             public INsdServiceConnector connect(INsdManagerCallback baseCb) {
                 // Wrap the callback in a transparent mock, to mock asBinder returning a