Merge "Address comment from ag/12107302" into main
diff --git a/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt b/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt
index ece4a34..464862d 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt
+++ b/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt
@@ -27,12 +27,14 @@
import androidx.test.core.app.ApplicationProvider
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.SkipPresubmit
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlin.test.assertEquals
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.junit.After
+import org.junit.AssumptionViolatedException
import org.junit.Before
import org.junit.runner.RunWith
@@ -67,10 +69,21 @@
@Test
@Throws(Exception::class)
+ @SkipPresubmit(reason = "b/293141085 Confirm non-flaky and move to presubmit after SLO")
fun testBidirectionalStream_GetStream_CompletesSuccessfully() {
stream = createBidirectionalStreamBuilder(URL).setHttpMethod("GET").build()
stream!!.start()
- callback.assumeCallback(ResponseStep.ON_SUCCEEDED)
+ // We call to a real server and hence the server may not be reachable, cancel this stream
+ // and rethrow the exception before tearDown,
+ // otherwise shutdown would fail with active request error.
+ try {
+ callback.assumeCallback(ResponseStep.ON_SUCCEEDED)
+ } catch (e: AssumptionViolatedException) {
+ stream!!.cancel()
+ callback.blockForDone()
+ throw e
+ }
+
val info = callback.mResponseInfo
assumeOKStatusCode(info)
MatcherAssert.assertThat(
@@ -185,5 +198,4 @@
stream = builder.build()
assertThat(stream!!.isDelayRequestHeadersUntilFirstFlushEnabled()).isTrue()
}
-
}
diff --git a/Cronet/tests/mts/jarjar_excludes.txt b/Cronet/tests/mts/jarjar_excludes.txt
index a3e86de..e8fd39b 100644
--- a/Cronet/tests/mts/jarjar_excludes.txt
+++ b/Cronet/tests/mts/jarjar_excludes.txt
@@ -1,5 +1,8 @@
-# It's prohibited to jarjar androidx packages
+# jarjar-gen can't handle some kotlin object expression, exclude packages that include them
androidx\..+
+kotlin\.test\..+
+kotlin\.reflect\..+
+org\.mockito\..+
# Do not jarjar the api classes
android\.net\..+
# cronet_tests.so is not jarjared and uses base classes. We can remove this when there's a
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 0326bf2..76e4af8 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -5,7 +5,12 @@
},
{
// In addition to ConnectivityCoverageTests, runs non-connectivity-module tests
- "name": "FrameworksNetTests"
+ "name": "FrameworksNetTests",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ }
+ ]
},
// Run in addition to mainline-presubmit as mainline-presubmit is not
// supported in every branch.
@@ -100,6 +105,9 @@
"name": "NetHttpCoverageTests",
"options": [
{
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
// These sometimes take longer than 1 min which is the presubmit timeout
"exclude-annotation": "androidx.test.filters.LargeTest"
}
@@ -120,6 +128,18 @@
},
{
"name": "FrameworksNetDeflakeTest"
+ },
+ // Postsubmit on virtual devices to monitor flakiness of @SkipPresubmit methods
+ {
+ "name": "CtsNetTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksNetTests"
}
],
"mainline-presubmit": [
@@ -130,6 +150,9 @@
"exclude-annotation": "com.android.testutils.SkipPresubmit"
},
{
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
"exclude-annotation": "androidx.test.filters.RequiresDevice"
}
]
@@ -141,6 +164,9 @@
"exclude-annotation": "com.android.testutils.SkipPresubmit"
},
{
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
"exclude-annotation": "androidx.test.filters.RequiresDevice"
}
]
@@ -152,6 +178,9 @@
"exclude-annotation": "com.android.testutils.SkipPresubmit"
},
{
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
"exclude-annotation": "androidx.test.filters.RequiresDevice"
}
]
@@ -163,6 +192,9 @@
"exclude-annotation": "com.android.testutils.SkipPresubmit"
},
{
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
"exclude-annotation": "androidx.test.filters.RequiresDevice"
}
]
@@ -176,10 +208,16 @@
"exclude-annotation": "com.android.testutils.SkipPresubmit"
},
{
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
"exclude-annotation": "androidx.test.filters.RequiresDevice"
},
{
"exclude-annotation": "com.android.testutils.ConnectivityModuleTest"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.DnsResolverModuleTest"
}
]
},
@@ -194,7 +232,13 @@
"exclude-annotation": "com.android.testutils.SkipPresubmit"
},
{
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
"exclude-annotation": "androidx.test.filters.RequiresDevice"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.DnsResolverModuleTest"
}
]
},
@@ -220,6 +264,9 @@
"name": "NetHttpCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]",
"options": [
{
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
// These sometimes take longer than 1 min which is the presubmit timeout
"exclude-annotation": "androidx.test.filters.LargeTest"
}
@@ -248,6 +295,15 @@
"exclude-annotation": "com.android.testutils.NetworkStackModuleTest"
}
]
+ },
+ // Postsubmit on virtual devices to monitor flakiness of @SkipMainlinePresubmit methods
+ {
+ "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ }
+ ]
}
],
"imports": [
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index 905b8fa..a104084 100644
--- a/bpf_progs/clatd.c
+++ b/bpf_progs/clatd.c
@@ -138,10 +138,11 @@
}
switch (proto) {
- case IPPROTO_TCP: // For TCP & UDP the checksum neutrality of the chosen IPv6
- case IPPROTO_UDP: // address means there is no need to update their checksums.
- case IPPROTO_GRE: // We do not need to bother looking at GRE/ESP headers,
- case IPPROTO_ESP: // since there is never a checksum to update.
+ case IPPROTO_TCP: // For TCP, UDP & UDPLITE the checksum neutrality of the chosen
+ case IPPROTO_UDP: // IPv6 address means there is no need to update their checksums.
+ case IPPROTO_UDPLITE: //
+ case IPPROTO_GRE: // We do not need to bother looking at GRE/ESP headers,
+ case IPPROTO_ESP: // since there is never a checksum to update.
break;
default: // do not know how to handle anything else
@@ -328,12 +329,13 @@
if (ip4->frag_off & ~htons(IP_DF)) return TC_ACT_PIPE;
switch (ip4->protocol) {
- case IPPROTO_TCP: // For TCP & UDP the checksum neutrality of the chosen IPv6
- case IPPROTO_GRE: // address means there is no need to update their checksums.
- case IPPROTO_ESP: // We do not need to bother looking at GRE/ESP headers,
- break; // since there is never a checksum to update.
+ case IPPROTO_TCP: // For TCP, UDP & UDPLITE the checksum neutrality of the chosen
+ case IPPROTO_UDPLITE: // IPv6 address means there is no need to update their checksums.
+ case IPPROTO_GRE: // We do not need to bother looking at GRE/ESP headers,
+ case IPPROTO_ESP: // since there is never a checksum to update.
+ break;
- case IPPROTO_UDP: // See above comment, but must also have UDP header...
+ case IPPROTO_UDP: // See above comment, but must also have UDP header...
if (data + sizeof(*ip4) + sizeof(struct udphdr) > data_end) return TC_ACT_PIPE;
const struct udphdr* uh = (const struct udphdr*)(ip4 + 1);
// If IPv4/UDP checksum is 0 then fallback to clatd so it can calculate the
diff --git a/remote_auth/OWNERS b/remote_auth/OWNERS
new file mode 100644
index 0000000..25a32b9
--- /dev/null
+++ b/remote_auth/OWNERS
@@ -0,0 +1,14 @@
+# Bug component: 1145231
+# Bug template url: http://b/new?component=1145231&template=1715387
+billyhuang@google.com
+boetger@google.com
+casbor@google.com
+derekjedral@google.com
+dlm@google.com
+igorzas@google.com
+jacobhobbie@google.com
+jasonsun@google.com
+jianbing@google.com
+jinjiechen@google.com
+justinmcclain@google.com
+salilr@google.com
diff --git a/remote_auth/README.md b/remote_auth/README.md
new file mode 100644
index 0000000..384fcf7
--- /dev/null
+++ b/remote_auth/README.md
@@ -0,0 +1,47 @@
+# RemoteAuth Mainline Module
+
+This directory contains code for the RemoteAuth module.
+
+## Directory Structure
+
+`framework`
+ - Contains client side APIs and AIDL files.
+
+`jni`
+ - JNI wrapper for invoking Android APIs from native code.
+
+`native`
+ - Native code implementation for RemoteAuth module services.
+
+`service`
+ - Server side implementation for RemoteAuth module services.
+
+`tests`
+ - Unit/Multi devices tests for RemoteAuth module (both Java and native code).
+
+## IDE setup
+
+### AIDEGen
+
+AIDEGen is deprecated, prefer ASfP [go/asfp](http://go/asfp)
+```sh
+$ source build/envsetup.sh && lunch <TARGET>
+$ cd packages/modules/Connectivity
+$ aidegen .
+# This will launch Intellij project for RemoteAuth module.
+```
+
+### ASfP
+
+See full instructions for ASfP at [go/asfp-getting-started](http://go/asfp-getting-started)
+
+## Build and Install
+
+```sh
+$ source build/envsetup.sh && lunch <TARGET>
+$ m com.google.android.tethering deapexer
+$ $ANDROID_BUILD_TOP/out/host/linux-x86/bin/deapexer decompress --input \
+ ${ANDROID_PRODUCT_OUT}/system/apex/com.google.android.tethering.capex \
+ --output /tmp/tethering.apex
+$ adb install -r /tmp/tethering.apex
+```
diff --git a/service-t/src/com/android/metrics/NetworkNsdReportedMetrics.java b/service-t/src/com/android/metrics/NetworkNsdReportedMetrics.java
index 6c8e273..bcedbef 100644
--- a/service-t/src/com/android/metrics/NetworkNsdReportedMetrics.java
+++ b/service-t/src/com/android/metrics/NetworkNsdReportedMetrics.java
@@ -16,6 +16,14 @@
package com.android.metrics;
+import static com.android.metrics.NetworkNsdReported.Builder;
+
+import android.stats.connectivity.MdnsQueryResult;
+import android.stats.connectivity.NsdEventType;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.ConnectivityStatsLog;
+
/**
* Class to record the NetworkNsdReported into statsd. Each client should create this class to
* report its data.
@@ -25,11 +33,93 @@
private final boolean mIsLegacy;
// The client id.
private final int mClientId;
+ private final Dependencies mDependencies;
public NetworkNsdReportedMetrics(boolean isLegacy, int clientId) {
- mIsLegacy = isLegacy;
- mClientId = clientId;
+ this(isLegacy, clientId, new Dependencies());
}
- // TODO: Report metrics data.
+ @VisibleForTesting
+ NetworkNsdReportedMetrics(boolean isLegacy, int clientId, Dependencies dependencies) {
+ mIsLegacy = isLegacy;
+ mClientId = clientId;
+ mDependencies = dependencies;
+ }
+
+ /**
+ * Dependencies of NetworkNsdReportedMetrics, for injection in tests.
+ */
+ public static class Dependencies {
+
+ /**
+ * @see ConnectivityStatsLog
+ */
+ public void statsWrite(NetworkNsdReported event) {
+ ConnectivityStatsLog.write(ConnectivityStatsLog.NETWORK_NSD_REPORTED,
+ event.getIsLegacy(),
+ event.getClientId(),
+ event.getTransactionId(),
+ event.getIsKnownService(),
+ event.getType().getNumber(),
+ event.getEventDurationMillisec(),
+ event.getQueryResult().getNumber(),
+ event.getFoundServiceCount(),
+ event.getFoundCallbackCount(),
+ event.getLostCallbackCount(),
+ event.getRepliedRequestsCount());
+ }
+ }
+
+ private Builder makeReportedBuilder() {
+ final Builder builder = NetworkNsdReported.newBuilder();
+ builder.setIsLegacy(mIsLegacy);
+ builder.setClientId(mClientId);
+ return builder;
+ }
+
+ /**
+ * Report service registration succeeded metric data.
+ *
+ * @param transactionId The transaction id of service registration.
+ * @param durationMs The duration of service registration success.
+ */
+ public void reportServiceRegistrationSucceeded(int transactionId, long durationMs) {
+ final Builder builder = makeReportedBuilder();
+ builder.setTransactionId(transactionId);
+ builder.setType(NsdEventType.NET_REGISTER);
+ builder.setQueryResult(MdnsQueryResult.MQR_SERVICE_REGISTERED);
+ builder.setEventDurationMillisec(durationMs);
+ mDependencies.statsWrite(builder.build());
+ }
+
+ /**
+ * Report service registration failed metric data.
+ *
+ * @param transactionId The transaction id of service registration.
+ * @param durationMs The duration of service registration failed.
+ */
+ public void reportServiceRegistrationFailed(int transactionId, long durationMs) {
+ final Builder builder = makeReportedBuilder();
+ builder.setTransactionId(transactionId);
+ builder.setType(NsdEventType.NET_REGISTER);
+ builder.setQueryResult(MdnsQueryResult.MQR_SERVICE_REGISTRATION_FAILED);
+ builder.setEventDurationMillisec(durationMs);
+ mDependencies.statsWrite(builder.build());
+ }
+
+ /**
+ * Report service unregistration success metric data.
+ *
+ * @param transactionId The transaction id of service registration.
+ * @param durationMs The duration of service stayed registered.
+ */
+ public void reportServiceUnregistration(int transactionId, long durationMs) {
+ final Builder builder = makeReportedBuilder();
+ builder.setTransactionId(transactionId);
+ builder.setType(NsdEventType.NET_REGISTER);
+ builder.setQueryResult(MdnsQueryResult.MQR_SERVICE_UNREGISTERED);
+ builder.setEventDurationMillisec(durationMs);
+ // TODO: Report repliedRequestsCount
+ mDependencies.statsWrite(builder.build());
+ }
}
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 95717c2..745c5bc 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -162,6 +162,7 @@
public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
private static final long CLEANUP_DELAY_MS = 10000;
private static final int IFACE_IDX_ANY = 0;
+ private static final int NO_TRANSACTION = -1;
private static final SharedLog LOGGER = new SharedLog("serviceDiscovery");
private final Context mContext;
@@ -178,6 +179,8 @@
private final MdnsSocketProvider mMdnsSocketProvider;
@NonNull
private final MdnsAdvertiser mAdvertiser;
+ @NonNull
+ private final Clock mClock;
private final SharedLog mServiceLogs = LOGGER.forSubComponent(TAG);
// WARNING : Accessing these values in any thread is not safe, it must only be changed in the
// state machine thread. If change this outside state machine, it will need to introduce
@@ -530,8 +533,9 @@
try {
cb.asBinder().linkToDeath(arg.connector, 0);
final String tag = "Client" + arg.uid + "-" + mClientNumberId++;
- final NetworkNsdReportedMetrics metrics = new NetworkNsdReportedMetrics(
- !arg.useJavaBackend, (int) new Clock().elapsedRealtime());
+ final NetworkNsdReportedMetrics metrics =
+ mDeps.makeNetworkNsdReportedMetrics(
+ !arg.useJavaBackend, (int) mClock.elapsedRealtime());
cInfo = new ClientInfo(cb, arg.uid, arg.useJavaBackend,
mServiceLogs.forSubComponent(tag), metrics);
mClients.put(arg.connector, cInfo);
@@ -569,7 +573,7 @@
case NsdManager.REGISTER_SERVICE:
cInfo = getClientInfoForReply(msg);
if (cInfo != null) {
- cInfo.onRegisterServiceFailed(
+ cInfo.onRegisterServiceFailedImmediately(
clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
}
break;
@@ -651,8 +655,8 @@
private void storeLegacyRequestMap(int clientRequestId, int transactionId,
ClientInfo clientInfo, int what) {
- clientInfo.mClientRequests.put(
- clientRequestId, new LegacyClientRequest(transactionId, what));
+ clientInfo.mClientRequests.put(clientRequestId, new LegacyClientRequest(
+ transactionId, what, mClock, mClock.elapsedRealtime()));
mTransactionIdToClientInfoMap.put(transactionId, clientInfo);
// Remove the cleanup event because here comes a new request.
cancelStop();
@@ -660,8 +664,8 @@
private void storeAdvertiserRequestMap(int clientRequestId, int transactionId,
ClientInfo clientInfo, @Nullable Network requestedNetwork) {
- clientInfo.mClientRequests.put(clientRequestId,
- new AdvertiserClientRequest(transactionId, requestedNetwork));
+ clientInfo.mClientRequests.put(clientRequestId, new AdvertiserClientRequest(
+ transactionId, requestedNetwork, mClock, mClock.elapsedRealtime()));
mTransactionIdToClientInfoMap.put(transactionId, clientInfo);
updateMulticastLock();
}
@@ -684,8 +688,9 @@
private void storeDiscoveryManagerRequestMap(int clientRequestId, int transactionId,
MdnsListener listener, ClientInfo clientInfo,
@Nullable Network requestedNetwork) {
- clientInfo.mClientRequests.put(clientRequestId,
- new DiscoveryManagerRequest(transactionId, listener, requestedNetwork));
+ clientInfo.mClientRequests.put(clientRequestId, new DiscoveryManagerRequest(
+ transactionId, listener, requestedNetwork, mClock,
+ mClock.elapsedRealtime()));
mTransactionIdToClientInfoMap.put(transactionId, clientInfo);
updateMulticastLock();
}
@@ -838,7 +843,7 @@
}
if (requestLimitReached(clientInfo)) {
- clientInfo.onRegisterServiceFailed(
+ clientInfo.onRegisterServiceFailedImmediately(
clientRequestId, NsdManager.FAILURE_MAX_LIMIT);
break;
}
@@ -854,8 +859,8 @@
|| useAdvertiserForType(registerServiceType)) {
if (registerServiceType == null) {
Log.e(TAG, "Invalid service type: " + serviceType);
- clientInfo.onRegisterServiceFailed(clientRequestId,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ clientInfo.onRegisterServiceFailedImmediately(
+ clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
break;
}
serviceInfo.setServiceType(registerServiceType);
@@ -882,7 +887,7 @@
// Return success after mDns reports success
} else {
unregisterService(transactionId);
- clientInfo.onRegisterServiceFailed(
+ clientInfo.onRegisterServiceFailedImmediately(
clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
}
@@ -914,10 +919,12 @@
// instead of looking at the flag value.
if (request instanceof AdvertiserClientRequest) {
mAdvertiser.removeService(transactionId);
- clientInfo.onUnregisterServiceSucceeded(clientRequestId);
+ clientInfo.onUnregisterServiceSucceeded(clientRequestId, transactionId,
+ request.calculateRequestDurationMs());
} else {
if (unregisterService(transactionId)) {
- clientInfo.onUnregisterServiceSucceeded(clientRequestId);
+ clientInfo.onUnregisterServiceSucceeded(clientRequestId,
+ transactionId, request.calculateRequestDurationMs());
} else {
clientInfo.onUnregisterServiceFailed(
clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
@@ -1181,12 +1188,18 @@
final RegistrationInfo info = (RegistrationInfo) obj;
final String name = info.serviceName;
servInfo = new NsdServiceInfo(name, null /* serviceType */);
- clientInfo.onRegisterServiceSucceeded(clientRequestId, servInfo);
+ final ClientRequest request =
+ clientInfo.mClientRequests.get(clientRequestId);
+ clientInfo.onRegisterServiceSucceeded(clientRequestId, servInfo,
+ transactionId, request.calculateRequestDurationMs());
break;
}
case IMDnsEventListener.SERVICE_REGISTRATION_FAILED:
- clientInfo.onRegisterServiceFailed(
- clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
+ final ClientRequest request =
+ clientInfo.mClientRequests.get(clientRequestId);
+ clientInfo.onRegisterServiceFailed(clientRequestId,
+ NsdManager.FAILURE_INTERNAL_ERROR, transactionId,
+ request.calculateRequestDurationMs());
break;
case IMDnsEventListener.SERVICE_RESOLVED: {
final ResolutionInfo info = (ResolutionInfo) obj;
@@ -1566,6 +1579,7 @@
handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager));
mAdvertiser = deps.makeMdnsAdvertiser(handler.getLooper(), mMdnsSocketProvider,
new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser"));
+ mClock = deps.makeClock();
}
/**
@@ -1655,6 +1669,21 @@
public int getCallingUid() {
return Binder.getCallingUid();
}
+
+ /**
+ * @see NetworkNsdReportedMetrics
+ */
+ public NetworkNsdReportedMetrics makeNetworkNsdReportedMetrics(
+ boolean isLegacy, int clientId) {
+ return new NetworkNsdReportedMetrics(isLegacy, clientId);
+ }
+
+ /**
+ * @see MdnsUtils.Clock
+ */
+ public Clock makeClock() {
+ return new Clock();
+ }
}
/**
@@ -1755,7 +1784,9 @@
// onRegisterServiceSucceeded only has the service name in its info. This aligns with
// historical behavior.
final NsdServiceInfo cbInfo = new NsdServiceInfo(registeredInfo.getServiceName(), null);
- clientInfo.onRegisterServiceSucceeded(clientRequestId, cbInfo);
+ final ClientRequest request = clientInfo.mClientRequests.get(clientRequestId);
+ clientInfo.onRegisterServiceSucceeded(
+ clientRequestId, cbInfo, transactionId, request.calculateRequestDurationMs());
}
@Override
@@ -1765,8 +1796,9 @@
final int clientRequestId = getClientRequestIdOrLog(clientInfo, transactionId);
if (clientRequestId < 0) return;
-
- clientInfo.onRegisterServiceFailed(clientRequestId, errorCode);
+ final ClientRequest request = clientInfo.mClientRequests.get(clientRequestId);
+ clientInfo.onRegisterServiceFailed(clientRequestId, errorCode, transactionId,
+ request.calculateRequestDurationMs());
}
private ClientInfo getClientInfoOrLog(int transactionId) {
@@ -2026,17 +2058,27 @@
private abstract static class ClientRequest {
private final int mTransactionId;
+ private final Clock mClock;
+ private final long mStartTimeMs;
- private ClientRequest(int transactionId) {
+ private ClientRequest(int transactionId, @NonNull Clock clock, long startTimeMs) {
mTransactionId = transactionId;
+ mClock = clock;
+ mStartTimeMs = startTimeMs;
+ }
+
+ public long calculateRequestDurationMs() {
+ final long stopTimeMs = mClock.elapsedRealtime();
+ return stopTimeMs - mStartTimeMs;
}
}
private static class LegacyClientRequest extends ClientRequest {
private final int mRequestCode;
- private LegacyClientRequest(int transactionId, int requestCode) {
- super(transactionId);
+ private LegacyClientRequest(int transactionId, int requestCode, @NonNull Clock clock,
+ long startTimeMs) {
+ super(transactionId, clock, startTimeMs);
mRequestCode = requestCode;
}
}
@@ -2045,8 +2087,9 @@
@Nullable
private final Network mRequestedNetwork;
- private JavaBackendClientRequest(int transactionId, @Nullable Network requestedNetwork) {
- super(transactionId);
+ private JavaBackendClientRequest(int transactionId, @Nullable Network requestedNetwork,
+ @NonNull Clock clock, long startTimeMs) {
+ super(transactionId, clock, startTimeMs);
mRequestedNetwork = requestedNetwork;
}
@@ -2057,8 +2100,9 @@
}
private static class AdvertiserClientRequest extends JavaBackendClientRequest {
- private AdvertiserClientRequest(int transactionId, @Nullable Network requestedNetwork) {
- super(transactionId, requestedNetwork);
+ private AdvertiserClientRequest(int transactionId, @Nullable Network requestedNetwork,
+ @NonNull Clock clock, long startTimeMs) {
+ super(transactionId, requestedNetwork, clock, startTimeMs);
}
}
@@ -2067,8 +2111,8 @@
private final MdnsListener mListener;
private DiscoveryManagerRequest(int transactionId, @NonNull MdnsListener listener,
- @Nullable Network requestedNetwork) {
- super(transactionId, requestedNetwork);
+ @Nullable Network requestedNetwork, @NonNull Clock clock, long startTimeMs) {
+ super(transactionId, requestedNetwork, clock, startTimeMs);
mListener = listener;
}
}
@@ -2161,6 +2205,8 @@
if (request instanceof AdvertiserClientRequest) {
mAdvertiser.removeService(transactionId);
+ mMetrics.reportServiceUnregistration(
+ transactionId, request.calculateRequestDurationMs());
continue;
}
@@ -2177,6 +2223,8 @@
break;
case NsdManager.REGISTER_SERVICE:
unregisterService(transactionId);
+ mMetrics.reportServiceUnregistration(
+ transactionId, request.calculateRequestDurationMs());
break;
default:
break;
@@ -2268,7 +2316,13 @@
}
}
- void onRegisterServiceFailed(int listenerKey, int error) {
+ void onRegisterServiceFailedImmediately(int listenerKey, int error) {
+ onRegisterServiceFailed(listenerKey, error, NO_TRANSACTION, 0 /* durationMs */);
+ }
+
+ void onRegisterServiceFailed(int listenerKey, int error, int transactionId,
+ long durationMs) {
+ mMetrics.reportServiceRegistrationFailed(transactionId, durationMs);
try {
mCb.onRegisterServiceFailed(listenerKey, error);
} catch (RemoteException e) {
@@ -2276,7 +2330,9 @@
}
}
- void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) {
+ void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info, int transactionId,
+ long durationMs) {
+ mMetrics.reportServiceRegistrationSucceeded(transactionId, durationMs);
try {
mCb.onRegisterServiceSucceeded(listenerKey, info);
} catch (RemoteException e) {
@@ -2292,7 +2348,8 @@
}
}
- void onUnregisterServiceSucceeded(int listenerKey) {
+ void onUnregisterServiceSucceeded(int listenerKey, int transactionId, long durationMs) {
+ mMetrics.reportServiceUnregistration(transactionId, durationMs);
try {
mCb.onUnregisterServiceSucceeded(listenerKey);
} catch (RemoteException e) {
diff --git a/service-t/src/com/android/server/connectivity/mdns/ExecutorProvider.java b/service-t/src/com/android/server/connectivity/mdns/ExecutorProvider.java
index 0eebc61..161669b 100644
--- a/service-t/src/com/android/server/connectivity/mdns/ExecutorProvider.java
+++ b/service-t/src/com/android/server/connectivity/mdns/ExecutorProvider.java
@@ -16,6 +16,7 @@
package com.android.server.connectivity.mdns;
+import android.annotation.NonNull;
import android.util.ArraySet;
import java.util.Set;
@@ -47,5 +48,17 @@
}
executor.shutdownNow();
}
+ serviceTypeClientSchedulerExecutors.clear();
+ }
+
+ /**
+ * Shutdown one executor service and remove the executor service from the set.
+ * @param executorService the executorService to be shutdown
+ */
+ public void shutdownExecutorService(@NonNull ScheduledExecutorService executorService) {
+ if (!executorService.isShutdown()) {
+ executorService.shutdownNow();
+ }
+ serviceTypeClientSchedulerExecutors.remove(executorService);
}
}
\ No newline at end of file
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
index f386dd4..d55098c 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
@@ -204,6 +204,7 @@
if (serviceTypeClient == null) return;
// Notify all listeners that all services are removed from this socket.
serviceTypeClient.notifySocketDestroyed();
+ executorProvider.shutdownExecutorService(serviceTypeClient.getExecutor());
perSocketServiceTypeClients.remove(serviceTypeClient);
}
});
@@ -238,6 +239,7 @@
if (serviceTypeClient.stopSendAndReceive(listener)) {
// No listener is registered for the service type anymore, remove it from the list
// of the service type clients.
+ executorProvider.shutdownExecutorService(serviceTypeClient.getExecutor());
perSocketServiceTypeClients.remove(serviceTypeClient);
}
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
index 0752c01..b5fd8a0 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -39,7 +39,6 @@
import java.net.Inet6Address;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -330,6 +329,13 @@
}
}
+ /**
+ * Get the executor service.
+ */
+ public ScheduledExecutorService getExecutor() {
+ return executor;
+ }
+
private void removeScheduledTask() {
dependencies.removeMessages(handler, EVENT_START_QUERYTASK);
sharedLog.log("Remove EVENT_START_QUERYTASK"
@@ -538,145 +544,6 @@
return new MdnsPacketWriter(DEFAULT_MTU);
}
- // A configuration for the PeriodicalQueryTask that contains parameters to build a query packet.
- // Call to getConfigForNextRun returns a config that can be used to build the next query task.
- @VisibleForTesting
- static 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 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;
- // The following fields are used by QueryTask so we need to test them.
- @VisibleForTesting
- final List<String> subtypes;
- private final boolean alwaysAskForUnicastResponse =
- MdnsConfigs.alwaysAskForUnicastResponseInEachBurst();
- private final boolean usePassiveMode;
- private final boolean onlyUseIpv6OnIpv6OnlyNetworks;
- private final int numOfQueriesBeforeBackoff;
- @VisibleForTesting
- final int transactionId;
- @VisibleForTesting
- final boolean expectUnicastResponse;
- private final int queriesPerBurst;
- private final int timeBetweenBurstsInMs;
- private final int burstCounter;
- private final long delayUntilNextTaskWithoutBackoffMs;
- private final boolean isFirstBurst;
- private final long queryCount;
- @NonNull private final SocketKey socketKey;
-
-
- QueryTaskConfig(@NonNull QueryTaskConfig other, long queryCount, int transactionId,
- boolean expectUnicastResponse, boolean isFirstBurst, int burstCounter,
- int queriesPerBurst, int timeBetweenBurstsInMs,
- long delayUntilNextTaskWithoutBackoffMs) {
- this.subtypes = new ArrayList<>(other.subtypes);
- this.usePassiveMode = other.usePassiveMode;
- this.onlyUseIpv6OnIpv6OnlyNetworks = other.onlyUseIpv6OnIpv6OnlyNetworks;
- this.numOfQueriesBeforeBackoff = other.numOfQueriesBeforeBackoff;
- this.transactionId = transactionId;
- this.expectUnicastResponse = expectUnicastResponse;
- this.queriesPerBurst = queriesPerBurst;
- this.timeBetweenBurstsInMs = timeBetweenBurstsInMs;
- this.burstCounter = burstCounter;
- this.delayUntilNextTaskWithoutBackoffMs = delayUntilNextTaskWithoutBackoffMs;
- this.isFirstBurst = isFirstBurst;
- this.queryCount = queryCount;
- this.socketKey = other.socketKey;
- }
- QueryTaskConfig(@NonNull Collection<String> subtypes,
- boolean usePassiveMode,
- boolean onlyUseIpv6OnIpv6OnlyNetworks,
- int numOfQueriesBeforeBackoff,
- @Nullable SocketKey socketKey) {
- this.usePassiveMode = usePassiveMode;
- this.onlyUseIpv6OnIpv6OnlyNetworks = onlyUseIpv6OnIpv6OnlyNetworks;
- this.numOfQueriesBeforeBackoff = numOfQueriesBeforeBackoff;
- this.subtypes = new ArrayList<>(subtypes);
- this.queriesPerBurst = QUERIES_PER_BURST;
- this.burstCounter = 0;
- this.transactionId = 1;
- this.expectUnicastResponse = true;
- this.isFirstBurst = true;
- // Config the scan frequency based on the scan mode.
- if (this.usePassiveMode) {
- // 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;
- } 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.socketKey = socketKey;
- this.queryCount = 0;
- this.delayUntilNextTaskWithoutBackoffMs = TIME_BETWEEN_QUERIES_IN_BURST_MS;
- }
-
- QueryTaskConfig getConfigForNextRun() {
- long newQueryCount = queryCount + 1;
- int newTransactionId = transactionId + 1;
- 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) {
- 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;
- if (usePassiveMode) {
- 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);
- }
-
- private boolean shouldUseQueryBackoff() {
- // Don't enable backoff mode during the burst or in the first burst
- if (burstCounter != 0 || isFirstBurst) {
- return false;
- }
- return queryCount > numOfQueriesBeforeBackoff;
- }
- }
-
private List<MdnsResponse> makeResponsesForResolve(@NonNull SocketKey socketKey) {
final List<MdnsResponse> resolveResponses = new ArrayList<>();
for (int i = 0; i < listeners.size(); i++) {
diff --git a/service-t/src/com/android/server/connectivity/mdns/QueryTaskConfig.java b/service-t/src/com/android/server/connectivity/mdns/QueryTaskConfig.java
new file mode 100644
index 0000000..19282b0
--- /dev/null
+++ b/service-t/src/com/android/server/connectivity/mdns/QueryTaskConfig.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.mdns;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * A configuration for the PeriodicalQueryTask that contains parameters to build a query packet.
+ * Call to getConfigForNextRun returns a config that can be used to build the next query task.
+ */
+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 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;
+ // The following fields are used by QueryTask so we need to test them.
+ @VisibleForTesting
+ final List<String> subtypes;
+ private final boolean alwaysAskForUnicastResponse =
+ MdnsConfigs.alwaysAskForUnicastResponseInEachBurst();
+ private final boolean usePassiveMode;
+ final boolean onlyUseIpv6OnIpv6OnlyNetworks;
+ private final int numOfQueriesBeforeBackoff;
+ @VisibleForTesting
+ final int transactionId;
+ @VisibleForTesting
+ final boolean expectUnicastResponse;
+ private final int queriesPerBurst;
+ private final int timeBetweenBurstsInMs;
+ private final int burstCounter;
+ final long delayUntilNextTaskWithoutBackoffMs;
+ private final boolean isFirstBurst;
+ private final long queryCount;
+ @NonNull
+ final SocketKey socketKey;
+
+ QueryTaskConfig(@NonNull QueryTaskConfig other, long queryCount, int transactionId,
+ boolean expectUnicastResponse, boolean isFirstBurst, int burstCounter,
+ int queriesPerBurst, int timeBetweenBurstsInMs,
+ long delayUntilNextTaskWithoutBackoffMs) {
+ this.subtypes = new ArrayList<>(other.subtypes);
+ this.usePassiveMode = other.usePassiveMode;
+ this.onlyUseIpv6OnIpv6OnlyNetworks = other.onlyUseIpv6OnIpv6OnlyNetworks;
+ this.numOfQueriesBeforeBackoff = other.numOfQueriesBeforeBackoff;
+ this.transactionId = transactionId;
+ this.expectUnicastResponse = expectUnicastResponse;
+ this.queriesPerBurst = queriesPerBurst;
+ this.timeBetweenBurstsInMs = timeBetweenBurstsInMs;
+ this.burstCounter = burstCounter;
+ this.delayUntilNextTaskWithoutBackoffMs = delayUntilNextTaskWithoutBackoffMs;
+ this.isFirstBurst = isFirstBurst;
+ this.queryCount = queryCount;
+ this.socketKey = other.socketKey;
+ }
+ QueryTaskConfig(@NonNull Collection<String> subtypes,
+ boolean usePassiveMode,
+ boolean onlyUseIpv6OnIpv6OnlyNetworks,
+ int numOfQueriesBeforeBackoff,
+ @Nullable SocketKey socketKey) {
+ this.usePassiveMode = usePassiveMode;
+ this.onlyUseIpv6OnIpv6OnlyNetworks = onlyUseIpv6OnIpv6OnlyNetworks;
+ this.numOfQueriesBeforeBackoff = numOfQueriesBeforeBackoff;
+ this.subtypes = new ArrayList<>(subtypes);
+ this.queriesPerBurst = QUERIES_PER_BURST;
+ this.burstCounter = 0;
+ this.transactionId = 1;
+ this.expectUnicastResponse = true;
+ this.isFirstBurst = true;
+ // Config the scan frequency based on the scan mode.
+ if (this.usePassiveMode) {
+ // 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;
+ } 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.socketKey = socketKey;
+ this.queryCount = 0;
+ this.delayUntilNextTaskWithoutBackoffMs = TIME_BETWEEN_QUERIES_IN_BURST_MS;
+ }
+
+ /**
+ * Get new QueryTaskConfig for next run.
+ */
+ public QueryTaskConfig getConfigForNextRun() {
+ long newQueryCount = queryCount + 1;
+ int newTransactionId = transactionId + 1;
+ 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) {
+ 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;
+ if (usePassiveMode) {
+ 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);
+ }
+
+ /**
+ * Determine if the query backoff should be used.
+ */
+ public boolean shouldUseQueryBackoff() {
+ // Don't enable backoff mode during the burst or in the first burst
+ if (burstCounter != 0 || isFirstBurst) {
+ return false;
+ }
+ return queryCount > numOfQueriesBeforeBackoff;
+ }
+}
diff --git a/tests/benchmark/Android.bp b/tests/benchmark/Android.bp
new file mode 100644
index 0000000..77383ad
--- /dev/null
+++ b/tests/benchmark/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "ConnectivityBenchmarkTests",
+ defaults: [
+ "framework-connectivity-internal-test-defaults",
+ ],
+ platform_apis: true,
+ srcs: [
+ "src/**/*.kt",
+ "src/**/*.aidl",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "mockito-target-minus-junit4",
+ "net-tests-utils",
+ "service-connectivity-pre-jarjar",
+ "service-connectivity-tiramisu-pre-jarjar",
+ ],
+ test_suites: ["device-tests"],
+ jarjar_rules: ":connectivity-jarjar-rules",
+}
+
diff --git a/tests/benchmark/AndroidManifest.xml b/tests/benchmark/AndroidManifest.xml
new file mode 100644
index 0000000..bd2fce5
--- /dev/null
+++ b/tests/benchmark/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.connectivity.benchmarktests">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.connectivity.benchmarktests"
+ android:label="Connectivity Benchmark Tests" />
+</manifest>
diff --git a/tests/benchmark/OWNERS b/tests/benchmark/OWNERS
new file mode 100644
index 0000000..3101da5
--- /dev/null
+++ b/tests/benchmark/OWNERS
@@ -0,0 +1,2 @@
+# Bug template url: http://b/new?component=31808
+# TODO: move bug template config to common owners file once b/226427845 is resolved
\ No newline at end of file
diff --git a/tests/benchmark/res/raw/netstats-many-uids-zip b/tests/benchmark/res/raw/netstats-many-uids-zip
new file mode 100644
index 0000000..22e8254
--- /dev/null
+++ b/tests/benchmark/res/raw/netstats-many-uids-zip
Binary files differ
diff --git a/tests/benchmark/src/android/net/netstats/benchmarktests/NetworkStatsTest.kt b/tests/benchmark/src/android/net/netstats/benchmarktests/NetworkStatsTest.kt
new file mode 100644
index 0000000..8492268
--- /dev/null
+++ b/tests/benchmark/src/android/net/netstats/benchmarktests/NetworkStatsTest.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net.benchmarktests
+
+import android.net.NetworkStats.NonMonotonicObserver
+import android.net.NetworkStatsCollection
+import android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID
+import android.os.DropBoxManager
+import androidx.test.InstrumentationRegistry
+import com.android.internal.util.FileRotator
+import com.android.internal.util.FileRotator.Reader
+import com.android.server.connectivity.benchmarktests.R
+import com.android.server.net.NetworkStatsRecorder
+import java.io.BufferedInputStream
+import java.io.DataInputStream
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileOutputStream
+import java.nio.file.Files
+import java.util.concurrent.TimeUnit
+import java.util.zip.ZipInputStream
+import kotlin.test.assertTrue
+import org.junit.BeforeClass
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.mock
+
+@RunWith(JUnit4::class)
+class NetworkStatsTest {
+ companion object {
+ private val DEFAULT_BUFFER_SIZE = 8192
+ private val UID_COLLECTION_BUCKET_DURATION_MS = TimeUnit.HOURS.toMillis(2)
+ private val UID_RECORDER_ROTATE_AGE_MS = TimeUnit.DAYS.toMillis(15)
+ private val UID_RECORDER_DELETE_AGE_MS = TimeUnit.DAYS.toMillis(90)
+
+ private val testFilesDir by lazy {
+ // These file generated by using real user dataset which has many uid records
+ // and agreed to share the dataset for testing purpose. These dataset can be
+ // extracted from rooted devices by using
+ // "adb pull /data/misc/apexdata/com.android.tethering/netstats" command.
+ val zipInputStream =
+ ZipInputStream(getInputStreamForResource(R.raw.netstats_many_uids_zip))
+ unzipToTempDir(zipInputStream)
+ }
+
+ private val uidTestFiles: List<File> by lazy {
+ getSortedListForPrefix(testFilesDir, "uid")
+ }
+
+ // Test results shows the test cases who read the file first will take longer time to
+ // execute, and reading time getting shorter each time. Read files several times prior to
+ // tests to minimize the impact. This cannot live in setUp() since the time
+ // spent on the file reading will be attributed to the time spent on the individual
+ // test case.
+ @JvmStatic
+ @BeforeClass
+ fun setUpOnce() {
+ for (i in 1..10) {
+ val collection = NetworkStatsCollection(UID_COLLECTION_BUCKET_DURATION_MS)
+ for (file in uidTestFiles) {
+ readFile(file, collection)
+ }
+ }
+ }
+
+ private fun getInputStreamForResource(resourceId: Int): DataInputStream {
+ return DataInputStream(
+ InstrumentationRegistry.getContext()
+ .getResources().openRawResource(resourceId)
+ )
+ }
+
+ private fun unzipToTempDir(zis: ZipInputStream): File {
+ val statsDir =
+ Files.createTempDirectory(NetworkStatsTest::class.simpleName).toFile()
+ while (true) {
+ val entryName = zis.nextEntry?.name ?: break
+ val file = File(statsDir, entryName)
+ FileOutputStream(file).use { zis.copyTo(it, DEFAULT_BUFFER_SIZE) }
+ }
+ return statsDir
+ }
+
+ // List [xt|uid|uid_tag].<start>-<end> files under the given directory.
+ private fun getSortedListForPrefix(statsDir: File, prefix: String): List<File> {
+ assertTrue(statsDir.exists())
+ return (statsDir.list() ?: arrayOf()).mapNotNull {
+ if (it.startsWith("$prefix.")) File(statsDir, it) else null
+ }.sorted()
+ }
+
+ private fun readFile(file: File, reader: Reader) =
+ BufferedInputStream(FileInputStream(file)).use {
+ reader.read(it)
+ }
+ }
+
+ @Test
+ fun testReadCollection_manyUids() {
+ for (i in 1..10) {
+ val collection = NetworkStatsCollection(UID_COLLECTION_BUCKET_DURATION_MS)
+ for (file in uidTestFiles) {
+ readFile(file, collection)
+ }
+ }
+ }
+
+ @Test
+ fun testReadFromRecorder_manyUids() {
+ for (i in 1..10) {
+ val recorder = NetworkStatsRecorder(
+ FileRotator(
+ testFilesDir, PREFIX_UID, UID_RECORDER_ROTATE_AGE_MS, UID_RECORDER_DELETE_AGE_MS
+ ),
+ mock<NonMonotonicObserver<String>>(),
+ mock(DropBoxManager::class.java),
+ PREFIX_UID,
+ UID_COLLECTION_BUCKET_DURATION_MS,
+ false /* includeTags */,
+ false /* wipeOnError */
+ )
+ recorder.orLoadCompleteLocked
+ }
+ }
+
+ inline fun <reified T : Any> mock(): T = mock(T::class.java)
+}
diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp
index 891c2dd..e55ba63 100644
--- a/tests/cts/hostside/Android.bp
+++ b/tests/cts/hostside/Android.bp
@@ -32,6 +32,7 @@
// Only compile source java files in this apk.
srcs: ["src/**/*.java"],
libs: [
+ "net-tests-utils-host-device-common",
"cts-tradefed",
"tradefed",
],
diff --git a/tests/cts/hostside/TEST_MAPPING b/tests/cts/hostside/TEST_MAPPING
index 2cfd7af..dc86fb1 100644
--- a/tests/cts/hostside/TEST_MAPPING
+++ b/tests/cts/hostside/TEST_MAPPING
@@ -11,6 +11,20 @@
},
{
"exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ // Postsubmit on virtual devices to monitor flakiness of @SkipPresubmit methods
+ "name": "CtsHostsideNetworkTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
}
]
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
index 691ac90..4f21af7 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
@@ -18,6 +18,8 @@
import android.platform.test.annotations.RequiresDevice;
+import com.android.testutils.SkipPresubmit;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -35,11 +37,13 @@
uninstallPackage(TEST_APP2_PKG, true);
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testChangeUnderlyingNetworks() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testChangeUnderlyingNetworks");
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testDefault() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testDefault");
@@ -162,6 +166,7 @@
runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testBlockIncomingPackets");
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testSetVpnDefaultForUids() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testSetVpnDefaultForUids");
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index dc22369..1d79806 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
+++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -49,6 +49,7 @@
import com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTP_URL
import com.android.testutils.DeviceConfigRule
import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
+import com.android.testutils.SkipMainlinePresubmit
import com.android.testutils.TestHttpServer
import com.android.testutils.TestHttpServer.Request
import com.android.testutils.TestableNetworkCallback
@@ -137,6 +138,7 @@
}
@Test
+ @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
fun testCaptivePortalIsNotDefaultNetwork() {
assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY))
assumeTrue(pm.hasSystemFeature(FEATURE_WIFI))
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index a0508e1..e978664 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -197,6 +197,8 @@
import com.android.testutils.DeviceInfoUtils;
import com.android.testutils.DumpTestUtils;
import com.android.testutils.RecorderCallback.CallbackEntry;
+import com.android.testutils.SkipMainlinePresubmit;
+import com.android.testutils.SkipPresubmit;
import com.android.testutils.TestHttpServer;
import com.android.testutils.TestNetworkTracker;
import com.android.testutils.TestableNetworkCallback;
@@ -1017,6 +1019,7 @@
@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testIsPrivateDnsBroken() throws InterruptedException {
final String invalidPrivateDnsServer = "invalidhostname.example.com";
final String goodPrivateDnsServer = "dns.google";
@@ -1124,6 +1127,7 @@
*/
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
+ @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testRegisterNetworkCallback_withPendingIntent() {
assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
@@ -1267,6 +1271,7 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
+ @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testRegisterNetworkRequest_identicalPendingIntents() throws Exception {
runIdenticalPendingIntentsRequestTest(false /* useListen */);
}
@@ -2129,6 +2134,7 @@
*/
@AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps")
@Test
+ @SkipPresubmit(reason = "Out of SLO flakiness")
public void testSetAirplaneMode() throws Exception{
// Starting from T, wifi supports airplane mode enhancement which may not disconnect wifi
// when airplane mode is on. The actual behavior that the device will have could only be
@@ -2560,10 +2566,9 @@
assertThrows(SecurityException.class, () -> mCm.factoryReset());
}
- // @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
- // @Test
- // Temporarily disable the unreliable test, which is blocked by b/254183718.
- private void testFactoryReset() throws Exception {
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
+ public void testFactoryReset() throws Exception {
assumeTrue(TestUtils.shouldTestSApis());
// Store current settings.
@@ -2592,6 +2597,7 @@
// prevent the race condition between airplane mode enabled and the followed
// up wifi tethering enabled.
tetherEventCallback.expectNoTetheringActive();
+ tetherUtils.expectSoftApDisabled();
// start wifi tethering
tetherUtils.startWifiTethering(tetherEventCallback);
@@ -2738,6 +2744,7 @@
*/
@AppModeFull(reason = "Instant apps cannot create test networks")
@Test
+ @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testSetOemNetworkPreferenceForTestOnlyPref() throws Exception {
// Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
// shims, and @IgnoreUpTo does not check that.
@@ -2892,6 +2899,7 @@
@AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
@Test
+ @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testRejectPartialConnectivity_TearDownNetwork() throws Exception {
assumeTrue(TestUtils.shouldTestSApis());
assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute"
@@ -3197,6 +3205,7 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
+ @SkipPresubmit(reason = "Out of SLO flakiness")
public void testMobileDataPreferredUids() throws Exception {
assumeTrue(TestUtils.shouldTestSApis());
final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java
index 3821cea..308aead 100644
--- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java
+++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java
@@ -59,6 +59,7 @@
import com.android.net.module.util.DnsPacket;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DnsResolverModuleTest;
import com.android.testutils.SkipPresubmit;
import org.junit.After;
@@ -317,51 +318,61 @@
}
@Test
+ @DnsResolverModuleTest
public void testRawQuery() throws Exception {
doTestRawQuery(mExecutor);
}
@Test
+ @DnsResolverModuleTest
public void testRawQueryInline() throws Exception {
doTestRawQuery(mExecutorInline);
}
@Test
+ @DnsResolverModuleTest
public void testRawQueryBlob() throws Exception {
doTestRawQueryBlob(mExecutor);
}
@Test
+ @DnsResolverModuleTest
public void testRawQueryBlobInline() throws Exception {
doTestRawQueryBlob(mExecutorInline);
}
@Test
+ @DnsResolverModuleTest
public void testRawQueryRoot() throws Exception {
doTestRawQueryRoot(mExecutor);
}
@Test
+ @DnsResolverModuleTest
public void testRawQueryRootInline() throws Exception {
doTestRawQueryRoot(mExecutorInline);
}
@Test
+ @DnsResolverModuleTest
public void testRawQueryNXDomain() throws Exception {
doTestRawQueryNXDomain(mExecutor);
}
@Test
+ @DnsResolverModuleTest
public void testRawQueryNXDomainInline() throws Exception {
doTestRawQueryNXDomain(mExecutorInline);
}
@Test
+ @DnsResolverModuleTest
public void testRawQueryNXDomainWithPrivateDns() throws Exception {
doTestRawQueryNXDomainWithPrivateDns(mExecutor);
}
@Test
+ @DnsResolverModuleTest
public void testRawQueryNXDomainInlineWithPrivateDns() throws Exception {
doTestRawQueryNXDomainWithPrivateDns(mExecutorInline);
}
@@ -610,41 +621,49 @@
}
@Test
+ @DnsResolverModuleTest
public void testQueryForInetAddress() throws Exception {
doTestQueryForInetAddress(mExecutor);
}
@Test
+ @DnsResolverModuleTest
public void testQueryForInetAddressInline() throws Exception {
doTestQueryForInetAddress(mExecutorInline);
}
@Test
+ @DnsResolverModuleTest
public void testQueryForInetAddressIpv4() throws Exception {
doTestQueryForInetAddressIpv4(mExecutor);
}
@Test
+ @DnsResolverModuleTest
public void testQueryForInetAddressIpv4Inline() throws Exception {
doTestQueryForInetAddressIpv4(mExecutorInline);
}
@Test
+ @DnsResolverModuleTest
public void testQueryForInetAddressIpv6() throws Exception {
doTestQueryForInetAddressIpv6(mExecutor);
}
@Test
+ @DnsResolverModuleTest
public void testQueryForInetAddressIpv6Inline() throws Exception {
doTestQueryForInetAddressIpv6(mExecutorInline);
}
@Test
+ @DnsResolverModuleTest
public void testContinuousQueries() throws Exception {
doTestContinuousQueries(mExecutor);
}
@Test
+ @DnsResolverModuleTest
@SkipPresubmit(reason = "Flaky: b/159762682; add to presubmit after fixing")
public void testContinuousQueriesInline() throws Exception {
doTestContinuousQueries(mExecutorInline);
diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
index 805dd65..81834a9 100644
--- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
+++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
@@ -71,6 +71,8 @@
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.RecorderCallback.CallbackEntry;
+import com.android.testutils.SkipMainlinePresubmit;
+import com.android.testutils.SkipPresubmit;
import com.android.testutils.TestableNetworkCallback;
import org.bouncycastle.x509.X509V1CertificateGenerator;
@@ -640,6 +642,7 @@
}
@Test
+ @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testStartStopVpnProfileV4() throws Exception {
doTestStartStopVpnProfile(false /* testIpv6Only */, false /* requiresValidation */,
false /* testSessionKey */, false /* testIkeTunConnParams */);
@@ -653,12 +656,14 @@
}
@Test
+ @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testStartStopVpnProfileV6() throws Exception {
doTestStartStopVpnProfile(true /* testIpv6Only */, false /* requiresValidation */,
false /* testSessionKey */, false /* testIkeTunConnParams */);
}
@Test @IgnoreUpTo(SC_V2)
+ @SkipPresubmit(reason = "Out of SLO flakiness")
public void testStartStopVpnProfileV6WithValidation() throws Exception {
assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(true /* testIpv6Only */, true /* requiresValidation */,
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
index cc0a5df..fe86a90 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -81,6 +81,7 @@
import com.android.modules.utils.build.SdkLevel;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.SkipMainlinePresubmit;
import org.junit.Rule;
import org.junit.Test;
@@ -716,6 +717,7 @@
}
@Test
+ @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testIkeOverUdpEncapSocket() throws Exception {
// IPv6 not supported for UDP-encap-ESP
InetAddress local = InetAddress.getByName(IPV4_LOOPBACK);
diff --git a/tests/unit/java/com/android/metrics/NetworkNsdReportedMetricsTest.kt b/tests/unit/java/com/android/metrics/NetworkNsdReportedMetricsTest.kt
new file mode 100644
index 0000000..961c422
--- /dev/null
+++ b/tests/unit/java/com/android/metrics/NetworkNsdReportedMetricsTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.metrics
+
+import android.os.Build
+import android.stats.connectivity.MdnsQueryResult
+import android.stats.connectivity.NsdEventType
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
+class NetworkNsdReportedMetricsTest {
+ private val deps = mock(NetworkNsdReportedMetrics.Dependencies::class.java)
+
+ @Test
+ fun testReportServiceRegistrationSucceeded() {
+ val clientId = 99
+ val transactionId = 100
+ val durationMs = 10L
+ val metrics = NetworkNsdReportedMetrics(true /* isLegacy */, clientId, deps)
+ metrics.reportServiceRegistrationSucceeded(transactionId, durationMs)
+
+ val eventCaptor = ArgumentCaptor.forClass(NetworkNsdReported::class.java)
+ verify(deps).statsWrite(eventCaptor.capture())
+ eventCaptor.value.let {
+ assertTrue(it.isLegacy)
+ assertEquals(clientId, it.clientId)
+ assertEquals(transactionId, it.transactionId)
+ assertEquals(NsdEventType.NET_REGISTER, it.type)
+ assertEquals(MdnsQueryResult.MQR_SERVICE_REGISTERED, it.queryResult)
+ assertEquals(durationMs, it.eventDurationMillisec)
+ }
+ }
+
+ @Test
+ fun testReportServiceRegistrationFailed() {
+ val clientId = 99
+ val transactionId = 100
+ val durationMs = 10L
+ val metrics = NetworkNsdReportedMetrics(false /* isLegacy */, clientId, deps)
+ metrics.reportServiceRegistrationFailed(transactionId, durationMs)
+
+ val eventCaptor = ArgumentCaptor.forClass(NetworkNsdReported::class.java)
+ verify(deps).statsWrite(eventCaptor.capture())
+ eventCaptor.value.let {
+ assertFalse(it.isLegacy)
+ assertEquals(clientId, it.clientId)
+ assertEquals(transactionId, it.transactionId)
+ assertEquals(NsdEventType.NET_REGISTER, it.type)
+ assertEquals(MdnsQueryResult.MQR_SERVICE_REGISTRATION_FAILED, it.queryResult)
+ assertEquals(durationMs, it.eventDurationMillisec)
+ }
+ }
+
+ @Test
+ fun testReportServiceUnregistration() {
+ val clientId = 99
+ val transactionId = 100
+ val durationMs = 10L
+ val metrics = NetworkNsdReportedMetrics(true /* isLegacy */, clientId, deps)
+ metrics.reportServiceUnregistration(transactionId, durationMs)
+
+ val eventCaptor = ArgumentCaptor.forClass(NetworkNsdReported::class.java)
+ verify(deps).statsWrite(eventCaptor.capture())
+ eventCaptor.value.let {
+ assertTrue(it.isLegacy)
+ assertEquals(clientId, it.clientId)
+ assertEquals(transactionId, it.transactionId)
+ assertEquals(NsdEventType.NET_REGISTER, it.type)
+ assertEquals(MdnsQueryResult.MQR_SERVICE_UNREGISTERED, it.queryResult)
+ assertEquals(durationMs, it.eventDurationMillisec)
+ }
+ }
+}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index bbde9b4..5dd4048 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -422,6 +422,7 @@
import com.android.testutils.FunctionalUtils.ThrowingRunnable;
import com.android.testutils.HandlerUtils;
import com.android.testutils.RecorderCallback.CallbackEntry;
+import com.android.testutils.SkipPresubmit;
import com.android.testutils.TestableNetworkCallback;
import com.android.testutils.TestableNetworkOfferCallback;
@@ -7414,6 +7415,7 @@
assertPinnedToWifiWithCellDefault();
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testNetworkCallbackMaximum() throws Exception {
final int MAX_REQUESTS = 100;
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index f51b28d..55384b3 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -43,7 +43,9 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.any;
@@ -95,6 +97,7 @@
import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
+import com.android.metrics.NetworkNsdReportedMetrics;
import com.android.server.NsdService.Dependencies;
import com.android.server.connectivity.mdns.MdnsAdvertiser;
import com.android.server.connectivity.mdns.MdnsDiscoveryManager;
@@ -104,6 +107,7 @@
import com.android.server.connectivity.mdns.MdnsServiceInfo;
import com.android.server.connectivity.mdns.MdnsSocketProvider;
import com.android.server.connectivity.mdns.MdnsSocketProvider.SocketRequestMonitor;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.HandlerUtils;
@@ -138,6 +142,7 @@
static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
private static final long CLEANUP_DELAY_MS = 500;
private static final long TIMEOUT_MS = 500;
+ private static final long TEST_TIME_MS = 123L;
private static final String SERVICE_NAME = "a_name";
private static final String SERVICE_TYPE = "_test._tcp";
private static final String SERVICE_FULL_NAME = SERVICE_NAME + "." + SERVICE_TYPE;
@@ -164,6 +169,8 @@
@Mock WifiManager mWifiManager;
@Mock WifiManager.MulticastLock mMulticastLock;
@Mock ActivityManager mActivityManager;
+ @Mock NetworkNsdReportedMetrics mMetrics;
+ @Mock MdnsUtils.Clock mClock;
SocketRequestMonitor mSocketRequestMonitor;
OnUidImportanceListener mUidImportanceListener;
HandlerThread mThread;
@@ -210,6 +217,9 @@
doReturn(DEFAULT_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF).when(mDeps).getDeviceConfigInt(
eq(NsdService.MDNS_CONFIG_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF), anyInt());
doReturn(mAdvertiser).when(mDeps).makeMdnsAdvertiser(any(), any(), any(), any());
+ doReturn(mMetrics).when(mDeps).makeNetworkNsdReportedMetrics(anyBoolean(), anyInt());
+ doReturn(mClock).when(mDeps).makeClock();
+ doReturn(TEST_TIME_MS).when(mClock).elapsedRealtime();
mService = makeService();
final ArgumentCaptor<SocketRequestMonitor> cbMonitorCaptor =
ArgumentCaptor.forClass(SocketRequestMonitor.class);
@@ -512,14 +522,16 @@
eq(SERVICE_NAME), eq(SERVICE_TYPE), eq(PORT), any(), eq(IFACE_IDX_ANY));
// Register service successfully.
+ final int regId = regIdCaptor.getValue();
final RegistrationInfo registrationInfo = new RegistrationInfo(
- regIdCaptor.getValue(),
+ regId,
IMDnsEventListener.SERVICE_REGISTERED,
SERVICE_NAME,
SERVICE_TYPE,
PORT,
new byte[0] /* txtRecord */,
IFACE_IDX_ANY);
+ doReturn(TEST_TIME_MS + 10L).when(mClock).elapsedRealtime();
eventListener.onServiceRegistrationStatus(registrationInfo);
final ArgumentCaptor<NsdServiceInfo> registeredInfoCaptor =
@@ -528,19 +540,22 @@
.onServiceRegistered(registeredInfoCaptor.capture());
final NsdServiceInfo registeredInfo = registeredInfoCaptor.getValue();
assertEquals(SERVICE_NAME, registeredInfo.getServiceName());
+ verify(mMetrics).reportServiceRegistrationSucceeded(regId, 10L /* durationMs */);
// Fail to register service.
final RegistrationInfo registrationFailedInfo = new RegistrationInfo(
- regIdCaptor.getValue(),
+ regId,
IMDnsEventListener.SERVICE_REGISTRATION_FAILED,
null /* serviceName */,
null /* registrationType */,
0 /* port */,
new byte[0] /* txtRecord */,
IFACE_IDX_ANY);
+ doReturn(TEST_TIME_MS + 20L).when(mClock).elapsedRealtime();
eventListener.onServiceRegistrationStatus(registrationFailedInfo);
verify(regListener, timeout(TIMEOUT_MS))
.onRegistrationFailed(any(), eq(FAILURE_INTERNAL_ERROR));
+ verify(mMetrics).reportServiceRegistrationFailed(regId, 20L /* durationMs */);
}
@Test
@@ -1215,17 +1230,22 @@
// Verify onServiceRegistered callback
final MdnsAdvertiser.AdvertiserCallback cb = cbCaptor.getValue();
- cb.onRegisterServiceSucceeded(idCaptor.getValue(), regInfo);
+ final int regId = idCaptor.getValue();
+ doReturn(TEST_TIME_MS + 10L).when(mClock).elapsedRealtime();
+ cb.onRegisterServiceSucceeded(regId, regInfo);
verify(regListener, timeout(TIMEOUT_MS)).onServiceRegistered(argThat(info -> matches(info,
new NsdServiceInfo(regInfo.getServiceName(), null))));
+ verify(mMetrics).reportServiceRegistrationSucceeded(regId, 10L /* durationMs */);
+ doReturn(TEST_TIME_MS + 100L).when(mClock).elapsedRealtime();
client.unregisterService(regListener);
waitForIdle();
verify(mAdvertiser).removeService(idCaptor.getValue());
verify(regListener, timeout(TIMEOUT_MS)).onServiceUnregistered(
argThat(info -> matches(info, regInfo)));
verify(mSocketProvider, timeout(TIMEOUT_MS)).requestStopWhenInactive();
+ verify(mMetrics).reportServiceUnregistration(regId, 100L /* durationMs */);
}
@Test
@@ -1251,6 +1271,7 @@
verify(regListener, timeout(TIMEOUT_MS)).onRegistrationFailed(
argThat(info -> matches(info, regInfo)), eq(FAILURE_INTERNAL_ERROR));
+ verify(mMetrics).reportServiceRegistrationFailed(anyInt(), anyLong());
}
@Test
@@ -1280,10 +1301,13 @@
// Verify onServiceRegistered callback
final MdnsAdvertiser.AdvertiserCallback cb = cbCaptor.getValue();
- cb.onRegisterServiceSucceeded(idCaptor.getValue(), regInfo);
+ final int regId = idCaptor.getValue();
+ doReturn(TEST_TIME_MS + 10L).when(mClock).elapsedRealtime();
+ cb.onRegisterServiceSucceeded(regId, regInfo);
verify(regListener, timeout(TIMEOUT_MS)).onServiceRegistered(
argThat(info -> matches(info, new NsdServiceInfo(regInfo.getServiceName(), null))));
+ verify(mMetrics).reportServiceRegistrationSucceeded(regId, 10L /* durationMs */);
}
@Test
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 967083e..b319c30 100644
--- a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -50,6 +50,7 @@
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
@@ -60,6 +61,7 @@
import android.telephony.TelephonyManager;
import android.testing.PollingCheck;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -428,6 +430,22 @@
// UiDevice.getLauncherPackageName() requires the test manifest to have a <queries> tag for
// the launcher intent.
+ // Attempted workaround for b/286550950 where Settings is reported as the launcher
+ PollingCheck.check(
+ "Launcher package name was still settings after " + TEST_TIMEOUT_MS + "ms",
+ TEST_TIMEOUT_MS,
+ () -> {
+ if ("com.android.settings".equals(uiDevice.getLauncherPackageName())) {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_HOME);
+ final List<ResolveInfo> acts = ctx.getPackageManager()
+ .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ Log.e(NetworkNotificationManagerTest.class.getSimpleName(),
+ "Got settings as launcher name; launcher activities: " + acts);
+ return false;
+ }
+ return true;
+ });
final String launcherPackageName = uiDevice.getLauncherPackageName();
assertTrue(String.format("Launcher (%s) is not shown", launcherPackageName),
uiDevice.wait(Until.hasObject(By.pkg(launcherPackageName)),
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index 9ae727d..2726267 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -182,6 +182,7 @@
import com.android.server.VpnTestBase;
import com.android.server.vcn.util.PersistableBundleUtils;
import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.SkipPresubmit;
import org.junit.Before;
import org.junit.Rule;
@@ -1713,6 +1714,7 @@
errorCode);
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testStartPlatformVpnFailedWithRecoverableError() throws Exception {
final IkeProtocolException exception = mock(IkeProtocolException.class);
@@ -1722,6 +1724,7 @@
VpnManager.CATEGORY_EVENT_IKE_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE, errorCode);
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testStartPlatformVpnFailedWithUnknownHostException() throws Exception {
final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
@@ -1733,6 +1736,7 @@
errorCode);
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testStartPlatformVpnFailedWithIkeTimeoutException() throws Exception {
final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
@@ -1754,6 +1758,7 @@
VpnManager.ERROR_CODE_NETWORK_LOST);
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testStartPlatformVpnFailedWithIOException() throws Exception {
final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
@@ -2386,6 +2391,7 @@
true /* areLongLivedTcpConnectionsExpensive */);
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testPreferredIpProtocolFromCarrierConfig_v4UDP() throws Exception {
doTestReadCarrierConfig(createTestCellNc(),
@@ -2398,6 +2404,7 @@
false /* areLongLivedTcpConnectionsExpensive */);
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testPreferredIpProtocolFromCarrierConfig_v6ESP() throws Exception {
doTestReadCarrierConfig(createTestCellNc(),
@@ -2410,6 +2417,7 @@
false /* areLongLivedTcpConnectionsExpensive */);
}
+ @SkipPresubmit(reason = "Out of SLO flakiness")
@Test
public void testPreferredIpProtocolFromCarrierConfig_v6UDP() throws Exception {
doTestReadCarrierConfig(createTestCellNc(),
@@ -2467,7 +2475,8 @@
if (expectedReadFromCarrierConfig) {
final ArgumentCaptor<NetworkCapabilities> ncCaptor =
ArgumentCaptor.forClass(NetworkCapabilities.class);
- verify(mMockNetworkAgent).doSendNetworkCapabilities(ncCaptor.capture());
+ verify(mMockNetworkAgent, timeout(TEST_TIMEOUT_MS))
+ .doSendNetworkCapabilities(ncCaptor.capture());
final VpnTransportInfo info =
(VpnTransportInfo) ncCaptor.getValue().getTransportInfo();
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
index 1a4ae5d..e869b91 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
@@ -53,6 +53,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
/** Tests for {@link MdnsDiscoveryManager}. */
@RunWith(DevSdkIgnoreRunner.class)
@@ -80,6 +81,7 @@
private static final Pair<String, SocketKey> PER_SOCKET_SERVICE_TYPE_2_NETWORK_2 =
Pair.create(SERVICE_TYPE_2, SOCKET_KEY_NETWORK_2);
@Mock private ExecutorProvider executorProvider;
+ @Mock private ScheduledExecutorService mockExecutorService;
@Mock private MdnsSocketClientBase socketClient;
@Mock private MdnsServiceTypeClient mockServiceTypeClientType1NullNetwork;
@Mock private MdnsServiceTypeClient mockServiceTypeClientType1Network1;
@@ -128,6 +130,7 @@
return null;
}
};
+ doReturn(mockExecutorService).when(mockServiceTypeClientType1NullNetwork).getExecutor();
}
@After
@@ -165,11 +168,25 @@
when(mockServiceTypeClientType1NullNetwork.stopSendAndReceive(mockListenerOne))
.thenReturn(true);
runOnHandler(() -> discoveryManager.unregisterListener(SERVICE_TYPE_1, mockListenerOne));
+ verify(executorProvider).shutdownExecutorService(mockExecutorService);
verify(mockServiceTypeClientType1NullNetwork).stopSendAndReceive(mockListenerOne);
verify(socketClient).stopDiscovery();
}
@Test
+ public void onSocketDestroy_shutdownExecutorService() throws IOException {
+ final MdnsSearchOptions options =
+ MdnsSearchOptions.newBuilder().setNetwork(null /* network */).build();
+ final SocketCreationCallback callback = expectSocketCreationCallback(
+ SERVICE_TYPE_1, mockListenerOne, options);
+ runOnHandler(() -> callback.onSocketCreated(SOCKET_KEY_NULL_NETWORK));
+ verify(mockServiceTypeClientType1NullNetwork).startSendAndReceive(mockListenerOne, options);
+
+ runOnHandler(() -> callback.onSocketDestroyed(SOCKET_KEY_NULL_NETWORK));
+ verify(executorProvider).shutdownExecutorService(mockExecutorService);
+ }
+
+ @Test
public void registerMultipleListeners() throws IOException {
final MdnsSearchOptions options =
MdnsSearchOptions.newBuilder().setNetwork(null /* network */).build();
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
index 92a2115..1fdfe09 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
@@ -52,7 +52,6 @@
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.SharedLog;
import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
-import com.android.server.connectivity.mdns.MdnsServiceTypeClient.QueryTaskConfig;
import com.android.server.connectivity.mdns.util.MdnsUtils;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;