Merge "Add aggressive query mode" into main
This commit is contained in:
commit
b4fba147cd
5 changed files with 255 additions and 41 deletions
|
|
@ -35,6 +35,7 @@ import static com.android.networkstack.apishim.ConstantsShim.REGISTER_NSD_OFFLOA
|
|||
import static com.android.server.connectivity.mdns.MdnsAdvertiser.AdvertiserMetrics;
|
||||
import static com.android.server.connectivity.mdns.MdnsConstants.NO_PACKET;
|
||||
import static com.android.server.connectivity.mdns.MdnsRecord.MAX_LABEL_LENGTH;
|
||||
import static com.android.server.connectivity.mdns.MdnsSearchOptions.AGGRESSIVE_QUERY_MODE;
|
||||
import static com.android.server.connectivity.mdns.MdnsSearchOptions.PASSIVE_QUERY_MODE;
|
||||
import static com.android.server.connectivity.mdns.util.MdnsUtils.Clock;
|
||||
|
||||
|
|
@ -252,6 +253,8 @@ public class NsdService extends INsdManager.Stub {
|
|||
|
||||
private final RemoteCallbackList<IOffloadEngine> mOffloadEngines =
|
||||
new RemoteCallbackList<>();
|
||||
@NonNull
|
||||
private final MdnsFeatureFlags mMdnsFeatureFlags;
|
||||
|
||||
private static class OffloadEngineInfo {
|
||||
@NonNull final String mInterfaceName;
|
||||
|
|
@ -794,7 +797,10 @@ public class NsdService extends INsdManager.Stub {
|
|||
MdnsSearchOptions.newBuilder()
|
||||
.setNetwork(discoveryRequest.getNetwork())
|
||||
.setRemoveExpiredService(true)
|
||||
.setQueryMode(PASSIVE_QUERY_MODE);
|
||||
.setQueryMode(
|
||||
mMdnsFeatureFlags.isAggressiveQueryModeEnabled()
|
||||
? AGGRESSIVE_QUERY_MODE
|
||||
: PASSIVE_QUERY_MODE);
|
||||
if (subtype != null) {
|
||||
// checkSubtypeLabels() ensures that subtypes start with '_' but
|
||||
// MdnsSearchOptions expects the underscore to not be present.
|
||||
|
|
@ -1063,7 +1069,9 @@ public class NsdService extends INsdManager.Stub {
|
|||
transactionId, resolveServiceType);
|
||||
final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
|
||||
.setNetwork(info.getNetwork())
|
||||
.setQueryMode(PASSIVE_QUERY_MODE)
|
||||
.setQueryMode(mMdnsFeatureFlags.isAggressiveQueryModeEnabled()
|
||||
? AGGRESSIVE_QUERY_MODE
|
||||
: PASSIVE_QUERY_MODE)
|
||||
.setResolveInstanceName(info.getServiceName())
|
||||
.setRemoveExpiredService(true)
|
||||
.build();
|
||||
|
|
@ -1161,7 +1169,9 @@ public class NsdService extends INsdManager.Stub {
|
|||
transactionId, resolveServiceType);
|
||||
final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
|
||||
.setNetwork(info.getNetwork())
|
||||
.setQueryMode(PASSIVE_QUERY_MODE)
|
||||
.setQueryMode(mMdnsFeatureFlags.isAggressiveQueryModeEnabled()
|
||||
? AGGRESSIVE_QUERY_MODE
|
||||
: PASSIVE_QUERY_MODE)
|
||||
.setResolveInstanceName(info.getServiceName())
|
||||
.setRemoveExpiredService(true)
|
||||
.build();
|
||||
|
|
@ -1787,7 +1797,7 @@ public class NsdService extends INsdManager.Stub {
|
|||
am.addOnUidImportanceListener(new UidImportanceListener(handler),
|
||||
mRunningAppActiveImportanceCutoff);
|
||||
|
||||
final MdnsFeatureFlags flags = new MdnsFeatureFlags.Builder()
|
||||
mMdnsFeatureFlags = new MdnsFeatureFlags.Builder()
|
||||
.setIsMdnsOffloadFeatureEnabled(mDeps.isTetheringFeatureNotChickenedOut(
|
||||
mContext, MdnsFeatureFlags.NSD_FORCE_DISABLE_MDNS_OFFLOAD))
|
||||
.setIncludeInetAddressRecordsInProbing(mDeps.isFeatureEnabled(
|
||||
|
|
@ -1800,18 +1810,21 @@ public class NsdService extends INsdManager.Stub {
|
|||
mContext, MdnsFeatureFlags.NSD_KNOWN_ANSWER_SUPPRESSION))
|
||||
.setIsUnicastReplyEnabled(mDeps.isFeatureEnabled(
|
||||
mContext, MdnsFeatureFlags.NSD_UNICAST_REPLY_ENABLED))
|
||||
.setIsAggressiveQueryModeEnabled(mDeps.isFeatureEnabled(
|
||||
mContext, MdnsFeatureFlags.NSD_AGGRESSIVE_QUERY_MODE))
|
||||
.setOverrideProvider(flag -> mDeps.isFeatureEnabled(
|
||||
mContext, FORCE_ENABLE_FLAG_FOR_TEST_PREFIX + flag))
|
||||
.build();
|
||||
mMdnsSocketClient =
|
||||
new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider,
|
||||
LOGGER.forSubComponent("MdnsMultinetworkSocketClient"), flags);
|
||||
LOGGER.forSubComponent("MdnsMultinetworkSocketClient"), mMdnsFeatureFlags);
|
||||
mMdnsDiscoveryManager = deps.makeMdnsDiscoveryManager(new ExecutorProvider(),
|
||||
mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager"), flags);
|
||||
mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager"),
|
||||
mMdnsFeatureFlags);
|
||||
handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager));
|
||||
mAdvertiser = deps.makeMdnsAdvertiser(handler.getLooper(), mMdnsSocketProvider,
|
||||
new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser"), flags,
|
||||
mContext);
|
||||
new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser"),
|
||||
mMdnsFeatureFlags, mContext);
|
||||
mClock = deps.makeClock();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,11 @@ public class MdnsFeatureFlags {
|
|||
*/
|
||||
public static final String NSD_UNICAST_REPLY_ENABLED = "nsd_unicast_reply_enabled";
|
||||
|
||||
/**
|
||||
* A feature flag to control whether the aggressive query mode should be enabled.
|
||||
*/
|
||||
public static final String NSD_AGGRESSIVE_QUERY_MODE = "nsd_aggressive_query_mode";
|
||||
|
||||
// Flag for offload feature
|
||||
public final boolean mIsMdnsOffloadFeatureEnabled;
|
||||
|
||||
|
|
@ -75,6 +80,9 @@ public class MdnsFeatureFlags {
|
|||
// Flag to enable replying unicast to queries requesting unicast replies
|
||||
public final boolean mIsUnicastReplyEnabled;
|
||||
|
||||
// Flag for aggressive query mode
|
||||
public final boolean mIsAggressiveQueryModeEnabled;
|
||||
|
||||
@Nullable
|
||||
private final FlagOverrideProvider mOverrideProvider;
|
||||
|
||||
|
|
@ -102,6 +110,13 @@ public class MdnsFeatureFlags {
|
|||
return mIsUnicastReplyEnabled || isForceEnabledForTest(NSD_UNICAST_REPLY_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether {@link #NSD_AGGRESSIVE_QUERY_MODE} is enabled, including for testing.
|
||||
*/
|
||||
public boolean isAggressiveQueryModeEnabled() {
|
||||
return mIsAggressiveQueryModeEnabled || isForceEnabledForTest(NSD_AGGRESSIVE_QUERY_MODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor for {@link MdnsFeatureFlags}.
|
||||
*/
|
||||
|
|
@ -111,6 +126,7 @@ public class MdnsFeatureFlags {
|
|||
boolean isLabelCountLimitEnabled,
|
||||
boolean isKnownAnswerSuppressionEnabled,
|
||||
boolean isUnicastReplyEnabled,
|
||||
boolean isAggressiveQueryModeEnabled,
|
||||
@Nullable FlagOverrideProvider overrideProvider) {
|
||||
mIsMdnsOffloadFeatureEnabled = isOffloadFeatureEnabled;
|
||||
mIncludeInetAddressRecordsInProbing = includeInetAddressRecordsInProbing;
|
||||
|
|
@ -118,6 +134,7 @@ public class MdnsFeatureFlags {
|
|||
mIsLabelCountLimitEnabled = isLabelCountLimitEnabled;
|
||||
mIsKnownAnswerSuppressionEnabled = isKnownAnswerSuppressionEnabled;
|
||||
mIsUnicastReplyEnabled = isUnicastReplyEnabled;
|
||||
mIsAggressiveQueryModeEnabled = isAggressiveQueryModeEnabled;
|
||||
mOverrideProvider = overrideProvider;
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +153,7 @@ public class MdnsFeatureFlags {
|
|||
private boolean mIsLabelCountLimitEnabled;
|
||||
private boolean mIsKnownAnswerSuppressionEnabled;
|
||||
private boolean mIsUnicastReplyEnabled;
|
||||
private boolean mIsAggressiveQueryModeEnabled;
|
||||
private FlagOverrideProvider mOverrideProvider;
|
||||
|
||||
/**
|
||||
|
|
@ -148,6 +166,7 @@ public class MdnsFeatureFlags {
|
|||
mIsLabelCountLimitEnabled = true; // Default enabled.
|
||||
mIsKnownAnswerSuppressionEnabled = false;
|
||||
mIsUnicastReplyEnabled = true;
|
||||
mIsAggressiveQueryModeEnabled = false;
|
||||
mOverrideProvider = null;
|
||||
}
|
||||
|
||||
|
|
@ -223,6 +242,16 @@ public class MdnsFeatureFlags {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the aggressive query mode is enabled.
|
||||
*
|
||||
* @see #NSD_AGGRESSIVE_QUERY_MODE
|
||||
*/
|
||||
public Builder setIsAggressiveQueryModeEnabled(boolean isAggressiveQueryModeEnabled) {
|
||||
mIsAggressiveQueryModeEnabled = isAggressiveQueryModeEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link MdnsFeatureFlags} with the arguments supplied to this builder.
|
||||
*/
|
||||
|
|
@ -233,6 +262,7 @@ public class MdnsFeatureFlags {
|
|||
mIsLabelCountLimitEnabled,
|
||||
mIsKnownAnswerSuppressionEnabled,
|
||||
mIsUnicastReplyEnabled,
|
||||
mIsAggressiveQueryModeEnabled,
|
||||
mOverrideProvider);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,10 @@ public class MdnsSearchOptions implements Parcelable {
|
|||
public static final int PASSIVE_QUERY_MODE = 0;
|
||||
// Active query mode scans frequently.
|
||||
public static final int ACTIVE_QUERY_MODE = 1;
|
||||
// Aggressive query mode scans more frequently than the active mode at first, and sends both
|
||||
// unicast and multicast queries simultaneously, but in long sessions it eventually sends as
|
||||
// many queries as the PASSIVE mode.
|
||||
public static final int AGGRESSIVE_QUERY_MODE = 2;
|
||||
|
||||
/** @hide */
|
||||
public static final Parcelable.Creator<MdnsSearchOptions> CREATOR =
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.android.server.connectivity.mdns;
|
||||
|
||||
import static com.android.server.connectivity.mdns.MdnsSearchOptions.AGGRESSIVE_QUERY_MODE;
|
||||
import static com.android.server.connectivity.mdns.MdnsSearchOptions.PASSIVE_QUERY_MODE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
|
@ -35,13 +36,23 @@ public class QueryTaskConfig {
|
|||
|
||||
private static final int INITIAL_TIME_BETWEEN_BURSTS_MS =
|
||||
(int) MdnsConfigs.initialTimeBetweenBurstsMs();
|
||||
private static final int TIME_BETWEEN_BURSTS_MS = (int) MdnsConfigs.timeBetweenBurstsMs();
|
||||
private static final int MAX_TIME_BETWEEN_ACTIVE_PASSIVE_BURSTS_MS =
|
||||
(int) MdnsConfigs.timeBetweenBurstsMs();
|
||||
private static final int QUERIES_PER_BURST = (int) MdnsConfigs.queriesPerBurst();
|
||||
private static final int TIME_BETWEEN_QUERIES_IN_BURST_MS =
|
||||
(int) MdnsConfigs.timeBetweenQueriesInBurstMs();
|
||||
private static final int QUERIES_PER_BURST_PASSIVE_MODE =
|
||||
(int) MdnsConfigs.queriesPerBurstPassive();
|
||||
private static final int UNSIGNED_SHORT_MAX_VALUE = 65536;
|
||||
@VisibleForTesting
|
||||
// RFC 6762 5.2: The interval between the first two queries MUST be at least one second.
|
||||
static final int INITIAL_AGGRESSIVE_TIME_BETWEEN_BURSTS_MS = 1000;
|
||||
@VisibleForTesting
|
||||
// Basically this tries to send one query per typical DTIM interval 100ms, to maximize the
|
||||
// chances that a query will be received if devices are using a DTIM multiplier (in which case
|
||||
// they only listen once every [multiplier] DTIM intervals).
|
||||
static final int TIME_BETWEEN_RETRANSMISSION_QUERIES_IN_BURST_MS = 100;
|
||||
static final int MAX_TIME_BETWEEN_AGGRESSIVE_BURSTS_MS = 60000;
|
||||
// The following fields are used by QueryTask so we need to test them.
|
||||
@VisibleForTesting
|
||||
final List<String> subtypes;
|
||||
|
|
@ -81,6 +92,7 @@ public class QueryTaskConfig {
|
|||
this.queryCount = queryCount;
|
||||
this.socketKey = other.socketKey;
|
||||
}
|
||||
|
||||
QueryTaskConfig(@NonNull Collection<String> subtypes,
|
||||
int queryMode,
|
||||
boolean onlyUseIpv6OnIpv6OnlyNetworks,
|
||||
|
|
@ -96,21 +108,59 @@ public class QueryTaskConfig {
|
|||
this.expectUnicastResponse = true;
|
||||
this.isFirstBurst = true;
|
||||
// Config the scan frequency based on the scan mode.
|
||||
if (this.queryMode == PASSIVE_QUERY_MODE) {
|
||||
if (this.queryMode == AGGRESSIVE_QUERY_MODE) {
|
||||
this.timeBetweenBurstsInMs = INITIAL_AGGRESSIVE_TIME_BETWEEN_BURSTS_MS;
|
||||
this.delayUntilNextTaskWithoutBackoffMs =
|
||||
TIME_BETWEEN_RETRANSMISSION_QUERIES_IN_BURST_MS;
|
||||
} else if (this.queryMode == PASSIVE_QUERY_MODE) {
|
||||
// In passive scan mode, sends a single burst of QUERIES_PER_BURST queries, and then
|
||||
// in each TIME_BETWEEN_BURSTS interval, sends QUERIES_PER_BURST_PASSIVE_MODE
|
||||
// queries.
|
||||
this.timeBetweenBurstsInMs = TIME_BETWEEN_BURSTS_MS;
|
||||
this.timeBetweenBurstsInMs = MAX_TIME_BETWEEN_ACTIVE_PASSIVE_BURSTS_MS;
|
||||
this.delayUntilNextTaskWithoutBackoffMs = TIME_BETWEEN_QUERIES_IN_BURST_MS;
|
||||
} else {
|
||||
// In active scan mode, sends a burst of QUERIES_PER_BURST queries,
|
||||
// TIME_BETWEEN_QUERIES_IN_BURST_MS apart, then waits for the scan interval, and
|
||||
// then repeats. The scan interval starts as INITIAL_TIME_BETWEEN_BURSTS_MS and
|
||||
// doubles until it maxes out at TIME_BETWEEN_BURSTS_MS.
|
||||
this.timeBetweenBurstsInMs = INITIAL_TIME_BETWEEN_BURSTS_MS;
|
||||
this.delayUntilNextTaskWithoutBackoffMs = TIME_BETWEEN_QUERIES_IN_BURST_MS;
|
||||
}
|
||||
this.socketKey = socketKey;
|
||||
this.queryCount = 0;
|
||||
this.delayUntilNextTaskWithoutBackoffMs = TIME_BETWEEN_QUERIES_IN_BURST_MS;
|
||||
}
|
||||
|
||||
long getDelayUntilNextTaskWithoutBackoff(boolean isFirstQueryInBurst,
|
||||
boolean isLastQueryInBurst) {
|
||||
if (isFirstQueryInBurst && queryMode == AGGRESSIVE_QUERY_MODE) {
|
||||
return 0;
|
||||
}
|
||||
if (isLastQueryInBurst) {
|
||||
return timeBetweenBurstsInMs;
|
||||
}
|
||||
return queryMode == AGGRESSIVE_QUERY_MODE
|
||||
? TIME_BETWEEN_RETRANSMISSION_QUERIES_IN_BURST_MS
|
||||
: TIME_BETWEEN_QUERIES_IN_BURST_MS;
|
||||
}
|
||||
|
||||
boolean getNextExpectUnicastResponse(boolean isLastQueryInBurst) {
|
||||
if (!isLastQueryInBurst) {
|
||||
return false;
|
||||
}
|
||||
if (queryMode == AGGRESSIVE_QUERY_MODE) {
|
||||
return true;
|
||||
}
|
||||
return alwaysAskForUnicastResponse;
|
||||
}
|
||||
|
||||
int getNextTimeBetweenBurstsMs(boolean isLastQueryInBurst) {
|
||||
if (!isLastQueryInBurst) {
|
||||
return timeBetweenBurstsInMs;
|
||||
}
|
||||
final int maxTimeBetweenBursts = queryMode == AGGRESSIVE_QUERY_MODE
|
||||
? MAX_TIME_BETWEEN_AGGRESSIVE_BURSTS_MS : MAX_TIME_BETWEEN_ACTIVE_PASSIVE_BURSTS_MS;
|
||||
return timeBetweenBurstsInMs < maxTimeBetweenBursts
|
||||
? Math.min(timeBetweenBurstsInMs * 2, maxTimeBetweenBursts) : timeBetweenBurstsInMs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -122,43 +172,28 @@ public class QueryTaskConfig {
|
|||
if (newTransactionId > UNSIGNED_SHORT_MAX_VALUE) {
|
||||
newTransactionId = 1;
|
||||
}
|
||||
boolean newExpectUnicastResponse = false;
|
||||
boolean newIsFirstBurst = isFirstBurst;
|
||||
int newQueriesPerBurst = queriesPerBurst;
|
||||
int newBurstCounter = burstCounter + 1;
|
||||
long newDelayUntilNextTaskWithoutBackoffMs = delayUntilNextTaskWithoutBackoffMs;
|
||||
int newTimeBetweenBurstsInMs = timeBetweenBurstsInMs;
|
||||
// Only the first query expects uni-cast response.
|
||||
if (newBurstCounter == queriesPerBurst) {
|
||||
final boolean isFirstQueryInBurst = newBurstCounter == 1;
|
||||
final boolean isLastQueryInBurst = newBurstCounter == queriesPerBurst;
|
||||
if (isLastQueryInBurst) {
|
||||
newBurstCounter = 0;
|
||||
|
||||
if (alwaysAskForUnicastResponse) {
|
||||
newExpectUnicastResponse = true;
|
||||
}
|
||||
// In passive scan mode, sends a single burst of QUERIES_PER_BURST queries, and
|
||||
// then in each TIME_BETWEEN_BURSTS interval, sends QUERIES_PER_BURST_PASSIVE_MODE
|
||||
// queries.
|
||||
if (isFirstBurst) {
|
||||
newIsFirstBurst = false;
|
||||
// In passive scan mode, sends a single burst of QUERIES_PER_BURST queries, and
|
||||
// then in each TIME_BETWEEN_BURSTS interval, sends QUERIES_PER_BURST_PASSIVE_MODE
|
||||
// queries.
|
||||
if (queryMode == PASSIVE_QUERY_MODE) {
|
||||
newQueriesPerBurst = QUERIES_PER_BURST_PASSIVE_MODE;
|
||||
}
|
||||
}
|
||||
// In active scan mode, sends a burst of QUERIES_PER_BURST queries,
|
||||
// TIME_BETWEEN_QUERIES_IN_BURST_MS apart, then waits for the scan interval, and
|
||||
// then repeats. The scan interval starts as INITIAL_TIME_BETWEEN_BURSTS_MS and
|
||||
// doubles until it maxes out at TIME_BETWEEN_BURSTS_MS.
|
||||
newDelayUntilNextTaskWithoutBackoffMs = timeBetweenBurstsInMs;
|
||||
if (timeBetweenBurstsInMs < TIME_BETWEEN_BURSTS_MS) {
|
||||
newTimeBetweenBurstsInMs = Math.min(timeBetweenBurstsInMs * 2,
|
||||
TIME_BETWEEN_BURSTS_MS);
|
||||
}
|
||||
} else {
|
||||
newDelayUntilNextTaskWithoutBackoffMs = TIME_BETWEEN_QUERIES_IN_BURST_MS;
|
||||
}
|
||||
|
||||
return new QueryTaskConfig(this, newQueryCount, newTransactionId,
|
||||
newExpectUnicastResponse, newIsFirstBurst, newBurstCounter, newQueriesPerBurst,
|
||||
newTimeBetweenBurstsInMs, newDelayUntilNextTaskWithoutBackoffMs);
|
||||
getNextExpectUnicastResponse(isLastQueryInBurst), newIsFirstBurst, newBurstCounter,
|
||||
newQueriesPerBurst, getNextTimeBetweenBurstsMs(isLastQueryInBurst),
|
||||
getDelayUntilNextTaskWithoutBackoff(isFirstQueryInBurst, isLastQueryInBurst));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,8 +17,12 @@
|
|||
package com.android.server.connectivity.mdns;
|
||||
|
||||
import static com.android.server.connectivity.mdns.MdnsSearchOptions.ACTIVE_QUERY_MODE;
|
||||
import static com.android.server.connectivity.mdns.MdnsSearchOptions.AGGRESSIVE_QUERY_MODE;
|
||||
import static com.android.server.connectivity.mdns.MdnsSearchOptions.PASSIVE_QUERY_MODE;
|
||||
import static com.android.server.connectivity.mdns.MdnsServiceTypeClient.EVENT_START_QUERYTASK;
|
||||
import static com.android.server.connectivity.mdns.QueryTaskConfig.INITIAL_AGGRESSIVE_TIME_BETWEEN_BURSTS_MS;
|
||||
import static com.android.server.connectivity.mdns.QueryTaskConfig.MAX_TIME_BETWEEN_AGGRESSIVE_BURSTS_MS;
|
||||
import static com.android.server.connectivity.mdns.QueryTaskConfig.TIME_BETWEEN_RETRANSMISSION_QUERIES_IN_BURST_MS;
|
||||
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
|
@ -147,8 +151,8 @@ public class MdnsServiceTypeClientTests {
|
|||
MockitoAnnotations.initMocks(this);
|
||||
doReturn(TEST_ELAPSED_REALTIME).when(mockDecoderClock).elapsedRealtime();
|
||||
|
||||
expectedIPv4Packets = new DatagramPacket[16];
|
||||
expectedIPv6Packets = new DatagramPacket[16];
|
||||
expectedIPv4Packets = new DatagramPacket[24];
|
||||
expectedIPv6Packets = new DatagramPacket[24];
|
||||
socketKey = new SocketKey(mockNetwork, INTERFACE_INDEX);
|
||||
|
||||
for (int i = 0; i < expectedIPv4Packets.length; ++i) {
|
||||
|
|
@ -173,7 +177,15 @@ public class MdnsServiceTypeClientTests {
|
|||
.thenReturn(expectedIPv4Packets[12])
|
||||
.thenReturn(expectedIPv4Packets[13])
|
||||
.thenReturn(expectedIPv4Packets[14])
|
||||
.thenReturn(expectedIPv4Packets[15]);
|
||||
.thenReturn(expectedIPv4Packets[15])
|
||||
.thenReturn(expectedIPv4Packets[16])
|
||||
.thenReturn(expectedIPv4Packets[17])
|
||||
.thenReturn(expectedIPv4Packets[18])
|
||||
.thenReturn(expectedIPv4Packets[19])
|
||||
.thenReturn(expectedIPv4Packets[20])
|
||||
.thenReturn(expectedIPv4Packets[21])
|
||||
.thenReturn(expectedIPv4Packets[22])
|
||||
.thenReturn(expectedIPv4Packets[23]);
|
||||
|
||||
when(mockPacketWriter.getPacket(IPV6_ADDRESS))
|
||||
.thenReturn(expectedIPv6Packets[0])
|
||||
|
|
@ -191,7 +203,15 @@ public class MdnsServiceTypeClientTests {
|
|||
.thenReturn(expectedIPv6Packets[12])
|
||||
.thenReturn(expectedIPv6Packets[13])
|
||||
.thenReturn(expectedIPv6Packets[14])
|
||||
.thenReturn(expectedIPv6Packets[15]);
|
||||
.thenReturn(expectedIPv6Packets[15])
|
||||
.thenReturn(expectedIPv6Packets[16])
|
||||
.thenReturn(expectedIPv6Packets[17])
|
||||
.thenReturn(expectedIPv6Packets[18])
|
||||
.thenReturn(expectedIPv6Packets[19])
|
||||
.thenReturn(expectedIPv6Packets[20])
|
||||
.thenReturn(expectedIPv6Packets[21])
|
||||
.thenReturn(expectedIPv6Packets[22])
|
||||
.thenReturn(expectedIPv6Packets[23]);
|
||||
|
||||
thread = new HandlerThread("MdnsServiceTypeClientTests");
|
||||
thread.start();
|
||||
|
|
@ -1672,6 +1692,118 @@ public class MdnsServiceTypeClientTests {
|
|||
socketKey);
|
||||
}
|
||||
|
||||
private int getBetweenBurstTime(int burstCounter, int currentBetweenTime, int maxBetweenTime,
|
||||
int initialBetweenTime) {
|
||||
return currentBetweenTime < maxBetweenTime
|
||||
? Math.min(initialBetweenTime * (int) Math.pow(2, burstCounter), maxBetweenTime)
|
||||
: currentBetweenTime;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendQueries_aggressiveScanMode() {
|
||||
final MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder()
|
||||
.addSubtype(SUBTYPE).setQueryMode(AGGRESSIVE_QUERY_MODE).build();
|
||||
startSendAndReceive(mockListenerOne, searchOptions);
|
||||
// Always try to remove the task.
|
||||
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||
|
||||
int burstCounter = 0;
|
||||
int betweenBurstTime = 0;
|
||||
for (int i = 0; i < expectedIPv4Packets.length; i += 3) {
|
||||
verifyAndSendQuery(i, betweenBurstTime, /* expectsUnicastResponse= */ true);
|
||||
verifyAndSendQuery(i + 1, /* timeInMs= */ 0, /* expectsUnicastResponse= */ false);
|
||||
verifyAndSendQuery(i + 2, TIME_BETWEEN_RETRANSMISSION_QUERIES_IN_BURST_MS,
|
||||
/* expectsUnicastResponse= */ false);
|
||||
betweenBurstTime = getBetweenBurstTime(burstCounter, betweenBurstTime,
|
||||
MAX_TIME_BETWEEN_AGGRESSIVE_BURSTS_MS,
|
||||
INITIAL_AGGRESSIVE_TIME_BETWEEN_BURSTS_MS);
|
||||
burstCounter++;
|
||||
}
|
||||
// Verify that Task is not removed before stopSendAndReceive was called.
|
||||
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||
|
||||
// Stop sending packets.
|
||||
stopSendAndReceive(mockListenerOne);
|
||||
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendQueries_reentry_aggressiveScanMode() {
|
||||
final MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder()
|
||||
.addSubtype(SUBTYPE).setQueryMode(AGGRESSIVE_QUERY_MODE).build();
|
||||
startSendAndReceive(mockListenerOne, searchOptions);
|
||||
// Always try to remove the task.
|
||||
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||
|
||||
// First burst, first query is sent.
|
||||
verifyAndSendQuery(0, /* timeInMs= */ 0, /* expectsUnicastResponse= */ true);
|
||||
|
||||
// After the first query is sent, change the subtypes, and restart.
|
||||
final MdnsSearchOptions searchOptions2 = MdnsSearchOptions.newBuilder().addSubtype(SUBTYPE)
|
||||
.addSubtype("_subtype2").setQueryMode(AGGRESSIVE_QUERY_MODE).build();
|
||||
startSendAndReceive(mockListenerOne, searchOptions2);
|
||||
// The previous scheduled task should be canceled.
|
||||
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||
|
||||
// Queries should continue to be sent.
|
||||
verifyAndSendQuery(1, /* timeInMs= */ 0, /* expectsUnicastResponse= */ true);
|
||||
verifyAndSendQuery(2, /* timeInMs= */ 0, /* expectsUnicastResponse= */ false);
|
||||
verifyAndSendQuery(3, TIME_BETWEEN_RETRANSMISSION_QUERIES_IN_BURST_MS,
|
||||
/* expectsUnicastResponse= */ false);
|
||||
|
||||
// Stop sending packets.
|
||||
stopSendAndReceive(mockListenerOne);
|
||||
verify(mockDeps, times(3)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendQueries_blendScanWithQueryBackoff() {
|
||||
final int numOfQueriesBeforeBackoff = 11;
|
||||
final MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder()
|
||||
.addSubtype(SUBTYPE)
|
||||
.setQueryMode(AGGRESSIVE_QUERY_MODE)
|
||||
.setNumOfQueriesBeforeBackoff(numOfQueriesBeforeBackoff)
|
||||
.build();
|
||||
startSendAndReceive(mockListenerOne, searchOptions);
|
||||
// Always try to remove the task.
|
||||
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||
|
||||
int burstCounter = 0;
|
||||
int betweenBurstTime = 0;
|
||||
for (int i = 0; i < numOfQueriesBeforeBackoff; i += 3) {
|
||||
verifyAndSendQuery(i, betweenBurstTime, /* expectsUnicastResponse= */ true);
|
||||
verifyAndSendQuery(i + 1, /* timeInMs= */ 0, /* expectsUnicastResponse= */ false);
|
||||
verifyAndSendQuery(i + 2, TIME_BETWEEN_RETRANSMISSION_QUERIES_IN_BURST_MS,
|
||||
/* expectsUnicastResponse= */ false);
|
||||
betweenBurstTime = getBetweenBurstTime(burstCounter, betweenBurstTime,
|
||||
MAX_TIME_BETWEEN_AGGRESSIVE_BURSTS_MS,
|
||||
INITIAL_AGGRESSIVE_TIME_BETWEEN_BURSTS_MS);
|
||||
burstCounter++;
|
||||
}
|
||||
// In backoff mode, the current scheduled task will be canceled and reschedule if the
|
||||
// 0.8 * smallestRemainingTtl is larger than time to next run.
|
||||
long currentTime = TEST_TTL / 2 + TEST_ELAPSED_REALTIME;
|
||||
doReturn(currentTime).when(mockDecoderClock).elapsedRealtime();
|
||||
doReturn(true).when(mockDeps).hasMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||
processResponse(createResponse(
|
||||
"service-instance-1", "192.0.2.123", 5353,
|
||||
SERVICE_TYPE_LABELS,
|
||||
Collections.emptyMap(), TEST_TTL), socketKey);
|
||||
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||
assertNotNull(delayMessage);
|
||||
verifyAndSendQuery(12 /* index */, (long) (TEST_TTL / 2 * 0.8) /* timeInMs */,
|
||||
true /* expectsUnicastResponse */, true /* multipleSocketDiscovery */,
|
||||
14 /* scheduledCount */);
|
||||
currentTime += (long) (TEST_TTL / 2 * 0.8);
|
||||
doReturn(currentTime).when(mockDecoderClock).elapsedRealtime();
|
||||
verifyAndSendQuery(13 /* index */, 0 /* timeInMs */,
|
||||
false /* expectsUnicastResponse */, true /* multipleSocketDiscovery */,
|
||||
15 /* scheduledCount */);
|
||||
verifyAndSendQuery(14 /* index */, TIME_BETWEEN_RETRANSMISSION_QUERIES_IN_BURST_MS,
|
||||
false /* expectsUnicastResponse */, true /* multipleSocketDiscovery */,
|
||||
16 /* scheduledCount */);
|
||||
}
|
||||
|
||||
private static MdnsServiceInfo matchServiceName(String name) {
|
||||
return argThat(info -> info.getServiceInstanceName().equals(name));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue