Merge "Log usage of legacy tether API with Wifi" into main
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
index ef0d0ea..d16a760 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
@@ -221,7 +221,7 @@
mDataStore.setProperty(Config.VERSION, version);
// Reset the number of consecutive log list failure updates back to zero.
- mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* value= */ 0L);
+ mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* value= */ 0);
mDataStore.store();
} else {
if (updateFailureCount()) {
@@ -244,11 +244,11 @@
* @return whether the failure count exceeds the threshold and should be logged.
*/
private boolean updateFailureCount() {
- long failure_count = mDataStore.getPropertyLong(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L);
- long new_failure_count = failure_count + 1L;
+ int failure_count = mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0);
+ int new_failure_count = failure_count + 1;
- mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, new_failure_count);
+ mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, new_failure_count);
mDataStore.store();
boolean shouldReport = new_failure_count >= Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD;
diff --git a/networksecurity/service/src/com/android/server/net/ct/Config.java b/networksecurity/service/src/com/android/server/net/ct/Config.java
index edd6a80..aafee60 100644
--- a/networksecurity/service/src/com/android/server/net/ct/Config.java
+++ b/networksecurity/service/src/com/android/server/net/ct/Config.java
@@ -63,5 +63,5 @@
static final String URL_PUBLIC_KEY = URL_PREFIX + "log_list.pub";
// Threshold amounts
- static final long LOG_LIST_UPDATE_FAILURE_THRESHOLD = 10L;
+ static final int LOG_LIST_UPDATE_FAILURE_THRESHOLD = 10;
}
diff --git a/networksecurity/service/src/com/android/server/net/ct/DataStore.java b/networksecurity/service/src/com/android/server/net/ct/DataStore.java
index cd6aebf..3779269 100644
--- a/networksecurity/service/src/com/android/server/net/ct/DataStore.java
+++ b/networksecurity/service/src/com/android/server/net/ct/DataStore.java
@@ -64,4 +64,12 @@
Object setPropertyLong(String key, long value) {
return setProperty(key, Long.toString(value));
}
+
+ int getPropertyInt(String key, int defaultValue) {
+ return Optional.ofNullable(getProperty(key)).map(Integer::parseInt).orElse(defaultValue);
+ }
+
+ Object setPropertyInt(String key, int value) {
+ return setProperty(key, Integer.toString(value));
+ }
}
diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
index 5c4a4e5..4748043 100644
--- a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
+++ b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
@@ -190,7 +190,7 @@
throws Exception {
long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
// Set the failure count to just below the threshold
- mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+ mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
setFailedDownload(
publicKeyId, // Failure cases where we give up on the download.
@@ -200,8 +200,8 @@
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
- assertThat(mDataStore.getPropertyLong(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
+ assertThat(mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
// TODO(378626065): Verify logged failure via statsd.
}
@@ -211,7 +211,7 @@
throws Exception {
long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
// Set the failure count to just below the threshold
- mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
+ mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
setFailedDownload(
publicKeyId, // Failure cases where we give up on the download.
DownloadManager.ERROR_INSUFFICIENT_SPACE,
@@ -220,8 +220,8 @@
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
- assertThat(mDataStore.getPropertyLong(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
+ assertThat(mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(1);
// TODO(378626065): Verify no failure logged via statsd.
}
@@ -260,7 +260,7 @@
throws Exception {
long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
// Set the failure count to just below the threshold
- mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+ mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
setFailedDownload(
metadataId,
@@ -271,8 +271,8 @@
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
- assertThat(mDataStore.getPropertyLong(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
+ assertThat(mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
// TODO(378626065): Verify logged failure via statsd.
}
@@ -282,7 +282,7 @@
throws Exception {
long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
// Set the failure count to just below the threshold
- mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
+ mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
setFailedDownload(
metadataId,
// Failure cases where we give up on the download.
@@ -292,8 +292,8 @@
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
- assertThat(mDataStore.getPropertyLong(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
+ assertThat(mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(1);
// TODO(378626065): Verify no failure logged via statsd.
}
@@ -342,7 +342,7 @@
throws Exception {
long contentId = mCertificateTransparencyDownloader.startContentDownload();
// Set the failure count to just below the threshold
- mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+ mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
setFailedDownload(
contentId,
@@ -353,8 +353,8 @@
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
- assertThat(mDataStore.getPropertyLong(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
+ assertThat(mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
// TODO(378626065): Verify logged failure via statsd.
}
@@ -364,7 +364,7 @@
throws Exception {
long contentId = mCertificateTransparencyDownloader.startContentDownload();
// Set the failure count to just below the threshold
- mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
+ mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
setFailedDownload(
contentId,
// Failure cases where we give up on the download.
@@ -374,8 +374,8 @@
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
- assertThat(mDataStore.getPropertyLong(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
+ assertThat(mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(1);
// TODO(378626065): Verify no failure logged via statsd.
}
@@ -413,7 +413,7 @@
long contentId = mCertificateTransparencyDownloader.startContentDownload();
setSuccessfulDownload(contentId, logListFile);
// Set the failure count to just below the threshold
- mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+ mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
when(mCertificateTransparencyInstaller.install(
eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
@@ -422,8 +422,8 @@
mCertificateTransparencyDownloader.onReceive(
mContext, makeDownloadCompleteIntent(contentId));
- assertThat(mDataStore.getPropertyLong(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
+ assertThat(mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
// TODO(378626065): Verify logged failure via statsd.
}
@@ -440,7 +440,7 @@
long contentId = mCertificateTransparencyDownloader.startContentDownload();
setSuccessfulDownload(contentId, logListFile);
// Set the failure count to just below the threshold
- mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
+ mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
when(mCertificateTransparencyInstaller.install(
eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
.thenReturn(false);
@@ -448,8 +448,8 @@
mCertificateTransparencyDownloader.onReceive(
mContext, makeDownloadCompleteIntent(contentId));
- assertThat(mDataStore.getPropertyLong(
- Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
+ assertThat(mDataStore.getPropertyInt(
+ Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(1);
// TODO(378626065): Verify no failure logged via statsd.
}
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 0adb290..fe1db3b 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -1943,6 +1943,8 @@
.setCachedServicesRetentionTime(mDeps.getDeviceConfigPropertyInt(
MdnsFeatureFlags.NSD_CACHED_SERVICES_RETENTION_TIME,
MdnsFeatureFlags.DEFAULT_CACHED_SERVICES_RETENTION_TIME_MILLISECONDS))
+ .setIsShortHostnamesEnabled(mDeps.isTetheringFeatureNotChickenedOut(
+ mContext, MdnsFeatureFlags.NSD_USE_SHORT_HOSTNAMES))
.setOverrideProvider(new MdnsFeatureFlags.FlagOverrideProvider() {
@Override
public boolean isForceEnabledForTest(@NonNull String flag) {
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 9c52eca..54f7ca3 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
@@ -46,6 +46,7 @@
import com.android.server.connectivity.ConnectivityResources;
import com.android.server.connectivity.mdns.util.MdnsUtils;
+import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -117,7 +118,7 @@
* Generates a unique hostname to be used by the device.
*/
@NonNull
- public String[] generateHostname() {
+ public String[] generateHostname(boolean useShortFormat) {
// Generate a very-probably-unique hostname. This allows minimizing possible conflicts
// to the point that probing for it is no longer necessary (as per RFC6762 8.1 last
// paragraph), and does not leak more information than what could already be obtained by
@@ -127,10 +128,24 @@
// Having a different hostname per interface is an acceptable option as per RFC6762 14.
// This hostname will change every time the interface is reconnected, so this does not
// allow tracking the device.
- // TODO: consider deriving a hostname from other sources, such as the IPv6 addresses
- // (reusing the same privacy-protecting mechanics).
- return new String[] {
- "Android_" + UUID.randomUUID().toString().replace("-", ""), LOCAL_TLD };
+ if (useShortFormat) {
+ // A short hostname helps reduce the size of APF mDNS filtering programs, and
+ // is necessary for compatibility with some Matter 1.0 devices which assumed
+ // 16 characters is the maximum length.
+ // Generate a hostname matching Android_[0-9A-Z]{8}, which has 36^8 possibilities.
+ // Even with 100 devices advertising the probability of collision is around 2E-9,
+ // which is negligible.
+ final SecureRandom sr = new SecureRandom();
+ final String allowedChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ final StringBuilder sb = new StringBuilder(8);
+ for (int i = 0; i < 8; i++) {
+ sb.append(allowedChars.charAt(sr.nextInt(allowedChars.length())));
+ }
+ return new String[]{ "Android_" + sb.toString(), LOCAL_TLD };
+ } else {
+ return new String[]{
+ "Android_" + UUID.randomUUID().toString().replace("-", ""), LOCAL_TLD};
+ }
}
}
@@ -825,7 +840,7 @@
mCb = cb;
mSocketProvider = socketProvider;
mDeps = deps;
- mDeviceHostName = deps.generateHostname();
+ mDeviceHostName = deps.generateHostname(mDnsFeatureFlags.isShortHostnamesEnabled());
mSharedLog = sharedLog;
mMdnsFeatureFlags = mDnsFeatureFlags;
final ConnectivityResources res = new ConnectivityResources(context);
@@ -943,7 +958,7 @@
mRegistrations.remove(id);
// Regenerates host name when registrations removed.
if (mRegistrations.size() == 0) {
- mDeviceHostName = mDeps.generateHostname();
+ mDeviceHostName = mDeps.generateHostname(mMdnsFeatureFlags.isShortHostnamesEnabled());
}
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsFeatureFlags.java b/service-t/src/com/android/server/connectivity/mdns/MdnsFeatureFlags.java
index c4a9110..1cf5e4d 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsFeatureFlags.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsFeatureFlags.java
@@ -81,6 +81,12 @@
public static final String NSD_CACHED_SERVICES_REMOVAL = "nsd_cached_services_removal";
/**
+ * A feature flag to control whether to use shorter (16 characters + .local) hostnames, instead
+ * of Android_[32 characters] hostnames.
+ */
+ public static final String NSD_USE_SHORT_HOSTNAMES = "nsd_use_short_hostnames";
+
+ /**
* A feature flag to control the retention time for cached services.
*
* <p> Making the retention time configurable allows for testing and future adjustments.
@@ -130,6 +136,9 @@
// Flag for accurate delay callback
public final boolean mIsAccurateDelayCallbackEnabled;
+ // Flag to use shorter (16 characters + .local) hostnames
+ public final boolean mIsShortHostnamesEnabled;
+
@Nullable
private final FlagOverrideProvider mOverrideProvider;
@@ -225,6 +234,10 @@
NSD_CACHED_SERVICES_RETENTION_TIME, (int) mCachedServicesRetentionTime);
}
+ public boolean isShortHostnamesEnabled() {
+ return mIsShortHostnamesEnabled || isForceEnabledForTest(NSD_USE_SHORT_HOSTNAMES);
+ }
+
/**
* Indicates whether {@link #NSD_ACCURATE_DELAY_CALLBACK} is enabled, including for testing.
*/
@@ -248,6 +261,7 @@
boolean isCachedServicesRemovalEnabled,
long cachedServicesRetentionTime,
boolean isAccurateDelayCallbackEnabled,
+ boolean isShortHostnamesEnabled,
@Nullable FlagOverrideProvider overrideProvider) {
mIsMdnsOffloadFeatureEnabled = isOffloadFeatureEnabled;
mIncludeInetAddressRecordsInProbing = includeInetAddressRecordsInProbing;
@@ -261,6 +275,7 @@
mIsCachedServicesRemovalEnabled = isCachedServicesRemovalEnabled;
mCachedServicesRetentionTime = cachedServicesRetentionTime;
mIsAccurateDelayCallbackEnabled = isAccurateDelayCallbackEnabled;
+ mIsShortHostnamesEnabled = isShortHostnamesEnabled;
mOverrideProvider = overrideProvider;
}
@@ -285,6 +300,7 @@
private boolean mIsCachedServicesRemovalEnabled;
private long mCachedServicesRetentionTime;
private boolean mIsAccurateDelayCallbackEnabled;
+ private boolean mIsShortHostnamesEnabled;
private FlagOverrideProvider mOverrideProvider;
/**
@@ -303,6 +319,7 @@
mIsCachedServicesRemovalEnabled = false;
mCachedServicesRetentionTime = DEFAULT_CACHED_SERVICES_RETENTION_TIME_MILLISECONDS;
mIsAccurateDelayCallbackEnabled = false;
+ mIsShortHostnamesEnabled = true; // Default enabled.
mOverrideProvider = null;
}
@@ -439,6 +456,16 @@
}
/**
+ * Set whether the short hostnames feature is enabled.
+ *
+ * @see #NSD_USE_SHORT_HOSTNAMES
+ */
+ public Builder setIsShortHostnamesEnabled(boolean isShortHostnamesEnabled) {
+ mIsShortHostnamesEnabled = isShortHostnamesEnabled;
+ return this;
+ }
+
+ /**
* Builds a {@link MdnsFeatureFlags} with the arguments supplied to this builder.
*/
public MdnsFeatureFlags build() {
@@ -454,6 +481,7 @@
mIsCachedServicesRemovalEnabled,
mCachedServicesRetentionTime,
mIsAccurateDelayCallbackEnabled,
+ mIsShortHostnamesEnabled,
mOverrideProvider);
}
}
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 df48f6c..ba62114 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
@@ -42,17 +42,20 @@
import java.util.Objects
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit
+import kotlin.test.assertTrue
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.argThat
import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.doCallRealMethod
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
@@ -185,12 +188,12 @@
@Before
fun setUp() {
thread.start()
- doReturn(TEST_HOSTNAME).`when`(mockDeps).generateHostname()
+ doReturn(TEST_HOSTNAME).`when`(mockDeps).generateHostname(anyBoolean())
doReturn(mockInterfaceAdvertiser1).`when`(mockDeps).makeAdvertiser(eq(mockSocket1),
- any(), any(), any(), any(), eq(TEST_HOSTNAME), any(), any()
+ any(), any(), any(), any(), any(), any(), any()
)
doReturn(mockInterfaceAdvertiser2).`when`(mockDeps).makeAdvertiser(eq(mockSocket2),
- any(), any(), any(), any(), eq(TEST_HOSTNAME), any(), any()
+ any(), any(), any(), any(), any(), any(), any()
)
doReturn(true).`when`(mockInterfaceAdvertiser1).isProbing(anyInt())
doReturn(true).`when`(mockInterfaceAdvertiser2).isProbing(anyInt())
@@ -578,11 +581,59 @@
fun testRemoveService_whenAllServiceRemoved_thenUpdateHostName() {
val advertiser =
MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)
- verify(mockDeps, times(1)).generateHostname()
+ verify(mockDeps, times(1)).generateHostname(anyBoolean())
postSync { advertiser.addOrUpdateService(SERVICE_ID_1, SERVICE_1,
DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
postSync { advertiser.removeService(SERVICE_ID_1) }
- verify(mockDeps, times(2)).generateHostname()
+ verify(mockDeps, times(2)).generateHostname(anyBoolean())
+ }
+
+ private fun doHostnameGenerationTest(shortHostname: Boolean): Array<String> {
+ doCallRealMethod().`when`(mockDeps).generateHostname(anyBoolean())
+ val flags = MdnsFeatureFlags.newBuilder().setIsShortHostnamesEnabled(shortHostname).build()
+ val advertiser =
+ MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)
+ postSync { advertiser.addOrUpdateService(SERVICE_ID_1, SERVICE_1,
+ DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
+
+ val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
+ verify(socketProvider).requestSocket(eq(TEST_NETWORK_1), socketCbCaptor.capture())
+
+ val socketCb = socketCbCaptor.value
+ postSync { socketCb.onSocketCreated(TEST_SOCKETKEY_1, mockSocket1, listOf(TEST_LINKADDR)) }
+
+ val hostnameCaptor = ArgumentCaptor.forClass(Array<String>::class.java)
+ verify(mockDeps).makeAdvertiser(
+ eq(mockSocket1),
+ eq(listOf(TEST_LINKADDR)),
+ eq(thread.looper),
+ any(),
+ any(),
+ hostnameCaptor.capture(),
+ any(),
+ any()
+ )
+ return hostnameCaptor.value
+ }
+
+ @Test
+ fun testShortHostnameGeneration() {
+ val hostname = doHostnameGenerationTest(shortHostname = true)
+ // Short hostnames are [8 uppercase letters or digits].local
+ assertEquals(2, hostname.size)
+ assertTrue(Regex("Android_[A-Z0-9]{8}").matches(hostname[0]),
+ "Unexpected hostname: ${hostname.contentToString()}")
+ assertEquals("local", hostname[1])
+ }
+
+ @Test
+ fun testLongHostnameGeneration() {
+ val hostname = doHostnameGenerationTest(shortHostname = false)
+ // Long hostnames are Android_[32 lowercase hex characters].local
+ assertEquals(2, hostname.size)
+ assertTrue(Regex("Android_[a-f0-9]{32}").matches(hostname[0]),
+ "Unexpected hostname: ${hostname.contentToString()}")
+ assertEquals("local", hostname[1])
}
private fun postSync(r: () -> Unit) {