Merge "Add config_nsdOffloadServicesDenyList to NsdService" into main am: 648d01b9f4

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/3513113

Change-Id: I55cc54d6d1778c5d2248817bcfdc5be020b1e3d6
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Yuyang Huang 2025-03-06 06:37:43 -08:00 • committed by Automerger Merge Worker
commit 747dd1deb3
4 changed files with 95 additions and 13 deletions

View file

@ -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<String, Integer> mServiceTypeToOffloadPriority;
private final ArraySet<String> 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<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 @@ 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<String, Integer> parseOffloadPriorityList(

View file

@ -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>

View file

@ -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"/>

View file

@ -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 =