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
This commit is contained in:
Paul Hu
2023-01-12 13:42:07 +08:00
parent 03a51d5674
commit 4bd98ef68e
2 changed files with 87 additions and 4 deletions

View File

@@ -18,7 +18,9 @@ package com.android.server;
import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.nsd.NsdManager.MDNS_SERVICE_EVENT; 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.Context;
import android.content.Intent; import android.content.Intent;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
@@ -39,6 +41,7 @@ import android.net.nsd.NsdServiceInfo;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
@@ -50,7 +53,13 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.State; import com.android.internal.util.State;
import com.android.internal.util.StateMachine; import com.android.internal.util.StateMachine;
import com.android.net.module.util.DeviceConfigUtils;
import com.android.net.module.util.PermissionUtils; 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.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -69,6 +78,7 @@ import java.util.HashMap;
public class NsdService extends INsdManager.Stub { public class NsdService extends INsdManager.Stub {
private static final String TAG = "NsdService"; private static final String TAG = "NsdService";
private static final String MDNS_TAG = "mDnsConnector"; 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 boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
private static final long CLEANUP_DELAY_MS = 10000; private static final long CLEANUP_DELAY_MS = 10000;
@@ -78,6 +88,12 @@ public class NsdService extends INsdManager.Stub {
private final NsdStateMachine mNsdStateMachine; private final NsdStateMachine mNsdStateMachine;
private final MDnsManager mMDnsManager; private final MDnsManager mMDnsManager;
private final MDnsEventCallback mMDnsEventCallback; 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 // 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 // state machine thread. If change this outside state machine, it will need to introduce
// synchronization. // synchronization.
@@ -650,12 +666,61 @@ public class NsdService extends INsdManager.Stub {
@VisibleForTesting @VisibleForTesting
NsdService(Context ctx, Handler handler, long cleanupDelayMs) { 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; mCleanupDelayMs = cleanupDelayMs;
mContext = ctx; mContext = ctx;
mNsdStateMachine = new NsdStateMachine(TAG, handler); mNsdStateMachine = new NsdStateMachine(TAG, handler);
mNsdStateMachine.start(); mNsdStateMachine.start();
mMDnsManager = ctx.getSystemService(MDnsManager.class); mMDnsManager = ctx.getSystemService(MDnsManager.class);
mMDnsEventCallback = new MDnsEventCallback(mNsdStateMachine); 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) { public static NsdService create(Context context) {

View File

@@ -18,6 +18,8 @@ package com.android.server;
import static android.net.nsd.NsdManager.FAILURE_INTERNAL_ERROR; 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.DisableCompatChanges;
import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
@@ -67,6 +69,7 @@ import android.os.Message;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.server.NsdService.Dependencies;
import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner; import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.HandlerUtils; import com.android.testutils.HandlerUtils;
@@ -112,6 +115,7 @@ public class NsdServiceTest {
@Mock Context mContext; @Mock Context mContext;
@Mock ContentResolver mResolver; @Mock ContentResolver mResolver;
@Mock MDnsManager mMockMDnsM; @Mock MDnsManager mMockMDnsM;
@Mock Dependencies mDeps;
HandlerThread mThread; HandlerThread mThread;
TestHandler mHandler; TestHandler mHandler;
NsdService mService; NsdService mService;
@@ -133,9 +137,7 @@ public class NsdServiceTest {
mThread.start(); mThread.start();
mHandler = new TestHandler(mThread.getLooper()); mHandler = new TestHandler(mThread.getLooper());
when(mContext.getContentResolver()).thenReturn(mResolver); when(mContext.getContentResolver()).thenReturn(mResolver);
doReturn(MDnsManager.MDNS_SERVICE).when(mContext) mockService(mContext, MDnsManager.class, MDnsManager.MDNS_SERVICE, mMockMDnsM);
.getSystemServiceName(MDnsManager.class);
doReturn(mMockMDnsM).when(mContext).getSystemService(MDnsManager.MDNS_SERVICE);
if (mContext.getSystemService(MDnsManager.class) == null) { if (mContext.getSystemService(MDnsManager.class) == null) {
// Test is using mockito-extended // Test is using mockito-extended
doCallRealMethod().when(mContext).getSystemService(MDnsManager.class); doCallRealMethod().when(mContext).getSystemService(MDnsManager.class);
@@ -146,6 +148,7 @@ public class NsdServiceTest {
doReturn(true).when(mMockMDnsM).discover(anyInt(), anyString(), anyInt()); doReturn(true).when(mMockMDnsM).discover(anyInt(), anyString(), anyInt());
doReturn(true).when(mMockMDnsM).resolve( doReturn(true).when(mMockMDnsM).resolve(
anyInt(), anyString(), anyString(), anyString(), anyInt()); anyInt(), anyString(), anyString(), anyString(), anyInt());
doReturn(false).when(mDeps).isMdnsDiscoveryManagerEnabled(any(Context.class));
mService = makeService(); mService = makeService();
} }
@@ -555,12 +558,27 @@ public class NsdServiceTest {
anyInt()/* interfaceIdx */); 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() { private void waitForIdle() {
HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS); HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
} }
NsdService makeService() { NsdService makeService() {
final NsdService service = new NsdService(mContext, mHandler, CLEANUP_DELAY_MS) { final NsdService service = new NsdService(mContext, mHandler, CLEANUP_DELAY_MS, mDeps) {
@Override @Override
public INsdServiceConnector connect(INsdManagerCallback baseCb) { public INsdServiceConnector connect(INsdManagerCallback baseCb) {
// Wrap the callback in a transparent mock, to mock asBinder returning a // Wrap the callback in a transparent mock, to mock asBinder returning a