Merge "Add config_nsdOffloadServicesDenyList to NsdService" into main
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 c3306bd..bd00b70 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.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 @@
new ArrayMap<>();
private final MdnsFeatureFlags mMdnsFeatureFlags;
private final Map<String, Integer> mServiceTypeToOffloadPriority;
+ private final ArraySet<String> mOffloadServiceTypeDenyList;
/**
* Dependencies for {@link MdnsAdvertiser}, useful for testing.
@@ -160,6 +162,16 @@
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 @@
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<OffloadServiceInfoWrapper> 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<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.
@@ -846,6 +864,8 @@
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<String, Integer> parseOffloadPriorityList(
diff --git a/service/ServiceConnectivityResources/res/values/config.xml b/service/ServiceConnectivityResources/res/values/config.xml
index 2d3647a..1b0f29d 100644
--- a/service/ServiceConnectivityResources/res/values/config.xml
+++ b/service/ServiceConnectivityResources/res/values/config.xml
@@ -135,6 +135,15 @@
<string-array translatable="false" name="config_nsdOffloadServicesPriority">
</string-array>
+ <!-- An array of service types that shouldn't be offloaded via NsdManager#registerOffloadEngine.
+ Format is [service type], for example: "_testservice._tcp"
+ Due to limited RAM in hardware offload, we prioritize user-impacting services.
+ _googlezone._tcp, an internal Googlecast service, was therefore blocked.
+ -->
+ <string-array name="config_nsdOffloadServicesDenyList" translatable="false">
+ <item>_googlezone._tcp</item>
+ </string-array>
+
<!-- Whether to use an ongoing notification for signing in to captive portals, instead of a
notification that can be dismissed. -->
<bool name="config_ongoingSignInNotification">false</bool>
diff --git a/service/ServiceConnectivityResources/res/values/overlayable.xml b/service/ServiceConnectivityResources/res/values/overlayable.xml
index 7ac86aa..5c0ba78 100644
--- a/service/ServiceConnectivityResources/res/values/overlayable.xml
+++ b/service/ServiceConnectivityResources/res/values/overlayable.xml
@@ -31,6 +31,7 @@
<item type="integer" name="config_networkWakeupPacketMask"/>
<item type="integer" name="config_networkNotifySwitchType"/>
<item type="array" name="config_networkNotifySwitches"/>
+ <item type="array" name="config_nsdOffloadServicesDenyList"/>
<item type="array" name="config_nsdOffloadServicesPriority"/>
<item type="bool" name="config_ongoingSignInNotification"/>
<item type="bool" name="config_autoCancelNetworkNotifications"/>
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 e6e6ecc..087617a 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 @@
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 @@
"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 @@
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)
}
@@ -524,6 +538,44 @@
}
@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 =
MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)