Report more advertising metrics data
Report more advertising metrics data below when the service is unregistered. - Replied request count (sum across interfaces) - Sent packet count (including announcements and probes) - Number of conflicts during probing - Nubmer of conflicts after probing Bug: 287546772 Test: atest FrameworksNetTestCases NsdManagerTest Merged-In: I50c54a35dc523422e3a7302c059bbbc38eac5631 Change-Id: I50c54a35dc523422e3a7302c059bbbc38eac5631
This commit is contained in:
@@ -24,16 +24,22 @@ import android.stats.connectivity.NsdEventType;
|
|||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.server.ConnectivityStatsLog;
|
import com.android.server.ConnectivityStatsLog;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to record the NetworkNsdReported into statsd. Each client should create this class to
|
* Class to record the NetworkNsdReported into statsd. Each client should create this class to
|
||||||
* report its data.
|
* report its data.
|
||||||
*/
|
*/
|
||||||
public class NetworkNsdReportedMetrics {
|
public class NetworkNsdReportedMetrics {
|
||||||
|
// The upper bound for the random number used in metrics data sampling determines the possible
|
||||||
|
// sample rate.
|
||||||
|
private static final int RANDOM_NUMBER_UPPER_BOUND = 1000;
|
||||||
// Whether this client is using legacy backend.
|
// Whether this client is using legacy backend.
|
||||||
private final boolean mIsLegacy;
|
private final boolean mIsLegacy;
|
||||||
// The client id.
|
// The client id.
|
||||||
private final int mClientId;
|
private final int mClientId;
|
||||||
private final Dependencies mDependencies;
|
private final Dependencies mDependencies;
|
||||||
|
private final Random mRandom;
|
||||||
|
|
||||||
public NetworkNsdReportedMetrics(boolean isLegacy, int clientId) {
|
public NetworkNsdReportedMetrics(boolean isLegacy, int clientId) {
|
||||||
this(isLegacy, clientId, new Dependencies());
|
this(isLegacy, clientId, new Dependencies());
|
||||||
@@ -44,6 +50,7 @@ public class NetworkNsdReportedMetrics {
|
|||||||
mIsLegacy = isLegacy;
|
mIsLegacy = isLegacy;
|
||||||
mClientId = clientId;
|
mClientId = clientId;
|
||||||
mDependencies = dependencies;
|
mDependencies = dependencies;
|
||||||
|
mRandom = dependencies.makeRandomGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,7 +74,18 @@ public class NetworkNsdReportedMetrics {
|
|||||||
event.getFoundCallbackCount(),
|
event.getFoundCallbackCount(),
|
||||||
event.getLostCallbackCount(),
|
event.getLostCallbackCount(),
|
||||||
event.getRepliedRequestsCount(),
|
event.getRepliedRequestsCount(),
|
||||||
event.getSentQueryCount());
|
event.getSentQueryCount(),
|
||||||
|
event.getSentPacketCount(),
|
||||||
|
event.getConflictDuringProbingCount(),
|
||||||
|
event.getConflictAfterProbingCount(),
|
||||||
|
event.getRandomNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Random
|
||||||
|
*/
|
||||||
|
public Random makeRandomGenerator() {
|
||||||
|
return new Random();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +93,7 @@ public class NetworkNsdReportedMetrics {
|
|||||||
final Builder builder = NetworkNsdReported.newBuilder();
|
final Builder builder = NetworkNsdReported.newBuilder();
|
||||||
builder.setIsLegacy(mIsLegacy);
|
builder.setIsLegacy(mIsLegacy);
|
||||||
builder.setClientId(mClientId);
|
builder.setClientId(mClientId);
|
||||||
|
builder.setRandomNumber(mRandom.nextInt(RANDOM_NUMBER_UPPER_BOUND));
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,14 +132,23 @@ public class NetworkNsdReportedMetrics {
|
|||||||
*
|
*
|
||||||
* @param transactionId The transaction id of service registration.
|
* @param transactionId The transaction id of service registration.
|
||||||
* @param durationMs The duration of service stayed registered.
|
* @param durationMs The duration of service stayed registered.
|
||||||
|
* @param repliedRequestsCount The replied request count of this service before unregistered it.
|
||||||
|
* @param sentPacketCount The total sent packet count of this service before unregistered it.
|
||||||
|
* @param conflictDuringProbingCount The number of conflict during probing.
|
||||||
|
* @param conflictAfterProbingCount The number of conflict after probing.
|
||||||
*/
|
*/
|
||||||
public void reportServiceUnregistration(int transactionId, long durationMs) {
|
public void reportServiceUnregistration(int transactionId, long durationMs,
|
||||||
|
int repliedRequestsCount, int sentPacketCount, int conflictDuringProbingCount,
|
||||||
|
int conflictAfterProbingCount) {
|
||||||
final Builder builder = makeReportedBuilder();
|
final Builder builder = makeReportedBuilder();
|
||||||
builder.setTransactionId(transactionId);
|
builder.setTransactionId(transactionId);
|
||||||
builder.setType(NsdEventType.NET_REGISTER);
|
builder.setType(NsdEventType.NET_REGISTER);
|
||||||
builder.setQueryResult(MdnsQueryResult.MQR_SERVICE_UNREGISTERED);
|
builder.setQueryResult(MdnsQueryResult.MQR_SERVICE_UNREGISTERED);
|
||||||
builder.setEventDurationMillisec(durationMs);
|
builder.setEventDurationMillisec(durationMs);
|
||||||
// TODO: Report repliedRequestsCount
|
builder.setRepliedRequestsCount(repliedRequestsCount);
|
||||||
|
builder.setSentPacketCount(sentPacketCount);
|
||||||
|
builder.setConflictDuringProbingCount(conflictDuringProbingCount);
|
||||||
|
builder.setConflictAfterProbingCount(conflictAfterProbingCount);
|
||||||
mDependencies.statsWrite(builder.build());
|
mDependencies.statsWrite(builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
|
|||||||
|
|
||||||
import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
|
import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
|
||||||
import static com.android.networkstack.apishim.ConstantsShim.REGISTER_NSD_OFFLOAD_ENGINE;
|
import static com.android.networkstack.apishim.ConstantsShim.REGISTER_NSD_OFFLOAD_ENGINE;
|
||||||
|
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.MdnsRecord.MAX_LABEL_LENGTH;
|
||||||
import static com.android.server.connectivity.mdns.util.MdnsUtils.Clock;
|
import static com.android.server.connectivity.mdns.util.MdnsUtils.Clock;
|
||||||
|
|
||||||
@@ -992,14 +994,20 @@ public class NsdService extends INsdManager.Stub {
|
|||||||
// instead of looking at the flag value.
|
// instead of looking at the flag value.
|
||||||
final long stopTimeMs = mClock.elapsedRealtime();
|
final long stopTimeMs = mClock.elapsedRealtime();
|
||||||
if (request instanceof AdvertiserClientRequest) {
|
if (request instanceof AdvertiserClientRequest) {
|
||||||
|
final AdvertiserMetrics metrics =
|
||||||
|
mAdvertiser.getAdvertiserMetrics(transactionId);
|
||||||
mAdvertiser.removeService(transactionId);
|
mAdvertiser.removeService(transactionId);
|
||||||
clientInfo.onUnregisterServiceSucceeded(clientRequestId, transactionId,
|
clientInfo.onUnregisterServiceSucceeded(clientRequestId, transactionId,
|
||||||
request.calculateRequestDurationMs(stopTimeMs));
|
request.calculateRequestDurationMs(stopTimeMs), metrics);
|
||||||
} else {
|
} else {
|
||||||
if (unregisterService(transactionId)) {
|
if (unregisterService(transactionId)) {
|
||||||
clientInfo.onUnregisterServiceSucceeded(clientRequestId,
|
clientInfo.onUnregisterServiceSucceeded(clientRequestId,
|
||||||
transactionId,
|
transactionId,
|
||||||
request.calculateRequestDurationMs(stopTimeMs));
|
request.calculateRequestDurationMs(stopTimeMs),
|
||||||
|
new AdvertiserMetrics(NO_PACKET /* repliedRequestsCount */,
|
||||||
|
NO_PACKET /* sentPacketCount */,
|
||||||
|
0 /* conflictDuringProbingCount */,
|
||||||
|
0 /* conflictAfterProbingCount */));
|
||||||
} else {
|
} else {
|
||||||
clientInfo.onUnregisterServiceFailed(
|
clientInfo.onUnregisterServiceFailed(
|
||||||
clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
|
clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
|
||||||
@@ -2496,9 +2504,14 @@ public class NsdService extends INsdManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (request instanceof AdvertiserClientRequest) {
|
if (request instanceof AdvertiserClientRequest) {
|
||||||
|
final AdvertiserMetrics metrics =
|
||||||
|
mAdvertiser.getAdvertiserMetrics(transactionId);
|
||||||
mAdvertiser.removeService(transactionId);
|
mAdvertiser.removeService(transactionId);
|
||||||
mMetrics.reportServiceUnregistration(transactionId,
|
mMetrics.reportServiceUnregistration(transactionId,
|
||||||
request.calculateRequestDurationMs(mClock.elapsedRealtime()));
|
request.calculateRequestDurationMs(mClock.elapsedRealtime()),
|
||||||
|
metrics.mRepliedRequestsCount, metrics.mSentPacketCount,
|
||||||
|
metrics.mConflictDuringProbingCount,
|
||||||
|
metrics.mConflictAfterProbingCount);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2524,7 +2537,11 @@ public class NsdService extends INsdManager.Stub {
|
|||||||
case NsdManager.REGISTER_SERVICE:
|
case NsdManager.REGISTER_SERVICE:
|
||||||
unregisterService(transactionId);
|
unregisterService(transactionId);
|
||||||
mMetrics.reportServiceUnregistration(transactionId,
|
mMetrics.reportServiceUnregistration(transactionId,
|
||||||
request.calculateRequestDurationMs(mClock.elapsedRealtime()));
|
request.calculateRequestDurationMs(mClock.elapsedRealtime()),
|
||||||
|
NO_PACKET /* repliedRequestsCount */,
|
||||||
|
NO_PACKET /* sentPacketCount */,
|
||||||
|
0 /* conflictDuringProbingCount */,
|
||||||
|
0 /* conflictAfterProbingCount */);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -2663,8 +2680,11 @@ public class NsdService extends INsdManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUnregisterServiceSucceeded(int listenerKey, int transactionId, long durationMs) {
|
void onUnregisterServiceSucceeded(int listenerKey, int transactionId, long durationMs,
|
||||||
mMetrics.reportServiceUnregistration(transactionId, durationMs);
|
AdvertiserMetrics metrics) {
|
||||||
|
mMetrics.reportServiceUnregistration(transactionId, durationMs,
|
||||||
|
metrics.mRepliedRequestsCount, metrics.mSentPacketCount,
|
||||||
|
metrics.mConflictDuringProbingCount, metrics.mConflictAfterProbingCount);
|
||||||
try {
|
try {
|
||||||
mCb.onUnregisterServiceSucceeded(listenerKey);
|
mCb.onUnregisterServiceSucceeded(listenerKey);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server.connectivity.mdns;
|
package com.android.server.connectivity.mdns;
|
||||||
|
|
||||||
|
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.MdnsRecord.MAX_LABEL_LENGTH;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
@@ -180,6 +181,7 @@ public class MdnsAdvertiser {
|
|||||||
// (with the old, conflicting, actually not used name as argument... The new
|
// (with the old, conflicting, actually not used name as argument... The new
|
||||||
// implementation will send callbacks with the new name).
|
// implementation will send callbacks with the new name).
|
||||||
registration.mNotifiedRegistrationSuccess = false;
|
registration.mNotifiedRegistrationSuccess = false;
|
||||||
|
registration.mConflictAfterProbingCount++;
|
||||||
|
|
||||||
// The service was done probing, just reset it to probing state (RFC6762 9.)
|
// The service was done probing, just reset it to probing state (RFC6762 9.)
|
||||||
forAllAdvertisers(a -> {
|
forAllAdvertisers(a -> {
|
||||||
@@ -195,6 +197,7 @@ public class MdnsAdvertiser {
|
|||||||
registration.updateForConflict(
|
registration.updateForConflict(
|
||||||
registration.makeNewServiceInfoForConflict(1 /* renameCount */),
|
registration.makeNewServiceInfoForConflict(1 /* renameCount */),
|
||||||
1 /* renameCount */);
|
1 /* renameCount */);
|
||||||
|
registration.mConflictDuringProbingCount++;
|
||||||
|
|
||||||
// Keep renaming if the new name conflicts in local registrations
|
// Keep renaming if the new name conflicts in local registrations
|
||||||
updateRegistrationUntilNoConflict((net, adv) -> adv.hasRegistration(registration),
|
updateRegistrationUntilNoConflict((net, adv) -> adv.hasRegistration(registration),
|
||||||
@@ -360,6 +363,22 @@ public class MdnsAdvertiser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getServiceRepliedRequestsCount(int id) {
|
||||||
|
int repliedRequestsCount = NO_PACKET;
|
||||||
|
for (int i = 0; i < mAdvertisers.size(); i++) {
|
||||||
|
repliedRequestsCount += mAdvertisers.valueAt(i).getServiceRepliedRequestsCount(id);
|
||||||
|
}
|
||||||
|
return repliedRequestsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSentPacketCount(int id) {
|
||||||
|
int sentPacketCount = NO_PACKET;
|
||||||
|
for (int i = 0; i < mAdvertisers.size(); i++) {
|
||||||
|
sentPacketCount += mAdvertisers.valueAt(i).getSentPacketCount(id);
|
||||||
|
}
|
||||||
|
return sentPacketCount;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSocketCreated(@NonNull SocketKey socketKey,
|
public void onSocketCreated(@NonNull SocketKey socketKey,
|
||||||
@NonNull MdnsInterfaceSocket socket,
|
@NonNull MdnsInterfaceSocket socket,
|
||||||
@@ -444,6 +463,8 @@ public class MdnsAdvertiser {
|
|||||||
private NsdServiceInfo mServiceInfo;
|
private NsdServiceInfo mServiceInfo;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final String mSubtype;
|
private final String mSubtype;
|
||||||
|
int mConflictDuringProbingCount;
|
||||||
|
int mConflictAfterProbingCount;
|
||||||
|
|
||||||
private Registration(@NonNull NsdServiceInfo serviceInfo, @Nullable String subtype) {
|
private Registration(@NonNull NsdServiceInfo serviceInfo, @Nullable String subtype) {
|
||||||
this.mOriginalName = serviceInfo.getServiceName();
|
this.mOriginalName = serviceInfo.getServiceName();
|
||||||
@@ -555,6 +576,24 @@ public class MdnsAdvertiser {
|
|||||||
@NonNull OffloadServiceInfo offloadServiceInfo);
|
@NonNull OffloadServiceInfo offloadServiceInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class of avdverting metrics.
|
||||||
|
*/
|
||||||
|
public static class AdvertiserMetrics {
|
||||||
|
public final int mRepliedRequestsCount;
|
||||||
|
public final int mSentPacketCount;
|
||||||
|
public final int mConflictDuringProbingCount;
|
||||||
|
public final int mConflictAfterProbingCount;
|
||||||
|
|
||||||
|
public AdvertiserMetrics(int repliedRequestsCount, int sentPacketCount,
|
||||||
|
int conflictDuringProbingCount, int conflictAfterProbingCount) {
|
||||||
|
mRepliedRequestsCount = repliedRequestsCount;
|
||||||
|
mSentPacketCount = sentPacketCount;
|
||||||
|
mConflictDuringProbingCount = conflictDuringProbingCount;
|
||||||
|
mConflictAfterProbingCount = conflictAfterProbingCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public MdnsAdvertiser(@NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider,
|
public MdnsAdvertiser(@NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider,
|
||||||
@NonNull AdvertiserCallback cb, @NonNull SharedLog sharedLog) {
|
@NonNull AdvertiserCallback cb, @NonNull SharedLog sharedLog) {
|
||||||
this(looper, socketProvider, cb, new Dependencies(), sharedLog);
|
this(looper, socketProvider, cb, new Dependencies(), sharedLog);
|
||||||
@@ -637,6 +676,34 @@ public class MdnsAdvertiser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get advertising metrics.
|
||||||
|
*
|
||||||
|
* @param id ID used when registering.
|
||||||
|
* @return The advertising metrics includes replied requests count, send packet count, conflict
|
||||||
|
* count during/after probing.
|
||||||
|
*/
|
||||||
|
public AdvertiserMetrics getAdvertiserMetrics(int id) {
|
||||||
|
checkThread();
|
||||||
|
final Registration registration = mRegistrations.get(id);
|
||||||
|
if (registration == null) {
|
||||||
|
return new AdvertiserMetrics(
|
||||||
|
NO_PACKET /* repliedRequestsCount */,
|
||||||
|
NO_PACKET /* sentPacketCount */,
|
||||||
|
0 /* conflictDuringProbingCount */,
|
||||||
|
0 /* conflictAfterProbingCount */);
|
||||||
|
}
|
||||||
|
int repliedRequestsCount = NO_PACKET;
|
||||||
|
int sentPacketCount = NO_PACKET;
|
||||||
|
for (int i = 0; i < mAdvertiserRequests.size(); i++) {
|
||||||
|
repliedRequestsCount +=
|
||||||
|
mAdvertiserRequests.valueAt(i).getServiceRepliedRequestsCount(id);
|
||||||
|
sentPacketCount += mAdvertiserRequests.valueAt(i).getSentPacketCount(id);
|
||||||
|
}
|
||||||
|
return new AdvertiserMetrics(repliedRequestsCount, sentPacketCount,
|
||||||
|
registration.mConflictDuringProbingCount, registration.mConflictAfterProbingCount);
|
||||||
|
}
|
||||||
|
|
||||||
private static <K, V> boolean any(@NonNull ArrayMap<K, V> map,
|
private static <K, V> boolean any(@NonNull ArrayMap<K, V> map,
|
||||||
@NonNull BiPredicate<K, V> predicate) {
|
@NonNull BiPredicate<K, V> predicate) {
|
||||||
for (int i = 0; i < map.size(); i++) {
|
for (int i = 0; i < map.size(); i++) {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public final class MdnsConstants {
|
|||||||
public static final int FLAG_TRUNCATED = 0x0200;
|
public static final int FLAG_TRUNCATED = 0x0200;
|
||||||
public static final int QCLASS_INTERNET = 0x0001;
|
public static final int QCLASS_INTERNET = 0x0001;
|
||||||
public static final int QCLASS_UNICAST = 0x8000;
|
public static final int QCLASS_UNICAST = 0x8000;
|
||||||
|
public static final int NO_PACKET = 0;
|
||||||
public static final String SUBTYPE_LABEL = "_sub";
|
public static final String SUBTYPE_LABEL = "_sub";
|
||||||
public static final String SUBTYPE_PREFIX = "_";
|
public static final String SUBTYPE_PREFIX = "_";
|
||||||
private static final String MDNS_IPV4_HOST_ADDRESS = "224.0.0.251";
|
private static final String MDNS_IPV4_HOST_ADDRESS = "224.0.0.251";
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.server.connectivity.mdns;
|
package com.android.server.connectivity.mdns;
|
||||||
|
|
||||||
|
import static com.android.server.connectivity.mdns.MdnsConstants.NO_PACKET;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
@@ -93,8 +95,11 @@ public class MdnsInterfaceAdvertiser implements MulticastPacketReader.PacketHand
|
|||||||
/**
|
/**
|
||||||
* Callbacks from {@link MdnsProber}.
|
* Callbacks from {@link MdnsProber}.
|
||||||
*/
|
*/
|
||||||
private class ProbingCallback implements
|
private class ProbingCallback implements PacketRepeaterCallback<MdnsProber.ProbingInfo> {
|
||||||
PacketRepeaterCallback<MdnsProber.ProbingInfo> {
|
@Override
|
||||||
|
public void onSent(int index, @NonNull MdnsProber.ProbingInfo info, int sentPacketCount) {
|
||||||
|
mRecordRepository.onProbingSent(info.getServiceId(), sentPacketCount);
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onFinished(MdnsProber.ProbingInfo info) {
|
public void onFinished(MdnsProber.ProbingInfo info) {
|
||||||
final MdnsAnnouncer.AnnouncementInfo announcementInfo;
|
final MdnsAnnouncer.AnnouncementInfo announcementInfo;
|
||||||
@@ -118,8 +123,8 @@ public class MdnsInterfaceAdvertiser implements MulticastPacketReader.PacketHand
|
|||||||
*/
|
*/
|
||||||
private class AnnouncingCallback implements PacketRepeaterCallback<BaseAnnouncementInfo> {
|
private class AnnouncingCallback implements PacketRepeaterCallback<BaseAnnouncementInfo> {
|
||||||
@Override
|
@Override
|
||||||
public void onSent(int index, @NonNull BaseAnnouncementInfo info) {
|
public void onSent(int index, @NonNull BaseAnnouncementInfo info, int sentPacketCount) {
|
||||||
mRecordRepository.onAdvertisementSent(info.getServiceId());
|
mRecordRepository.onAdvertisementSent(info.getServiceId(), sentPacketCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -259,6 +264,22 @@ public class MdnsInterfaceAdvertiser implements MulticastPacketReader.PacketHand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the replied request count from given service id.
|
||||||
|
*/
|
||||||
|
public int getServiceRepliedRequestsCount(int id) {
|
||||||
|
if (!mRecordRepository.hasActiveService(id)) return NO_PACKET;
|
||||||
|
return mRecordRepository.getServiceRepliedRequestsCount(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the total sent packet count from given service id.
|
||||||
|
*/
|
||||||
|
public int getSentPacketCount(int id) {
|
||||||
|
if (!mRecordRepository.hasActiveService(id)) return NO_PACKET;
|
||||||
|
return mRecordRepository.getSentPacketCount(id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update interface addresses used to advertise.
|
* Update interface addresses used to advertise.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public abstract class MdnsPacketRepeater<T extends MdnsPacketRepeater.Request> {
|
|||||||
/**
|
/**
|
||||||
* Called when a packet was sent.
|
* Called when a packet was sent.
|
||||||
*/
|
*/
|
||||||
default void onSent(int index, @NonNull T info) {}
|
default void onSent(int index, @NonNull T info, int sentPacketCount) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the {@link MdnsPacketRepeater} is done sending packets.
|
* Called when the {@link MdnsPacketRepeater} is done sending packets.
|
||||||
@@ -114,9 +114,10 @@ public abstract class MdnsPacketRepeater<T extends MdnsPacketRepeater.Request> {
|
|||||||
}
|
}
|
||||||
// Send to both v4 and v6 addresses; the reply sender will take care of ignoring the
|
// Send to both v4 and v6 addresses; the reply sender will take care of ignoring the
|
||||||
// send when the socket has not joined the relevant group.
|
// send when the socket has not joined the relevant group.
|
||||||
|
int sentPacketCount = 0;
|
||||||
for (InetSocketAddress destination : ALL_ADDRS) {
|
for (InetSocketAddress destination : ALL_ADDRS) {
|
||||||
try {
|
try {
|
||||||
mReplySender.sendNow(packet, destination);
|
sentPacketCount += mReplySender.sendNow(packet, destination);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
mSharedLog.e("Error sending packet to " + destination, e);
|
mSharedLog.e("Error sending packet to " + destination, e);
|
||||||
}
|
}
|
||||||
@@ -135,7 +136,7 @@ public abstract class MdnsPacketRepeater<T extends MdnsPacketRepeater.Request> {
|
|||||||
|
|
||||||
// Call onSent after scheduling the next run, to allow the callback to cancel it
|
// Call onSent after scheduling the next run, to allow the callback to cancel it
|
||||||
if (mCb != null) {
|
if (mCb != null) {
|
||||||
mCb.onSent(index, request);
|
mCb.onSent(index, request, sentPacketCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.server.connectivity.mdns;
|
package com.android.server.connectivity.mdns;
|
||||||
|
|
||||||
|
import static com.android.server.connectivity.mdns.MdnsConstants.NO_PACKET;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
@@ -174,6 +176,16 @@ public class MdnsRecordRepository {
|
|||||||
*/
|
*/
|
||||||
public boolean exiting = false;
|
public boolean exiting = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The replied query packet count of this service.
|
||||||
|
*/
|
||||||
|
public int repliedServiceCount = NO_PACKET;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sent packet count of this service (including announcements and probes).
|
||||||
|
*/
|
||||||
|
public int sentPacketCount = NO_PACKET;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a ServiceRegistration for dns-sd service registration (RFC6763).
|
* Create a ServiceRegistration for dns-sd service registration (RFC6763).
|
||||||
*
|
*
|
||||||
@@ -181,7 +193,7 @@ public class MdnsRecordRepository {
|
|||||||
* @param serviceInfo Service to advertise
|
* @param serviceInfo Service to advertise
|
||||||
*/
|
*/
|
||||||
ServiceRegistration(@NonNull String[] deviceHostname, @NonNull NsdServiceInfo serviceInfo,
|
ServiceRegistration(@NonNull String[] deviceHostname, @NonNull NsdServiceInfo serviceInfo,
|
||||||
@Nullable String subtype) {
|
@Nullable String subtype, int repliedServiceCount, int sentPacketCount) {
|
||||||
this.serviceInfo = serviceInfo;
|
this.serviceInfo = serviceInfo;
|
||||||
this.subtype = subtype;
|
this.subtype = subtype;
|
||||||
|
|
||||||
@@ -254,6 +266,8 @@ public class MdnsRecordRepository {
|
|||||||
true /* sharedName */, true /* probing */));
|
true /* sharedName */, true /* probing */));
|
||||||
|
|
||||||
this.allRecords = Collections.unmodifiableList(allRecords);
|
this.allRecords = Collections.unmodifiableList(allRecords);
|
||||||
|
this.repliedServiceCount = repliedServiceCount;
|
||||||
|
this.sentPacketCount = sentPacketCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setProbing(boolean probing) {
|
void setProbing(boolean probing) {
|
||||||
@@ -316,7 +330,8 @@ public class MdnsRecordRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final ServiceRegistration registration = new ServiceRegistration(
|
final ServiceRegistration registration = new ServiceRegistration(
|
||||||
mDeviceHostname, serviceInfo, subtype);
|
mDeviceHostname, serviceInfo, subtype, NO_PACKET /* repliedServiceCount */,
|
||||||
|
NO_PACKET /* sentPacketCount */);
|
||||||
mServices.put(serviceId, registration);
|
mServices.put(serviceId, registration);
|
||||||
|
|
||||||
// Remove existing exiting service
|
// Remove existing exiting service
|
||||||
@@ -405,6 +420,24 @@ public class MdnsRecordRepository {
|
|||||||
return mServices.size();
|
return mServices.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The replied request count of the service.
|
||||||
|
*/
|
||||||
|
public int getServiceRepliedRequestsCount(int id) {
|
||||||
|
final ServiceRegistration service = mServices.get(id);
|
||||||
|
if (service == null) return NO_PACKET;
|
||||||
|
return service.repliedServiceCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The total sent packet count of the service.
|
||||||
|
*/
|
||||||
|
public int getSentPacketCount(int id) {
|
||||||
|
final ServiceRegistration service = mServices.get(id);
|
||||||
|
if (service == null) return NO_PACKET;
|
||||||
|
return service.sentPacketCount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all services from the repository
|
* Remove all services from the repository
|
||||||
* @return IDs of the removed services
|
* @return IDs of the removed services
|
||||||
@@ -472,9 +505,12 @@ public class MdnsRecordRepository {
|
|||||||
for (int i = 0; i < mServices.size(); i++) {
|
for (int i = 0; i < mServices.size(); i++) {
|
||||||
final ServiceRegistration registration = mServices.valueAt(i);
|
final ServiceRegistration registration = mServices.valueAt(i);
|
||||||
if (registration.exiting) continue;
|
if (registration.exiting) continue;
|
||||||
addReplyFromService(question, registration.allRecords, registration.ptrRecords,
|
if (addReplyFromService(question, registration.allRecords, registration.ptrRecords,
|
||||||
registration.srvRecord, registration.txtRecord, replyUnicast, now,
|
registration.srvRecord, registration.txtRecord, replyUnicast, now,
|
||||||
answerInfo, additionalAnswerRecords);
|
answerInfo, additionalAnswerRecords)) {
|
||||||
|
registration.repliedServiceCount++;
|
||||||
|
registration.sentPacketCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +563,7 @@ public class MdnsRecordRepository {
|
|||||||
/**
|
/**
|
||||||
* Add answers and additional answers for a question, from a ServiceRegistration.
|
* Add answers and additional answers for a question, from a ServiceRegistration.
|
||||||
*/
|
*/
|
||||||
private void addReplyFromService(@NonNull MdnsRecord question,
|
private boolean addReplyFromService(@NonNull MdnsRecord question,
|
||||||
@NonNull List<RecordInfo<?>> serviceRecords,
|
@NonNull List<RecordInfo<?>> serviceRecords,
|
||||||
@Nullable List<RecordInfo<MdnsPointerRecord>> servicePtrRecords,
|
@Nullable List<RecordInfo<MdnsPointerRecord>> servicePtrRecords,
|
||||||
@Nullable RecordInfo<MdnsServiceRecord> serviceSrvRecord,
|
@Nullable RecordInfo<MdnsServiceRecord> serviceSrvRecord,
|
||||||
@@ -596,7 +632,7 @@ public class MdnsRecordRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No more records to add if no answer
|
// No more records to add if no answer
|
||||||
if (answerInfo.size() == answersStartIndex) return;
|
if (answerInfo.size() == answersStartIndex) return false;
|
||||||
|
|
||||||
final List<RecordInfo<?>> additionalAnswerInfo = new ArrayList<>();
|
final List<RecordInfo<?>> additionalAnswerInfo = new ArrayList<>();
|
||||||
// RFC6763 12.1: if including PTR record, include the SRV and TXT records it names
|
// RFC6763 12.1: if including PTR record, include the SRV and TXT records it names
|
||||||
@@ -626,6 +662,7 @@ public class MdnsRecordRepository {
|
|||||||
addNsecRecordsForUniqueNames(additionalAnswerRecords,
|
addNsecRecordsForUniqueNames(additionalAnswerRecords,
|
||||||
answerInfo.listIterator(answersStartIndex),
|
answerInfo.listIterator(answersStartIndex),
|
||||||
additionalAnswerInfo.listIterator());
|
additionalAnswerInfo.listIterator());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -862,8 +899,8 @@ public class MdnsRecordRepository {
|
|||||||
final ServiceRegistration existing = mServices.get(serviceId);
|
final ServiceRegistration existing = mServices.get(serviceId);
|
||||||
if (existing == null) return null;
|
if (existing == null) return null;
|
||||||
|
|
||||||
final ServiceRegistration newService = new ServiceRegistration(
|
final ServiceRegistration newService = new ServiceRegistration(mDeviceHostname, newInfo,
|
||||||
mDeviceHostname, newInfo, existing.subtype);
|
existing.subtype, existing.repliedServiceCount, existing.sentPacketCount);
|
||||||
mServices.put(serviceId, newService);
|
mServices.put(serviceId, newService);
|
||||||
return makeProbingInfo(serviceId, newService.srvRecord.record);
|
return makeProbingInfo(serviceId, newService.srvRecord.record);
|
||||||
}
|
}
|
||||||
@@ -871,7 +908,7 @@ public class MdnsRecordRepository {
|
|||||||
/**
|
/**
|
||||||
* Called when {@link MdnsAdvertiser} sent an advertisement for the given service.
|
* Called when {@link MdnsAdvertiser} sent an advertisement for the given service.
|
||||||
*/
|
*/
|
||||||
public void onAdvertisementSent(int serviceId) {
|
public void onAdvertisementSent(int serviceId, int sentPacketCount) {
|
||||||
final ServiceRegistration registration = mServices.get(serviceId);
|
final ServiceRegistration registration = mServices.get(serviceId);
|
||||||
if (registration == null) return;
|
if (registration == null) return;
|
||||||
|
|
||||||
@@ -880,8 +917,19 @@ public class MdnsRecordRepository {
|
|||||||
record.lastSentTimeMs = now;
|
record.lastSentTimeMs = now;
|
||||||
record.lastAdvertisedTimeMs = now;
|
record.lastAdvertisedTimeMs = now;
|
||||||
}
|
}
|
||||||
|
registration.sentPacketCount += sentPacketCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when {@link MdnsAdvertiser} sent a probing for the given service.
|
||||||
|
*/
|
||||||
|
public void onProbingSent(int serviceId, int sentPacketCount) {
|
||||||
|
final ServiceRegistration registration = mServices.get(serviceId);
|
||||||
|
if (registration == null) return;
|
||||||
|
registration.sentPacketCount += sentPacketCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute:
|
* Compute:
|
||||||
* 2001:db8::1 --> 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa
|
* 2001:db8::1 --> 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ import java.util.Collections;
|
|||||||
public class MdnsReplySender {
|
public class MdnsReplySender {
|
||||||
private static final boolean DBG = MdnsAdvertiser.DBG;
|
private static final boolean DBG = MdnsAdvertiser.DBG;
|
||||||
private static final int MSG_SEND = 1;
|
private static final int MSG_SEND = 1;
|
||||||
|
private static final int PACKET_NOT_SENT = 0;
|
||||||
|
private static final int PACKET_SENT = 1;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final MdnsInterfaceSocket mSocket;
|
private final MdnsInterfaceSocket mSocket;
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -79,16 +82,17 @@ public class MdnsReplySender {
|
|||||||
*
|
*
|
||||||
* Must be called on the looper thread used by the {@link MdnsReplySender}.
|
* Must be called on the looper thread used by the {@link MdnsReplySender}.
|
||||||
*/
|
*/
|
||||||
public void sendNow(@NonNull MdnsPacket packet, @NonNull InetSocketAddress destination)
|
public int sendNow(@NonNull MdnsPacket packet, @NonNull InetSocketAddress destination)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
ensureRunningOnHandlerThread(mHandler);
|
ensureRunningOnHandlerThread(mHandler);
|
||||||
if (!((destination.getAddress() instanceof Inet6Address && mSocket.hasJoinedIpv6())
|
if (!((destination.getAddress() instanceof Inet6Address && mSocket.hasJoinedIpv6())
|
||||||
|| (destination.getAddress() instanceof Inet4Address && mSocket.hasJoinedIpv4()))) {
|
|| (destination.getAddress() instanceof Inet4Address && mSocket.hasJoinedIpv4()))) {
|
||||||
// Skip sending if the socket has not joined the v4/v6 group (there was no address)
|
// Skip sending if the socket has not joined the v4/v6 group (there was no address)
|
||||||
return;
|
return PACKET_NOT_SENT;
|
||||||
}
|
}
|
||||||
final byte[] outBuffer = MdnsUtils.createRawDnsPacket(mPacketCreationBuffer, packet);
|
final byte[] outBuffer = MdnsUtils.createRawDnsPacket(mPacketCreationBuffer, packet);
|
||||||
mSocket.send(new DatagramPacket(outBuffer, 0, outBuffer.length, destination));
|
mSocket.send(new DatagramPacket(outBuffer, 0, outBuffer.length, destination));
|
||||||
|
return PACKET_SENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the packetCreationBuffer */
|
/** Get the packetCreationBuffer */
|
||||||
|
|||||||
@@ -64,6 +64,18 @@ message NetworkNsdReported {
|
|||||||
|
|
||||||
// Record sent query count before stopped discovery
|
// Record sent query count before stopped discovery
|
||||||
optional int32 sent_query_count = 12;
|
optional int32 sent_query_count = 12;
|
||||||
|
|
||||||
|
// Record sent packet count before unregistered service
|
||||||
|
optional int32 sent_packet_count = 13;
|
||||||
|
|
||||||
|
// Record number of conflict during probing
|
||||||
|
optional int32 conflict_during_probing_count = 14;
|
||||||
|
|
||||||
|
// Record number of conflict after probing
|
||||||
|
optional int32 conflict_after_probing_count = 15;
|
||||||
|
|
||||||
|
// The random number between 0 ~ 999 for sampling
|
||||||
|
optional int32 random_number = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,12 +21,15 @@ import android.stats.connectivity.MdnsQueryResult
|
|||||||
import android.stats.connectivity.NsdEventType
|
import android.stats.connectivity.NsdEventType
|
||||||
import com.android.testutils.DevSdkIgnoreRule
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
import com.android.testutils.DevSdkIgnoreRunner
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
import java.util.Random
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.ArgumentCaptor
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Mockito.doReturn
|
||||||
import org.mockito.Mockito.mock
|
import org.mockito.Mockito.mock
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
|
|
||||||
@@ -34,6 +37,12 @@ import org.mockito.Mockito.verify
|
|||||||
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
|
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
|
||||||
class NetworkNsdReportedMetricsTest {
|
class NetworkNsdReportedMetricsTest {
|
||||||
private val deps = mock(NetworkNsdReportedMetrics.Dependencies::class.java)
|
private val deps = mock(NetworkNsdReportedMetrics.Dependencies::class.java)
|
||||||
|
private val random = mock(Random::class.java)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
doReturn(random).`when`(deps).makeRandomGenerator()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testReportServiceRegistrationSucceeded() {
|
fun testReportServiceRegistrationSucceeded() {
|
||||||
@@ -80,8 +89,13 @@ class NetworkNsdReportedMetricsTest {
|
|||||||
val clientId = 99
|
val clientId = 99
|
||||||
val transactionId = 100
|
val transactionId = 100
|
||||||
val durationMs = 10L
|
val durationMs = 10L
|
||||||
|
val repliedRequestsCount = 25
|
||||||
|
val sentPacketCount = 50
|
||||||
|
val conflictDuringProbingCount = 2
|
||||||
|
val conflictAfterProbingCount = 1
|
||||||
val metrics = NetworkNsdReportedMetrics(true /* isLegacy */, clientId, deps)
|
val metrics = NetworkNsdReportedMetrics(true /* isLegacy */, clientId, deps)
|
||||||
metrics.reportServiceUnregistration(transactionId, durationMs)
|
metrics.reportServiceUnregistration(transactionId, durationMs, repliedRequestsCount,
|
||||||
|
sentPacketCount, conflictDuringProbingCount, conflictAfterProbingCount)
|
||||||
|
|
||||||
val eventCaptor = ArgumentCaptor.forClass(NetworkNsdReported::class.java)
|
val eventCaptor = ArgumentCaptor.forClass(NetworkNsdReported::class.java)
|
||||||
verify(deps).statsWrite(eventCaptor.capture())
|
verify(deps).statsWrite(eventCaptor.capture())
|
||||||
@@ -92,6 +106,10 @@ class NetworkNsdReportedMetricsTest {
|
|||||||
assertEquals(NsdEventType.NET_REGISTER, it.type)
|
assertEquals(NsdEventType.NET_REGISTER, it.type)
|
||||||
assertEquals(MdnsQueryResult.MQR_SERVICE_UNREGISTERED, it.queryResult)
|
assertEquals(MdnsQueryResult.MQR_SERVICE_UNREGISTERED, it.queryResult)
|
||||||
assertEquals(durationMs, it.eventDurationMillisec)
|
assertEquals(durationMs, it.eventDurationMillisec)
|
||||||
|
assertEquals(repliedRequestsCount, it.repliedRequestsCount)
|
||||||
|
assertEquals(sentPacketCount, it.sentPacketCount)
|
||||||
|
assertEquals(conflictDuringProbingCount, it.conflictDuringProbingCount)
|
||||||
|
assertEquals(conflictAfterProbingCount, it.conflictAfterProbingCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1222,6 +1222,8 @@ public class NsdServiceTest {
|
|||||||
verify(mMockMDnsM).stopOperation(legacyIdCaptor.getValue());
|
verify(mMockMDnsM).stopOperation(legacyIdCaptor.getValue());
|
||||||
verify(mAdvertiser, never()).removeService(anyInt());
|
verify(mAdvertiser, never()).removeService(anyInt());
|
||||||
|
|
||||||
|
doReturn(mock(MdnsAdvertiser.AdvertiserMetrics.class))
|
||||||
|
.when(mAdvertiser).getAdvertiserMetrics(anyInt());
|
||||||
client.unregisterService(regListenerWithFeature);
|
client.unregisterService(regListenerWithFeature);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
verify(mAdvertiser).removeService(serviceIdCaptor.getValue());
|
verify(mAdvertiser).removeService(serviceIdCaptor.getValue());
|
||||||
@@ -1312,14 +1314,20 @@ public class NsdServiceTest {
|
|||||||
new NsdServiceInfo(regInfo.getServiceName(), null))));
|
new NsdServiceInfo(regInfo.getServiceName(), null))));
|
||||||
verify(mMetrics).reportServiceRegistrationSucceeded(regId, 10L /* durationMs */);
|
verify(mMetrics).reportServiceRegistrationSucceeded(regId, 10L /* durationMs */);
|
||||||
|
|
||||||
|
final MdnsAdvertiser.AdvertiserMetrics metrics = new MdnsAdvertiser.AdvertiserMetrics(
|
||||||
|
50 /* repliedRequestCount */, 100 /* sentPacketCount */,
|
||||||
|
3 /* conflictDuringProbingCount */, 2 /* conflictAfterProbingCount */);
|
||||||
doReturn(TEST_TIME_MS + 100L).when(mClock).elapsedRealtime();
|
doReturn(TEST_TIME_MS + 100L).when(mClock).elapsedRealtime();
|
||||||
|
doReturn(metrics).when(mAdvertiser).getAdvertiserMetrics(regId);
|
||||||
client.unregisterService(regListener);
|
client.unregisterService(regListener);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
verify(mAdvertiser).removeService(idCaptor.getValue());
|
verify(mAdvertiser).removeService(idCaptor.getValue());
|
||||||
verify(regListener, timeout(TIMEOUT_MS)).onServiceUnregistered(
|
verify(regListener, timeout(TIMEOUT_MS)).onServiceUnregistered(
|
||||||
argThat(info -> matches(info, regInfo)));
|
argThat(info -> matches(info, regInfo)));
|
||||||
verify(mSocketProvider, timeout(TIMEOUT_MS)).requestStopWhenInactive();
|
verify(mSocketProvider, timeout(TIMEOUT_MS)).requestStopWhenInactive();
|
||||||
verify(mMetrics).reportServiceUnregistration(regId, 100L /* durationMs */);
|
verify(mMetrics).reportServiceUnregistration(regId, 100L /* durationMs */,
|
||||||
|
50 /* repliedRequestCount */, 100 /* sentPacketCount */,
|
||||||
|
3 /* conflictDuringProbingCount */, 2 /* conflictAfterProbingCount */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -33,7 +33,10 @@ import com.android.testutils.DevSdkIgnoreRunner
|
|||||||
import com.android.testutils.waitForIdle
|
import com.android.testutils.waitForIdle
|
||||||
import java.net.NetworkInterface
|
import java.net.NetworkInterface
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
@@ -206,6 +209,18 @@ class MdnsAdvertiserTest {
|
|||||||
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), argThat { it.matches(SERVICE_1) })
|
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), argThat { it.matches(SERVICE_1) })
|
||||||
verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO_NO_SUBTYPE))
|
verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO_NO_SUBTYPE))
|
||||||
|
|
||||||
|
// Service is conflicted.
|
||||||
|
postSync { intAdvCbCaptor.value.onServiceConflict(mockInterfaceAdvertiser1, SERVICE_ID_1) }
|
||||||
|
|
||||||
|
// Verify the metrics data
|
||||||
|
doReturn(25).`when`(mockInterfaceAdvertiser1).getServiceRepliedRequestsCount(SERVICE_ID_1)
|
||||||
|
doReturn(40).`when`(mockInterfaceAdvertiser1).getSentPacketCount(SERVICE_ID_1)
|
||||||
|
val metrics = postReturn { advertiser.getAdvertiserMetrics(SERVICE_ID_1) }
|
||||||
|
assertEquals(25, metrics.mRepliedRequestsCount)
|
||||||
|
assertEquals(40, metrics.mSentPacketCount)
|
||||||
|
assertEquals(0, metrics.mConflictDuringProbingCount)
|
||||||
|
assertEquals(1, metrics.mConflictAfterProbingCount)
|
||||||
|
|
||||||
doReturn(TEST_OFFLOAD_PACKET2).`when`(mockInterfaceAdvertiser1)
|
doReturn(TEST_OFFLOAD_PACKET2).`when`(mockInterfaceAdvertiser1)
|
||||||
.getRawOffloadPayload(
|
.getRawOffloadPayload(
|
||||||
SERVICE_ID_1
|
SERVICE_ID_1
|
||||||
@@ -265,6 +280,22 @@ class MdnsAdvertiserTest {
|
|||||||
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1),
|
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1),
|
||||||
argThat { it.matches(ALL_NETWORKS_SERVICE) })
|
argThat { it.matches(ALL_NETWORKS_SERVICE) })
|
||||||
|
|
||||||
|
// Services are conflicted.
|
||||||
|
postSync { intAdvCbCaptor1.value.onServiceConflict(mockInterfaceAdvertiser1, SERVICE_ID_1) }
|
||||||
|
postSync { intAdvCbCaptor1.value.onServiceConflict(mockInterfaceAdvertiser1, SERVICE_ID_1) }
|
||||||
|
postSync { intAdvCbCaptor2.value.onServiceConflict(mockInterfaceAdvertiser2, SERVICE_ID_1) }
|
||||||
|
|
||||||
|
// Verify the metrics data
|
||||||
|
doReturn(10).`when`(mockInterfaceAdvertiser1).getServiceRepliedRequestsCount(SERVICE_ID_1)
|
||||||
|
doReturn(5).`when`(mockInterfaceAdvertiser2).getServiceRepliedRequestsCount(SERVICE_ID_1)
|
||||||
|
doReturn(22).`when`(mockInterfaceAdvertiser1).getSentPacketCount(SERVICE_ID_1)
|
||||||
|
doReturn(12).`when`(mockInterfaceAdvertiser2).getSentPacketCount(SERVICE_ID_1)
|
||||||
|
val metrics = postReturn { advertiser.getAdvertiserMetrics(SERVICE_ID_1) }
|
||||||
|
assertEquals(15, metrics.mRepliedRequestsCount)
|
||||||
|
assertEquals(34, metrics.mSentPacketCount)
|
||||||
|
assertEquals(2, metrics.mConflictDuringProbingCount)
|
||||||
|
assertEquals(1, metrics.mConflictAfterProbingCount)
|
||||||
|
|
||||||
// Unregister the service
|
// Unregister the service
|
||||||
postSync { advertiser.removeService(SERVICE_ID_1) }
|
postSync { advertiser.removeService(SERVICE_ID_1) }
|
||||||
verify(mockInterfaceAdvertiser1).removeService(SERVICE_ID_1)
|
verify(mockInterfaceAdvertiser1).removeService(SERVICE_ID_1)
|
||||||
@@ -376,6 +407,14 @@ class MdnsAdvertiserTest {
|
|||||||
handler.post(r)
|
handler.post(r)
|
||||||
handler.waitForIdle(TIMEOUT_MS)
|
handler.waitForIdle(TIMEOUT_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <T> postReturn(r: (() -> T)): T {
|
||||||
|
val future = CompletableFuture<T>()
|
||||||
|
handler.post {
|
||||||
|
future.complete(r())
|
||||||
|
}
|
||||||
|
return future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NsdServiceInfo does not implement equals; this is useful to use in argument matchers
|
// NsdServiceInfo does not implement equals; this is useful to use in argument matchers
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ class MdnsAnnouncerTest {
|
|||||||
|
|
||||||
val captor = ArgumentCaptor.forClass(DatagramPacket::class.java)
|
val captor = ArgumentCaptor.forClass(DatagramPacket::class.java)
|
||||||
repeat(FIRST_ANNOUNCES_COUNT) { i ->
|
repeat(FIRST_ANNOUNCES_COUNT) { i ->
|
||||||
verify(cb, timeout(TEST_TIMEOUT_MS)).onSent(i, request)
|
verify(cb, timeout(TEST_TIMEOUT_MS)).onSent(i, request, 1 /* sentPacketCount */)
|
||||||
verify(socket, atLeast(i + 1)).send(any())
|
verify(socket, atLeast(i + 1)).send(any())
|
||||||
val now = SystemClock.elapsedRealtime()
|
val now = SystemClock.elapsedRealtime()
|
||||||
assertTrue(now > timeStart + startDelay + i * FIRST_ANNOUNCES_DELAY)
|
assertTrue(now > timeStart + startDelay + i * FIRST_ANNOUNCES_DELAY)
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class MdnsProberTest {
|
|||||||
|
|
||||||
private fun assertProbesSent(probeInfo: TestProbeInfo, expectedHex: String) {
|
private fun assertProbesSent(probeInfo: TestProbeInfo, expectedHex: String) {
|
||||||
repeat(probeInfo.numSends) { i ->
|
repeat(probeInfo.numSends) { i ->
|
||||||
verify(cb, timeout(TEST_TIMEOUT_MS)).onSent(i, probeInfo)
|
verify(cb, timeout(TEST_TIMEOUT_MS)).onSent(i, probeInfo, 1 /* sentPacketCount */)
|
||||||
// If the probe interval is short, more than (i+1) probes may have been sent already
|
// If the probe interval is short, more than (i+1) probes may have been sent already
|
||||||
verify(socket, atLeast(i + 1)).send(any())
|
verify(socket, atLeast(i + 1)).send(any())
|
||||||
}
|
}
|
||||||
@@ -190,7 +190,7 @@ class MdnsProberTest {
|
|||||||
prober.startProbing(probeInfo)
|
prober.startProbing(probeInfo)
|
||||||
|
|
||||||
// Expect the initial probe
|
// Expect the initial probe
|
||||||
verify(cb, timeout(TEST_TIMEOUT_MS)).onSent(0, probeInfo)
|
verify(cb, timeout(TEST_TIMEOUT_MS)).onSent(0, probeInfo, 1 /* sentPacketCount */)
|
||||||
|
|
||||||
// Stop probing
|
// Stop probing
|
||||||
val stopResult = CompletableFuture<Boolean>()
|
val stopResult = CompletableFuture<Boolean>()
|
||||||
@@ -200,7 +200,7 @@ class MdnsProberTest {
|
|||||||
|
|
||||||
// Wait for a bit (more than the probe delay) to ensure no more probes were sent
|
// Wait for a bit (more than the probe delay) to ensure no more probes were sent
|
||||||
Thread.sleep(SHORT_TIMEOUT_MS * 2)
|
Thread.sleep(SHORT_TIMEOUT_MS * 2)
|
||||||
verify(cb, never()).onSent(1, probeInfo)
|
verify(cb, never()).onSent(1, probeInfo, 1 /* sentPacketCount */)
|
||||||
verify(cb, never()).onFinished(probeInfo)
|
verify(cb, never()).onFinished(probeInfo)
|
||||||
|
|
||||||
// Only one sent packet
|
// Only one sent packet
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ class MdnsRecordRepositoryTest {
|
|||||||
|
|
||||||
val probingInfo = repository.setServiceProbing(TEST_SERVICE_ID_1)
|
val probingInfo = repository.setServiceProbing(TEST_SERVICE_ID_1)
|
||||||
repository.onProbingSucceeded(probingInfo)
|
repository.onProbingSucceeded(probingInfo)
|
||||||
repository.onAdvertisementSent(TEST_SERVICE_ID_1)
|
repository.onAdvertisementSent(TEST_SERVICE_ID_1, 2 /* sentPacketCount */)
|
||||||
assertTrue(repository.hasActiveService(TEST_SERVICE_ID_1))
|
assertTrue(repository.hasActiveService(TEST_SERVICE_ID_1))
|
||||||
|
|
||||||
repository.exitService(TEST_SERVICE_ID_1)
|
repository.exitService(TEST_SERVICE_ID_1)
|
||||||
@@ -166,7 +166,7 @@ class MdnsRecordRepositoryTest {
|
|||||||
fun testExitAnnouncements() {
|
fun testExitAnnouncements() {
|
||||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
||||||
repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
|
repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
|
||||||
repository.onAdvertisementSent(TEST_SERVICE_ID_1)
|
repository.onAdvertisementSent(TEST_SERVICE_ID_1, 2 /* sentPacketCount */)
|
||||||
|
|
||||||
val exitAnnouncement = repository.exitService(TEST_SERVICE_ID_1)
|
val exitAnnouncement = repository.exitService(TEST_SERVICE_ID_1)
|
||||||
assertNotNull(exitAnnouncement)
|
assertNotNull(exitAnnouncement)
|
||||||
@@ -195,7 +195,7 @@ class MdnsRecordRepositoryTest {
|
|||||||
fun testExitAnnouncements_WithSubtype() {
|
fun testExitAnnouncements_WithSubtype() {
|
||||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
||||||
repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1, TEST_SUBTYPE)
|
repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1, TEST_SUBTYPE)
|
||||||
repository.onAdvertisementSent(TEST_SERVICE_ID_1)
|
repository.onAdvertisementSent(TEST_SERVICE_ID_1, 2 /* sentPacketCount */)
|
||||||
|
|
||||||
val exitAnnouncement = repository.exitService(TEST_SERVICE_ID_1)
|
val exitAnnouncement = repository.exitService(TEST_SERVICE_ID_1)
|
||||||
assertNotNull(exitAnnouncement)
|
assertNotNull(exitAnnouncement)
|
||||||
@@ -230,7 +230,7 @@ class MdnsRecordRepositoryTest {
|
|||||||
fun testExitingServiceReAdded() {
|
fun testExitingServiceReAdded() {
|
||||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
||||||
repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
|
repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
|
||||||
repository.onAdvertisementSent(TEST_SERVICE_ID_1)
|
repository.onAdvertisementSent(TEST_SERVICE_ID_1, 2 /* sentPacketCount */)
|
||||||
repository.exitService(TEST_SERVICE_ID_1)
|
repository.exitService(TEST_SERVICE_ID_1)
|
||||||
|
|
||||||
assertEquals(TEST_SERVICE_ID_1,
|
assertEquals(TEST_SERVICE_ID_1,
|
||||||
@@ -246,7 +246,7 @@ class MdnsRecordRepositoryTest {
|
|||||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
||||||
val announcementInfo = repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1,
|
val announcementInfo = repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1,
|
||||||
TEST_SUBTYPE)
|
TEST_SUBTYPE)
|
||||||
repository.onAdvertisementSent(TEST_SERVICE_ID_1)
|
repository.onAdvertisementSent(TEST_SERVICE_ID_1, 2 /* sentPacketCount */)
|
||||||
val packet = announcementInfo.getPacket(0)
|
val packet = announcementInfo.getPacket(0)
|
||||||
|
|
||||||
assertEquals(0x8400 /* response, authoritative */, packet.flags)
|
assertEquals(0x8400 /* response, authoritative */, packet.flags)
|
||||||
@@ -657,6 +657,34 @@ class MdnsRecordRepositoryTest {
|
|||||||
// Above records are identical to the actual registrations: no conflict
|
// Above records are identical to the actual registrations: no conflict
|
||||||
assertEquals(emptySet(), repository.getConflictingServices(packet))
|
assertEquals(emptySet(), repository.getConflictingServices(packet))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testGetServiceRepliedRequestsCount() {
|
||||||
|
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
||||||
|
repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
|
||||||
|
// Verify that there is no packet replied.
|
||||||
|
assertEquals(MdnsConstants.NO_PACKET,
|
||||||
|
repository.getServiceRepliedRequestsCount(TEST_SERVICE_ID_1))
|
||||||
|
|
||||||
|
val questions = listOf(MdnsPointerRecord(arrayOf("_testservice", "_tcp", "local"),
|
||||||
|
0L /* receiptTimeMillis */,
|
||||||
|
false /* cacheFlush */,
|
||||||
|
// TTL and data is empty for a question
|
||||||
|
0L /* ttlMillis */,
|
||||||
|
null /* pointer */))
|
||||||
|
val query = MdnsPacket(0 /* flags */, questions, listOf() /* answers */,
|
||||||
|
listOf() /* authorityRecords */, listOf() /* additionalRecords */)
|
||||||
|
val src = InetSocketAddress(parseNumericAddress("192.0.2.123"), 5353)
|
||||||
|
|
||||||
|
// Reply to the question and verify there is one packet replied.
|
||||||
|
val reply = repository.getReply(query, src)
|
||||||
|
assertNotNull(reply)
|
||||||
|
assertEquals(1, repository.getServiceRepliedRequestsCount(TEST_SERVICE_ID_1))
|
||||||
|
|
||||||
|
// No package replied for unknown service.
|
||||||
|
assertEquals(MdnsConstants.NO_PACKET,
|
||||||
|
repository.getServiceRepliedRequestsCount(TEST_SERVICE_ID_2))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MdnsRecordRepository.initWithService(
|
private fun MdnsRecordRepository.initWithService(
|
||||||
|
|||||||
Reference in New Issue
Block a user