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 c3306bd3b9..bd00b706e8 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java @@ -35,6 +35,7 @@ import android.os.Build; import android.os.Looper; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; @@ -93,6 +94,7 @@ public class MdnsAdvertiser { new ArrayMap<>(); private final MdnsFeatureFlags mMdnsFeatureFlags; private final Map mServiceTypeToOffloadPriority; + private final ArraySet mOffloadServiceTypeDenyList; /** * Dependencies for {@link MdnsAdvertiser}, useful for testing. @@ -160,6 +162,16 @@ public class MdnsAdvertiser { return mInterfaceOffloadServices.getOrDefault(interfaceName, Collections.emptyList()); } + private boolean isInOffloadDenyList(@NonNull String serviceType) { + for (int i = 0; i < mOffloadServiceTypeDenyList.size(); ++i) { + final String denyListServiceType = mOffloadServiceTypeDenyList.valueAt(i); + if (DnsUtils.equalsIgnoreDnsCase(serviceType, denyListServiceType)) { + return true; + } + } + return false; + } + private final MdnsInterfaceAdvertiser.Callback mInterfaceAdvertiserCb = new MdnsInterfaceAdvertiser.Callback() { @Override @@ -173,19 +185,25 @@ public class MdnsAdvertiser { if (mMdnsFeatureFlags.mIsMdnsOffloadFeatureEnabled // TODO: Enable offload when the serviceInfo contains a custom host. && TextUtils.isEmpty(registration.getServiceInfo().getHostname())) { - final String interfaceName = advertiser.getSocketInterfaceName(); - final List existingOffloadServiceInfoWrappers = - mInterfaceOffloadServices.computeIfAbsent(interfaceName, - k -> new ArrayList<>()); - // Remove existing offload services from cache for update. - existingOffloadServiceInfoWrappers.removeIf(item -> item.mServiceId == serviceId); + final String serviceType = registration.getServiceInfo().getServiceType(); + if (isInOffloadDenyList(serviceType)) { + mSharedLog.i("Offload denied for service type: " + serviceType); + } else { + final String interfaceName = advertiser.getSocketInterfaceName(); + final List 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. @@ -846,6 +864,8 @@ public class MdnsAdvertiser { final ConnectivityResources res = new ConnectivityResources(context); mServiceTypeToOffloadPriority = parseOffloadPriorityList( res.get().getStringArray(R.array.config_nsdOffloadServicesPriority), sharedLog); + mOffloadServiceTypeDenyList = new ArraySet<>( + res.get().getStringArray(R.array.config_nsdOffloadServicesDenyList)); } private static Map parseOffloadPriorityList( diff --git a/service/ServiceConnectivityResources/res/values/config.xml b/service/ServiceConnectivityResources/res/values/config.xml index 2d3647a67f..1b0f29dcd6 100644 --- a/service/ServiceConnectivityResources/res/values/config.xml +++ b/service/ServiceConnectivityResources/res/values/config.xml @@ -135,6 +135,15 @@ + + + _googlezone._tcp + + false diff --git a/service/ServiceConnectivityResources/res/values/overlayable.xml b/service/ServiceConnectivityResources/res/values/overlayable.xml index 7ac86aacd6..5c0ba7879c 100644 --- a/service/ServiceConnectivityResources/res/values/overlayable.xml +++ b/service/ServiceConnectivityResources/res/values/overlayable.xml @@ -31,6 +31,7 @@ + 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 e6e6ecca7c..087617ad62 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt @@ -99,6 +99,13 @@ private val GOOGLECAST_SERVICE = NsdServiceInfo("TestServiceName", "_googlecast. network = TEST_NETWORK_1 } +private val GOOGLEZONE_SERVICE = NsdServiceInfo("TestServiceName", "_GOOglezone._tcp").apply { + subtypes = setOf(TEST_SUBTYPE) + port = 12345 + hostAddresses = listOf(TEST_ADDR) + network = TEST_NETWORK_1 +} + private val SERVICE_1_SUBTYPE = NsdServiceInfo("TestServiceName", "_advertisertest._tcp").apply { subtypes = setOf(TEST_SUBTYPE) port = 12345 @@ -183,6 +190,10 @@ private val SERVICES_PRIORITY_LIST = arrayOf( "5:_otherprioritytest._tcp" ) +private val SERVICES_DENY_LIST = arrayOf( + "_googlezone._tcp", +) + @RunWith(DevSdkIgnoreRunner::class) @IgnoreUpTo(Build.VERSION_CODES.S_V2) class MdnsAdvertiserTest { @@ -247,6 +258,9 @@ class MdnsAdvertiserTest { doReturn(SERVICES_PRIORITY_LIST).`when`(resources).getStringArray( R.array.config_nsdOffloadServicesPriority ) + doReturn(SERVICES_DENY_LIST).`when`(resources).getStringArray( + R.array.config_nsdOffloadServicesDenyList + ) ConnectivityResources.setResourcesContextForTest(context) } @@ -523,6 +537,44 @@ class MdnsAdvertiserTest { ))) } + @Test + fun testAddService_NoOffloadForServiceTypeInDenyList() { + val advertiser = + MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context) + postSync { + advertiser.addOrUpdateService( + SERVICE_ID_1, + GOOGLEZONE_SERVICE, + DEFAULT_ADVERTISING_OPTION, + TEST_CLIENT_UID_1 + ) + } + val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java) + verify(socketProvider).requestSocket(eq(SERVICE_1.network), socketCbCaptor.capture()) + + val socketCb = socketCbCaptor.value + postSync { socketCb.onSocketCreated(TEST_SOCKETKEY_1, mockSocket1, listOf(TEST_LINKADDR)) } + + val intAdvCbCaptor1 = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java) + verify(mockDeps).makeAdvertiser( + eq(mockSocket1), + eq(listOf(TEST_LINKADDR)), + eq(thread.looper), + any(), + intAdvCbCaptor1.capture(), + eq(TEST_HOSTNAME), + any(), + any() + ) + + doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1) + postSync { + intAdvCbCaptor1.value.onServiceProbingSucceeded(mockInterfaceAdvertiser1, SERVICE_ID_1) + } + + verify(cb, never()).onOffloadStartOrUpdate(eq(TEST_INTERFACE1), any()) + } + @Test fun testAddService_NoSubtypeForGoogleCastOffload() { val advertiser =