Merge changes from topic "MDns_AIDL"

* changes:
  Use MDns aidl on NsdService
  Add MDnsManager
This commit is contained in:
Paul Hu
2022-04-07 02:06:35 +00:00
committed by Gerrit Code Review
8 changed files with 421 additions and 344 deletions

View File

@@ -19,10 +19,12 @@ package com.android.server;
import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -36,6 +38,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.net.nsd.INsdManagerCallback;
import android.net.nsd.INsdServiceConnector;
import android.net.nsd.MDnsManager;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.os.Binder;
@@ -49,9 +52,6 @@ import android.os.Message;
import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
import com.android.server.NsdService.DaemonConnection;
import com.android.server.NsdService.DaemonConnectionSupplier;
import com.android.server.NsdService.NativeCallbackReceiver;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.HandlerUtils;
@@ -63,10 +63,8 @@ import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.AdditionalAnswers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import java.util.LinkedList;
import java.util.Queue;
@@ -92,8 +90,7 @@ public class NsdServiceTest {
public TestRule compatChangeRule = new PlatformCompatChangeRule();
@Mock Context mContext;
@Mock ContentResolver mResolver;
NativeCallbackReceiver mDaemonCallback;
@Spy DaemonConnection mDaemon = new DaemonConnection(mDaemonCallback);
@Mock MDnsManager mMockMDnsM;
HandlerThread mThread;
TestHandler mHandler;
@@ -112,9 +109,17 @@ public class NsdServiceTest {
MockitoAnnotations.initMocks(this);
mThread = new HandlerThread("mock-service-handler");
mThread.start();
doReturn(true).when(mDaemon).execute(any());
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);
doReturn(true).when(mMockMDnsM).registerService(
anyInt(), anyString(), anyString(), anyInt(), any(), anyInt());
doReturn(true).when(mMockMDnsM).stopOperation(anyInt());
doReturn(true).when(mMockMDnsM).discover(anyInt(), anyString(), anyInt());
doReturn(true).when(mMockMDnsM).resolve(
anyInt(), anyString(), anyString(), anyString(), anyInt());
}
@After
@@ -135,24 +140,25 @@ public class NsdServiceTest {
waitForIdle();
final INsdManagerCallback cb1 = getCallback();
final IBinder.DeathRecipient deathRecipient1 = verifyLinkToDeath(cb1);
verify(mDaemon, times(1)).maybeStart();
verifyDaemonCommands("start-service");
verify(mMockMDnsM, times(1)).registerEventListener(any());
verify(mMockMDnsM, times(1)).startDaemon();
connectClient(service);
waitForIdle();
final INsdManagerCallback cb2 = getCallback();
final IBinder.DeathRecipient deathRecipient2 = verifyLinkToDeath(cb2);
verify(mDaemon, times(1)).maybeStart();
// Daemon has been started, it should not try to start it again.
verify(mMockMDnsM, times(1)).registerEventListener(any());
verify(mMockMDnsM, times(1)).startDaemon();
deathRecipient1.binderDied();
// Still 1 client remains, daemon shouldn't be stopped.
waitForIdle();
verify(mDaemon, never()).maybeStop();
verify(mMockMDnsM, never()).stopDaemon();
deathRecipient2.binderDied();
// All clients are disconnected, the daemon should be stopped.
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
verifyDaemonCommands("stop-service");
}
@Test
@@ -160,28 +166,30 @@ public class NsdServiceTest {
public void testNoDaemonStartedWhenClientsConnect() throws Exception {
final NsdService service = makeService();
// Creating an NsdManager will not cause any cmds executed, which means
// no daemon is started.
// Creating an NsdManager will not cause daemon startup.
connectClient(service);
waitForIdle();
verify(mDaemon, never()).execute(any());
verify(mMockMDnsM, never()).registerEventListener(any());
verify(mMockMDnsM, never()).startDaemon();
final INsdManagerCallback cb1 = getCallback();
final IBinder.DeathRecipient deathRecipient1 = verifyLinkToDeath(cb1);
// Creating another NsdManager will not cause any cmds executed.
// Creating another NsdManager will not cause daemon startup either.
connectClient(service);
waitForIdle();
verify(mDaemon, never()).execute(any());
verify(mMockMDnsM, never()).registerEventListener(any());
verify(mMockMDnsM, never()).startDaemon();
final INsdManagerCallback cb2 = getCallback();
final IBinder.DeathRecipient deathRecipient2 = verifyLinkToDeath(cb2);
// If there is no active request, try to clean up the daemon
// every time the client disconnects.
// If there is no active request, try to clean up the daemon but should not do it because
// daemon has not been started.
deathRecipient1.binderDied();
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
reset(mDaemon);
verify(mMockMDnsM, never()).unregisterEventListener(any());
verify(mMockMDnsM, never()).stopDaemon();
deathRecipient2.binderDied();
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
verify(mMockMDnsM, never()).unregisterEventListener(any());
verify(mMockMDnsM, never()).stopDaemon();
}
private IBinder.DeathRecipient verifyLinkToDeath(INsdManagerCallback cb)
@@ -200,8 +208,8 @@ public class NsdServiceTest {
waitForIdle();
final INsdManagerCallback cb1 = getCallback();
final IBinder.DeathRecipient deathRecipient = verifyLinkToDeath(cb1);
verify(mDaemon, never()).maybeStart();
verify(mDaemon, never()).execute(any());
verify(mMockMDnsM, never()).registerEventListener(any());
verify(mMockMDnsM, never()).startDaemon();
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
request.setPort(2201);
@@ -210,29 +218,31 @@ public class NsdServiceTest {
NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
client.registerService(request, PROTOCOL, listener1);
waitForIdle();
verify(mDaemon, times(1)).maybeStart();
verifyDaemonCommands("start-service", "register 2 a_name a_type 2201");
verify(mMockMDnsM, times(1)).registerEventListener(any());
verify(mMockMDnsM, times(1)).startDaemon();
verify(mMockMDnsM, times(1)).registerService(
eq(2), eq("a_name"), eq("a_type"), eq(2201), any(), eq(0));
// Client discovery request
NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
client.discoverServices("a_type", PROTOCOL, listener2);
waitForIdle();
verify(mDaemon, times(1)).maybeStart();
verifyDaemonCommand("discover 3 a_type 0");
verify(mMockMDnsM, times(1)).discover(eq(3), eq("a_type"), eq(0));
// Client resolve request
NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
client.resolveService(request, listener3);
waitForIdle();
verify(mDaemon, times(1)).maybeStart();
verifyDaemonCommand("resolve 4 a_name a_type local. 0");
verify(mMockMDnsM, times(1)).resolve(
eq(4), eq("a_name"), eq("a_type"), eq("local."), eq(0));
// Client disconnects, stop the daemon after CLEANUP_DELAY_MS.
deathRecipient.binderDied();
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
// checks that request are cleaned
verifyDaemonCommands("stop-register 2", "stop-discover 3",
"stop-resolve 4", "stop-service");
verify(mMockMDnsM, times(1)).stopOperation(eq(2));
verify(mMockMDnsM, times(1)).stopOperation(eq(3));
verify(mMockMDnsM, times(1)).stopOperation(eq(4));
}
@Test
@@ -246,20 +256,23 @@ public class NsdServiceTest {
NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
client.registerService(request, PROTOCOL, listener1);
waitForIdle();
verify(mDaemon, times(1)).maybeStart();
verify(mMockMDnsM, times(1)).registerEventListener(any());
verify(mMockMDnsM, times(1)).startDaemon();
final INsdManagerCallback cb1 = getCallback();
final IBinder.DeathRecipient deathRecipient = verifyLinkToDeath(cb1);
verifyDaemonCommands("start-service", "register 2 a_name a_type 2201");
verify(mMockMDnsM, times(1)).registerService(
eq(2), eq("a_name"), eq("a_type"), eq(2201), any(), eq(0));
client.unregisterService(listener1);
verifyDaemonCommand("stop-register 2");
waitForIdle();
verify(mMockMDnsM, times(1)).stopOperation(eq(2));
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
verifyDaemonCommand("stop-service");
reset(mDaemon);
reset(mMockMDnsM);
deathRecipient.binderDied();
// Client disconnects, after CLEANUP_DELAY_MS, maybeStop the daemon.
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
// Client disconnects, daemon should not be stopped after CLEANUP_DELAY_MS.
verify(mMockMDnsM, never()).unregisterEventListener(any());
verify(mMockMDnsM, never()).stopDaemon();
}
private void waitForIdle() {
@@ -267,11 +280,7 @@ public class NsdServiceTest {
}
NsdService makeService() {
DaemonConnectionSupplier supplier = (callback) -> {
mDaemonCallback = callback;
return mDaemon;
};
final NsdService service = new NsdService(mContext, mHandler, supplier, CLEANUP_DELAY_MS) {
final NsdService service = new NsdService(mContext, mHandler, CLEANUP_DELAY_MS) {
@Override
public INsdServiceConnector connect(INsdManagerCallback baseCb) {
// Wrap the callback in a transparent mock, to mock asBinder returning a
@@ -285,7 +294,6 @@ public class NsdServiceTest {
return super.connect(cb);
}
};
verify(mDaemon, never()).execute(any(String.class));
return service;
}
@@ -297,34 +305,15 @@ public class NsdServiceTest {
return new NsdManager(mContext, service);
}
void verifyDelayMaybeStopDaemon(long cleanupDelayMs) {
void verifyDelayMaybeStopDaemon(long cleanupDelayMs) throws Exception {
waitForIdle();
// Stop daemon shouldn't be called immediately.
verify(mDaemon, never()).maybeStop();
verify(mMockMDnsM, never()).unregisterEventListener(any());
verify(mMockMDnsM, never()).stopDaemon();
// Clean up the daemon after CLEANUP_DELAY_MS.
verify(mDaemon, timeout(cleanupDelayMs + TIMEOUT_MS)).maybeStop();
}
void verifyDaemonCommands(String... wants) {
verifyDaemonCommand(String.join(" ", wants), wants.length);
}
void verifyDaemonCommand(String want) {
verifyDaemonCommand(want, 1);
}
void verifyDaemonCommand(String want, int n) {
waitForIdle();
final ArgumentCaptor<Object> argumentsCaptor = ArgumentCaptor.forClass(Object.class);
verify(mDaemon, times(n)).execute(argumentsCaptor.capture());
String got = "";
for (Object o : argumentsCaptor.getAllValues()) {
got += o + " ";
}
assertEquals(want, got.trim());
// rearm deamon for next command verification
reset(mDaemon);
doReturn(true).when(mDaemon).execute(any());
verify(mMockMDnsM, timeout(cleanupDelayMs + TIMEOUT_MS)).unregisterEventListener(any());
verify(mMockMDnsM, timeout(cleanupDelayMs + TIMEOUT_MS)).stopDaemon();
}
public static class TestHandler extends Handler {