Merge "Ensure Wifi eventually becomes default"
diff --git a/Cronet/tests/common/Android.bp b/Cronet/tests/common/Android.bp
index f8bdb08..939a81c 100644
--- a/Cronet/tests/common/Android.bp
+++ b/Cronet/tests/common/Android.bp
@@ -27,7 +27,9 @@
android_test {
name: "NetHttpCoverageTests",
defaults: ["CronetTestJavaDefaults"],
+ enforce_default_target_sdk_version: true,
sdk_version: "test_current",
+ min_sdk_version: "30",
test_suites: ["general-tests", "mts-tethering"],
static_libs: [
"modules-utils-native-coverage-listener",
diff --git a/Cronet/tests/common/AndroidManifest.xml b/Cronet/tests/common/AndroidManifest.xml
index efe880c..b00fc90 100644
--- a/Cronet/tests/common/AndroidManifest.xml
+++ b/Cronet/tests/common/AndroidManifest.xml
@@ -18,6 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.android.net.http.tests.coverage">
+
<!-- NetHttpCoverageTests combines CtsNetHttpTestCases and NetHttpTests targets,
so permissions and others are declared in their respective manifests -->
<application tools:replace="android:label"
diff --git a/Cronet/tests/common/AndroidTest.xml b/Cronet/tests/common/AndroidTest.xml
index ca298dd..2ac418f 100644
--- a/Cronet/tests/common/AndroidTest.xml
+++ b/Cronet/tests/common/AndroidTest.xml
@@ -20,8 +20,11 @@
</target_preparer>
<option name="test-tag" value="NetHttpCoverageTests" />
<!-- Tethering/Connectivity is a SDK 30+ module -->
+ <!-- TODO Switch back to Sdk30 when b/270049141 is fixed -->
<object type="module_controller"
- class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+ class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" />
+ <option name="config-descriptor:metadata" key="mainline-param"
+ value="CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.net.http.tests.coverage" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/Cronet/tests/cts/Android.bp b/Cronet/tests/cts/Android.bp
index 945b220..d969b54 100644
--- a/Cronet/tests/cts/Android.bp
+++ b/Cronet/tests/cts/Android.bp
@@ -29,6 +29,10 @@
java_defaults {
name: "CronetTestJavaDefaultsEnabled",
enabled: true,
+ // TODO(danstahr): move to unconditional static_libs once the T branch is abandoned
+ static_libs: [
+ "truth",
+ ],
}
java_defaults {
@@ -43,7 +47,12 @@
android_library {
name: "CtsNetHttpTestsLib",
+ defaults: [
+ "cts_defaults",
+ "CronetTestJavaDefaults",
+ ],
sdk_version: "test_current",
+ min_sdk_version: "30",
srcs: [
"src/**/*.java",
"src/**/*.kt",
@@ -62,6 +71,7 @@
"framework-tethering",
"org.apache.http.legacy",
],
+ lint: { test: true }
}
android_test {
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 13c220d..bead1f8 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt
+++ b/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt
@@ -63,7 +63,7 @@
}
private fun createBidirectionalStreamBuilder(url: String): BidirectionalStream.Builder {
- return httpEngine.newBidirectionalStreamBuilder(url, callback, callback.executor)
+ return httpEngine.newBidirectionalStreamBuilder(url, callback.executor, callback)
}
@Test
diff --git a/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt
index e17b63f..749389e 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt
+++ b/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt
@@ -53,7 +53,7 @@
val callback = TestUrlRequestCallback()
callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_RESPONSE_STARTED)
val request = httpEngine
- .newUrlRequestBuilder(server.successUrl, callback, callback.executor)
+ .newUrlRequestBuilder(server.successUrl, callback.executor, callback)
.build()
request.start()
diff --git a/Cronet/tests/cts/src/android/net/http/cts/ConnectionMigrationOptionsTest.kt b/Cronet/tests/cts/src/android/net/http/cts/ConnectionMigrationOptionsTest.kt
index 2701ed0..77cb30e 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/ConnectionMigrationOptionsTest.kt
+++ b/Cronet/tests/cts/src/android/net/http/cts/ConnectionMigrationOptionsTest.kt
@@ -17,30 +17,52 @@
package android.net.http.cts
import android.net.http.ConnectionMigrationOptions
+import android.net.http.ConnectionMigrationOptions.MIGRATION_OPTION_ENABLED
+import android.net.http.ConnectionMigrationOptions.MIGRATION_OPTION_UNSPECIFIED
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlin.test.Test
-import kotlin.test.assertNotNull
-import kotlin.test.assertTrue
+import kotlin.test.assertEquals
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ConnectionMigrationOptionsTest {
@Test
+ fun testConnectionMigrationOptions_defaultValues() {
+ val options =
+ ConnectionMigrationOptions.Builder().build()
+
+ assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.allowNonDefaultNetworkUsageEnabled)
+ assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.defaultNetworkMigrationEnabled)
+ assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.pathDegradationMigrationEnabled)
+ }
+
+ @Test
fun testConnectionMigrationOptions_enableDefaultNetworkMigration_returnSetValue() {
val options =
- ConnectionMigrationOptions.Builder().setEnableDefaultNetworkMigration(true).build()
+ ConnectionMigrationOptions.Builder()
+ .setDefaultNetworkMigrationEnabled(MIGRATION_OPTION_ENABLED)
+ .build()
- assertNotNull(options.enableDefaultNetworkMigration)
- assertTrue(options.enableDefaultNetworkMigration!!)
+ assertEquals(MIGRATION_OPTION_ENABLED, options.defaultNetworkMigrationEnabled)
}
@Test
fun testConnectionMigrationOptions_enablePathDegradationMigration_returnSetValue() {
val options =
- ConnectionMigrationOptions.Builder().setEnablePathDegradationMigration(true).build()
+ ConnectionMigrationOptions.Builder()
+ .setPathDegradationMigrationEnabled(MIGRATION_OPTION_ENABLED)
+ .build()
- assertNotNull(options.enablePathDegradationMigration)
- assertTrue(options.enablePathDegradationMigration!!)
+ assertEquals(MIGRATION_OPTION_ENABLED, options.pathDegradationMigrationEnabled)
+ }
+
+ @Test
+ fun testConnectionMigrationOptions_allowNonDefaultNetworkUsage_returnSetValue() {
+ val options =
+ ConnectionMigrationOptions.Builder()
+ .setAllowNonDefaultNetworkUsageEnabled(MIGRATION_OPTION_ENABLED).build()
+
+ assertEquals(MIGRATION_OPTION_ENABLED, options.allowNonDefaultNetworkUsageEnabled)
}
}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/DnsOptionsTest.kt b/Cronet/tests/cts/src/android/net/http/cts/DnsOptionsTest.kt
index b96e931..7b17ca6 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/DnsOptionsTest.kt
+++ b/Cronet/tests/cts/src/android/net/http/cts/DnsOptionsTest.kt
@@ -17,13 +17,14 @@
package android.net.http.cts
import android.net.http.DnsOptions
+import android.net.http.DnsOptions.DNS_OPTION_ENABLED
+import android.net.http.DnsOptions.DNS_OPTION_UNSPECIFIED
import androidx.test.ext.junit.runners.AndroidJUnit4
import java.time.Duration
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull
-import kotlin.test.assertTrue
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@@ -33,20 +34,22 @@
fun testDnsOptions_defaultValues() {
val options = DnsOptions.Builder().build()
- assertNull(options.persistHostCache)
+ assertEquals(DNS_OPTION_UNSPECIFIED, options.persistHostCacheEnabled)
assertNull(options.persistHostCachePeriod)
- assertNull(options.enableStaleDns)
+ assertEquals(DNS_OPTION_UNSPECIFIED, options.staleDnsEnabled)
assertNull(options.staleDnsOptions)
- assertNull(options.useHttpStackDnsResolver)
- assertNull(options.preestablishConnectionsToStaleDnsResults)
+ assertEquals(DNS_OPTION_UNSPECIFIED, options.useHttpStackDnsResolverEnabled)
+ assertEquals(DNS_OPTION_UNSPECIFIED,
+ options.preestablishConnectionsToStaleDnsResultsEnabled)
}
@Test
fun testDnsOptions_persistHostCache_returnSetValue() {
- val options = DnsOptions.Builder().setPersistHostCache(true).build()
+ val options = DnsOptions.Builder()
+ .setPersistHostCacheEnabled(DNS_OPTION_ENABLED)
+ .build()
- assertNotNull(options.persistHostCache)
- assertTrue(options.persistHostCache!!)
+ assertEquals(DNS_OPTION_ENABLED, options.persistHostCacheEnabled)
}
@Test
@@ -59,44 +62,48 @@
@Test
fun testDnsOptions_enableStaleDns_returnSetValue() {
- val options = DnsOptions.Builder().setEnableStaleDns(true).build()
+ val options = DnsOptions.Builder()
+ .setStaleDnsEnabled(DNS_OPTION_ENABLED)
+ .build()
- assertNotNull(options.enableStaleDns)
- assertTrue(options.enableStaleDns!!)
+ assertEquals(DNS_OPTION_ENABLED, options.staleDnsEnabled)
}
@Test
fun testDnsOptions_useHttpStackDnsResolver_returnsSetValue() {
- val options = DnsOptions.Builder().setUseHttpStackDnsResolver(true).build()
+ val options = DnsOptions.Builder()
+ .setUseHttpStackDnsResolverEnabled(DNS_OPTION_ENABLED)
+ .build()
- assertNotNull(options.useHttpStackDnsResolver)
- assertTrue(options.useHttpStackDnsResolver!!)
+ assertEquals(DNS_OPTION_ENABLED, options.useHttpStackDnsResolverEnabled)
}
@Test
fun testDnsOptions_preestablishConnectionsToStaleDnsResults_returnsSetValue() {
- val options = DnsOptions.Builder().setPreestablishConnectionsToStaleDnsResults(true).build()
+ val options = DnsOptions.Builder()
+ .setPreestablishConnectionsToStaleDnsResultsEnabled(DNS_OPTION_ENABLED)
+ .build()
- assertNotNull(options.preestablishConnectionsToStaleDnsResults)
- assertTrue(options.preestablishConnectionsToStaleDnsResults!!)
+ assertEquals(DNS_OPTION_ENABLED,
+ options.preestablishConnectionsToStaleDnsResultsEnabled)
}
@Test
fun testStaleDnsOptions_defaultValues() {
val options = DnsOptions.StaleDnsOptions.Builder().build()
- assertNull(options.allowCrossNetworkUsage)
- assertNull(options.freshLookupTimeoutMillis)
- assertNull(options.maxExpiredDelayMillis)
- assertNull(options.useStaleOnNameNotResolved)
+ assertEquals(DNS_OPTION_UNSPECIFIED, options.allowCrossNetworkUsageEnabled)
+ assertNull(options.freshLookupTimeout)
+ assertNull(options.maxExpiredDelay)
+ assertEquals(DNS_OPTION_UNSPECIFIED, options.useStaleOnNameNotResolvedEnabled)
}
@Test
fun testStaleDnsOptions_allowCrossNetworkUsage_returnsSetValue() {
- val options = DnsOptions.StaleDnsOptions.Builder().setAllowCrossNetworkUsage(true).build()
+ val options = DnsOptions.StaleDnsOptions.Builder()
+ .setAllowCrossNetworkUsageEnabled(DNS_OPTION_ENABLED).build()
- assertNotNull(options.allowCrossNetworkUsage)
- assertTrue(options.allowCrossNetworkUsage!!)
+ assertEquals(DNS_OPTION_ENABLED, options.allowCrossNetworkUsageEnabled)
}
@Test
@@ -104,17 +111,17 @@
val duration = Duration.ofMillis(12345)
val options = DnsOptions.StaleDnsOptions.Builder().setFreshLookupTimeout(duration).build()
- assertNotNull(options.freshLookupTimeoutMillis)
- assertEquals(duration.toMillis(), options.freshLookupTimeoutMillis!!)
+ assertNotNull(options.freshLookupTimeout)
+ assertEquals(duration, options.freshLookupTimeout!!)
}
@Test
fun testStaleDnsOptions_useStaleOnNameNotResolved_returnsSetValue() {
- val options =
- DnsOptions.StaleDnsOptions.Builder().setUseStaleOnNameNotResolved(true).build()
+ val options = DnsOptions.StaleDnsOptions.Builder()
+ .setUseStaleOnNameNotResolvedEnabled(DNS_OPTION_ENABLED)
+ .build()
- assertNotNull(options.useStaleOnNameNotResolved)
- assertTrue(options.useStaleOnNameNotResolved!!)
+ assertEquals(DNS_OPTION_ENABLED, options.useStaleOnNameNotResolvedEnabled)
}
@Test
@@ -122,7 +129,7 @@
val duration = Duration.ofMillis(12345)
val options = DnsOptions.StaleDnsOptions.Builder().setMaxExpiredDelay(duration).build()
- assertNotNull(options.maxExpiredDelayMillis)
- assertEquals(duration.toMillis(), options.maxExpiredDelayMillis!!)
+ assertNotNull(options.maxExpiredDelay)
+ assertEquals(duration, options.maxExpiredDelay!!)
}
}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java b/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
index 45d27bf..d247201 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
+++ b/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
@@ -20,15 +20,19 @@
import static android.net.http.cts.util.TestUtilsKt.assumeOKStatusCode;
import static android.net.http.cts.util.TestUtilsKt.skipIfNoInternetConnection;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.net.http.HttpEngine;
import android.net.http.UrlRequest;
import android.net.http.UrlResponseInfo;
+import android.net.http.cts.util.HttpCtsTestServer;
import android.net.http.cts.util.TestUrlRequestCallback;
import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep;
@@ -49,12 +53,13 @@
private TestUrlRequestCallback mCallback;
private UrlRequest mRequest;
private HttpEngine mEngine;
+ private Context mContext;
@Before
public void setUp() throws Exception {
- Context context = ApplicationProvider.getApplicationContext();
- skipIfNoInternetConnection(context);
- mEngineBuilder = new HttpEngine.Builder(context);
+ mContext = ApplicationProvider.getApplicationContext();
+ skipIfNoInternetConnection(mContext);
+ mEngineBuilder = new HttpEngine.Builder(mContext);
mCallback = new TestUrlRequestCallback();
}
@@ -77,7 +82,7 @@
public void testHttpEngine_Default() throws Exception {
mEngine = mEngineBuilder.build();
UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(URL, mCallback, mCallback.getExecutor());
+ mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback);
mRequest = builder.build();
mRequest.start();
@@ -90,10 +95,42 @@
}
@Test
+ public void testHttpEngine_EnableHttpCache() {
+ // We need a server which sets cache-control != no-cache.
+ String url = "https://www.example.com";
+ mEngine =
+ mEngineBuilder
+ .setStoragePath(mContext.getApplicationInfo().dataDir)
+ .setEnableHttpCache(HttpEngine.Builder.HTTP_CACHE_DISK,
+ /* maxSize */ 100 * 1024)
+ .build();
+
+ UrlRequest.Builder builder =
+ mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback);
+ mRequest = builder.build();
+ mRequest.start();
+ // This tests uses a non-hermetic server. Instead of asserting, assume the next callback.
+ // This way, if the request were to fail, the test would just be skipped instead of failing.
+ mCallback.assumeCallback(ResponseStep.ON_SUCCEEDED);
+ UrlResponseInfo info = mCallback.mResponseInfo;
+ assumeOKStatusCode(info);
+ assertFalse(info.wasCached());
+
+ mCallback = new TestUrlRequestCallback();
+ builder = mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback);
+ mRequest = builder.build();
+ mRequest.start();
+ mCallback.assumeCallback(ResponseStep.ON_SUCCEEDED);
+ info = mCallback.mResponseInfo;
+ assertOKStatusCode(info);
+ assertTrue(info.wasCached());
+ }
+
+ @Test
public void testHttpEngine_DisableHttp2() throws Exception {
mEngine = mEngineBuilder.setEnableHttp2(false).build();
UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(URL, mCallback, mCallback.getExecutor());
+ mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback);
mRequest = builder.build();
mRequest.start();
@@ -106,6 +143,36 @@
}
@Test
+ public void testHttpEngine_EnablePublicKeyPinningBypassForLocalTrustAnchors() {
+ // For known hosts, requests should succeed whether we're bypassing the local trust anchor
+ // or not.
+ mEngine = mEngineBuilder.setEnablePublicKeyPinningBypassForLocalTrustAnchors(false).build();
+ UrlRequest.Builder builder =
+ mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback);
+ mRequest = builder.build();
+ mRequest.start();
+ mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
+
+ mEngine.shutdown();
+ mEngine = mEngineBuilder.setEnablePublicKeyPinningBypassForLocalTrustAnchors(true).build();
+ mCallback = new TestUrlRequestCallback();
+ builder = mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback);
+ mRequest = builder.build();
+ mRequest.start();
+ mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
+
+ // TODO(b/270918920): We should also test with a certificate not present in the device's
+ // trusted store.
+ // This requires either:
+ // * Mocking the underlying CertificateVerifier.
+ // * Or, having the server return a root certificate not present in the device's trusted
+ // store.
+ // The former doesn't make sense for a CTS test as it would depend on the underlying
+ // implementation. The latter is something we should support once we write a proper test
+ // server.
+ }
+
+ @Test
public void testHttpEngine_EnableQuic() throws Exception {
mEngine = mEngineBuilder.setEnableQuic(true).addQuicHint(HOST, 443, 443).build();
// The hint doesn't guarantee that QUIC will win the race, just that it will race TCP.
@@ -114,7 +181,7 @@
for (int i = 0; i < 5; i++) {
mCallback = new TestUrlRequestCallback();
UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(URL, mCallback, mCallback.getExecutor());
+ mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback);
mRequest = builder.build();
mRequest.start();
@@ -136,4 +203,54 @@
public void testHttpEngine_GetDefaultUserAgent() throws Exception {
assertThat(mEngineBuilder.getDefaultUserAgent(), containsString("AndroidHttpClient"));
}
+
+ @Test
+ public void testHttpEngine_requestUsesDefaultUserAgent() throws Exception {
+ mEngine = mEngineBuilder.build();
+ HttpCtsTestServer server =
+ new HttpCtsTestServer(ApplicationProvider.getApplicationContext());
+
+ String url = server.getUserAgentUrl();
+ UrlRequest request =
+ mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback).build();
+ request.start();
+
+ mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
+ UrlResponseInfo info = mCallback.mResponseInfo;
+ assertOKStatusCode(info);
+ String receivedUserAgent = extractUserAgent(mCallback.mResponseAsString);
+
+ assertThat(receivedUserAgent).isEqualTo(mEngineBuilder.getDefaultUserAgent());
+ }
+
+ @Test
+ public void testHttpEngine_requestUsesCustomUserAgent() throws Exception {
+ String userAgent = "CtsTests User Agent";
+ HttpCtsTestServer server =
+ new HttpCtsTestServer(ApplicationProvider.getApplicationContext());
+ mEngine =
+ new HttpEngine.Builder(ApplicationProvider.getApplicationContext())
+ .setUserAgent(userAgent)
+ .build();
+
+ String url = server.getUserAgentUrl();
+ UrlRequest request =
+ mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback).build();
+ request.start();
+
+ mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
+ UrlResponseInfo info = mCallback.mResponseInfo;
+ assertOKStatusCode(info);
+ String receivedUserAgent = extractUserAgent(mCallback.mResponseAsString);
+
+ assertThat(receivedUserAgent).isEqualTo(userAgent);
+ }
+
+ private static String extractUserAgent(String userAgentResponseBody) {
+ // If someone wants to be evil and have the title HTML tag a part of the user agent,
+ // they'll have to fix this method :)
+ return userAgentResponseBody
+ .replaceFirst(".*<title>", "")
+ .replaceFirst("</title>.*", "");
+ }
}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt
index dd07a41..dd4cf0d 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt
+++ b/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt
@@ -50,7 +50,7 @@
val httpEngine = HttpEngine.Builder(ApplicationProvider.getApplicationContext()).build()
val callback = TestUrlRequestCallback()
val request =
- httpEngine.newUrlRequestBuilder("http://localhost", callback, callback.executor).build()
+ httpEngine.newUrlRequestBuilder("http://localhost", callback.executor, callback).build()
request.start()
callback.blockForDone()
diff --git a/Cronet/tests/cts/src/android/net/http/cts/QuicOptionsTest.kt b/Cronet/tests/cts/src/android/net/http/cts/QuicOptionsTest.kt
new file mode 100644
index 0000000..5f9b7d4
--- /dev/null
+++ b/Cronet/tests/cts/src/android/net/http/cts/QuicOptionsTest.kt
@@ -0,0 +1,70 @@
+/*
+ * 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 android.net.http.cts
+
+import android.net.http.QuicOptions
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class QuicOptionsTest {
+ @Test
+ fun testQuicOptions_defaultValues() {
+ val quicOptions = QuicOptions.Builder().build()
+ assertThat(quicOptions.allowedQuicHosts).isEmpty()
+ assertThat(quicOptions.handshakeUserAgent).isNull()
+ // TODO(danstahr): idleConnectionTimeout getter should be public
+ // assertThat(quicOptions.idleConnectionTimeout).isNull()
+ assertThat(quicOptions.inMemoryServerConfigsCacheSize).isNull()
+ }
+
+ @Test
+ fun testQuicOptions_quicHostAllowlist_returnsAddedValues() {
+ val quicOptions = QuicOptions.Builder()
+ .addAllowedQuicHost("foo")
+ .addAllowedQuicHost("bar")
+ .addAllowedQuicHost("foo")
+ .addAllowedQuicHost("baz")
+ .build()
+ assertThat(quicOptions.allowedQuicHosts)
+ .containsExactly("foo", "bar", "baz")
+ .inOrder()
+ }
+
+ // TODO(danstahr): idleConnectionTimeout getter should be public
+ /*
+ @Test
+ fun testQuicOptions_idleConnectionTimeout_returnsSetValue() {
+ val timeout = Duration.ofMinutes(10)
+ val quicOptions = QuicOptions.Builder()
+ .setIdleConnectionTimeout(timeout)
+ .build()
+ assertThat(quicOptions.idleConnectionTimeout)
+ .isEqualTo(timeout)
+ }
+ */
+
+ @Test
+ fun testQuicOptions_inMemoryServerConfigsCacheSize_returnsSetValue() {
+ val quicOptions = QuicOptions.Builder()
+ .setInMemoryServerConfigsCacheSize(42)
+ .build()
+ assertThat(quicOptions.inMemoryServerConfigsCacheSize)
+ .isEqualTo(42)
+ }
+}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java b/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java
index 2bec9e6..a364e29 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java
+++ b/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java
@@ -19,13 +19,21 @@
import static android.net.http.cts.util.TestUtilsKt.assertOKStatusCode;
import static android.net.http.cts.util.TestUtilsKt.skipIfNoInternetConnection;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.net.http.HttpEngine;
+import android.net.http.HttpException;
+import android.net.http.InlineExecutionProhibitedException;
+import android.net.http.UploadDataProvider;
+import android.net.http.UploadDataSink;
import android.net.http.UrlRequest;
import android.net.http.UrlRequest.Status;
import android.net.http.UrlResponseInfo;
@@ -34,17 +42,31 @@
import android.net.http.cts.util.TestUploadDataProvider;
import android.net.http.cts.util.TestUrlRequestCallback;
import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep;
+import android.net.http.cts.util.UploadDataProviders;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.google.common.base.Strings;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.URLEncoder;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
@RunWith(AndroidJUnit4.class)
public class UrlRequestTest {
+ private static final Executor DIRECT_EXECUTOR = Runnable::run;
+
private TestUrlRequestCallback mCallback;
private HttpCtsTestServer mTestServer;
private HttpEngine mHttpEngine;
@@ -70,7 +92,7 @@
}
private UrlRequest.Builder createUrlRequestBuilder(String url) {
- return mHttpEngine.newUrlRequestBuilder(url, mCallback, mCallback.getExecutor());
+ return mHttpEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback);
}
@Test
@@ -113,8 +135,9 @@
String testData = "test";
UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getEchoBodyUrl());
- TestUploadDataProvider dataProvider = new TestUploadDataProvider(
- TestUploadDataProvider.SuccessCallbackMode.SYNC, mCallback.getExecutor());
+ TestUploadDataProvider dataProvider =
+ new TestUploadDataProvider(
+ TestUploadDataProvider.SuccessCallbackMode.SYNC, mCallback.getExecutor());
dataProvider.addRead(testData.getBytes());
builder.setUploadDataProvider(dataProvider, mCallback.getExecutor());
builder.addHeader("Content-Type", "text/html");
@@ -127,8 +150,228 @@
}
@Test
- public void testUrlRequestFail_FailedCalled() throws Exception {
+ public void testUrlRequestFail_FailedCalled() {
createUrlRequestBuilder("http://0.0.0.0:0/").build().start();
mCallback.expectCallback(ResponseStep.ON_FAILED);
}
+
+ @Test
+ public void testUrlRequest_directExecutor_allowed() throws InterruptedException {
+ TestUrlRequestCallback callback = new TestUrlRequestCallback();
+ callback.setAllowDirectExecutor(true);
+ UrlRequest.Builder builder = mHttpEngine.newUrlRequestBuilder(
+ mTestServer.getEchoBodyUrl(), DIRECT_EXECUTOR, callback);
+ UploadDataProvider dataProvider = InMemoryUploadDataProvider.fromUtf8String("test");
+ builder.setUploadDataProvider(dataProvider, DIRECT_EXECUTOR);
+ builder.addHeader("Content-Type", "text/plain;charset=UTF-8");
+ builder.setDirectExecutorAllowed(true);
+ builder.build().start();
+ callback.blockForDone();
+
+ if (callback.mOnErrorCalled) {
+ throw new AssertionError("Expected no exception", callback.mError);
+ }
+
+ assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+ assertEquals("test", callback.mResponseAsString);
+ }
+
+ @Test
+ public void testUrlRequest_directExecutor_disallowed_uploadDataProvider() throws Exception {
+ TestUrlRequestCallback callback = new TestUrlRequestCallback();
+ // This applies just locally to the test callback, not to SUT
+ callback.setAllowDirectExecutor(true);
+
+ UrlRequest.Builder builder = mHttpEngine.newUrlRequestBuilder(
+ mTestServer.getEchoBodyUrl(), Executors.newSingleThreadExecutor(), callback);
+ UploadDataProvider dataProvider = InMemoryUploadDataProvider.fromUtf8String("test");
+
+ builder.setUploadDataProvider(dataProvider, DIRECT_EXECUTOR)
+ .addHeader("Content-Type", "text/plain;charset=UTF-8")
+ .build()
+ .start();
+ callback.blockForDone();
+
+ assertTrue(callback.mOnErrorCalled);
+ assertTrue(callback.mError.getCause() instanceof InlineExecutionProhibitedException);
+ }
+
+ @Test
+ public void testUrlRequest_directExecutor_disallowed_responseCallback() throws Exception {
+ TestUrlRequestCallback callback = new TestUrlRequestCallback();
+ // This applies just locally to the test callback, not to SUT
+ callback.setAllowDirectExecutor(true);
+
+ UrlRequest.Builder builder = mHttpEngine.newUrlRequestBuilder(
+ mTestServer.getEchoBodyUrl(), DIRECT_EXECUTOR, callback);
+ UploadDataProvider dataProvider = InMemoryUploadDataProvider.fromUtf8String("test");
+
+ builder.setUploadDataProvider(dataProvider, Executors.newSingleThreadExecutor())
+ .addHeader("Content-Type", "text/plain;charset=UTF-8")
+ .build()
+ .start();
+ callback.blockForDone();
+
+ assertTrue(callback.mOnErrorCalled);
+ assertTrue(callback.mError.getCause() instanceof InlineExecutionProhibitedException);
+ }
+
+ @Test
+ public void testUrlRequest_nonDirectByteBuffer() throws Exception {
+ BlockingQueue<HttpException> onFailedException = new ArrayBlockingQueue<>(1);
+
+ UrlRequest request =
+ mHttpEngine
+ .newUrlRequestBuilder(
+ mTestServer.getSuccessUrl(),
+ Executors.newSingleThreadExecutor(),
+ new StubUrlRequestCallback() {
+ @Override
+ public void onResponseStarted(
+ UrlRequest request, UrlResponseInfo info) {
+ // note: allocate, not allocateDirect
+ request.read(ByteBuffer.allocate(1024));
+ }
+
+ @Override
+ public void onFailed(
+ UrlRequest request,
+ UrlResponseInfo info,
+ HttpException error) {
+ onFailedException.add(error);
+ }
+ })
+ .build();
+ request.start();
+
+ HttpException e = onFailedException.poll(5, TimeUnit.SECONDS);
+ assertNotNull(e);
+ assertTrue(e.getCause() instanceof IllegalArgumentException);
+ assertTrue(e.getCause().getMessage().contains("direct"));
+ }
+
+ @Test
+ public void testUrlRequest_fullByteBuffer() throws Exception {
+ BlockingQueue<HttpException> onFailedException = new ArrayBlockingQueue<>(1);
+
+ UrlRequest request =
+ mHttpEngine
+ .newUrlRequestBuilder(
+ mTestServer.getSuccessUrl(),
+ Executors.newSingleThreadExecutor(),
+ new StubUrlRequestCallback() {
+ @Override
+ public void onResponseStarted(
+ UrlRequest request, UrlResponseInfo info) {
+ ByteBuffer bb = ByteBuffer.allocateDirect(1024);
+ bb.position(bb.limit());
+ request.read(bb);
+ }
+
+ @Override
+ public void onFailed(
+ UrlRequest request,
+ UrlResponseInfo info,
+ HttpException error) {
+ onFailedException.add(error);
+ }
+ })
+ .build();
+ request.start();
+
+ HttpException e = onFailedException.poll(5, TimeUnit.SECONDS);
+ assertNotNull(e);
+ assertTrue(e.getCause() instanceof IllegalArgumentException);
+ assertTrue(e.getCause().getMessage().contains("full"));
+ }
+
+ @Test
+ public void testUrlRequestPost_withRedirect() throws Exception {
+ String body = Strings.repeat(
+ "Hello, this is a really interesting body, so write this 100 times.", 100);
+
+ String redirectUrlParameter =
+ URLEncoder.encode(mTestServer.getEchoBodyUrl(), "UTF-8");
+ createUrlRequestBuilder(
+ String.format(
+ "%s/alt_redirect?dest=%s&statusCode=307",
+ mTestServer.getBaseUri(),
+ redirectUrlParameter))
+ .setHttpMethod("POST")
+ .addHeader("Content-Type", "text/plain")
+ .setUploadDataProvider(
+ UploadDataProviders.create(body.getBytes(StandardCharsets.UTF_8)),
+ mCallback.getExecutor())
+ .build()
+ .start();
+ mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
+
+ assertOKStatusCode(mCallback.mResponseInfo);
+ assertThat(mCallback.mResponseAsString).isEqualTo(body);
+ }
+
+ private static class StubUrlRequestCallback extends UrlRequest.Callback {
+
+ @Override
+ public void onRedirectReceived(
+ UrlRequest request, UrlResponseInfo info, String newLocationUrl) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onReadCompleted(
+ UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onSucceeded(UrlRequest request, UrlResponseInfo info) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onFailed(UrlRequest request, UrlResponseInfo info, HttpException error) {
+ throw new UnsupportedOperationException(error);
+ }
+ }
+
+ private static class InMemoryUploadDataProvider extends UploadDataProvider {
+ private final byte[] mBody;
+ private int mNextChunkStartIndex = 0;
+
+ private InMemoryUploadDataProvider(byte[] body) {
+ this.mBody = body;
+ }
+
+ static InMemoryUploadDataProvider fromUtf8String(String body) {
+ return new InMemoryUploadDataProvider(body.getBytes(StandardCharsets.UTF_8));
+ }
+
+ @Override
+ public long getLength() {
+ return mBody.length;
+ }
+
+ @Override
+ public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) {
+ if (mNextChunkStartIndex >= getLength()) {
+ throw new IllegalStateException("Body of known length is exhausted");
+ }
+ int nextChunkSize =
+ Math.min(mBody.length - mNextChunkStartIndex, byteBuffer.remaining());
+ byteBuffer.put(mBody, mNextChunkStartIndex, nextChunkSize);
+ mNextChunkStartIndex += nextChunkSize;
+ uploadDataSink.onReadSucceeded(false);
+ }
+
+ @Override
+ public void rewind(UploadDataSink uploadDataSink) {
+ mNextChunkStartIndex = 0;
+ }
+ }
}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/UrlResponseInfoTest.kt b/Cronet/tests/cts/src/android/net/http/cts/UrlResponseInfoTest.kt
new file mode 100644
index 0000000..38da9c5
--- /dev/null
+++ b/Cronet/tests/cts/src/android/net/http/cts/UrlResponseInfoTest.kt
@@ -0,0 +1,67 @@
+/*
+ * 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 android.net.http.cts
+
+import android.content.Context
+import android.net.http.HttpEngine
+import android.net.http.cts.util.HttpCtsTestServer
+import android.net.http.cts.util.TestUrlRequestCallback
+import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class UrlResponseInfoTest {
+
+ @Test
+ fun testUrlResponseInfo_apisReturnCorrectInfo() {
+ // start the engine and send a request
+ val context: Context = ApplicationProvider.getApplicationContext()
+ val server = HttpCtsTestServer(context)
+ val httpEngine = HttpEngine.Builder(context).build()
+ val callback = TestUrlRequestCallback()
+ val url = server.successUrl
+ val request = httpEngine.newUrlRequestBuilder(url, callback.executor, callback).build()
+
+ request.start()
+ callback.expectCallback(ResponseStep.ON_SUCCEEDED)
+
+ val info = callback.mResponseInfo
+ assertFalse(info.headers.asList.isEmpty())
+ assertEquals(200, info.httpStatusCode)
+ assertTrue(info.receivedByteCount > 0)
+ assertEquals(url, info.url)
+ assertEquals(listOf(url), info.urlChain)
+ assertFalse(info.wasCached())
+
+ // TODO Current test server does not set these values. Uncomment when we use one that does.
+ // assertEquals("OK", info.httpStatusText)
+ // assertEquals("http/1.1", info.negotiatedProtocol)
+
+ // cronet defaults to port 0 when no proxy is specified.
+ // This is not a behaviour we want to enforce since null is reasonable too.
+ // assertEquals(":0", info.proxyServer)
+
+ server.shutdown()
+ httpEngine.shutdown()
+ }
+}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/util/TestBidirectionalStreamCallback.java b/Cronet/tests/cts/src/android/net/http/cts/util/TestBidirectionalStreamCallback.java
index e82b24d..1e7333c 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/util/TestBidirectionalStreamCallback.java
+++ b/Cronet/tests/cts/src/android/net/http/cts/util/TestBidirectionalStreamCallback.java
@@ -26,6 +26,7 @@
import static org.junit.Assume.assumeTrue;
import android.net.http.BidirectionalStream;
+import android.net.http.HeaderBlock;
import android.net.http.HttpException;
import android.net.http.UrlResponseInfo;
import android.os.ConditionVariable;
@@ -43,7 +44,7 @@
* the stream completes on another thread. Allows to cancel, block stream or throw an exception from
* an arbitrary step.
*/
-public class TestBidirectionalStreamCallback extends BidirectionalStream.Callback {
+public class TestBidirectionalStreamCallback implements BidirectionalStream.Callback {
private static final int TIMEOUT_MS = 12_000;
public UrlResponseInfo mResponseInfo;
public HttpException mError;
@@ -56,7 +57,7 @@
public int mHttpResponseDataLength;
public String mResponseAsString = "";
- public UrlResponseInfo.HeaderBlock mTrailers;
+ public HeaderBlock mTrailers;
private static final int READ_BUFFER_SIZE = 32 * 1024;
@@ -337,7 +338,7 @@
public void onResponseTrailersReceived(
BidirectionalStream stream,
UrlResponseInfo info,
- UrlResponseInfo.HeaderBlock trailers) {
+ HeaderBlock trailers) {
checkOnValidThread();
assertFalse(stream.isDone());
assertNull(mError);
diff --git a/Cronet/tests/cts/src/android/net/http/cts/util/TestStatusListener.kt b/Cronet/tests/cts/src/android/net/http/cts/util/TestStatusListener.kt
index e526c7d..3a4486f 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/util/TestStatusListener.kt
+++ b/Cronet/tests/cts/src/android/net/http/cts/util/TestStatusListener.kt
@@ -24,7 +24,7 @@
private const val TIMEOUT_MS = 12000L
/** Test status listener for requests */
-class TestStatusListener : StatusListener() {
+class TestStatusListener : StatusListener {
private val statusFuture = CompletableFuture<Int>()
override fun onStatus(status: Int) {
diff --git a/Cronet/tests/cts/src/android/net/http/cts/util/UploadDataProviders.java b/Cronet/tests/cts/src/android/net/http/cts/util/UploadDataProviders.java
new file mode 100644
index 0000000..889f8f2
--- /dev/null
+++ b/Cronet/tests/cts/src/android/net/http/cts/util/UploadDataProviders.java
@@ -0,0 +1,198 @@
+/*
+ * 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 android.net.http.cts.util;
+
+import android.net.http.UploadDataProvider;
+import android.net.http.UploadDataSink;
+import android.os.ParcelFileDescriptor;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+/**
+ * Provides implementations of {@link UploadDataProvider} for common use cases. Corresponds to
+ * {@code android.net.http.apihelpers.UploadDataProviders} which is not an exposed API.
+ */
+public final class UploadDataProviders {
+ /**
+ * Uploads an entire file.
+ *
+ * @param file The file to upload
+ * @return A new UploadDataProvider for the given file
+ */
+ public static UploadDataProvider create(final File file) {
+ return new FileUploadProvider(() -> new FileInputStream(file).getChannel());
+ }
+
+ /**
+ * Uploads an entire file, closing the descriptor when it is no longer needed.
+ *
+ * @param fd The file descriptor to upload
+ * @throws IllegalArgumentException if {@code fd} is not a file.
+ * @return A new UploadDataProvider for the given file descriptor
+ */
+ public static UploadDataProvider create(final ParcelFileDescriptor fd) {
+ return new FileUploadProvider(() -> {
+ if (fd.getStatSize() != -1) {
+ return new ParcelFileDescriptor.AutoCloseInputStream(fd).getChannel();
+ } else {
+ fd.close();
+ throw new IllegalArgumentException("Not a file: " + fd);
+ }
+ });
+ }
+
+ /**
+ * Uploads a ByteBuffer, from the current {@code buffer.position()} to {@code buffer.limit()}
+ *
+ * @param buffer The data to upload
+ * @return A new UploadDataProvider for the given buffer
+ */
+ public static UploadDataProvider create(ByteBuffer buffer) {
+ return new ByteBufferUploadProvider(buffer.slice());
+ }
+
+ /**
+ * Uploads {@code length} bytes from {@code data}, starting from {@code offset}
+ *
+ * @param data Array containing data to upload
+ * @param offset Offset within data to start with
+ * @param length Number of bytes to upload
+ * @return A new UploadDataProvider for the given data
+ */
+ public static UploadDataProvider create(byte[] data, int offset, int length) {
+ return new ByteBufferUploadProvider(ByteBuffer.wrap(data, offset, length).slice());
+ }
+
+ /**
+ * Uploads the contents of {@code data}
+ *
+ * @param data Array containing data to upload
+ * @return A new UploadDataProvider for the given data
+ */
+ public static UploadDataProvider create(byte[] data) {
+ return create(data, 0, data.length);
+ }
+
+ private interface FileChannelProvider {
+ FileChannel getChannel() throws IOException;
+ }
+
+ private static final class FileUploadProvider extends UploadDataProvider {
+ private volatile FileChannel mChannel;
+ private final FileChannelProvider mProvider;
+ /** Guards initialization of {@code mChannel} */
+ private final Object mLock = new Object();
+
+ private FileUploadProvider(FileChannelProvider provider) {
+ this.mProvider = provider;
+ }
+
+ @Override
+ public long getLength() throws IOException {
+ return getChannel().size();
+ }
+
+ @Override
+ public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) throws IOException {
+ if (!byteBuffer.hasRemaining()) {
+ throw new IllegalStateException("Cronet passed a buffer with no bytes remaining");
+ }
+ FileChannel channel = getChannel();
+ int bytesRead = 0;
+ while (bytesRead == 0) {
+ int read = channel.read(byteBuffer);
+ if (read == -1) {
+ break;
+ } else {
+ bytesRead += read;
+ }
+ }
+ uploadDataSink.onReadSucceeded(false);
+ }
+
+ @Override
+ public void rewind(UploadDataSink uploadDataSink) throws IOException {
+ getChannel().position(0);
+ uploadDataSink.onRewindSucceeded();
+ }
+
+ /**
+ * Lazily initializes the channel so that a blocking operation isn't performed
+ * on a non-executor thread.
+ */
+ private FileChannel getChannel() throws IOException {
+ if (mChannel == null) {
+ synchronized (mLock) {
+ if (mChannel == null) {
+ mChannel = mProvider.getChannel();
+ }
+ }
+ }
+ return mChannel;
+ }
+
+ @Override
+ public void close() throws IOException {
+ FileChannel channel = mChannel;
+ if (channel != null) {
+ channel.close();
+ }
+ }
+ }
+
+ private static final class ByteBufferUploadProvider extends UploadDataProvider {
+ private final ByteBuffer mUploadBuffer;
+
+ private ByteBufferUploadProvider(ByteBuffer uploadBuffer) {
+ this.mUploadBuffer = uploadBuffer;
+ }
+
+ @Override
+ public long getLength() {
+ return mUploadBuffer.limit();
+ }
+
+ @Override
+ public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) {
+ if (!byteBuffer.hasRemaining()) {
+ throw new IllegalStateException("Cronet passed a buffer with no bytes remaining");
+ }
+ if (byteBuffer.remaining() >= mUploadBuffer.remaining()) {
+ byteBuffer.put(mUploadBuffer);
+ } else {
+ int oldLimit = mUploadBuffer.limit();
+ mUploadBuffer.limit(mUploadBuffer.position() + byteBuffer.remaining());
+ byteBuffer.put(mUploadBuffer);
+ mUploadBuffer.limit(oldLimit);
+ }
+ uploadDataSink.onReadSucceeded(false);
+ }
+
+ @Override
+ public void rewind(UploadDataSink uploadDataSink) {
+ mUploadBuffer.position(0);
+ uploadDataSink.onRewindSucceeded();
+ }
+ }
+
+ // Prevent instantiation
+ private UploadDataProviders() {}
+}
diff --git a/Cronet/tests/mts/Android.bp b/Cronet/tests/mts/Android.bp
index 1cabd63..ac71653 100644
--- a/Cronet/tests/mts/Android.bp
+++ b/Cronet/tests/mts/Android.bp
@@ -19,7 +19,9 @@
android_library {
name: "NetHttpTestsLibPreJarJar",
- srcs: [":cronet_aml_javatests_sources"],
+ srcs: ["//external/cronet:cronet_aml_javatests_sources"],
+ sdk_version: "test_current",
+ min_sdk_version: "30",
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
@@ -28,7 +30,8 @@
libs: [
"android.test.base",
"framework-tethering-pre-jarjar",
- ]
+ ],
+ lint: { test: true }
}
android_test {
diff --git a/Cronet/tests/mts/AndroidTest.xml b/Cronet/tests/mts/AndroidTest.xml
index 8cb549e..0d780a1 100644
--- a/Cronet/tests/mts/AndroidTest.xml
+++ b/Cronet/tests/mts/AndroidTest.xml
@@ -16,8 +16,9 @@
-->
<configuration description="Runs NetHttp Mainline Tests.">
<!-- Only run tests if the device under test is SDK version 30 or above. -->
+ <!-- TODO Switch back to Sdk30 when b/270049141 is fixed -->
<object type="module_controller"
- class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+ class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="NetHttpTests.apk" />
diff --git a/Cronet/tools/import/import_cronet.sh b/Cronet/tools/import/import_cronet.sh
index 7642914..eb82551 100755
--- a/Cronet/tools/import/import_cronet.sh
+++ b/Cronet/tools/import/import_cronet.sh
@@ -19,40 +19,70 @@
# Environment:
# ANDROID_BUILD_TOP: path the root of the current Android directory.
# Arguments:
-# -l: The last revision that was imported.
-# -n: The new revision to import.
+# -l rev: The last revision that was imported.
+# Optional Arguments:
+# -n rev: The new revision to import.
+# -f: Force copybara to ignore a failure to find the last imported revision.
-OPTSTRING=l:n:
+OPTSTRING=fl:n:
usage() {
cat <<EOF
-Usage: import_cronet.sh -l last-rev -n new-rev
+Usage: import_cronet.sh -n new-rev [-l last-rev] [-f]
EOF
exit 1
}
#######################################
+# Create upstream-import branch in external/cronet.
+# Globals:
+# ANDROID_BUILD_TOP
+# Arguments:
+# none
+#######################################
+setup_upstream_import_branch() {
+ local git_dir="${ANDROID_BUILD_TOP}/external/cronet"
+ local initial_empty_repo_sha="d1add53d6e90815f363c91d433735556ce79b0d2"
+
+ # Suppress error message if branch already exists.
+ (cd "${git_dir}" && git branch upstream-import "${initial_empty_repo_sha}") 2>/dev/null
+}
+
+#######################################
# Runs the copybara import of Chromium
# Globals:
# ANDROID_BUILD_TOP
# Arguments:
-# last_rev, string
# new_rev, string
+# last_rev, string or empty
+# force, string or empty
#######################################
do_run_copybara() {
- local _last_rev=$1
- local _new_rev=$2
+ local _new_rev=$1
+ local _last_rev=$2
+ local _force=$3
+
+ local -a flags
+ flags+=(--git-destination-url="file://${ANDROID_BUILD_TOP}/external/cronet")
+ flags+=(--repo-timeout 3h)
+
+ if [ ! -z "${_force}" ]; then
+ flags+=(--force)
+ fi
+
+ if [ ! -z "${_last_rev}" ]; then
+ flags+=(--last-rev "${_last_rev}")
+ fi
/google/bin/releases/copybara/public/copybara/copybara \
- --git-destination-url="file://${ANDROID_BUILD_TOP}/external/cronet" \
- --last-rev "${_last_rev}" \
- --repo-timeout 3h \
+ "${flags[@]}" \
"${ANDROID_BUILD_TOP}/packages/modules/Connectivity/Cronet/tools/import/copy.bara.sky" \
import_cronet "${_new_rev}"
}
while getopts $OPTSTRING opt; do
case "${opt}" in
+ f) force=true ;;
l) last_rev="${OPTARG}" ;;
n) new_rev="${OPTARG}" ;;
?) usage ;;
@@ -60,17 +90,11 @@
esac
done
-# TODO: Get last-rev from METADATA file.
-# Setting last-rev may only be required for the first commit.
-if [ -z "${last_rev}" ]; then
- echo "-l argument required"
- usage
-fi
-
if [ -z "${new_rev}" ]; then
echo "-n argument required"
usage
fi
-do_run_copybara "${last_rev}" "${new_rev}"
+setup_upstream_import_branch
+do_run_copybara "${new_rev}" "${last_rev}" "${force}"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 4d3ecdf..70c5f85 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -213,6 +213,9 @@
},
{
"name": "libnetworkstats_test[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
+ },
+ {
+ "name": "NetHttpCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
}
],
"mainline-postsubmit": [
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 67206cd..ff5acf5 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -66,11 +66,19 @@
apex_defaults {
name: "CronetInTetheringApexDefaultsEnabled",
- jni_libs: ["cronet_aml_components_cronet_android_cronet"],
+ jni_libs: [
+ "//external/cronet:cronet_aml_components_cronet_android_cronet",
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
+ ],
arch: {
riscv64: {
// TODO: remove this when there is a riscv64 libcronet
- exclude_jni_libs: ["cronet_aml_components_cronet_android_cronet"],
+ exclude_jni_libs: [
+ "//external/cronet:cronet_aml_components_cronet_android_cronet",
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
+ ],
},
},
}
diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp
index 4c677d0..b99c9e4 100644
--- a/Tethering/common/TetheringLib/Android.bp
+++ b/Tethering/common/TetheringLib/Android.bp
@@ -65,6 +65,7 @@
hostdex: true, // for hiddenapi check
permitted_packages: ["android.net"],
+ lint: { strict_updatability_linting: true },
}
java_defaults {
@@ -74,27 +75,18 @@
java_defaults {
name: "CronetJavaDefaultsEnabled",
- srcs: [":cronet_aml_api_sources"],
+ srcs: ["//external/cronet:cronet_aml_api_sources"],
libs: [
"androidx.annotation_annotation",
],
impl_only_static_libs: [
- "cronet_aml_java",
+ "//external/cronet:cronet_aml_java",
],
- // STOPSHIP(b/265674359): fix all Cronet lint warnings and re-enable lint
- // directly in framework-tethering
- lint: {
- enabled: false,
- },
- api_lint: {
- enabled: false,
- },
api_dir: "cronet_enabled/api",
}
java_defaults {
name: "CronetJavaDefaultsDisabled",
- lint: { strict_updatability_linting: true },
}
java_defaults {
@@ -109,8 +101,8 @@
java_defaults {
name: "CronetJavaPrejarjarDefaultsEnabled",
static_libs: [
- "cronet_aml_api_java",
- "cronet_aml_java"
+ "//external/cronet:cronet_aml_api_java",
+ "//external/cronet:cronet_aml_java"
],
}
diff --git a/Tethering/common/TetheringLib/cronet_enabled/api/current.txt b/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
index 777138d..cf441ce 100644
--- a/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
+++ b/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
@@ -5,21 +5,18 @@
ctor public BidirectionalStream();
method public abstract void cancel();
method public abstract void flush();
+ method @NonNull public abstract android.net.http.HeaderBlock getHeaders();
+ method @NonNull public abstract String getHttpMethod();
+ method public abstract int getPriority();
+ method public abstract int getTrafficStatsTag();
+ method public abstract int getTrafficStatsUid();
+ method public abstract boolean hasTrafficStatsTag();
+ method public abstract boolean hasTrafficStatsUid();
+ method public abstract boolean isDelayRequestHeadersUntilFirstFlushEnabled();
method public abstract boolean isDone();
- method public abstract void read(java.nio.ByteBuffer);
+ method public abstract void read(@NonNull java.nio.ByteBuffer);
method public abstract void start();
- method public abstract void write(java.nio.ByteBuffer, boolean);
- }
-
- public abstract static class BidirectionalStream.Builder {
- ctor public BidirectionalStream.Builder();
- method public abstract android.net.http.BidirectionalStream.Builder addHeader(String, String);
- method public abstract android.net.http.BidirectionalStream build();
- method public abstract android.net.http.BidirectionalStream.Builder delayRequestHeadersUntilFirstFlush(boolean);
- method public abstract android.net.http.BidirectionalStream.Builder setHttpMethod(String);
- method public abstract android.net.http.BidirectionalStream.Builder setPriority(int);
- method public abstract android.net.http.BidirectionalStream.Builder setTrafficStatsTag(int);
- method public abstract android.net.http.BidirectionalStream.Builder setTrafficStatsUid(int);
+ method public abstract void write(@NonNull java.nio.ByteBuffer, boolean);
field public static final int STREAM_PRIORITY_HIGHEST = 4; // 0x4
field public static final int STREAM_PRIORITY_IDLE = 0; // 0x0
field public static final int STREAM_PRIORITY_LOW = 2; // 0x2
@@ -27,98 +24,120 @@
field public static final int STREAM_PRIORITY_MEDIUM = 3; // 0x3
}
- public abstract static class BidirectionalStream.Callback {
- ctor public BidirectionalStream.Callback();
- method public void onCanceled(android.net.http.BidirectionalStream, android.net.http.UrlResponseInfo);
- method public abstract void onFailed(android.net.http.BidirectionalStream, android.net.http.UrlResponseInfo, android.net.http.HttpException);
- method public abstract void onReadCompleted(android.net.http.BidirectionalStream, android.net.http.UrlResponseInfo, java.nio.ByteBuffer, boolean);
- method public abstract void onResponseHeadersReceived(android.net.http.BidirectionalStream, android.net.http.UrlResponseInfo);
- method public void onResponseTrailersReceived(android.net.http.BidirectionalStream, android.net.http.UrlResponseInfo, android.net.http.UrlResponseInfo.HeaderBlock);
- method public abstract void onStreamReady(android.net.http.BidirectionalStream);
- method public abstract void onSucceeded(android.net.http.BidirectionalStream, android.net.http.UrlResponseInfo);
- method public abstract void onWriteCompleted(android.net.http.BidirectionalStream, android.net.http.UrlResponseInfo, java.nio.ByteBuffer, boolean);
+ public abstract static class BidirectionalStream.Builder {
+ ctor public BidirectionalStream.Builder();
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder addHeader(@NonNull String, @NonNull String);
+ method @NonNull public abstract android.net.http.BidirectionalStream build();
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder setDelayRequestHeadersUntilFirstFlushEnabled(boolean);
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder setHttpMethod(@NonNull String);
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder setPriority(int);
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder setTrafficStatsTag(int);
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder setTrafficStatsUid(int);
+ }
+
+ public static interface BidirectionalStream.Callback {
+ method public void onCanceled(@NonNull android.net.http.BidirectionalStream, @Nullable android.net.http.UrlResponseInfo);
+ method public void onFailed(@NonNull android.net.http.BidirectionalStream, @Nullable android.net.http.UrlResponseInfo, @NonNull android.net.http.HttpException);
+ method public void onReadCompleted(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer, boolean);
+ method public void onResponseHeadersReceived(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo);
+ method public void onResponseTrailersReceived(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull android.net.http.HeaderBlock);
+ method public void onStreamReady(@NonNull android.net.http.BidirectionalStream);
+ method public void onSucceeded(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo);
+ method public void onWriteCompleted(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer, boolean);
}
public abstract class CallbackException extends android.net.http.HttpException {
- ctor protected CallbackException(String, Throwable);
+ ctor protected CallbackException(@Nullable String, @Nullable Throwable);
}
public class ConnectionMigrationOptions {
- method @Nullable public Boolean getAllowNonDefaultNetworkUsage();
- method @Nullable public Boolean getEnableDefaultNetworkMigration();
- method @Nullable public Boolean getEnablePathDegradationMigration();
+ method public int getAllowNonDefaultNetworkUsageEnabled();
+ method public int getDefaultNetworkMigrationEnabled();
+ method public int getPathDegradationMigrationEnabled();
+ field public static final int MIGRATION_OPTION_DISABLED = 2; // 0x2
+ field public static final int MIGRATION_OPTION_ENABLED = 1; // 0x1
+ field public static final int MIGRATION_OPTION_UNSPECIFIED = 0; // 0x0
}
- public static class ConnectionMigrationOptions.Builder {
+ public static final class ConnectionMigrationOptions.Builder {
ctor public ConnectionMigrationOptions.Builder();
- method public android.net.http.ConnectionMigrationOptions build();
- method public android.net.http.ConnectionMigrationOptions.Builder setAllowNonDefaultNetworkUsage(boolean);
- method public android.net.http.ConnectionMigrationOptions.Builder setEnableDefaultNetworkMigration(boolean);
- method public android.net.http.ConnectionMigrationOptions.Builder setEnablePathDegradationMigration(boolean);
+ method @NonNull public android.net.http.ConnectionMigrationOptions build();
+ method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setAllowNonDefaultNetworkUsageEnabled(int);
+ method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setDefaultNetworkMigrationEnabled(int);
+ method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setPathDegradationMigrationEnabled(int);
}
public final class DnsOptions {
- method @Nullable public Boolean getEnableStaleDns();
- method @Nullable public Boolean getPersistHostCache();
+ method public int getPersistHostCacheEnabled();
method @Nullable public java.time.Duration getPersistHostCachePeriod();
- method @Nullable public Boolean getPreestablishConnectionsToStaleDnsResults();
+ method public int getPreestablishConnectionsToStaleDnsResultsEnabled();
+ method public int getStaleDnsEnabled();
method @Nullable public android.net.http.DnsOptions.StaleDnsOptions getStaleDnsOptions();
- method @Nullable public Boolean getUseHttpStackDnsResolver();
+ method public int getUseHttpStackDnsResolverEnabled();
+ field public static final int DNS_OPTION_DISABLED = 2; // 0x2
+ field public static final int DNS_OPTION_ENABLED = 1; // 0x1
+ field public static final int DNS_OPTION_UNSPECIFIED = 0; // 0x0
}
public static final class DnsOptions.Builder {
ctor public DnsOptions.Builder();
- method public android.net.http.DnsOptions build();
- method public android.net.http.DnsOptions.Builder setEnableStaleDns(boolean);
- method public android.net.http.DnsOptions.Builder setPersistHostCache(boolean);
- method public android.net.http.DnsOptions.Builder setPersistHostCachePeriod(java.time.Duration);
- method public android.net.http.DnsOptions.Builder setPreestablishConnectionsToStaleDnsResults(boolean);
- method public android.net.http.DnsOptions.Builder setStaleDnsOptions(android.net.http.DnsOptions.StaleDnsOptions);
- method public android.net.http.DnsOptions.Builder setUseHttpStackDnsResolver(boolean);
+ method @NonNull public android.net.http.DnsOptions build();
+ method @NonNull public android.net.http.DnsOptions.Builder setPersistHostCacheEnabled(int);
+ method @NonNull public android.net.http.DnsOptions.Builder setPersistHostCachePeriod(@NonNull java.time.Duration);
+ method @NonNull public android.net.http.DnsOptions.Builder setPreestablishConnectionsToStaleDnsResultsEnabled(int);
+ method @NonNull public android.net.http.DnsOptions.Builder setStaleDnsEnabled(int);
+ method @NonNull public android.net.http.DnsOptions.Builder setStaleDnsOptions(@NonNull android.net.http.DnsOptions.StaleDnsOptions);
+ method @NonNull public android.net.http.DnsOptions.Builder setUseHttpStackDnsResolverEnabled(int);
}
public static class DnsOptions.StaleDnsOptions {
- method @Nullable public Boolean getAllowCrossNetworkUsage();
- method @Nullable public Long getFreshLookupTimeoutMillis();
- method @Nullable public Long getMaxExpiredDelayMillis();
- method @Nullable public Boolean getUseStaleOnNameNotResolved();
+ method public int getAllowCrossNetworkUsageEnabled();
+ method @Nullable public java.time.Duration getFreshLookupTimeout();
+ method @Nullable public java.time.Duration getMaxExpiredDelay();
+ method public int getUseStaleOnNameNotResolvedEnabled();
}
public static final class DnsOptions.StaleDnsOptions.Builder {
ctor public DnsOptions.StaleDnsOptions.Builder();
- method public android.net.http.DnsOptions.StaleDnsOptions build();
- method public android.net.http.DnsOptions.StaleDnsOptions.Builder setAllowCrossNetworkUsage(boolean);
- method public android.net.http.DnsOptions.StaleDnsOptions.Builder setFreshLookupTimeout(java.time.Duration);
- method public android.net.http.DnsOptions.StaleDnsOptions.Builder setMaxExpiredDelay(java.time.Duration);
- method public android.net.http.DnsOptions.StaleDnsOptions.Builder setUseStaleOnNameNotResolved(boolean);
+ method @NonNull public android.net.http.DnsOptions.StaleDnsOptions build();
+ method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setAllowCrossNetworkUsageEnabled(int);
+ method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setFreshLookupTimeout(@NonNull java.time.Duration);
+ method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setMaxExpiredDelay(@NonNull java.time.Duration);
+ method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setUseStaleOnNameNotResolvedEnabled(int);
+ }
+
+ public abstract class HeaderBlock {
+ ctor public HeaderBlock();
+ method @NonNull public abstract java.util.List<java.util.Map.Entry<java.lang.String,java.lang.String>> getAsList();
+ method @NonNull public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> getAsMap();
}
public abstract class HttpEngine {
method public void bindToNetwork(@Nullable android.net.Network);
- method public abstract java.net.URLStreamHandlerFactory createURLStreamHandlerFactory();
- method public static String getVersionString();
- method public abstract android.net.http.BidirectionalStream.Builder newBidirectionalStreamBuilder(String, android.net.http.BidirectionalStream.Callback, java.util.concurrent.Executor);
- method public abstract android.net.http.UrlRequest.Builder newUrlRequestBuilder(String, android.net.http.UrlRequest.Callback, java.util.concurrent.Executor);
- method public abstract java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
+ method @NonNull public abstract java.net.URLStreamHandlerFactory createUrlStreamHandlerFactory();
+ method @NonNull public static String getVersionString();
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder newBidirectionalStreamBuilder(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.http.BidirectionalStream.Callback);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder newUrlRequestBuilder(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.http.UrlRequest.Callback);
+ method @NonNull public abstract java.net.URLConnection openConnection(@NonNull java.net.URL) throws java.io.IOException;
method public abstract void shutdown();
}
public static class HttpEngine.Builder {
- ctor public HttpEngine.Builder(android.content.Context);
- method public android.net.http.HttpEngine.Builder addPublicKeyPins(String, java.util.Set<byte[]>, boolean, java.time.Instant);
- method public android.net.http.HttpEngine.Builder addQuicHint(String, int, int);
- method public android.net.http.HttpEngine build();
- method public String getDefaultUserAgent();
- method public android.net.http.HttpEngine.Builder setConnectionMigrationOptions(android.net.http.ConnectionMigrationOptions);
- method public android.net.http.HttpEngine.Builder setDnsOptions(android.net.http.DnsOptions);
- method public android.net.http.HttpEngine.Builder setEnableBrotli(boolean);
- method public android.net.http.HttpEngine.Builder setEnableHttp2(boolean);
- method public android.net.http.HttpEngine.Builder setEnableHttpCache(int, long);
- method public android.net.http.HttpEngine.Builder setEnablePublicKeyPinningBypassForLocalTrustAnchors(boolean);
- method public android.net.http.HttpEngine.Builder setEnableQuic(boolean);
- method public android.net.http.HttpEngine.Builder setQuicOptions(android.net.http.QuicOptions);
- method public android.net.http.HttpEngine.Builder setStoragePath(String);
- method public android.net.http.HttpEngine.Builder setUserAgent(String);
+ ctor public HttpEngine.Builder(@NonNull android.content.Context);
+ method @NonNull public android.net.http.HttpEngine.Builder addPublicKeyPins(@NonNull String, @NonNull java.util.Set<byte[]>, boolean, @NonNull java.time.Instant);
+ method @NonNull public android.net.http.HttpEngine.Builder addQuicHint(@NonNull String, int, int);
+ method @NonNull public android.net.http.HttpEngine build();
+ method @NonNull public String getDefaultUserAgent();
+ method @NonNull public android.net.http.HttpEngine.Builder setConnectionMigrationOptions(@NonNull android.net.http.ConnectionMigrationOptions);
+ method @NonNull public android.net.http.HttpEngine.Builder setDnsOptions(@NonNull android.net.http.DnsOptions);
+ method @NonNull public android.net.http.HttpEngine.Builder setEnableBrotli(boolean);
+ method @NonNull public android.net.http.HttpEngine.Builder setEnableHttp2(boolean);
+ method @NonNull public android.net.http.HttpEngine.Builder setEnableHttpCache(int, long);
+ method @NonNull public android.net.http.HttpEngine.Builder setEnablePublicKeyPinningBypassForLocalTrustAnchors(boolean);
+ method @NonNull public android.net.http.HttpEngine.Builder setEnableQuic(boolean);
+ method @NonNull public android.net.http.HttpEngine.Builder setQuicOptions(@NonNull android.net.http.QuicOptions);
+ method @NonNull public android.net.http.HttpEngine.Builder setStoragePath(@NonNull String);
+ method @NonNull public android.net.http.HttpEngine.Builder setUserAgent(@NonNull String);
field public static final int HTTP_CACHE_DISABLED = 0; // 0x0
field public static final int HTTP_CACHE_DISK = 3; // 0x3
field public static final int HTTP_CACHE_DISK_NO_HTTP = 2; // 0x2
@@ -126,7 +145,7 @@
}
public class HttpException extends java.io.IOException {
- ctor public HttpException(String, Throwable);
+ ctor public HttpException(@Nullable String, @Nullable Throwable);
}
public final class InlineExecutionProhibitedException extends java.util.concurrent.RejectedExecutionException {
@@ -134,7 +153,7 @@
}
public abstract class NetworkException extends android.net.http.HttpException {
- ctor public NetworkException(String, Throwable);
+ ctor public NetworkException(@Nullable String, @Nullable Throwable);
method public abstract int getErrorCode();
method public abstract boolean isImmediatelyRetryable();
field public static final int ERROR_ADDRESS_UNREACHABLE = 9; // 0x9
@@ -151,60 +170,57 @@
}
public abstract class QuicException extends android.net.http.NetworkException {
- ctor protected QuicException(String, Throwable);
+ ctor protected QuicException(@Nullable String, @Nullable Throwable);
}
public class QuicOptions {
+ method @NonNull public java.util.Set<java.lang.String> getAllowedQuicHosts();
method @Nullable public String getHandshakeUserAgent();
+ method @Nullable public java.time.Duration getIdleConnectionTimeout();
method @Nullable public Integer getInMemoryServerConfigsCacheSize();
- method public java.util.Set<java.lang.String> getQuicHostAllowlist();
}
- public static class QuicOptions.Builder {
+ public static final class QuicOptions.Builder {
ctor public QuicOptions.Builder();
- method public android.net.http.QuicOptions.Builder addAllowedQuicHost(String);
- method public android.net.http.QuicOptions build();
- method public android.net.http.QuicOptions.Builder setHandshakeUserAgent(String);
- method public android.net.http.QuicOptions.Builder setIdleConnectionTimeout(java.time.Duration);
- method public android.net.http.QuicOptions.Builder setInMemoryServerConfigsCacheSize(int);
+ method @NonNull public android.net.http.QuicOptions.Builder addAllowedQuicHost(@NonNull String);
+ method @NonNull public android.net.http.QuicOptions build();
+ method @NonNull public android.net.http.QuicOptions.Builder setHandshakeUserAgent(@NonNull String);
+ method @NonNull public android.net.http.QuicOptions.Builder setIdleConnectionTimeout(@NonNull java.time.Duration);
+ method @NonNull public android.net.http.QuicOptions.Builder setInMemoryServerConfigsCacheSize(int);
}
public abstract class UploadDataProvider implements java.io.Closeable {
ctor public UploadDataProvider();
method public void close() throws java.io.IOException;
method public abstract long getLength() throws java.io.IOException;
- method public abstract void read(android.net.http.UploadDataSink, java.nio.ByteBuffer) throws java.io.IOException;
- method public abstract void rewind(android.net.http.UploadDataSink) throws java.io.IOException;
+ method public abstract void read(@NonNull android.net.http.UploadDataSink, @NonNull java.nio.ByteBuffer) throws java.io.IOException;
+ method public abstract void rewind(@NonNull android.net.http.UploadDataSink) throws java.io.IOException;
}
public abstract class UploadDataSink {
ctor public UploadDataSink();
- method public abstract void onReadError(Exception);
+ method public abstract void onReadError(@NonNull Exception);
method public abstract void onReadSucceeded(boolean);
- method public abstract void onRewindError(Exception);
+ method public abstract void onRewindError(@NonNull Exception);
method public abstract void onRewindSucceeded();
}
public abstract class UrlRequest {
method public abstract void cancel();
method public abstract void followRedirect();
- method public abstract void getStatus(android.net.http.UrlRequest.StatusListener);
+ method @NonNull public abstract android.net.http.HeaderBlock getHeaders();
+ method @Nullable public abstract String getHttpMethod();
+ method public abstract int getPriority();
+ method public abstract void getStatus(@NonNull android.net.http.UrlRequest.StatusListener);
+ method public abstract int getTrafficStatsTag();
+ method public abstract int getTrafficStatsUid();
+ method public abstract boolean hasTrafficStatsTag();
+ method public abstract boolean hasTrafficStatsUid();
+ method public abstract boolean isCacheDisabled();
+ method public abstract boolean isDirectExecutorAllowed();
method public abstract boolean isDone();
- method public abstract void read(java.nio.ByteBuffer);
+ method public abstract void read(@NonNull java.nio.ByteBuffer);
method public abstract void start();
- }
-
- public abstract static class UrlRequest.Builder {
- method public abstract android.net.http.UrlRequest.Builder addHeader(String, String);
- method public abstract android.net.http.UrlRequest.Builder allowDirectExecutor();
- method public abstract android.net.http.UrlRequest.Builder bindToNetwork(@Nullable android.net.Network);
- method public abstract android.net.http.UrlRequest build();
- method public abstract android.net.http.UrlRequest.Builder disableCache();
- method public abstract android.net.http.UrlRequest.Builder setHttpMethod(String);
- method public abstract android.net.http.UrlRequest.Builder setPriority(int);
- method public abstract android.net.http.UrlRequest.Builder setTrafficStatsTag(int);
- method public abstract android.net.http.UrlRequest.Builder setTrafficStatsUid(int);
- method public abstract android.net.http.UrlRequest.Builder setUploadDataProvider(android.net.http.UploadDataProvider, java.util.concurrent.Executor);
field public static final int REQUEST_PRIORITY_HIGHEST = 4; // 0x4
field public static final int REQUEST_PRIORITY_IDLE = 0; // 0x0
field public static final int REQUEST_PRIORITY_LOW = 2; // 0x2
@@ -212,14 +228,27 @@
field public static final int REQUEST_PRIORITY_MEDIUM = 3; // 0x3
}
+ public abstract static class UrlRequest.Builder {
+ method @NonNull public abstract android.net.http.UrlRequest.Builder addHeader(@NonNull String, @NonNull String);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder bindToNetwork(@Nullable android.net.Network);
+ method @NonNull public abstract android.net.http.UrlRequest build();
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setCacheDisabled(boolean);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setDirectExecutorAllowed(boolean);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setHttpMethod(@NonNull String);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setPriority(int);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setTrafficStatsTag(int);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setTrafficStatsUid(int);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setUploadDataProvider(@NonNull android.net.http.UploadDataProvider, @NonNull java.util.concurrent.Executor);
+ }
+
public abstract static class UrlRequest.Callback {
ctor public UrlRequest.Callback();
- method public void onCanceled(android.net.http.UrlRequest, android.net.http.UrlResponseInfo);
- method public abstract void onFailed(android.net.http.UrlRequest, android.net.http.UrlResponseInfo, android.net.http.HttpException);
- method public abstract void onReadCompleted(android.net.http.UrlRequest, android.net.http.UrlResponseInfo, java.nio.ByteBuffer) throws java.lang.Exception;
- method public abstract void onRedirectReceived(android.net.http.UrlRequest, android.net.http.UrlResponseInfo, String) throws java.lang.Exception;
- method public abstract void onResponseStarted(android.net.http.UrlRequest, android.net.http.UrlResponseInfo) throws java.lang.Exception;
- method public abstract void onSucceeded(android.net.http.UrlRequest, android.net.http.UrlResponseInfo);
+ method public void onCanceled(@NonNull android.net.http.UrlRequest, @Nullable android.net.http.UrlResponseInfo);
+ method public abstract void onFailed(@NonNull android.net.http.UrlRequest, @Nullable android.net.http.UrlResponseInfo, @NonNull android.net.http.HttpException);
+ method public abstract void onReadCompleted(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer) throws java.lang.Exception;
+ method public abstract void onRedirectReceived(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo, @NonNull String) throws java.lang.Exception;
+ method public abstract void onResponseStarted(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo) throws java.lang.Exception;
+ method public abstract void onSucceeded(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo);
}
public static class UrlRequest.Status {
@@ -241,29 +270,21 @@
field public static final int WAITING_FOR_STALLED_SOCKET_POOL = 1; // 0x1
}
- public abstract static class UrlRequest.StatusListener {
- ctor public UrlRequest.StatusListener();
- method public abstract void onStatus(int);
+ public static interface UrlRequest.StatusListener {
+ method public void onStatus(int);
}
public abstract class UrlResponseInfo {
ctor public UrlResponseInfo();
- method public abstract android.net.http.UrlResponseInfo.HeaderBlock getHeaders();
+ method @NonNull public abstract android.net.http.HeaderBlock getHeaders();
method public abstract int getHttpStatusCode();
- method public abstract String getHttpStatusText();
- method public abstract String getNegotiatedProtocol();
- method public abstract String getProxyServer();
+ method @NonNull public abstract String getHttpStatusText();
+ method @NonNull public abstract String getNegotiatedProtocol();
method public abstract long getReceivedByteCount();
- method public abstract String getUrl();
- method public abstract java.util.List<java.lang.String> getUrlChain();
+ method @NonNull public abstract String getUrl();
+ method @NonNull public abstract java.util.List<java.lang.String> getUrlChain();
method public abstract boolean wasCached();
}
- public abstract static class UrlResponseInfo.HeaderBlock {
- ctor public UrlResponseInfo.HeaderBlock();
- method public abstract java.util.List<java.util.Map.Entry<java.lang.String,java.lang.String>> getAsList();
- method public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> getAsMap();
- }
-
}
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 9f8d9b1..976f5df 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -37,6 +37,7 @@
import android.app.usage.NetworkStatsManager;
import android.net.INetd;
+import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.NetworkStats;
import android.net.NetworkStats.Entry;
@@ -878,6 +879,27 @@
return true;
}
+ private int getMtu(@NonNull final String ifaceName, @NonNull final LinkProperties lp) {
+ int mtu = INVALID_MTU;
+
+ if (ifaceName.equals(lp.getInterfaceName())) {
+ mtu = lp.getMtu();
+ }
+
+ // Get mtu via kernel if mtu is not found in LinkProperties.
+ if (mtu == INVALID_MTU) {
+ mtu = mDeps.getNetworkInterfaceMtu(ifaceName);
+ }
+
+ // Use default mtu if can't find any.
+ if (mtu == INVALID_MTU) mtu = NetworkStackConstants.ETHER_MTU;
+
+ // Clamp to minimum ipv4 mtu
+ if (mtu < IPV4_MIN_MTU) mtu = IPV4_MIN_MTU;
+
+ return mtu;
+ }
+
/**
* Call when UpstreamNetworkState may be changed.
* If upstream has ipv4 for tethering, update this new UpstreamNetworkState
@@ -900,16 +922,7 @@
final String ifaceName = ns.linkProperties.getInterfaceName();
final InterfaceParams params = mDeps.getInterfaceParams(ifaceName);
final boolean isVcn = isVcnInterface(ifaceName);
- mtu = ns.linkProperties.getMtu();
- if (mtu == INVALID_MTU) {
- // Get mtu via kernel if mtu is not found in LinkProperties.
- mtu = mDeps.getNetworkInterfaceMtu(ifaceName);
- }
-
- // Use default mtu if can't find any.
- if (mtu == INVALID_MTU) mtu = NetworkStackConstants.ETHER_MTU;
- // Clamp to minimum ipv4 mtu
- if (mtu < IPV4_MIN_MTU) mtu = IPV4_MIN_MTU;
+ mtu = getMtu(ifaceName, ns.linkProperties);
if (!isVcn && params != null && !params.hasMacAddress /* raw ip upstream only */) {
upstreamIndex = params.index;
diff --git a/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
index 7685981..f2cf1d0 100644
--- a/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
+++ b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
@@ -72,6 +72,8 @@
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.PacketBuilder;
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.structs.Ipv6Header;
import com.android.testutils.HandlerUtils;
import com.android.testutils.TapPacketReader;
import com.android.testutils.TestNetworkTracker;
@@ -1013,6 +1015,18 @@
return new TetheringTester(mDownstreamReader, mUpstreamReader);
}
+ @NonNull
+ protected Inet6Address getClatIpv6Address(TetheringTester tester, TetheredDevice tethered)
+ throws Exception {
+ // Send an IPv4 UDP packet from client and check that a CLAT translated IPv6 UDP packet can
+ // be found on upstream interface. Get CLAT IPv6 address from the CLAT translated IPv6 UDP
+ // packet.
+ byte[] expectedPacket = probeV4TetheringConnectivity(tester, tethered, true /* is4To6 */);
+
+ // Above has guaranteed that the found packet is an IPv6 packet without ether header.
+ return Struct.parse(Ipv6Header.class, ByteBuffer.wrap(expectedPacket)).srcIp;
+ }
+
protected <T> List<T> toList(T... array) {
return Arrays.asList(array);
}
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index fb4b9fa..12ac454 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -62,7 +62,6 @@
import com.android.net.module.util.structs.EthernetHeader;
import com.android.net.module.util.structs.Icmpv4Header;
import com.android.net.module.util.structs.Ipv4Header;
-import com.android.net.module.util.structs.Ipv6Header;
import com.android.net.module.util.structs.UdpHeader;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -522,18 +521,6 @@
runUdp4Test();
}
- @NonNull
- private Inet6Address getClatIpv6Address(TetheringTester tester, TetheredDevice tethered)
- throws Exception {
- // Send an IPv4 UDP packet from client and check that a CLAT translated IPv6 UDP packet can
- // be found on upstream interface. Get CLAT IPv6 address from the CLAT translated IPv6 UDP
- // packet.
- byte[] expectedPacket = probeV4TetheringConnectivity(tester, tethered, true /* is4To6 */);
-
- // Above has guaranteed that the found packet is an IPv6 packet without ether header.
- return Struct.parse(Ipv6Header.class, ByteBuffer.wrap(expectedPacket)).srcIp;
- }
-
// Test network topology:
//
// public network (rawip) private network
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index 84da79d..e068d8a 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -350,10 +350,10 @@
static __always_inline inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid,
bool egress, const unsigned kver) {
- if (skip_owner_match(skb, kver)) return PASS;
-
if (is_system_uid(uid)) return PASS;
+ if (skip_owner_match(skb, kver)) return PASS;
+
BpfConfig enabledRules = getConfig(UID_RULES_CONFIGURATION_KEY);
UidOwnerValue* uidEntry = bpf_uid_owner_map_lookup_elem(&uid);
@@ -415,11 +415,6 @@
}
int match = bpf_owner_match(skb, sock_uid, egress, kver);
- if (egress && (match == DROP)) {
- // If an outbound packet is going to be dropped, we do not count that
- // traffic.
- return match;
- }
// Workaround for secureVPN with VpnIsolation enabled, refer to b/159994981 for details.
// Keep TAG_SYSTEM_DNS in sync with DnsResolver/include/netd_resolv/resolv.h
@@ -432,6 +427,9 @@
if (match == DROP_UNLESS_DNS) match = DROP;
}
+ // If an outbound packet is going to be dropped, we do not count that traffic.
+ if (egress && (match == DROP)) return DROP;
+
StatsKey key = {.uid = uid, .tag = tag, .counterSet = 0, .ifaceIndex = skb->ifindex};
uint8_t* counterSet = bpf_uid_counterset_map_lookup_elem(&uid);
diff --git a/framework-t/Android.bp b/framework-t/Android.bp
index 7ef20c5..1a8d46b 100644
--- a/framework-t/Android.bp
+++ b/framework-t/Android.bp
@@ -156,7 +156,7 @@
"//frameworks/opt/telephony/tests/telephonytests",
"//packages/modules/CaptivePortalLogin/tests",
"//packages/modules/Connectivity/Tethering/tests:__subpackages__",
- "//packages/modules/Connectivity/nearby/tests:__subpackages__",
+ "//packages/modules/Connectivity/nearby:__subpackages__",
"//packages/modules/Connectivity/tests:__subpackages__",
"//packages/modules/IPsec/tests/iketests",
"//packages/modules/NetworkStack/tests:__subpackages__",
diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java
index edfd21c..947a092 100644
--- a/framework-t/src/android/net/NetworkIdentity.java
+++ b/framework-t/src/android/net/NetworkIdentity.java
@@ -32,6 +32,7 @@
import android.net.wifi.WifiInfo;
import android.service.NetworkIdentityProto;
import android.telephony.TelephonyManager;
+import android.util.Log;
import android.util.proto.ProtoOutputStream;
import com.android.net.module.util.BitUtils;
@@ -406,10 +407,18 @@
setOemManaged(getOemBitfield(snapshot.getNetworkCapabilities()));
if (mType == TYPE_WIFI) {
- final TransportInfo transportInfo = snapshot.getNetworkCapabilities()
- .getTransportInfo();
+ final NetworkCapabilities nc = snapshot.getNetworkCapabilities();
+ final TransportInfo transportInfo = nc.getTransportInfo();
if (transportInfo instanceof WifiInfo) {
final WifiInfo info = (WifiInfo) transportInfo;
+ // Log.wtf to catch trying to set a null wifiNetworkKey into NetworkIdentity.
+ // See b/266598304. The problematic data that has null wifi network key is
+ // thrown out when storing data, which is handled by the service.
+ if (info.getNetworkKey() == null) {
+ Log.wtf(TAG, "WifiInfo contains a null wifiNetworkKey and it will"
+ + " be set into NetworkIdentity, netId=" + snapshot.getNetwork()
+ + "NetworkCapabilities=" + nc);
+ }
setWifiNetworkKey(info.getNetworkKey());
}
} else if (mType == TYPE_TEST) {
diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java
index 4a1632b..d90bd8d 100644
--- a/framework-t/src/android/net/NetworkTemplate.java
+++ b/framework-t/src/android/net/NetworkTemplate.java
@@ -51,6 +51,7 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkIdentityUtils;
@@ -246,6 +247,38 @@
return new NetworkTemplate.Builder(MATCH_ETHERNET).build();
}
+ /**
+ * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style
+ * networks together.
+ *
+ * @hide
+ */
+ // TODO(b/270089918): Remove this method. This can only be done after there are no more callers,
+ // including in OEM code which can access this by linking against the framework.
+ public static NetworkTemplate buildTemplateBluetooth() {
+ if (SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "buildTemplateBluetooth is not supported on Android U devices or above");
+ }
+ return new NetworkTemplate.Builder(MATCH_BLUETOOTH).build();
+ }
+
+ /**
+ * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style
+ * networks together.
+ *
+ * @hide
+ */
+ // TODO(b/270089918): Remove this method. This can only be done after there are no more callers,
+ // including in OEM code which can access this by linking against the framework.
+ public static NetworkTemplate buildTemplateProxy() {
+ if (SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "buildTemplateProxy is not supported on Android U devices or above");
+ }
+ return new NetworkTemplate(MATCH_PROXY, null, null);
+ }
+
private final int mMatchRule;
/**
@@ -316,6 +349,10 @@
if (matchRule == 6 || matchRule == 7) {
Log.e(TAG, "Use MATCH_MOBILE with empty subscriberIds or MATCH_WIFI with empty "
+ "wifiNetworkKeys instead of template with matchRule=" + matchRule);
+ if (SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "Wildcard templates are not supported on Android U devices or above");
+ }
}
}
@@ -337,6 +374,43 @@
}
/** @hide */
+ // TODO(b/270089918): Remove this method after no callers.
+ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
+ String wifiNetworkKey) {
+ // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates
+ // to metered networks. It is now possible to match mobile with any meteredness, but
+ // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
+ // constructor passes METERED_YES for these types.
+ this(getBackwardsCompatibleMatchRule(matchRule), matchSubscriberIds,
+ wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
+ getMeterednessForBackwardsCompatibility(matchRule),
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL);
+ if (SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "This constructor is not supported on Android U devices or above");
+ }
+ }
+
+ /** @hide */
+ // TODO(b/269974916): Remove this method after Android U is released.
+ // This is only used by CTS of Android T.
+ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
+ String[] matchWifiNetworkKeys, int metered, int roaming,
+ int defaultNetwork, int ratType, int oemManaged, int subscriberIdMatchRule) {
+ // subscriberId and subscriberIdMatchRule aren't used since they are replaced by
+ // matchSubscriberIds, which could be null to indicate the intention of matching any
+ // subscriberIds.
+ this(getBackwardsCompatibleMatchRule(matchRule),
+ matchSubscriberIds == null ? new String[]{} : matchSubscriberIds,
+ matchWifiNetworkKeys, metered, roaming, defaultNetwork, ratType, oemManaged);
+ if (SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "This constructor is not supported on Android U devices or above");
+ }
+ }
+
+ /** @hide */
public NetworkTemplate(int matchRule, String[] matchSubscriberIds,
String[] matchWifiNetworkKeys, int metered, int roaming, int defaultNetwork,
int ratType, int oemManaged) {
@@ -436,9 +510,14 @@
return false;
}
- // TODO(b/270089918): Remove this method after no callers.
+ // TODO(b/270089918): Remove this method. This can only be done after there are no more callers,
+ // including in OEM code which can access this by linking against the framework.
/** @hide */
public boolean isMatchRuleMobile() {
+ if (SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "isMatchRuleMobile is not supported on Android U devices or above");
+ }
switch (mMatchRule) {
case MATCH_MOBILE:
// Old MATCH_MOBILE_WILDCARD
@@ -621,7 +700,15 @@
* to know details about the key.
*/
private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) {
- Objects.requireNonNull(wifiNetworkKey);
+ // Note that this code accepts null wifi network keys because of a past bug where wifi
+ // code was sending a null network key for some connected networks, which isn't expected
+ // and ended up stored in the data on many devices.
+ // A null network key in the data matches a wildcard template (one where
+ // {@code mMatchWifiNetworkKeys} is empty), but not one where {@code MatchWifiNetworkKeys}
+ // contains null. See b/266598304.
+ if (wifiNetworkKey == null) {
+ return CollectionUtils.isEmpty(mMatchWifiNetworkKeys);
+ }
return CollectionUtils.isEmpty(mMatchWifiNetworkKeys)
|| CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey);
}
diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java
index b4f8897..36808cf 100644
--- a/framework-t/src/android/net/nsd/NsdManager.java
+++ b/framework-t/src/android/net/nsd/NsdManager.java
@@ -1312,7 +1312,7 @@
* before registering other callbacks. Upon failure to register a callback for example if
* it's a duplicated registration, the application is notified through
* {@link ServiceInfoCallback#onServiceInfoCallbackRegistrationFailed} with
- * {@link #FAILURE_BAD_PARAMETERS} or {@link #FAILURE_ALREADY_ACTIVE}.
+ * {@link #FAILURE_BAD_PARAMETERS}.
*
* @param serviceInfo the service to receive updates for
* @param executor Executor to run callbacks with
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 196e023..4a2ed8a 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -470,7 +470,7 @@
}
public abstract class SocketKeepalive implements java.lang.AutoCloseable {
- method public final void start(@IntRange(from=0xa, to=0xe10) int, int, @NonNull android.net.Network);
+ method public final void start(@IntRange(from=0xa, to=0xe10) int, int, @Nullable android.net.Network);
field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
field public static final int FLAG_AUTOMATIC_ON_OFF = 1; // 0x1
field public static final int SUCCESS = 0; // 0x0
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 7cef58b..381a18a 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -2521,7 +2521,7 @@
@RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD)
public @NonNull SocketKeepalive createSocketKeepalive(@NonNull Network network,
@NonNull Socket socket,
- @NonNull Executor executor,
+ @NonNull @CallbackExecutor Executor executor,
@NonNull Callback callback) {
ParcelFileDescriptor dup;
try {
@@ -5494,9 +5494,9 @@
* @return {@code uid} if the connection is found and the app has permission to observe it
* (e.g., if it is associated with the calling VPN app's VpnService tunnel) or {@link
* android.os.Process#INVALID_UID} if the connection is not found.
- * @throws {@link SecurityException} if the caller is not the active VpnService for the current
+ * @throws SecurityException if the caller is not the active VpnService for the current
* user.
- * @throws {@link IllegalArgumentException} if an unsupported protocol is requested.
+ * @throws IllegalArgumentException if an unsupported protocol is requested.
*/
public int getConnectionOwnerUid(
int protocol, @NonNull InetSocketAddress local, @NonNull InetSocketAddress remote) {
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 427eac1..324f565 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -53,18 +53,70 @@
import java.util.StringJoiner;
/**
- * Representation of the capabilities of an active network. Instances are
- * typically obtained through
- * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)}
- * or {@link ConnectivityManager#getNetworkCapabilities(Network)}.
- * <p>
- * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of
- * network selection. Rather than indicate a need for Wi-Fi because an
- * application needs high bandwidth and risk obsolescence when a new, fast
- * network appears (like LTE), the application should specify it needs high
- * bandwidth. Similarly if an application needs an unmetered network for a bulk
- * transfer it can specify that rather than assuming all cellular based
- * connections are metered and all Wi-Fi based connections are not.
+ * Representation of the capabilities of an active network.
+ *
+ * <p>@see <a href="https://developer.android.com/training/basics/network-ops/reading-network-state>
+ * this general guide</a> on how to use NetworkCapabilities and related classes.
+ *
+ * <p>NetworkCapabilities represent what a network can do and what its
+ * characteristics are like. The principal attribute of NetworkCapabilities
+ * is in the capabilities bits, which are checked with
+ * {@link #hasCapability(int)}. See the list of capabilities and each
+ * capability for a description of what it means.
+ *
+ * <p>Some prime examples include {@code NET_CAPABILITY_MMS}, which means that the
+ * network is capable of sending MMS. A network without this capability
+ * is not capable of sending MMS.
+ * <p>The {@code NET_CAPABILITY_INTERNET} capability means that the network is
+ * configured to reach the general Internet. It may or may not actually
+ * provide connectivity ; the {@code NET_CAPABILITY_VALIDATED} bit indicates that
+ * the system found actual connectivity to the general Internet the last
+ * time it checked. Apps interested in actual connectivity should usually
+ * look at both these capabilities.
+ * <p>The {@code NET_CAPABILITY_NOT_METERED} capability is set for networks that
+ * do not bill the user for consumption of bytes. Applications are
+ * encouraged to consult this to determine appropriate usage, and to
+ * limit usage of metered network where possible, including deferring
+ * big downloads until such a time that an unmetered network is connected.
+ * Also see {@link android.app.job.JobScheduler} to help with scheduling such
+ * downloads, in particular
+ * {@link android.app.job.JobInfo.Builder#setRequiredNetwork(NetworkRequest)}.
+ * <p>NetworkCapabilities contain a number of other capabilities that
+ * represent what modern networks can and can't do. Look up the individual
+ * capabilities in this class to learn about each of them.
+ *
+ * <p>NetworkCapabilities typically represent attributes that can apply to
+ * any network. The attributes that apply only to specific transports like
+ * cellular or Wi-Fi can be found in the specifier (for requestable attributes)
+ * or in the transport info (for non-requestable ones). See
+ * {@link #getNetworkSpecifier} and {@link #getTransportInfo}. An app would
+ * downcast these to the specific class for the transport they need if they
+ * are interested in transport-specific attributes. Also see
+ * {@link android.net.wifi.WifiNetworkSpecifier} or
+ * {@link android.net.wifi.WifiInfo} for some examples of each of these.
+ *
+ * <p>NetworkCapabilities also contains other attributes like the estimated
+ * upstream and downstream bandwidth and the specific transport of that
+ * network (e.g. {@link #TRANSPORT_CELLULAR}). Generally, apps should normally
+ * have little reason to check for the type of transport ; for example, to
+ * query whether a network costs money to the user, do not look at the
+ * transport, but instead look at the absence or presence of
+ * {@link #NET_CAPABILITY_NOT_METERED} which will correctly account for
+ * metered Wi-Fis and free of charge cell connections.
+ *
+ * <p>The system communicates with apps about connected networks and uses
+ * NetworkCapabilities to express these capabilities about these networks.
+ * Apps should register callbacks with the {@link ConnectivityManager#requestNetwork}
+ * or {@link ConnectivityManager#registerNetworkCallback} family of methods
+ * to learn about the capabilities of a network on a continuous basis
+ * and be able to react to changes to capabilities. For quick debugging Android also
+ * provides {@link ConnectivityManager#getNetworkCapabilities(Network)},
+ * but the dynamic nature of networking makes this ill-suited to production
+ * code since capabilities obtained in this way can go stale immediately.
+ *
+ * <p>Also see {@link NetworkRequest} which uses the same capabilities
+ * together with {@link ConnectivityManager#requestNetwork} for how to
+ * request the system brings up the kind of network your application needs.
*/
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
@@ -622,11 +674,19 @@
/**
* Indicates that this network should be able to prioritize latency for the internet.
+ *
+ * Starting with {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, requesting this capability with
+ * {@link ConnectivityManager#requestNetwork} requires declaration in the self-certified
+ * network capabilities. See {@link NetworkRequest} for the self-certification documentation.
*/
public static final int NET_CAPABILITY_PRIORITIZE_LATENCY = 34;
/**
* Indicates that this network should be able to prioritize bandwidth for the internet.
+ *
+ * Starting with {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, requesting this capability with
+ * {@link ConnectivityManager#requestNetwork} requires declaration in the self-certified
+ * network capabilities. See {@link NetworkRequest} for the self-certification documentation.
*/
public static final int NET_CAPABILITY_PRIORITIZE_BANDWIDTH = 35;
diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java
index b7a6076..6c351d0 100644
--- a/framework/src/android/net/NetworkRequest.java
+++ b/framework/src/android/net/NetworkRequest.java
@@ -54,9 +54,92 @@
import java.util.Set;
/**
- * Defines a request for a network, made through {@link NetworkRequest.Builder} and used
- * to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes
- * via {@link ConnectivityManager#registerNetworkCallback}.
+ * An object describing a network that the application is interested in.
+ *
+ * <p>@see <a href="https://developer.android.com/training/basics/network-ops/reading-network-state>
+ * this general guide</a> on how to use NetworkCapabilities and related classes.
+ *
+ * NetworkRequest defines a request for a network, made through
+ * {@link NetworkRequest.Builder} and used to request a network via
+ * {@link ConnectivityManager#requestNetwork} or to listen for changes
+ * via the {@link ConnectivityManager#registerNetworkCallback} family of
+ * functions.
+ *
+ * <p>{@link ConnectivityManager#requestNetwork} will try to find a connected
+ * network matching the NetworkRequest, and return it if there is one.
+ * As long as the request is outstanding, the system will try to find the best
+ * possible network that matches the request. The request will keep up the
+ * currently best connected network, and if a better one is found (e.g. cheaper
+ * or faster) the system will bring up that better network to better serve the
+ * request. A request filed with {@link ConnectivityManager#requestNetwork} will
+ * only match one network at a time (the one the system thinks is best), even if
+ * other networks can match the request that are being kept up by other requests.
+ *
+ * For example, an application needing a network with
+ * {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} should use
+ * {@link ConnectivityManager#requestNetwork} to request the system keeps one up.
+ * A general cellular network can satisfy this request, but if the system finds
+ * a free Wi-Fi network which is expected to be faster, it will try and connect
+ * to that Wi-Fi network and switch the request over to it once it is connected.
+ * The cell network may stay connected if there are outstanding requests (from
+ * the same app or from other apps on the system) that match the cell network
+ * but not the Wi-Fi network, such as a request with {@link NetworkCapabilities#NET_CAPABILITY_MMS}.
+ *
+ * When a network is no longer needed to serve any request, the system can
+ * tear it down at any time and usually does so immediately, so make sure to
+ * keep up requests for the networks your app needs.
+ *
+ * <p>By contrast, requests filed with {@link ConnectivityManager#registerNetworkCallback}
+ * will receive callbacks for all matching networks, and will not cause the system to
+ * keep up the networks they match. Use this to listen to networks that the device is
+ * connected to, but that you don't want the system to keep up for your use case.
+ *
+ * <p>Applications build a NetworkRequest and pass it to one of the
+ * {@link ConnectivityManager} methods above together with a
+ * {@link ConnectivityManager.NetworkCallback} object. The callback
+ * will then start receiving method calls about networks that match
+ * the request.
+ *
+ * <p>Networks are brought up and/or matched according to the capabilities
+ * set in the builder. For example, a request with
+ * {@link NetworkCapabilities#NET_CAPABILITY_MMS} lets the system match
+ * and/or bring up a network that is capable to send MMS. A request with
+ * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} matches a network
+ * that doesn't charge the user for usage. See
+ * {@link NetworkCapabilities} for a list of capabilities and their
+ * description.
+ *
+ * <p>While all capabilities can be matched with the
+ * {@link ConnectivityManager#registerNetworkCallback} family of methods,
+ * not all capabilities can be used to request that the system brings
+ * up a network with {@link ConnectivityManager#requestNetwork}. For example,
+ * an application cannot use {@link ConnectivityManager#requestNetwork} to
+ * ask the system to bring up a network with
+ * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}, because the
+ * system won't know if a network has a captive portal before it connects
+ * to that network. Similarly, some capabilities may require a specific
+ * permission or privilege to be requested.
+ *
+ * Look up the specific capability and the {@link ConnectivityManager#requestNetwork}
+ * method for limitations applicable to each capability.
+ *
+ * <p>Also, starting with {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, some capabilities
+ * require the application to self-certify by explicitly adding the
+ * {@link android.content.pm.PackageManager#PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES}
+ * property in the AndroidManifest.xml, which points to an XML resource file. In the
+ * XML resource file, the application declares what kind of network capabilities the application
+ * wants to have.
+ *
+ * Here is an example self-certification XML resource file :
+ * <pre>
+ * {@code
+ * <network-capabilities-declaration xmlns:android="http://schemas.android.com/apk/res/android">
+ * <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_LATENCY"/>
+ * <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_BANDWIDTH"/>
+ * </network-capabilities-declaration>
+ * }
+ * </pre>
+ * Look up the specific capability to learn whether its usage requires this self-certification.
*/
public class NetworkRequest implements Parcelable {
/**
diff --git a/framework/src/android/net/SocketKeepalive.java b/framework/src/android/net/SocketKeepalive.java
index 311126e..10daf17 100644
--- a/framework/src/android/net/SocketKeepalive.java
+++ b/framework/src/android/net/SocketKeepalive.java
@@ -21,6 +21,7 @@
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
@@ -374,12 +375,14 @@
* the supplied {@link Callback} will see a call to
* {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
* @param flags Flags to enable/disable available options on this keepalive.
- * @param underpinnedNetwork The underpinned network of this keepalive.
+ * @param underpinnedNetwork an optional network running over mNetwork that this
+ * keepalive is intended to keep up, e.g. an IPSec
+ * tunnel running over mNetwork.
* @hide
*/
@SystemApi(client = PRIVILEGED_APPS)
public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
- int intervalSec, @StartFlags int flags, @NonNull Network underpinnedNetwork) {
+ int intervalSec, @StartFlags int flags, @Nullable Network underpinnedNetwork) {
startImpl(intervalSec, flags, underpinnedNetwork);
}
diff --git a/framework/src/android/net/TcpSocketKeepalive.java b/framework/src/android/net/TcpSocketKeepalive.java
index b548f6d..696889f 100644
--- a/framework/src/android/net/TcpSocketKeepalive.java
+++ b/framework/src/android/net/TcpSocketKeepalive.java
@@ -55,6 +55,12 @@
throw new IllegalArgumentException("Illegal flag value for "
+ this.getClass().getSimpleName() + " : " + flags);
}
+
+ if (underpinnedNetwork != null) {
+ throw new IllegalArgumentException("Illegal underpinned network for "
+ + this.getClass().getSimpleName() + " : " + underpinnedNetwork);
+ }
+
mExecutor.execute(() -> {
try {
mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback);
diff --git a/nearby/halfsheet/Android.bp b/nearby/halfsheet/Android.bp
index 2d0d327..8011dc6 100644
--- a/nearby/halfsheet/Android.bp
+++ b/nearby/halfsheet/Android.bp
@@ -27,7 +27,7 @@
certificate: ":com.android.nearby.halfsheetcertificate",
libs: [
"framework-bluetooth",
- "framework-connectivity-t",
+ "framework-connectivity-t.impl",
"nearby-service-string",
],
static_libs: [
diff --git a/service-t/native/libs/libnetworkstats/Android.bp b/service-t/native/libs/libnetworkstats/Android.bp
index aa1ee41..f2c569f 100644
--- a/service-t/native/libs/libnetworkstats/Android.bp
+++ b/service-t/native/libs/libnetworkstats/Android.bp
@@ -26,6 +26,7 @@
srcs: [
"BpfNetworkStats.cpp",
"NetworkTraceHandler.cpp",
+ "NetworkTracePoller.cpp",
],
shared_libs: [
"libbase",
@@ -61,7 +62,7 @@
header_libs: ["bpf_connectivity_headers"],
srcs: [
"BpfNetworkStatsTest.cpp",
- "NetworkTraceHandlerTest.cpp",
+ "NetworkTracePollerTest.cpp",
],
cflags: [
"-Wall",
diff --git a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
index aeadb4a..8e70950 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
@@ -33,6 +33,7 @@
namespace android {
namespace bpf {
+using ::android::bpf::internal::NetworkTracePoller;
using ::perfetto::protos::pbzero::NetworkPacketEvent;
using ::perfetto::protos::pbzero::NetworkPacketTraceConfig;
using ::perfetto::protos::pbzero::TracePacket;
@@ -55,13 +56,12 @@
NetworkTraceHandler::RegisterDataSource();
}
-NetworkTraceHandler::NetworkTraceHandler()
- : NetworkTraceHandler([this](const PacketTrace& pkt) {
- NetworkTraceHandler::Trace(
- [this, pkt](NetworkTraceHandler::TraceContext ctx) {
- Fill(pkt, *ctx.NewTracePacket());
- });
- }) {}
+// static
+NetworkTracePoller NetworkTraceHandler::sPoller([](const PacketTrace& pkt) {
+ NetworkTraceHandler::Trace([pkt](NetworkTraceHandler::TraceContext ctx) {
+ NetworkTraceHandler::Fill(pkt, *ctx.NewTracePacket());
+ });
+});
void NetworkTraceHandler::OnSetup(const SetupArgs& args) {
const std::string& raw = args.config->network_packet_trace_config_raw();
@@ -75,21 +75,15 @@
}
void NetworkTraceHandler::OnStart(const StartArgs&) {
- if (!Start()) return;
- mTaskRunner = perfetto::Platform::GetDefaultPlatform()->CreateTaskRunner({});
- Loop();
+ mStarted = sPoller.Start(mPollMs);
}
void NetworkTraceHandler::OnStop(const StopArgs&) {
- Stop();
- mTaskRunner.reset();
+ if (mStarted) sPoller.Stop();
+ mStarted = false;
}
-void NetworkTraceHandler::Loop() {
- mTaskRunner->PostDelayedTask([this]() { Loop(); }, mPollMs);
- ConsumeAll();
-}
-
+// static class method
void NetworkTraceHandler::Fill(const PacketTrace& src, TracePacket& dst) {
dst.set_timestamp(src.timestampNs);
auto* event = dst.set_network_packet();
@@ -113,60 +107,5 @@
}
}
-bool NetworkTraceHandler::Start() {
- ALOGD("Starting datasource");
-
- auto status = mConfigurationMap.init(PACKET_TRACE_ENABLED_MAP_PATH);
- if (!status.ok()) {
- ALOGW("Failed to bind config map: %s", status.error().message().c_str());
- return false;
- }
-
- auto rb = BpfRingbuf<PacketTrace>::Create(PACKET_TRACE_RINGBUF_PATH);
- if (!rb.ok()) {
- ALOGW("Failed to create ringbuf: %s", rb.error().message().c_str());
- return false;
- }
-
- mRingBuffer = std::move(*rb);
-
- auto res = mConfigurationMap.writeValue(0, true, BPF_ANY);
- if (!res.ok()) {
- ALOGW("Failed to enable tracing: %s", res.error().message().c_str());
- return false;
- }
-
- return true;
-}
-
-bool NetworkTraceHandler::Stop() {
- ALOGD("Stopping datasource");
-
- auto res = mConfigurationMap.writeValue(0, false, BPF_ANY);
- if (!res.ok()) {
- ALOGW("Failed to disable tracing: %s", res.error().message().c_str());
- return false;
- }
-
- mRingBuffer.reset();
-
- return true;
-}
-
-bool NetworkTraceHandler::ConsumeAll() {
- if (mRingBuffer == nullptr) {
- ALOGW("Tracing is not active");
- return false;
- }
-
- base::Result<int> ret = mRingBuffer->ConsumeAll(mCallback);
- if (!ret.ok()) {
- ALOGW("Failed to poll ringbuf: %s", ret.error().message().c_str());
- return false;
- }
-
- return true;
-}
-
} // namespace bpf
} // namespace android
diff --git a/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp b/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
new file mode 100644
index 0000000..34dbf9e
--- /dev/null
+++ b/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "NetworkTrace"
+
+#include "netdbpf/NetworkTracePoller.h"
+
+#include <bpf/BpfUtils.h>
+#include <log/log.h>
+#include <perfetto/tracing/platform.h>
+#include <perfetto/tracing/tracing.h>
+
+namespace android {
+namespace bpf {
+namespace internal {
+
+void NetworkTracePoller::SchedulePolling() {
+ // Schedules another run of ourselves to recursively poll periodically.
+ mTaskRunner->PostDelayedTask(
+ [this]() {
+ mMutex.lock();
+ SchedulePolling();
+ ConsumeAllLocked();
+ mMutex.unlock();
+ },
+ mPollMs);
+}
+
+bool NetworkTracePoller::Start(uint32_t pollMs) {
+ ALOGD("Starting datasource");
+
+ std::scoped_lock<std::mutex> lock(mMutex);
+ if (mSessionCount > 0) {
+ if (mPollMs != pollMs) {
+ // Nothing technical prevents mPollMs from changing, it's just unclear
+ // what the right behavior is. Taking the min of active values could poll
+ // too frequently giving some sessions too much data. Taking the max could
+ // be too infrequent. For now, do nothing.
+ ALOGI("poll_ms can't be changed while running, ignoring poll_ms=%d",
+ pollMs);
+ }
+ mSessionCount++;
+ return true;
+ }
+
+ auto status = mConfigurationMap.init(PACKET_TRACE_ENABLED_MAP_PATH);
+ if (!status.ok()) {
+ ALOGW("Failed to bind config map: %s", status.error().message().c_str());
+ return false;
+ }
+
+ auto rb = BpfRingbuf<PacketTrace>::Create(PACKET_TRACE_RINGBUF_PATH);
+ if (!rb.ok()) {
+ ALOGW("Failed to create ringbuf: %s", rb.error().message().c_str());
+ return false;
+ }
+
+ mRingBuffer = std::move(*rb);
+
+ auto res = mConfigurationMap.writeValue(0, true, BPF_ANY);
+ if (!res.ok()) {
+ ALOGW("Failed to enable tracing: %s", res.error().message().c_str());
+ return false;
+ }
+
+ // Start a task runner to run ConsumeAll every mPollMs milliseconds.
+ mTaskRunner = perfetto::Platform::GetDefaultPlatform()->CreateTaskRunner({});
+ mPollMs = pollMs;
+ SchedulePolling();
+
+ mSessionCount++;
+ return true;
+}
+
+bool NetworkTracePoller::Stop() {
+ ALOGD("Stopping datasource");
+
+ std::scoped_lock<std::mutex> lock(mMutex);
+ if (mSessionCount == 0) return false; // This should never happen
+
+ // If this isn't the last session, don't clean up yet.
+ if (--mSessionCount > 0) return true;
+
+ auto res = mConfigurationMap.writeValue(0, false, BPF_ANY);
+ if (!res.ok()) {
+ ALOGW("Failed to disable tracing: %s", res.error().message().c_str());
+ }
+
+ mTaskRunner.reset();
+ mRingBuffer.reset();
+
+ return res.ok();
+}
+
+bool NetworkTracePoller::ConsumeAll() {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ return ConsumeAllLocked();
+}
+
+bool NetworkTracePoller::ConsumeAllLocked() {
+ if (mRingBuffer == nullptr) {
+ ALOGW("Tracing is not active");
+ return false;
+ }
+
+ base::Result<int> ret = mRingBuffer->ConsumeAll(mCallback);
+ if (!ret.ok()) {
+ ALOGW("Failed to poll ringbuf: %s", ret.error().message().c_str());
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace internal
+} // namespace bpf
+} // namespace android
diff --git a/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp b/service-t/native/libs/libnetworkstats/NetworkTracePollerTest.cpp
similarity index 85%
rename from service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp
rename to service-t/native/libs/libnetworkstats/NetworkTracePollerTest.cpp
index 560194f..28ec208 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTracePollerTest.cpp
@@ -28,7 +28,7 @@
#include <vector>
-#include "netdbpf/NetworkTraceHandler.h"
+#include "netdbpf/NetworkTracePoller.h"
using ::testing::AllOf;
using ::testing::AnyOf;
@@ -39,6 +39,10 @@
namespace android {
namespace bpf {
+namespace internal {
+// Use uint32 max to cause the handler to never Loop. Instead, the tests will
+// manually drive things by calling ConsumeAll explicitly.
+constexpr uint32_t kNeverPoll = std::numeric_limits<uint32_t>::max();
__be16 bindAndListen(int s) {
sockaddr_in sin = {.sin_family = AF_INET};
@@ -83,7 +87,7 @@
}
};
-class NetworkTraceHandlerTest : public testing::Test {
+class NetworkTracePollerTest : public testing::Test {
protected:
void SetUp() {
if (access(PACKET_TRACE_RINGBUF_PATH, R_OK)) {
@@ -95,31 +99,49 @@
}
};
-TEST_F(NetworkTraceHandlerTest, PollWhileInactive) {
- NetworkTraceHandler handler([&](const PacketTrace& pkt) {});
+TEST_F(NetworkTracePollerTest, PollWhileInactive) {
+ NetworkTracePoller handler([&](const PacketTrace& pkt) {});
// One succeed after start and before stop.
EXPECT_FALSE(handler.ConsumeAll());
- ASSERT_TRUE(handler.Start());
+ ASSERT_TRUE(handler.Start(kNeverPoll));
EXPECT_TRUE(handler.ConsumeAll());
ASSERT_TRUE(handler.Stop());
EXPECT_FALSE(handler.ConsumeAll());
}
-TEST_F(NetworkTraceHandlerTest, TraceTcpSession) {
+TEST_F(NetworkTracePollerTest, ConcurrentSessions) {
+ // Simulate two concurrent sessions (two starts followed by two stops). Check
+ // that tracing is stopped only after both sessions finish.
+ NetworkTracePoller handler([&](const PacketTrace& pkt) {});
+
+ ASSERT_TRUE(handler.Start(kNeverPoll));
+ EXPECT_TRUE(handler.ConsumeAll());
+
+ ASSERT_TRUE(handler.Start(kNeverPoll));
+ EXPECT_TRUE(handler.ConsumeAll());
+
+ ASSERT_TRUE(handler.Stop());
+ EXPECT_TRUE(handler.ConsumeAll());
+
+ ASSERT_TRUE(handler.Stop());
+ EXPECT_FALSE(handler.ConsumeAll());
+}
+
+TEST_F(NetworkTracePollerTest, TraceTcpSession) {
__be16 server_port = 0;
std::vector<PacketTrace> packets;
// Record all packets with the bound address and current uid. This callback is
// involked only within ConsumeAll, at which point the port should have
// already been filled in and all packets have been processed.
- NetworkTraceHandler handler([&](const PacketTrace& pkt) {
+ NetworkTracePoller handler([&](const PacketTrace& pkt) {
if (pkt.sport != server_port && pkt.dport != server_port) return;
if (pkt.uid != getuid()) return;
packets.push_back(pkt);
});
- ASSERT_TRUE(handler.Start());
+ ASSERT_TRUE(handler.Start(kNeverPoll));
const uint32_t kClientTag = 2468;
const uint32_t kServerTag = 1357;
@@ -197,5 +219,6 @@
<< PacketPrinter{packets};
}
+} // namespace internal
} // namespace bpf
} // namespace android
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
index c257aa0..1266237 100644
--- a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
@@ -22,8 +22,7 @@
#include <string>
#include <unordered_map>
-#include "bpf/BpfMap.h"
-#include "bpf/BpfRingbuf.h"
+#include "netdbpf/NetworkTracePoller.h"
// For PacketTrace struct definition
#include "netd.h"
@@ -31,6 +30,9 @@
namespace android {
namespace bpf {
+// NetworkTraceHandler implements the android.network_packets data source. This
+// class is registered with Perfetto and is instantiated when tracing starts and
+// destroyed when tracing ends. There is one instance per trace session.
class NetworkTraceHandler : public perfetto::DataSource<NetworkTraceHandler> {
public:
// Registers this DataSource.
@@ -39,45 +41,19 @@
// Connects to the system Perfetto daemon and registers the trace handler.
static void InitPerfettoTracing();
- // Initialize with the default Perfetto callback.
- NetworkTraceHandler();
-
- // Testonly: initialize with a callback capable of intercepting data.
- NetworkTraceHandler(std::function<void(const PacketTrace&)> callback)
- : mCallback(std::move(callback)) {}
-
- // Testonly: standalone functions without perfetto dependency.
- bool Start();
- bool Stop();
- bool ConsumeAll();
-
// perfetto::DataSource overrides:
- void OnSetup(const SetupArgs&) override;
+ void OnSetup(const SetupArgs& args) override;
void OnStart(const StartArgs&) override;
void OnStop(const StopArgs&) override;
- // Convert a PacketTrace into a Perfetto trace packet.
- void Fill(const PacketTrace& src,
- ::perfetto::protos::pbzero::TracePacket& dst);
-
private:
- void Loop();
+ // Convert a PacketTrace into a Perfetto trace packet.
+ static void Fill(const PacketTrace& src,
+ ::perfetto::protos::pbzero::TracePacket& dst);
- // How often to poll the ring buffer, defined by the trace config.
+ static internal::NetworkTracePoller sPoller;
uint32_t mPollMs;
-
- // The function to process PacketTrace, typically a Perfetto sink.
- std::function<void(const PacketTrace&)> mCallback;
-
- // The BPF ring buffer handle.
- std::unique_ptr<BpfRingbuf<PacketTrace>> mRingBuffer;
-
- // The packet tracing config map (really a 1-element array).
- BpfMap<uint32_t, bool> mConfigurationMap;
-
- // This must be the last member, causing it to be the first deleted. If it is
- // not, members required for callbacks can be deleted before it's stopped.
- std::unique_ptr<perfetto::base::TaskRunner> mTaskRunner;
+ bool mStarted;
};
} // namespace bpf
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h
new file mode 100644
index 0000000..b0189a7
--- /dev/null
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h
@@ -0,0 +1,85 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <perfetto/base/task_runner.h>
+#include <perfetto/tracing.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "android-base/thread_annotations.h"
+#include "bpf/BpfMap.h"
+#include "bpf/BpfRingbuf.h"
+
+// For PacketTrace struct definition
+#include "netd.h"
+
+namespace android {
+namespace bpf {
+namespace internal {
+
+// NetworkTracePoller is responsible for interactions with the BPF ring buffer
+// including polling. This class is an internal helper for NetworkTraceHandler,
+// it is not meant to be used elsewhere.
+class NetworkTracePoller {
+ public:
+ // Testonly: initialize with a callback capable of intercepting data.
+ NetworkTracePoller(std::function<void(const PacketTrace&)> callback)
+ : mCallback(std::move(callback)) {}
+
+ // Starts tracing with the given poll interval.
+ bool Start(uint32_t pollMs) EXCLUDES(mMutex);
+
+ // Stops tracing and release any held state.
+ bool Stop() EXCLUDES(mMutex);
+
+ // Consumes all available events from the ringbuffer.
+ bool ConsumeAll() EXCLUDES(mMutex);
+
+ private:
+ void SchedulePolling() REQUIRES(mMutex);
+ bool ConsumeAllLocked() REQUIRES(mMutex);
+
+ std::mutex mMutex;
+
+ // Records the number of successfully started active sessions so that only the
+ // first active session attempts setup and only the last cleans up. Note that
+ // the session count will remain zero if Start fails. It is expected that Stop
+ // will not be called for any trace session where Start fails.
+ int mSessionCount GUARDED_BY(mMutex);
+
+ // How often to poll the ring buffer, defined by the trace config.
+ uint32_t mPollMs GUARDED_BY(mMutex);
+
+ // The function to process PacketTrace, typically a Perfetto sink.
+ std::function<void(const PacketTrace&)> mCallback GUARDED_BY(mMutex);
+
+ // The BPF ring buffer handle.
+ std::unique_ptr<BpfRingbuf<PacketTrace>> mRingBuffer GUARDED_BY(mMutex);
+
+ // The packet tracing config map (really a 1-element array).
+ BpfMap<uint32_t, bool> mConfigurationMap GUARDED_BY(mMutex);
+
+ // This must be the last member, causing it to be the first deleted. If it is
+ // not, members required for callbacks can be deleted before it's stopped.
+ std::unique_ptr<perfetto::base::TaskRunner> mTaskRunner GUARDED_BY(mMutex);
+};
+
+} // namespace internal
+} // namespace bpf
+} // namespace android
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 3bc09db..c92e9a9 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -20,6 +20,9 @@
import static android.net.nsd.NsdManager.MDNS_DISCOVERY_MANAGER_EVENT;
import static android.net.nsd.NsdManager.MDNS_SERVICE_EVENT;
import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
+import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
+
+import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -79,10 +82,10 @@
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -110,6 +113,34 @@
*/
private static final String MDNS_ADVERTISER_VERSION = "mdns_advertiser_version";
+ /**
+ * Comma-separated list of type:flag mappings indicating the flags to use to allowlist
+ * discovery/advertising using MdnsDiscoveryManager / MdnsAdvertiser for a given type.
+ *
+ * For example _mytype._tcp.local and _othertype._tcp.local would be configured with:
+ * _mytype._tcp:mytype,_othertype._tcp.local:othertype
+ *
+ * In which case the flags:
+ * "mdns_discovery_manager_allowlist_mytype_version",
+ * "mdns_advertiser_allowlist_mytype_version",
+ * "mdns_discovery_manager_allowlist_othertype_version",
+ * "mdns_advertiser_allowlist_othertype_version"
+ * would be used to toggle MdnsDiscoveryManager / MdnsAdvertiser for each type. The flags will
+ * be read with
+ * {@link DeviceConfigUtils#isFeatureEnabled(Context, String, String, String, boolean)}.
+ *
+ * @see #MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX
+ * @see #MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX
+ * @see #MDNS_ALLOWLIST_FLAG_SUFFIX
+ */
+ private static final String MDNS_TYPE_ALLOWLIST_FLAGS = "mdns_type_allowlist_flags";
+
+ private static final String MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX =
+ "mdns_discovery_manager_allowlist_";
+ private static final String MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX =
+ "mdns_advertiser_allowlist_";
+ private static final String MDNS_ALLOWLIST_FLAG_SUFFIX = "_version";
+
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;
@@ -235,6 +266,35 @@
}
}
+ private class ServiceInfoListener extends MdnsListener {
+
+ ServiceInfoListener(int clientId, int transactionId, @NonNull NsdServiceInfo reqServiceInfo,
+ @NonNull String listenServiceType) {
+ super(clientId, transactionId, reqServiceInfo, listenServiceType);
+ }
+
+ @Override
+ public void onServiceFound(@NonNull MdnsServiceInfo serviceInfo) {
+ mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
+ NsdManager.SERVICE_UPDATED,
+ new MdnsEvent(mClientId, mReqServiceInfo.getServiceType(), serviceInfo));
+ }
+
+ @Override
+ public void onServiceUpdated(@NonNull MdnsServiceInfo serviceInfo) {
+ mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
+ NsdManager.SERVICE_UPDATED,
+ new MdnsEvent(mClientId, mReqServiceInfo.getServiceType(), serviceInfo));
+ }
+
+ @Override
+ public void onServiceRemoved(@NonNull MdnsServiceInfo serviceInfo) {
+ mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
+ NsdManager.SERVICE_UPDATED_LOST,
+ new MdnsEvent(mClientId, mReqServiceInfo.getServiceType(), serviceInfo));
+ }
+ }
+
/**
* Data class of mdns service callback information.
*/
@@ -491,37 +551,6 @@
mIdToClientInfoMap.put(globalId, clientInfo);
}
- private void clearRegisteredServiceInfo(ClientInfo clientInfo) {
- clientInfo.mRegisteredService = null;
- clientInfo.mClientIdForServiceUpdates = 0;
- }
-
- /**
- * Check the given service type is valid and construct it to a service type
- * which can use for discovery / resolution service.
- *
- * <p> The valid service type should be 2 labels, or 3 labels if the query is for a
- * subtype (see RFC6763 7.1). Each label is up to 63 characters and must start with an
- * underscore; they are alphanumerical characters or dashes or underscore, except the
- * last one that is just alphanumerical. The last label must be _tcp or _udp.
- *
- * @param serviceType the request service type for discovery / resolution service
- * @return constructed service type or null if the given service type is invalid.
- */
- @Nullable
- private String constructServiceType(String serviceType) {
- if (TextUtils.isEmpty(serviceType)) return null;
-
- final Pattern serviceTypePattern = Pattern.compile(
- "^(_[a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]\\.)?"
- + "(_[a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]\\._(?:tcp|udp))$");
- final Matcher matcher = serviceTypePattern.matcher(serviceType);
- if (!matcher.matches()) return null;
- return matcher.group(1) == null
- ? serviceType
- : matcher.group(1) + "_sub." + matcher.group(2);
- }
-
/**
* Truncate a service name to up to 63 UTF-8 bytes.
*
@@ -545,6 +574,12 @@
return new String(out.array(), 0, out.position(), utf8);
}
+ private void stopDiscoveryManagerRequest(ClientRequest request, int clientId, int id,
+ ClientInfo clientInfo) {
+ clientInfo.unregisterMdnsListenerFromRequest(request);
+ removeRequestMap(clientId, id, clientInfo);
+ }
+
@Override
public boolean processMessage(Message msg) {
final ClientInfo clientInfo;
@@ -572,8 +607,9 @@
final NsdServiceInfo info = args.serviceInfo;
id = getUniqueId();
- if (mDeps.isMdnsDiscoveryManagerEnabled(mContext)) {
- final String serviceType = constructServiceType(info.getServiceType());
+ final String serviceType = constructServiceType(info.getServiceType());
+ if (mDeps.isMdnsDiscoveryManagerEnabled(mContext)
+ || useDiscoveryManagerForType(serviceType)) {
if (serviceType == null) {
clientInfo.onDiscoverServicesFailed(clientId,
NsdManager.FAILURE_INTERNAL_ERROR);
@@ -631,11 +667,7 @@
// point, so this needs to check the type of the original request to
// unregister instead of looking at the flag value.
if (request instanceof DiscoveryManagerRequest) {
- final MdnsListener listener =
- ((DiscoveryManagerRequest) request).mListener;
- mMdnsDiscoveryManager.unregisterListener(
- listener.getListenedServiceType(), listener);
- removeRequestMap(clientId, id, clientInfo);
+ stopDiscoveryManagerRequest(request, clientId, id, clientInfo);
clientInfo.onStopDiscoverySucceeded(clientId);
} else {
removeRequestMap(clientId, id, clientInfo);
@@ -667,10 +699,11 @@
}
id = getUniqueId();
- if (mDeps.isMdnsAdvertiserEnabled(mContext)) {
- final NsdServiceInfo serviceInfo = args.serviceInfo;
- final String serviceType = serviceInfo.getServiceType();
- final String registerServiceType = constructServiceType(serviceType);
+ final NsdServiceInfo serviceInfo = args.serviceInfo;
+ final String serviceType = serviceInfo.getServiceType();
+ final String registerServiceType = constructServiceType(serviceType);
+ if (mDeps.isMdnsAdvertiserEnabled(mContext)
+ || useAdvertiserForType(registerServiceType)) {
if (registerServiceType == null) {
Log.e(TAG, "Invalid service type: " + serviceType);
clientInfo.onRegisterServiceFailed(clientId,
@@ -686,7 +719,7 @@
storeAdvertiserRequestMap(clientId, id, clientInfo);
} else {
maybeStartDaemon();
- if (registerService(id, args.serviceInfo)) {
+ if (registerService(id, serviceInfo)) {
if (DBG) Log.d(TAG, "Register " + clientId + " " + id);
storeLegacyRequestMap(clientId, id, clientInfo, msg.what);
// Return success after mDns reports success
@@ -748,8 +781,9 @@
final NsdServiceInfo info = args.serviceInfo;
id = getUniqueId();
- if (mDeps.isMdnsDiscoveryManagerEnabled(mContext)) {
- final String serviceType = constructServiceType(info.getServiceType());
+ final String serviceType = constructServiceType(info.getServiceType());
+ if (mDeps.isMdnsDiscoveryManagerEnabled(mContext)
+ || useDiscoveryManagerForType(serviceType)) {
if (serviceType == null) {
clientInfo.onResolveServiceFailed(clientId,
NsdManager.FAILURE_INTERNAL_ERROR);
@@ -804,18 +838,25 @@
break;
}
id = request.mGlobalId;
- removeRequestMap(clientId, id, clientInfo);
- if (stopResolveService(id)) {
+ // Note isMdnsDiscoveryManagerEnabled may have changed to false at this
+ // point, so this needs to check the type of the original request to
+ // unregister instead of looking at the flag value.
+ if (request instanceof DiscoveryManagerRequest) {
+ stopDiscoveryManagerRequest(request, clientId, id, clientInfo);
clientInfo.onStopResolutionSucceeded(clientId);
} else {
- clientInfo.onStopResolutionFailed(
- clientId, NsdManager.FAILURE_OPERATION_NOT_RUNNING);
+ removeRequestMap(clientId, id, clientInfo);
+ if (stopResolveService(id)) {
+ clientInfo.onStopResolutionSucceeded(clientId);
+ } else {
+ clientInfo.onStopResolutionFailed(
+ clientId, NsdManager.FAILURE_OPERATION_NOT_RUNNING);
+ }
+ clientInfo.mResolvedService = null;
}
- clientInfo.mResolvedService = null;
- // TODO: Implement the stop resolution with MdnsDiscoveryManager.
break;
}
- case NsdManager.REGISTER_SERVICE_CALLBACK:
+ case NsdManager.REGISTER_SERVICE_CALLBACK: {
if (DBG) Log.d(TAG, "Register a service callback");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
@@ -827,23 +868,29 @@
break;
}
- if (clientInfo.mRegisteredService != null) {
- clientInfo.onServiceInfoCallbackRegistrationFailed(
- clientId, NsdManager.FAILURE_ALREADY_ACTIVE);
+ final NsdServiceInfo info = args.serviceInfo;
+ id = getUniqueId();
+ final String serviceType = constructServiceType(info.getServiceType());
+ if (serviceType == null) {
+ clientInfo.onServiceInfoCallbackRegistrationFailed(clientId,
+ NsdManager.FAILURE_BAD_PARAMETERS);
break;
}
+ final String resolveServiceType = serviceType + ".local";
- maybeStartDaemon();
- id = getUniqueId();
- if (resolveService(id, args.serviceInfo)) {
- clientInfo.mRegisteredService = new NsdServiceInfo();
- clientInfo.mClientIdForServiceUpdates = clientId;
- storeLegacyRequestMap(clientId, id, clientInfo, msg.what);
- } else {
- clientInfo.onServiceInfoCallbackRegistrationFailed(
- clientId, NsdManager.FAILURE_BAD_PARAMETERS);
- }
+ maybeStartMonitoringSockets();
+ final MdnsListener listener =
+ new ServiceInfoListener(clientId, id, info, resolveServiceType);
+ final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
+ .setNetwork(info.getNetwork())
+ .setIsPassiveMode(true)
+ .setResolveInstanceName(info.getServiceName())
+ .build();
+ mMdnsDiscoveryManager.registerListener(
+ resolveServiceType, listener, options);
+ storeDiscoveryManagerRequestMap(clientId, id, listener, clientInfo);
break;
+ }
case NsdManager.UNREGISTER_SERVICE_CALLBACK: {
if (DBG) Log.d(TAG, "Unregister a service callback");
args = (ListenerArgs) msg.obj;
@@ -858,17 +905,16 @@
final ClientRequest request = clientInfo.mClientRequests.get(clientId);
if (request == null) {
- Log.e(TAG, "Unknown client request in STOP_RESOLUTION");
+ Log.e(TAG, "Unknown client request in UNREGISTER_SERVICE_CALLBACK");
break;
}
id = request.mGlobalId;
- removeRequestMap(clientId, id, clientInfo);
- if (stopResolveService(id)) {
+ if (request instanceof DiscoveryManagerRequest) {
+ stopDiscoveryManagerRequest(request, clientId, id, clientInfo);
clientInfo.onServiceInfoCallbackUnregistered(clientId);
} else {
- Log.e(TAG, "Failed to unregister service info callback");
+ loge("Unregister failed with non-DiscoveryManagerRequest.");
}
- clearRegisteredServiceInfo(clientInfo);
break;
}
case MDNS_SERVICE_EVENT:
@@ -887,19 +933,6 @@
return HANDLED;
}
- private void notifyResolveFailedResult(boolean isListenedToUpdates, int clientId,
- ClientInfo clientInfo, int error) {
- if (isListenedToUpdates) {
- clientInfo.onServiceInfoCallbackRegistrationFailed(clientId, error);
- clearRegisteredServiceInfo(clientInfo);
- } else {
- // The resolve API always returned FAILURE_INTERNAL_ERROR on error; keep it
- // for backwards compatibility.
- clientInfo.onResolveServiceFailed(clientId, NsdManager.FAILURE_INTERNAL_ERROR);
- clientInfo.mResolvedService = null;
- }
- }
-
private boolean handleMDnsServiceEvent(int code, int id, Object obj) {
NsdServiceInfo servInfo;
ClientInfo clientInfo = mIdToClientInfoMap.get(id);
@@ -956,8 +989,6 @@
// found services on the same interface index and their network at the time
setServiceNetworkForCallback(servInfo, lostNetId, info.interfaceIdx);
clientInfo.onServiceLost(clientId, servInfo);
- // TODO: also support registered service lost when not discovering
- clientInfo.maybeNotifyRegisteredServiceLost(servInfo);
break;
}
case IMDnsEventListener.SERVICE_DISCOVERY_FAILED:
@@ -994,11 +1025,7 @@
String rest = fullName.substring(index);
String type = rest.replace(".local.", "");
- final boolean isListenedToUpdates =
- clientId == clientInfo.mClientIdForServiceUpdates;
- final NsdServiceInfo serviceInfo = isListenedToUpdates
- ? clientInfo.mRegisteredService : clientInfo.mResolvedService;
-
+ final NsdServiceInfo serviceInfo = clientInfo.mResolvedService;
serviceInfo.setServiceName(name);
serviceInfo.setServiceType(type);
serviceInfo.setPort(info.port);
@@ -1013,8 +1040,9 @@
storeLegacyRequestMap(clientId, id2, clientInfo,
NsdManager.RESOLVE_SERVICE);
} else {
- notifyResolveFailedResult(isListenedToUpdates, clientId, clientInfo,
- NsdManager.FAILURE_BAD_PARAMETERS);
+ clientInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+ clientInfo.mResolvedService = null;
}
break;
}
@@ -1022,17 +1050,17 @@
/* NNN resolveId errorCode */
stopResolveService(id);
removeRequestMap(clientId, id, clientInfo);
- notifyResolveFailedResult(
- clientId == clientInfo.mClientIdForServiceUpdates,
- clientId, clientInfo, NsdManager.FAILURE_BAD_PARAMETERS);
+ clientInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+ clientInfo.mResolvedService = null;
break;
case IMDnsEventListener.SERVICE_GET_ADDR_FAILED:
/* NNN resolveId errorCode */
stopGetAddrInfo(id);
removeRequestMap(clientId, id, clientInfo);
- notifyResolveFailedResult(
- clientId == clientInfo.mClientIdForServiceUpdates,
- clientId, clientInfo, NsdManager.FAILURE_BAD_PARAMETERS);
+ clientInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+ clientInfo.mResolvedService = null;
break;
case IMDnsEventListener.SERVICE_GET_ADDR_SUCCESS: {
/* NNN resolveId hostname ttl addr interfaceIdx netId */
@@ -1049,38 +1077,19 @@
// If the resolved service is on an interface without a network, consider it
// as a failure: it would not be usable by apps as they would need
// privileged permissions.
- if (clientId == clientInfo.mClientIdForServiceUpdates) {
- if (netId != NETID_UNSET && serviceHost != null) {
- setServiceNetworkForCallback(clientInfo.mRegisteredService,
- netId, info.interfaceIdx);
- final List<InetAddress> addresses =
- clientInfo.mRegisteredService.getHostAddresses();
- addresses.add(serviceHost);
- clientInfo.mRegisteredService.setHostAddresses(addresses);
- clientInfo.onServiceUpdated(
- clientId, clientInfo.mRegisteredService);
- } else {
- stopGetAddrInfo(id);
- removeRequestMap(clientId, id, clientInfo);
- clearRegisteredServiceInfo(clientInfo);
- clientInfo.onServiceInfoCallbackRegistrationFailed(
- clientId, NsdManager.FAILURE_BAD_PARAMETERS);
- }
+ if (netId != NETID_UNSET && serviceHost != null) {
+ clientInfo.mResolvedService.setHost(serviceHost);
+ setServiceNetworkForCallback(clientInfo.mResolvedService,
+ netId, info.interfaceIdx);
+ clientInfo.onResolveServiceSucceeded(
+ clientId, clientInfo.mResolvedService);
} else {
- if (netId != NETID_UNSET && serviceHost != null) {
- clientInfo.mResolvedService.setHost(serviceHost);
- setServiceNetworkForCallback(clientInfo.mResolvedService,
- netId, info.interfaceIdx);
- clientInfo.onResolveServiceSucceeded(
- clientId, clientInfo.mResolvedService);
- } else {
- clientInfo.onResolveServiceFailed(
- clientId, NsdManager.FAILURE_INTERNAL_ERROR);
- }
- stopGetAddrInfo(id);
- removeRequestMap(clientId, id, clientInfo);
- clientInfo.mResolvedService = null;
+ clientInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
}
+ stopGetAddrInfo(id);
+ removeRequestMap(clientId, id, clientInfo);
+ clientInfo.mResolvedService = null;
break;
}
default:
@@ -1145,17 +1154,27 @@
Log.e(TAG, "Invalid attribute", e);
}
}
- try {
- if (serviceInfo.getIpv4Address() != null) {
- info.setHost(InetAddresses.parseNumericAddress(
- serviceInfo.getIpv4Address()));
- } else {
- info.setHost(InetAddresses.parseNumericAddress(
- serviceInfo.getIpv6Address()));
+ final List<InetAddress> addresses = new ArrayList<>();
+ for (String ipv4Address : serviceInfo.getIpv4Addresses()) {
+ try {
+ addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
+ } catch (IllegalArgumentException e) {
+ Log.wtf(TAG, "Invalid ipv4 address", e);
}
+ }
+ for (String ipv6Address : serviceInfo.getIpv6Addresses()) {
+ try {
+ addresses.add(InetAddresses.parseNumericAddress(ipv6Address));
+ } catch (IllegalArgumentException e) {
+ Log.wtf(TAG, "Invalid ipv6 address", e);
+ }
+ }
+
+ if (addresses.size() != 0) {
+ info.setHostAddresses(addresses);
clientInfo.onResolveServiceSucceeded(clientId, info);
- } catch (IllegalArgumentException e) {
- Log.wtf(TAG, "Invalid address in RESOLVE_SERVICE_SUCCEEDED", e);
+ } else {
+ // No address. Notify resolution failure.
clientInfo.onResolveServiceFailed(
clientId, NsdManager.FAILURE_INTERNAL_ERROR);
}
@@ -1165,12 +1184,45 @@
Log.wtf(TAG, "non-DiscoveryManager request in DiscoveryManager event");
break;
}
- final MdnsListener listener = ((DiscoveryManagerRequest) request).mListener;
- mMdnsDiscoveryManager.unregisterListener(
- listener.getListenedServiceType(), listener);
- removeRequestMap(clientId, transactionId, clientInfo);
+ stopDiscoveryManagerRequest(request, clientId, transactionId, clientInfo);
break;
}
+ case NsdManager.SERVICE_UPDATED: {
+ final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo;
+ info.setPort(serviceInfo.getPort());
+
+ Map<String, String> attrs = serviceInfo.getAttributes();
+ for (Map.Entry<String, String> kv : attrs.entrySet()) {
+ final String key = kv.getKey();
+ try {
+ info.setAttribute(key, serviceInfo.getAttributeAsBytes(key));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Invalid attribute", e);
+ }
+ }
+
+ final List<InetAddress> addresses = new ArrayList<>();
+ for (String ipv4Address : serviceInfo.getIpv4Addresses()) {
+ try {
+ addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
+ } catch (IllegalArgumentException e) {
+ Log.wtf(TAG, "Invalid ipv4 address", e);
+ }
+ }
+ for (String ipv6Address : serviceInfo.getIpv6Addresses()) {
+ try {
+ addresses.add(InetAddresses.parseNumericAddress(ipv6Address));
+ } catch (IllegalArgumentException e) {
+ Log.wtf(TAG, "Invalid ipv6 address", e);
+ }
+ }
+ info.setHostAddresses(addresses);
+ clientInfo.onServiceUpdated(clientId, info);
+ break;
+ }
+ case NsdManager.SERVICE_UPDATED_LOST:
+ clientInfo.onServiceUpdatedLost(clientId);
+ break;
default:
return false;
}
@@ -1228,6 +1280,34 @@
return sb.toString();
}
+ /**
+ * Check the given service type is valid and construct it to a service type
+ * which can use for discovery / resolution service.
+ *
+ * <p> The valid service type should be 2 labels, or 3 labels if the query is for a
+ * subtype (see RFC6763 7.1). Each label is up to 63 characters and must start with an
+ * underscore; they are alphanumerical characters or dashes or underscore, except the
+ * last one that is just alphanumerical. The last label must be _tcp or _udp.
+ *
+ * @param serviceType the request service type for discovery / resolution service
+ * @return constructed service type or null if the given service type is invalid.
+ */
+ @Nullable
+ public static String constructServiceType(String serviceType) {
+ if (TextUtils.isEmpty(serviceType)) return null;
+
+ final Pattern serviceTypePattern = Pattern.compile(
+ "^(_[a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]\\.)?"
+ + "(_[a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]\\._(?:tcp|udp))"
+ // Drop '.' at the end of service type that is compatible with old backend.
+ + "\\.?$");
+ final Matcher matcher = serviceTypePattern.matcher(serviceType);
+ if (!matcher.matches()) return null;
+ return matcher.group(1) == null
+ ? matcher.group(2)
+ : matcher.group(1) + "_sub." + matcher.group(2);
+ }
+
@VisibleForTesting
NsdService(Context ctx, Handler handler, long cleanupDelayMs) {
this(ctx, handler, cleanupDelayMs, new Dependencies());
@@ -1265,8 +1345,9 @@
* @return true if the MdnsDiscoveryManager feature is enabled.
*/
public boolean isMdnsDiscoveryManagerEnabled(Context context) {
- return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY,
- MDNS_DISCOVERY_MANAGER_VERSION, false /* defaultEnabled */);
+ return isAtLeastU() || DeviceConfigUtils.isFeatureEnabled(context,
+ NAMESPACE_CONNECTIVITY, MDNS_DISCOVERY_MANAGER_VERSION,
+ false /* defaultEnabled */);
}
/**
@@ -1276,8 +1357,26 @@
* @return true if the MdnsAdvertiser feature is enabled.
*/
public boolean isMdnsAdvertiserEnabled(Context context) {
- return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY,
- MDNS_ADVERTISER_VERSION, false /* defaultEnabled */);
+ return isAtLeastU() || DeviceConfigUtils.isFeatureEnabled(context,
+ NAMESPACE_CONNECTIVITY, MDNS_ADVERTISER_VERSION, false /* defaultEnabled */);
+ }
+
+ /**
+ * Get the type allowlist flag value.
+ * @see #MDNS_TYPE_ALLOWLIST_FLAGS
+ */
+ @Nullable
+ public String getTypeAllowlistFlags() {
+ return DeviceConfigUtils.getDeviceConfigProperty(NAMESPACE_TETHERING,
+ MDNS_TYPE_ALLOWLIST_FLAGS, null);
+ }
+
+ /**
+ * @see DeviceConfigUtils#isFeatureEnabled(Context, String, String, String, boolean)
+ */
+ public boolean isFeatureEnabled(Context context, String feature) {
+ return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_TETHERING,
+ feature, DeviceConfigUtils.TETHERING_MODULE_NAME, false /* defaultEnabled */);
}
/**
@@ -1305,6 +1404,41 @@
}
}
+ /**
+ * Return whether a type is allowlisted to use the Java backend.
+ * @param type The service type
+ * @param flagPrefix One of {@link #MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX} or
+ * {@link #MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX}.
+ */
+ private boolean isTypeAllowlistedForJavaBackend(@Nullable String type,
+ @NonNull String flagPrefix) {
+ if (type == null) return false;
+ final String typesConfig = mDeps.getTypeAllowlistFlags();
+ if (TextUtils.isEmpty(typesConfig)) return false;
+
+ final String mappingPrefix = type + ":";
+ String mappedFlag = null;
+ for (String mapping : TextUtils.split(typesConfig, ",")) {
+ if (mapping.startsWith(mappingPrefix)) {
+ mappedFlag = mapping.substring(mappingPrefix.length());
+ break;
+ }
+ }
+
+ if (mappedFlag == null) return false;
+
+ return mDeps.isFeatureEnabled(mContext,
+ flagPrefix + mappedFlag + MDNS_ALLOWLIST_FLAG_SUFFIX);
+ }
+
+ private boolean useDiscoveryManagerForType(@Nullable String type) {
+ return isTypeAllowlistedForJavaBackend(type, MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX);
+ }
+
+ private boolean useAdvertiserForType(@Nullable String type) {
+ return isTypeAllowlistedForJavaBackend(type, MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX);
+ }
+
public static NsdService create(Context context) {
HandlerThread thread = new HandlerThread(TAG);
thread.start();
@@ -1660,11 +1794,6 @@
// The target SDK of this client < Build.VERSION_CODES.S
private boolean mIsPreSClient = false;
- /*** The service that is registered to listen to its updates */
- private NsdServiceInfo mRegisteredService;
- /*** The client id that listen to updates */
- private int mClientIdForServiceUpdates;
-
private ClientInfo(INsdManagerCallback cb) {
mCb = cb;
if (DBG) Log.d(TAG, "New client");
@@ -1695,6 +1824,13 @@
mIsPreSClient = true;
}
+ private void unregisterMdnsListenerFromRequest(ClientRequest request) {
+ final MdnsListener listener =
+ ((DiscoveryManagerRequest) request).mListener;
+ mMdnsDiscoveryManager.unregisterListener(
+ listener.getListenedServiceType(), listener);
+ }
+
// Remove any pending requests from the global map when we get rid of a client,
// and send cancellations to the daemon.
private void expungeAllRequests() {
@@ -1710,10 +1846,7 @@
}
if (request instanceof DiscoveryManagerRequest) {
- final MdnsListener listener =
- ((DiscoveryManagerRequest) request).mListener;
- mMdnsDiscoveryManager.unregisterListener(
- listener.getListenedServiceType(), listener);
+ unregisterMdnsListenerFromRequest(request);
continue;
}
@@ -1755,18 +1888,6 @@
return -1;
}
- private void maybeNotifyRegisteredServiceLost(@NonNull NsdServiceInfo info) {
- if (mRegisteredService == null) return;
- if (!Objects.equals(mRegisteredService.getServiceName(), info.getServiceName())) return;
- // Resolved services have a leading dot appended at the beginning of their type, but in
- // discovered info it's at the end
- if (!Objects.equals(
- mRegisteredService.getServiceType() + ".", "." + info.getServiceType())) {
- return;
- }
- onServiceUpdatedLost(mClientIdForServiceUpdates);
- }
-
void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) {
try {
mCb.onDiscoverServicesStarted(listenerKey, info);
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 67059e7..fb8af8d 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
@@ -16,19 +16,25 @@
package com.android.server.connectivity.mdns;
+import static com.android.server.connectivity.mdns.MdnsSocketProvider.isNetworkMatched;
+
import android.Manifest.permission;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.net.Network;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.Pair;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.connectivity.mdns.util.MdnsLogger;
import java.io.IOException;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
/**
* This class keeps tracking the set of registered {@link MdnsServiceBrowserListener} instances, and
@@ -42,12 +48,62 @@
private final ExecutorProvider executorProvider;
private final MdnsSocketClientBase socketClient;
- private final Map<String, MdnsServiceTypeClient> serviceTypeClients = new ArrayMap<>();
+ @GuardedBy("this")
+ @NonNull private final PerNetworkServiceTypeClients perNetworkServiceTypeClients;
+
+ private static class PerNetworkServiceTypeClients {
+ private final ArrayMap<Pair<String, Network>, MdnsServiceTypeClient> clients =
+ new ArrayMap<>();
+
+ public void put(@NonNull String serviceType, @Nullable Network network,
+ @NonNull MdnsServiceTypeClient client) {
+ final Pair<String, Network> perNetworkServiceType = new Pair<>(serviceType, network);
+ clients.put(perNetworkServiceType, client);
+ }
+
+ @Nullable
+ public MdnsServiceTypeClient get(@NonNull String serviceType, @Nullable Network network) {
+ final Pair<String, Network> perNetworkServiceType = new Pair<>(serviceType, network);
+ return clients.getOrDefault(perNetworkServiceType, null);
+ }
+
+ public List<MdnsServiceTypeClient> getByServiceType(@NonNull String serviceType) {
+ final List<MdnsServiceTypeClient> list = new ArrayList<>();
+ for (int i = 0; i < clients.size(); i++) {
+ final Pair<String, Network> perNetworkServiceType = clients.keyAt(i);
+ if (serviceType.equals(perNetworkServiceType.first)) {
+ list.add(clients.valueAt(i));
+ }
+ }
+ return list;
+ }
+
+ public List<MdnsServiceTypeClient> getByMatchingNetwork(@Nullable Network network) {
+ final List<MdnsServiceTypeClient> list = new ArrayList<>();
+ for (int i = 0; i < clients.size(); i++) {
+ final Pair<String, Network> perNetworkServiceType = clients.keyAt(i);
+ if (isNetworkMatched(network, perNetworkServiceType.second)) {
+ list.add(clients.valueAt(i));
+ }
+ }
+ return list;
+ }
+
+ public void remove(@NonNull MdnsServiceTypeClient client) {
+ final int index = clients.indexOfValue(client);
+ clients.removeAt(index);
+ }
+
+ public boolean isEmpty() {
+ return clients.isEmpty();
+ }
+ }
public MdnsDiscoveryManager(@NonNull ExecutorProvider executorProvider,
@NonNull MdnsSocketClientBase socketClient) {
this.executorProvider = executorProvider;
this.socketClient = socketClient;
+ perNetworkServiceTypeClients = new PerNetworkServiceTypeClients();
}
/**
@@ -67,7 +123,7 @@
LOGGER.log(
"Registering listener for subtypes: %s",
TextUtils.join(",", searchOptions.getSubtypes()));
- if (serviceTypeClients.isEmpty()) {
+ if (perNetworkServiceTypeClients.isEmpty()) {
// First listener. Starts the socket client.
try {
socketClient.startDiscovery();
@@ -77,16 +133,18 @@
}
}
// Request the network for discovery.
- socketClient.notifyNetworkRequested(listener, searchOptions.getNetwork());
-
- // All listeners of the same service types shares the same MdnsServiceTypeClient.
- MdnsServiceTypeClient serviceTypeClient = serviceTypeClients.get(serviceType);
- if (serviceTypeClient == null) {
- serviceTypeClient = createServiceTypeClient(serviceType);
- serviceTypeClients.put(serviceType, serviceTypeClient);
- }
- // TODO(b/264634275): Wait for a socket to be created before sending packets.
- serviceTypeClient.startSendAndReceive(listener, searchOptions);
+ socketClient.notifyNetworkRequested(listener, searchOptions.getNetwork(), network -> {
+ synchronized (this) {
+ // All listeners of the same service types shares the same MdnsServiceTypeClient.
+ MdnsServiceTypeClient serviceTypeClient =
+ perNetworkServiceTypeClients.get(serviceType, network);
+ if (serviceTypeClient == null) {
+ serviceTypeClient = createServiceTypeClient(serviceType, network);
+ perNetworkServiceTypeClients.put(serviceType, network, serviceTypeClient);
+ }
+ serviceTypeClient.startSendAndReceive(listener, searchOptions);
+ }
+ });
}
/**
@@ -101,17 +159,21 @@
@NonNull String serviceType, @NonNull MdnsServiceBrowserListener listener) {
LOGGER.log("Unregistering listener for service type: %s", serviceType);
if (DBG) Log.d(TAG, "Unregistering listener for serviceType:" + serviceType);
- MdnsServiceTypeClient serviceTypeClient = serviceTypeClients.get(serviceType);
- if (serviceTypeClient == null) {
+ final List<MdnsServiceTypeClient> serviceTypeClients =
+ perNetworkServiceTypeClients.getByServiceType(serviceType);
+ if (serviceTypeClients.isEmpty()) {
return;
}
- if (serviceTypeClient.stopSendAndReceive(listener)) {
- // No listener is registered for the service type anymore, remove it from the list of
- // the service type clients.
- serviceTypeClients.remove(serviceType);
- if (serviceTypeClients.isEmpty()) {
- // No discovery request. Stops the socket client.
- socketClient.stopDiscovery();
+ for (int i = 0; i < serviceTypeClients.size(); i++) {
+ final MdnsServiceTypeClient serviceTypeClient = serviceTypeClients.get(i);
+ if (serviceTypeClient.stopSendAndReceive(listener)) {
+ // No listener is registered for the service type anymore, remove it from the list
+ // of the service type clients.
+ perNetworkServiceTypeClients.remove(serviceTypeClient);
+ if (perNetworkServiceTypeClients.isEmpty()) {
+ // No discovery request. Stops the socket client.
+ socketClient.stopDiscovery();
+ }
}
}
// Unrequested the network.
@@ -121,22 +183,26 @@
@Override
public synchronized void onResponseReceived(@NonNull MdnsPacket packet,
int interfaceIndex, Network network) {
- for (MdnsServiceTypeClient serviceTypeClient : serviceTypeClients.values()) {
+ for (MdnsServiceTypeClient serviceTypeClient
+ : perNetworkServiceTypeClients.getByMatchingNetwork(network)) {
serviceTypeClient.processResponse(packet, interfaceIndex, network);
}
}
@Override
- public synchronized void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode) {
- for (MdnsServiceTypeClient serviceTypeClient : serviceTypeClients.values()) {
+ public synchronized void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode,
+ Network network) {
+ for (MdnsServiceTypeClient serviceTypeClient
+ : perNetworkServiceTypeClients.getByMatchingNetwork(network)) {
serviceTypeClient.onFailedToParseMdnsResponse(receivedPacketNumber, errorCode);
}
}
@VisibleForTesting
- MdnsServiceTypeClient createServiceTypeClient(@NonNull String serviceType) {
+ MdnsServiceTypeClient createServiceTypeClient(@NonNull String serviceType,
+ @Nullable Network network) {
return new MdnsServiceTypeClient(
serviceType, socketClient,
- executorProvider.newServiceTypeClientSchedulerExecutor());
+ executorProvider.newServiceTypeClientSchedulerExecutor(), network);
}
}
\ No newline at end of file
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
index 93972d9..5254342 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
@@ -63,6 +63,12 @@
}
private class InterfaceSocketCallback implements MdnsSocketProvider.SocketCallback {
+ private final SocketCreationCallback mSocketCreationCallback;
+
+ InterfaceSocketCallback(SocketCreationCallback socketCreationCallback) {
+ mSocketCreationCallback = socketCreationCallback;
+ }
+
@Override
public void onSocketCreated(@NonNull Network network,
@NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) {
@@ -76,6 +82,7 @@
}
socket.addPacketHandler(handler);
mActiveNetworkSockets.put(socket, network);
+ mSocketCreationCallback.onSocketCreated(network);
}
@Override
@@ -114,10 +121,11 @@
* @param listener the listener for discovery.
* @param network the target network for discovery. Null means discovery on all possible
* interfaces.
+ * @param socketCreationCallback the callback to notify socket creation.
*/
@Override
public void notifyNetworkRequested(@NonNull MdnsServiceBrowserListener listener,
- @Nullable Network network) {
+ @Nullable Network network, @NonNull SocketCreationCallback socketCreationCallback) {
ensureRunningOnHandlerThread(mHandler);
InterfaceSocketCallback callback = mRequestedNetworks.get(listener);
if (callback != null) {
@@ -125,7 +133,7 @@
}
if (DBG) Log.d(TAG, "notifyNetworkRequested: network=" + network);
- callback = new InterfaceSocketCallback();
+ callback = new InterfaceSocketCallback(socketCreationCallback);
mRequestedNetworks.put(listener, callback);
mSocketProvider.requestSocket(network, callback);
}
@@ -173,7 +181,7 @@
if (e.code != MdnsResponseErrorCode.ERROR_NOT_RESPONSE_MESSAGE) {
Log.e(TAG, e.getMessage(), e);
if (mCallback != null) {
- mCallback.onFailedToParseMdnsResponse(packetNumber, e.code);
+ mCallback.onFailedToParseMdnsResponse(packetNumber, e.code, network);
}
}
return;
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java
index a6e3762..be2555b 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java
@@ -25,6 +25,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -36,8 +37,8 @@
private final List<MdnsPointerRecord> pointerRecords;
private MdnsServiceRecord serviceRecord;
private MdnsTextRecord textRecord;
- private MdnsInetAddressRecord inet4AddressRecord;
- private MdnsInetAddressRecord inet6AddressRecord;
+ @NonNull private List<MdnsInetAddressRecord> inet4AddressRecords;
+ @NonNull private List<MdnsInetAddressRecord> inet6AddressRecords;
private long lastUpdateTime;
private final int interfaceIndex;
@Nullable private final Network network;
@@ -49,6 +50,8 @@
lastUpdateTime = now;
records = new LinkedList<>();
pointerRecords = new LinkedList<>();
+ inet4AddressRecords = new ArrayList<>();
+ inet6AddressRecords = new ArrayList<>();
this.interfaceIndex = interfaceIndex;
this.network = network;
this.serviceName = serviceName;
@@ -59,8 +62,8 @@
pointerRecords = new ArrayList<>(base.pointerRecords);
serviceRecord = base.serviceRecord;
textRecord = base.textRecord;
- inet4AddressRecord = base.inet4AddressRecord;
- inet6AddressRecord = base.inet6AddressRecord;
+ inet4AddressRecords = new ArrayList<>(base.inet4AddressRecords);
+ inet6AddressRecords = new ArrayList<>(base.inet6AddressRecords);
lastUpdateTime = base.lastUpdateTime;
serviceName = base.serviceName;
interfaceIndex = base.interfaceIndex;
@@ -94,8 +97,8 @@
if (recordsAreSame(pointerRecord, pointerRecords.get(existing))) {
return false;
}
- pointerRecords.remove(existing);
- records.remove(existing);
+ final MdnsRecord record = pointerRecords.remove(existing);
+ records.remove(record);
}
pointerRecords.add(pointerRecord);
records.add(pointerRecord);
@@ -201,46 +204,60 @@
return textRecord != null;
}
- /** Sets the IPv4 address record. */
- public synchronized boolean setInet4AddressRecord(
- @Nullable MdnsInetAddressRecord newInet4AddressRecord) {
- if (recordsAreSame(this.inet4AddressRecord, newInet4AddressRecord)) {
- return false;
+ /** Add the IPv4 address record. */
+ public synchronized boolean addInet4AddressRecord(
+ @NonNull MdnsInetAddressRecord newInet4AddressRecord) {
+ final int existing = inet4AddressRecords.indexOf(newInet4AddressRecord);
+ if (existing >= 0) {
+ if (recordsAreSame(newInet4AddressRecord, inet4AddressRecords.get(existing))) {
+ return false;
+ }
+ final MdnsRecord record = inet4AddressRecords.remove(existing);
+ records.remove(record);
}
- if (this.inet4AddressRecord != null) {
- records.remove(this.inet4AddressRecord);
- this.inet4AddressRecord = null;
- }
- if (newInet4AddressRecord != null && newInet4AddressRecord.getInet4Address() != null) {
- this.inet4AddressRecord = newInet4AddressRecord;
- records.add(this.inet4AddressRecord);
- }
+ inet4AddressRecords.add(newInet4AddressRecord);
+ records.add(newInet4AddressRecord);
return true;
}
- /** Gets the IPv4 address record. */
+ /** Gets the IPv4 address records. */
+ @NonNull
+ public synchronized List<MdnsInetAddressRecord> getInet4AddressRecords() {
+ return Collections.unmodifiableList(inet4AddressRecords);
+ }
+
+ /** Return the first IPv4 address record or null if no record. */
+ @Nullable
public synchronized MdnsInetAddressRecord getInet4AddressRecord() {
- return inet4AddressRecord;
+ return inet4AddressRecords.isEmpty() ? null : inet4AddressRecords.get(0);
}
+ /** Check whether response has IPv4 address record */
public synchronized boolean hasInet4AddressRecord() {
- return inet4AddressRecord != null;
+ return !inet4AddressRecords.isEmpty();
}
- /** Sets the IPv6 address record. */
- public synchronized boolean setInet6AddressRecord(
- @Nullable MdnsInetAddressRecord newInet6AddressRecord) {
- if (recordsAreSame(this.inet6AddressRecord, newInet6AddressRecord)) {
- return false;
+ /** Clear all IPv4 address records */
+ synchronized void clearInet4AddressRecords() {
+ for (MdnsInetAddressRecord record : inet4AddressRecords) {
+ records.remove(record);
}
- if (this.inet6AddressRecord != null) {
- records.remove(this.inet6AddressRecord);
- this.inet6AddressRecord = null;
+ inet4AddressRecords.clear();
+ }
+
+ /** Sets the IPv6 address records. */
+ public synchronized boolean addInet6AddressRecord(
+ @NonNull MdnsInetAddressRecord newInet6AddressRecord) {
+ final int existing = inet6AddressRecords.indexOf(newInet6AddressRecord);
+ if (existing >= 0) {
+ if (recordsAreSame(newInet6AddressRecord, inet6AddressRecords.get(existing))) {
+ return false;
+ }
+ final MdnsRecord record = inet6AddressRecords.remove(existing);
+ records.remove(record);
}
- if (newInet6AddressRecord != null && newInet6AddressRecord.getInet6Address() != null) {
- this.inet6AddressRecord = newInet6AddressRecord;
- records.add(this.inet6AddressRecord);
- }
+ inet6AddressRecords.add(newInet6AddressRecord);
+ records.add(newInet6AddressRecord);
return true;
}
@@ -260,13 +277,28 @@
return network;
}
- /** Gets the IPv6 address record. */
- public synchronized MdnsInetAddressRecord getInet6AddressRecord() {
- return inet6AddressRecord;
+ /** Gets all IPv6 address records. */
+ public synchronized List<MdnsInetAddressRecord> getInet6AddressRecords() {
+ return Collections.unmodifiableList(inet6AddressRecords);
}
+ /** Return the first IPv6 address record or null if no record. */
+ @Nullable
+ public synchronized MdnsInetAddressRecord getInet6AddressRecord() {
+ return inet6AddressRecords.isEmpty() ? null : inet6AddressRecords.get(0);
+ }
+
+ /** Check whether response has IPv6 address record */
public synchronized boolean hasInet6AddressRecord() {
- return inet6AddressRecord != null;
+ return !inet6AddressRecords.isEmpty();
+ }
+
+ /** Clear all IPv6 address records */
+ synchronized void clearInet6AddressRecords() {
+ for (MdnsInetAddressRecord record : inet6AddressRecords) {
+ records.remove(record);
+ }
+ inet6AddressRecords.clear();
}
/** Gets all of the records. */
@@ -283,22 +315,22 @@
if (this.serviceRecord == null) return false;
boolean dropAddressRecords = false;
- if (this.inet4AddressRecord != null) {
+ for (MdnsInetAddressRecord inetAddressRecord : getInet4AddressRecords()) {
if (!Arrays.equals(
- this.serviceRecord.getServiceHost(), this.inet4AddressRecord.getName())) {
+ this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) {
dropAddressRecords = true;
}
}
- if (this.inet6AddressRecord != null) {
+ for (MdnsInetAddressRecord inetAddressRecord : getInet6AddressRecords()) {
if (!Arrays.equals(
- this.serviceRecord.getServiceHost(), this.inet6AddressRecord.getName())) {
+ this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) {
dropAddressRecords = true;
}
}
if (dropAddressRecords) {
- setInet4AddressRecord(null);
- setInet6AddressRecord(null);
+ clearInet4AddressRecords();
+ clearInet6AddressRecords();
return true;
}
return false;
@@ -312,7 +344,7 @@
public synchronized boolean isComplete() {
return (serviceRecord != null)
&& (textRecord != null)
- && (inet4AddressRecord != null || inet6AddressRecord != null);
+ && (!inet4AddressRecords.isEmpty() || !inet6AddressRecords.isEmpty());
}
/**
@@ -378,13 +410,13 @@
++count;
}
- if (inet4AddressRecord != null) {
- inet4AddressRecord.write(writer, now);
+ for (MdnsInetAddressRecord inetAddressRecord : inet4AddressRecords) {
+ inetAddressRecord.write(writer, now);
++count;
}
- if (inet6AddressRecord != null) {
- inet6AddressRecord.write(writer, now);
+ for (MdnsInetAddressRecord inetAddressRecord : inet6AddressRecords) {
+ inetAddressRecord.write(writer, now);
++count;
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
index 7878b0b..0151202 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
@@ -205,39 +205,79 @@
}
}
- // Loop 3: find A and AAAA records, which reference the host name in the SRV record.
+ // Loop 3-1: find A and AAAA records and clear addresses if the cache-flush bit set, which
+ // reference the host name in the SRV record.
+ final List<MdnsInetAddressRecord> inetRecords = new ArrayList<>();
for (MdnsRecord record : records) {
if (record instanceof MdnsInetAddressRecord) {
MdnsInetAddressRecord inetRecord = (MdnsInetAddressRecord) record;
+ inetRecords.add(inetRecord);
if (allowMultipleSrvRecordsPerHost) {
List<MdnsResponse> matchingResponses =
findResponsesWithHostName(responses, inetRecord.getName());
for (MdnsResponse response : matchingResponses) {
- if (assignInetRecord(response, inetRecord)) {
- modified.add(response);
+ // Per RFC6762 10.2, clear all address records if the cache-flush bit set.
+ // This bit, the cache-flush bit, tells neighboring hosts
+ // that this is not a shared record type. Instead of merging this new
+ // record additively into the cache in addition to any previous records with
+ // the same name, rrtype, and rrclass, all old records with that name,
+ // rrtype, and rrclass that were received more than one second ago are
+ // declared invalid, and marked to expire from the cache in one second.
+ if (inetRecord.getCacheFlush()) {
+ response.clearInet4AddressRecords();
+ response.clearInet6AddressRecords();
}
}
} else {
MdnsResponse response =
findResponseWithHostName(responses, inetRecord.getName());
if (response != null) {
- if (assignInetRecord(response, inetRecord)) {
- modified.add(response);
+ // Per RFC6762 10.2, clear all address records if the cache-flush bit set.
+ // This bit, the cache-flush bit, tells neighboring hosts
+ // that this is not a shared record type. Instead of merging this new
+ // record additively into the cache in addition to any previous records with
+ // the same name, rrtype, and rrclass, all old records with that name,
+ // rrtype, and rrclass that were received more than one second ago are
+ // declared invalid, and marked to expire from the cache in one second.
+ if (inetRecord.getCacheFlush()) {
+ response.clearInet4AddressRecords();
+ response.clearInet6AddressRecords();
}
}
}
}
}
+ // Loop 3-2: Assign addresses, which reference the host name in the SRV record.
+ for (MdnsInetAddressRecord inetRecord : inetRecords) {
+ if (allowMultipleSrvRecordsPerHost) {
+ List<MdnsResponse> matchingResponses =
+ findResponsesWithHostName(responses, inetRecord.getName());
+ for (MdnsResponse response : matchingResponses) {
+ if (assignInetRecord(response, inetRecord)) {
+ modified.add(response);
+ }
+ }
+ } else {
+ MdnsResponse response =
+ findResponseWithHostName(responses, inetRecord.getName());
+ if (response != null) {
+ if (assignInetRecord(response, inetRecord)) {
+ modified.add(response);
+ }
+ }
+ }
+ }
+
return modified;
}
private static boolean assignInetRecord(
MdnsResponse response, MdnsInetAddressRecord inetRecord) {
if (inetRecord.getInet4Address() != null) {
- return response.setInet4AddressRecord(inetRecord);
+ return response.addInet4AddressRecord(inetRecord);
} else if (inetRecord.getInet6Address() != null) {
- return response.setInet6AddressRecord(inetRecord);
+ return response.addInet6AddressRecord(inetRecord);
}
return false;
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceInfo.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceInfo.java
index 938fc3f..78df6df 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceInfo.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceInfo.java
@@ -31,10 +31,10 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.TreeMap;
/**
* A class representing a discovered mDNS service instance.
@@ -57,8 +57,8 @@
source.createStringArrayList(),
source.createStringArray(),
source.readInt(),
- source.readString(),
- source.readString(),
+ source.createStringArrayList(),
+ source.createStringArrayList(),
source.createStringArrayList(),
source.createTypedArrayList(TextEntry.CREATOR),
source.readInt(),
@@ -76,10 +76,10 @@
private final List<String> subtypes;
private final String[] hostName;
private final int port;
- @Nullable
- private final String ipv4Address;
- @Nullable
- private final String ipv6Address;
+ @NonNull
+ private final List<String> ipv4Addresses;
+ @NonNull
+ private final List<String> ipv6Addresses;
final List<String> textStrings;
@Nullable
final List<TextEntry> textEntries;
@@ -105,8 +105,8 @@
subtypes,
hostName,
port,
- ipv4Address,
- ipv6Address,
+ List.of(ipv4Address),
+ List.of(ipv6Address),
textStrings,
/* textEntries= */ null,
/* interfaceIndex= */ INTERFACE_INDEX_UNSPECIFIED,
@@ -130,8 +130,8 @@
subtypes,
hostName,
port,
- ipv4Address,
- ipv6Address,
+ List.of(ipv4Address),
+ List.of(ipv6Address),
textStrings,
textEntries,
/* interfaceIndex= */ INTERFACE_INDEX_UNSPECIFIED,
@@ -160,8 +160,8 @@
subtypes,
hostName,
port,
- ipv4Address,
- ipv6Address,
+ List.of(ipv4Address),
+ List.of(ipv6Address),
textStrings,
textEntries,
interfaceIndex,
@@ -179,8 +179,8 @@
@Nullable List<String> subtypes,
String[] hostName,
int port,
- @Nullable String ipv4Address,
- @Nullable String ipv6Address,
+ @NonNull List<String> ipv4Addresses,
+ @NonNull List<String> ipv6Addresses,
@Nullable List<String> textStrings,
@Nullable List<TextEntry> textEntries,
int interfaceIndex,
@@ -193,8 +193,8 @@
}
this.hostName = hostName;
this.port = port;
- this.ipv4Address = ipv4Address;
- this.ipv6Address = ipv6Address;
+ this.ipv4Addresses = new ArrayList<>(ipv4Addresses);
+ this.ipv6Addresses = new ArrayList<>(ipv6Addresses);
this.textStrings = new ArrayList<>();
if (textStrings != null) {
this.textStrings.addAll(textStrings);
@@ -205,17 +205,14 @@
// compatibility. We should prefer only {@code textEntries} if it's not null.
List<TextEntry> entries =
(this.textEntries != null) ? this.textEntries : parseTextStrings(this.textStrings);
- Map<String, byte[]> attributes = new HashMap<>(entries.size());
+ // The map of attributes is case-insensitive.
+ final Map<String, byte[]> attributes = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (TextEntry entry : entries) {
- String key = entry.getKey().toLowerCase(Locale.ENGLISH);
-
// Per https://datatracker.ietf.org/doc/html/rfc6763#section-6.4, only the first entry
// of the same key should be accepted:
// If a client receives a TXT record containing the same key more than once, then the
// client MUST silently ignore all but the first occurrence of that attribute.
- if (!attributes.containsKey(key)) {
- attributes.put(key, entry.getValue());
- }
+ attributes.putIfAbsent(entry.getKey(), entry.getValue());
}
this.attributes = Collections.unmodifiableMap(attributes);
this.interfaceIndex = interfaceIndex;
@@ -263,16 +260,41 @@
return port;
}
- /** Returns the IPV4 address of this service instance. */
+ /** Returns the IPV4 addresses of this service instance. */
+ @NonNull
+ public List<String> getIpv4Addresses() {
+ return Collections.unmodifiableList(ipv4Addresses);
+ }
+
+ /**
+ * Returns the first IPV4 address of this service instance.
+ *
+ * @deprecated Use {@link #getIpv4Addresses()} to get the entire list of IPV4
+ * addresses for
+ * the host.
+ */
@Nullable
+ @Deprecated
public String getIpv4Address() {
- return ipv4Address;
+ return ipv4Addresses.isEmpty() ? null : ipv4Addresses.get(0);
}
/** Returns the IPV6 address of this service instance. */
+ @NonNull
+ public List<String> getIpv6Addresses() {
+ return Collections.unmodifiableList(ipv6Addresses);
+ }
+
+ /**
+ * Returns the first IPV6 address of this service instance.
+ *
+ * @deprecated Use {@link #getIpv6Addresses()} to get the entire list of IPV6 addresses for
+ * the host.
+ */
@Nullable
+ @Deprecated
public String getIpv6Address() {
- return ipv6Address;
+ return ipv6Addresses.isEmpty() ? null : ipv6Addresses.get(0);
}
/**
@@ -311,12 +333,12 @@
*/
@Nullable
public byte[] getAttributeAsBytes(@NonNull String key) {
- return attributes.get(key.toLowerCase(Locale.ENGLISH));
+ return attributes.get(key);
}
/** Returns an immutable map of all attributes. */
public Map<String, String> getAttributes() {
- Map<String, String> map = new HashMap<>(attributes.size());
+ Map<String, String> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (Map.Entry<String, byte[]> kv : attributes.entrySet()) {
final byte[] value = kv.getValue();
map.put(kv.getKey(), value == null ? null : new String(value, UTF_8));
@@ -336,8 +358,8 @@
out.writeStringList(subtypes);
out.writeStringArray(hostName);
out.writeInt(port);
- out.writeString(ipv4Address);
- out.writeString(ipv6Address);
+ out.writeStringList(ipv4Addresses);
+ out.writeStringList(ipv6Addresses);
out.writeStringList(textStrings);
out.writeTypedList(textEntries);
out.writeInt(interfaceIndex);
@@ -346,13 +368,16 @@
@Override
public String toString() {
- return String.format(
- Locale.ROOT,
- "Name: %s, subtypes: %s, ip: %s, port: %d",
- serviceInstanceName,
- TextUtils.join(",", subtypes),
- ipv4Address,
- port);
+ return "Name: " + serviceInstanceName
+ + ", type: " + TextUtils.join(".", serviceType)
+ + ", subtypes: " + TextUtils.join(",", subtypes)
+ + ", ip: " + ipv4Addresses
+ + ", ipv6: " + ipv6Addresses
+ + ", port: " + port
+ + ", interfaceIndex: " + interfaceIndex
+ + ", network: " + network
+ + ", textStrings: " + textStrings
+ + ", textEntries: " + textEntries;
}
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 f886948..f87804b 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -57,6 +57,7 @@
private final MdnsSocketClientBase socketClient;
private final MdnsResponseDecoder responseDecoder;
private final ScheduledExecutorService executor;
+ @Nullable private final Network network;
private final Object lock = new Object();
private final ArrayMap<MdnsServiceBrowserListener, MdnsSearchOptions> listeners =
new ArrayMap<>();
@@ -88,8 +89,9 @@
public MdnsServiceTypeClient(
@NonNull String serviceType,
@NonNull MdnsSocketClientBase socketClient,
- @NonNull ScheduledExecutorService executor) {
- this(serviceType, socketClient, executor, new MdnsResponseDecoder.Clock());
+ @NonNull ScheduledExecutorService executor,
+ @Nullable Network network) {
+ this(serviceType, socketClient, executor, new MdnsResponseDecoder.Clock(), network);
}
@VisibleForTesting
@@ -97,13 +99,15 @@
@NonNull String serviceType,
@NonNull MdnsSocketClientBase socketClient,
@NonNull ScheduledExecutorService executor,
- @NonNull MdnsResponseDecoder.Clock clock) {
+ @NonNull MdnsResponseDecoder.Clock clock,
+ @Nullable Network network) {
this.serviceType = serviceType;
this.socketClient = socketClient;
this.executor = executor;
this.serviceTypeLabels = TextUtils.split(serviceType, "\\.");
this.responseDecoder = new MdnsResponseDecoder(clock, serviceTypeLabels);
this.clock = clock;
+ this.network = network;
}
private static MdnsServiceInfo buildMdnsServiceInfoFromResponse(
@@ -115,15 +119,19 @@
port = response.getServiceRecord().getServicePort();
}
- String ipv4Address = null;
- String ipv6Address = null;
+ final List<String> ipv4Addresses = new ArrayList<>();
+ final List<String> ipv6Addresses = new ArrayList<>();
if (response.hasInet4AddressRecord()) {
- Inet4Address inet4Address = response.getInet4AddressRecord().getInet4Address();
- ipv4Address = (inet4Address == null) ? null : inet4Address.getHostAddress();
+ for (MdnsInetAddressRecord inetAddressRecord : response.getInet4AddressRecords()) {
+ final Inet4Address inet4Address = inetAddressRecord.getInet4Address();
+ ipv4Addresses.add((inet4Address == null) ? null : inet4Address.getHostAddress());
+ }
}
if (response.hasInet6AddressRecord()) {
- Inet6Address inet6Address = response.getInet6AddressRecord().getInet6Address();
- ipv6Address = (inet6Address == null) ? null : inet6Address.getHostAddress();
+ for (MdnsInetAddressRecord inetAddressRecord : response.getInet6AddressRecords()) {
+ final Inet6Address inet6Address = inetAddressRecord.getInet6Address();
+ ipv6Addresses.add((inet6Address == null) ? null : inet6Address.getHostAddress());
+ }
}
String serviceInstanceName = response.getServiceInstanceName();
if (serviceInstanceName == null) {
@@ -143,8 +151,8 @@
response.getSubtypes(),
hostName,
port,
- ipv4Address,
- ipv6Address,
+ ipv4Addresses,
+ ipv6Addresses,
textStrings,
textEntries,
response.getInterfaceIndex(),
@@ -200,7 +208,9 @@
*/
public boolean stopSendAndReceive(@NonNull MdnsServiceBrowserListener listener) {
synchronized (lock) {
- listeners.remove(listener);
+ if (listeners.remove(listener) == null) {
+ return listeners.isEmpty();
+ }
if (listeners.isEmpty() && requestTaskFuture != null) {
requestTaskFuture.cancel(true);
requestTaskFuture = null;
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java
index c03e6aa..783b18a 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java
@@ -423,7 +423,7 @@
LOGGER.w(String.format("Error while decoding %s packet (%d): %d",
responseType, packetNumber, e.code));
if (callback != null) {
- callback.onFailedToParseMdnsResponse(packetNumber, e.code);
+ callback.onFailedToParseMdnsResponse(packetNumber, e.code, network);
}
return e.code;
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java
index 796dc83..ebafc49 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java
@@ -64,7 +64,9 @@
/*** Notify that the given network is requested for mdns discovery / resolution */
default void notifyNetworkRequested(@NonNull MdnsServiceBrowserListener listener,
- @Nullable Network network) { }
+ @Nullable Network network, @NonNull SocketCreationCallback socketCreationCallback) {
+ socketCreationCallback.onSocketCreated(network);
+ }
/*** Notify that the network is unrequested */
default void notifyNetworkUnrequested(@NonNull MdnsServiceBrowserListener listener) { }
@@ -76,6 +78,13 @@
@Nullable Network network);
/*** Parse a mdns response failed */
- void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode);
+ void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode,
+ @Nullable Network network);
+ }
+
+ /*** Callback for requested socket creation */
+ interface SocketCreationCallback {
+ /*** Notify requested socket is created */
+ void onSocketCreated(@Nullable Network network);
}
}
diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
index f6a55c8..e7af569 100644
--- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
+++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
@@ -92,7 +92,7 @@
@Override
public String[] getAvailableInterfaces() throws RemoteException {
PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
- return mTracker.getInterfaces(checkUseRestrictedNetworksPermission());
+ return mTracker.getClientModeInterfaces(checkUseRestrictedNetworksPermission());
}
/**
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java
index 852cf42..d520757 100644
--- a/service-t/src/com/android/server/ethernet/EthernetTracker.java
+++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -385,7 +385,7 @@
return mFactory.hasInterface(iface);
}
- String[] getInterfaces(boolean includeRestricted) {
+ String[] getClientModeInterfaces(boolean includeRestricted) {
return mFactory.getAvailableInterfaces(includeRestricted);
}
@@ -428,9 +428,12 @@
// Remote process has already died
return;
}
- for (String iface : getInterfaces(canUseRestrictedNetworks)) {
+ for (String iface : getClientModeInterfaces(canUseRestrictedNetworks)) {
unicastInterfaceStateChange(listener, iface);
}
+ if (mTetheringInterfaceMode == INTERFACE_MODE_SERVER) {
+ unicastInterfaceStateChange(listener, mTetheringInterface);
+ }
unicastEthernetStateChange(listener, mEthernetState);
});
diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java
index e0abdf1..5952eae 100644
--- a/service-t/src/com/android/server/net/NetworkStatsFactory.java
+++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java
@@ -34,8 +34,6 @@
import java.io.IOException;
import java.net.ProtocolException;
-import java.util.Arrays;
-import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -147,36 +145,6 @@
}
/**
- * Get a set of interfaces containing specified ifaces and stacked interfaces.
- *
- * <p>The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces
- * on which the specified ones are stacked. Stacked interfaces are those noted with
- * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method
- * is called are guaranteed to be included.
- */
- public String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) {
- if (requiredIfaces == NetworkStats.INTERFACES_ALL) {
- return null;
- }
-
- HashSet<String> relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces));
- // ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse
- // elements as they existed upon construction exactly once, and may
- // (but are not guaranteed to) reflect any modifications subsequent to construction".
- // This is enough here.
- for (Map.Entry<String, String> entry : mStackedIfaces.entrySet()) {
- if (relatedIfaces.contains(entry.getKey())) {
- relatedIfaces.add(entry.getValue());
- } else if (relatedIfaces.contains(entry.getValue())) {
- relatedIfaces.add(entry.getKey());
- }
- }
-
- String[] outArray = new String[relatedIfaces.size()];
- return relatedIfaces.toArray(outArray);
- }
-
- /**
* Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}.
* @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map)
*/
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 9176ec2..961337d 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -106,6 +106,7 @@
import android.net.TetherStatsParcel;
import android.net.TetheringManager;
import android.net.TrafficStats;
+import android.net.TransportInfo;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.netstats.IUsageCallback;
@@ -113,6 +114,7 @@
import android.net.netstats.provider.INetworkStatsProvider;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.net.netstats.provider.NetworkStatsProvider;
+import android.net.wifi.WifiInfo;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -537,7 +539,8 @@
BroadcastOptions.makeBasic())
.setDeliveryGroupPolicy(
ConstantsShim.DELIVERY_GROUP_POLICY_MOST_RECENT)
- .setDeferUntilActive(true)
+ .setDeferralPolicy(
+ ConstantsShim.DEFERRAL_POLICY_UNTIL_ACTIVE)
.toBundle();
} catch (UnsupportedApiLevelException e) {
Log.wtf(TAG, "Using unsupported API" + e);
@@ -1729,11 +1732,7 @@
PermissionUtils.enforceNetworkStackPermission(mContext);
try {
final String[] ifaceArray = getAllIfacesSinceBoot(transport);
- // TODO(b/215633405) : mMobileIfaces and mWifiIfaces already contain the stacked
- // interfaces, so this is not useful, remove it.
- final String[] ifacesToQuery =
- mStatsFactory.augmentWithStackedInterfaces(ifaceArray);
- final NetworkStats stats = getNetworkStatsUidDetail(ifacesToQuery);
+ final NetworkStats stats = getNetworkStatsUidDetail(ifaceArray);
// Clear the interfaces of the stats before returning, so callers won't get this
// information. This is because no caller needs this information for now, and it
// makes it easier to change the implementation later by using the histories in the
@@ -2125,6 +2124,14 @@
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
isDefault, ratType);
+ // If WifiInfo contains a null network key then this identity should not be added into
+ // the network identity set. See b/266598304.
+ final TransportInfo transportInfo = snapshot.getNetworkCapabilities()
+ .getTransportInfo();
+ if (transportInfo instanceof WifiInfo) {
+ final WifiInfo info = (WifiInfo) transportInfo;
+ if (info.getNetworkKey() == null) continue;
+ }
// Traffic occurring on the base interface is always counted for
// both total usage and UID details.
final String baseIface = snapshot.getLinkProperties().getInterfaceName();
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index 5b42659..dae45f3 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -177,7 +177,7 @@
jobject clazz) {
// Will eventually be bound to htons(ETH_P_IPV6) protocol,
// but only after appropriate bpf filter is attached.
- int sock = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ const int sock = socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC, 0);
if (sock < 0) {
throwIOException(env, "packet socket failed", errno);
return -1;
diff --git a/service/native/libs/libclat/Android.bp b/service/native/libs/libclat/Android.bp
index 54d40ac..996706e 100644
--- a/service/native/libs/libclat/Android.bp
+++ b/service/native/libs/libclat/Android.bp
@@ -23,6 +23,9 @@
"clatutils.cpp",
],
stl: "libc++_static",
+ header_libs: [
+ "bpf_headers",
+ ],
static_libs: [
"libip_checksum",
],
diff --git a/service/native/libs/libclat/clatutils.cpp b/service/native/libs/libclat/clatutils.cpp
index c6a9781..6c5c9e3 100644
--- a/service/native/libs/libclat/clatutils.cpp
+++ b/service/native/libs/libclat/clatutils.cpp
@@ -25,6 +25,8 @@
#include <string.h>
#include <unistd.h>
+#include <bpf/BpfClassic.h>
+
extern "C" {
#include "checksum.h"
}
@@ -33,11 +35,9 @@
namespace net {
namespace clat {
-bool isIpv4AddressFree(in_addr_t addr) {
- int s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (s == -1) {
- return 0;
- }
+bool isIpv4AddressFree(const in_addr_t addr) {
+ const int s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (s == -1) return 0;
// Attempt to connect to the address. If the connection succeeds and getsockname returns the
// same then the address is already assigned to the system and we can't use it.
@@ -47,9 +47,10 @@
.sin_addr = {addr},
};
socklen_t len = sizeof(sin);
- bool inuse = connect(s, (struct sockaddr*)&sin, sizeof(sin)) == 0 &&
- getsockname(s, (struct sockaddr*)&sin, &len) == 0 && (size_t)len >= sizeof(sin) &&
- sin.sin_addr.s_addr == addr;
+ const bool inuse = !connect(s, (struct sockaddr*)&sin, sizeof(sin)) &&
+ !getsockname(s, (struct sockaddr*)&sin, &len) &&
+ len == (socklen_t)sizeof(sin) &&
+ sin.sin_addr.s_addr == addr;
close(s);
return !inuse;
@@ -59,36 +60,30 @@
// ip - the IP address from the configuration file
// prefixlen - the length of the prefix from which addresses may be selected.
// returns: the IPv4 address, or INADDR_NONE if no addresses were available
-in_addr_t selectIpv4Address(const in_addr ip, int16_t prefixlen) {
+in_addr_t selectIpv4Address(const in_addr ip, const int16_t prefixlen) {
return selectIpv4AddressInternal(ip, prefixlen, isIpv4AddressFree);
}
// Only allow testing to use this function directly. Otherwise call selectIpv4Address(ip, pfxlen)
// which has applied valid isIpv4AddressFree function pointer.
-in_addr_t selectIpv4AddressInternal(const in_addr ip, int16_t prefixlen,
- isIpv4AddrFreeFn isIpv4AddressFreeFunc) {
+in_addr_t selectIpv4AddressInternal(const in_addr ip, const int16_t prefixlen,
+ const isIpv4AddrFreeFn isIpv4AddressFreeFunc) {
// Impossible! Only test allows to apply fn.
- if (isIpv4AddressFreeFunc == nullptr) {
- return INADDR_NONE;
- }
+ if (isIpv4AddressFreeFunc == nullptr) return INADDR_NONE;
// Don't accept prefixes that are too large because we scan addresses one by one.
- if (prefixlen < 16 || prefixlen > 32) {
- return INADDR_NONE;
- }
+ if (prefixlen < 16 || prefixlen > 32) return INADDR_NONE;
// All these are in host byte order.
- in_addr_t mask = 0xffffffff >> (32 - prefixlen) << (32 - prefixlen);
- in_addr_t ipv4 = ntohl(ip.s_addr);
- in_addr_t first_ipv4 = ipv4;
- in_addr_t prefix = ipv4 & mask;
+ const uint32_t mask = 0xffffffff >> (32 - prefixlen) << (32 - prefixlen);
+ uint32_t ipv4 = ntohl(ip.s_addr);
+ const uint32_t first_ipv4 = ipv4;
+ const uint32_t prefix = ipv4 & mask;
// Pick the first IPv4 address in the pool, wrapping around if necessary.
// So, for example, 192.0.0.4 -> 192.0.0.5 -> 192.0.0.6 -> 192.0.0.7 -> 192.0.0.0.
do {
- if (isIpv4AddressFreeFunc(htonl(ipv4))) {
- return htonl(ipv4);
- }
+ if (isIpv4AddressFreeFunc(htonl(ipv4))) return htonl(ipv4);
ipv4 = prefix | ((ipv4 + 1) & ~mask);
} while (ipv4 != first_ipv4);
@@ -96,7 +91,7 @@
}
// Alters the bits in the IPv6 address to make them checksum neutral with v4 and nat64Prefix.
-void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix) {
+void makeChecksumNeutral(in6_addr* const v6, const in_addr v4, const in6_addr& nat64Prefix) {
// Fill last 8 bytes of IPv6 address with random bits.
arc4random_buf(&v6->s6_addr[8], 8);
@@ -118,33 +113,35 @@
}
// Picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix.
-int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix,
- in6_addr* v6, uint32_t mark) {
- int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+int generateIpv6Address(const char* const iface, const in_addr v4, const in6_addr& nat64Prefix,
+ in6_addr* const v6, const uint32_t mark) {
+ const int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (s == -1) return -errno;
// Socket's mark affects routing decisions (network selection)
// An fwmark is necessary for clat to bypass the VPN during initialization.
if (setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))) {
- int ret = errno;
- ALOGE("setsockopt(SOL_SOCKET, SO_MARK) failed: %s", strerror(errno));
+ const int err = errno;
+ ALOGE("setsockopt(SOL_SOCKET, SO_MARK) failed: %s", strerror(err));
close(s);
- return -ret;
+ return -err;
}
- if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface) + 1) == -1) {
+ if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface) + 1)) {
+ const int err = errno;
+ ALOGE("setsockopt(SOL_SOCKET, SO_BINDTODEVICE, '%s') failed: %s", iface, strerror(err));
close(s);
- return -errno;
+ return -err;
}
sockaddr_in6 sin6 = {.sin6_family = AF_INET6, .sin6_addr = nat64Prefix};
- if (connect(s, reinterpret_cast<struct sockaddr*>(&sin6), sizeof(sin6)) == -1) {
+ if (connect(s, reinterpret_cast<struct sockaddr*>(&sin6), sizeof(sin6))) {
close(s);
return -errno;
}
socklen_t len = sizeof(sin6);
- if (getsockname(s, reinterpret_cast<struct sockaddr*>(&sin6), &len) == -1) {
+ if (getsockname(s, reinterpret_cast<struct sockaddr*>(&sin6), &len)) {
close(s);
return -errno;
}
@@ -163,21 +160,22 @@
return 0;
}
-int detect_mtu(const struct in6_addr* plat_subnet, uint32_t plat_suffix, uint32_t mark) {
+int detect_mtu(const struct in6_addr* const plat_subnet, const uint32_t plat_suffix,
+ const uint32_t mark) {
// Create an IPv6 UDP socket.
- int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ const int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (s < 0) {
- int ret = errno;
- ALOGE("socket(AF_INET6, SOCK_DGRAM, 0) failed: %s", strerror(errno));
- return -ret;
+ const int err = errno;
+ ALOGE("socket(AF_INET6, SOCK_DGRAM, 0) failed: %s", strerror(err));
+ return -err;
}
// Socket's mark affects routing decisions (network selection)
if (setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))) {
- int ret = errno;
- ALOGE("setsockopt(SOL_SOCKET, SO_MARK) failed: %s", strerror(errno));
+ const int err = errno;
+ ALOGE("setsockopt(SOL_SOCKET, SO_MARK) failed: %s", strerror(err));
close(s);
- return -ret;
+ return -err;
}
// Try to connect udp socket to plat_subnet(96 bits):plat_suffix(32 bits)
@@ -187,20 +185,20 @@
};
dst.sin6_addr.s6_addr32[3] = plat_suffix;
if (connect(s, (struct sockaddr*)&dst, sizeof(dst))) {
- int ret = errno;
- ALOGE("connect() failed: %s", strerror(errno));
+ const int err = errno;
+ ALOGE("connect() failed: %s", strerror(err));
close(s);
- return -ret;
+ return -err;
}
// Fetch the socket's IPv6 mtu - this is effectively fetching mtu from routing table
int mtu;
socklen_t sz_mtu = sizeof(mtu);
if (getsockopt(s, SOL_IPV6, IPV6_MTU, &mtu, &sz_mtu)) {
- int ret = errno;
- ALOGE("getsockopt(SOL_IPV6, IPV6_MTU) failed: %s", strerror(errno));
+ const int err = errno;
+ ALOGE("getsockopt(SOL_IPV6, IPV6_MTU) failed: %s", strerror(err));
close(s);
- return -ret;
+ return -err;
}
if (sz_mtu != sizeof(mtu)) {
ALOGE("getsockopt(SOL_IPV6, IPV6_MTU) returned unexpected size: %d", sz_mtu);
@@ -219,34 +217,26 @@
* ifindex - index of interface to add the filter to
* returns: 0 on success, -errno on failure
*/
-int configure_packet_socket(int sock, in6_addr* addr, int ifindex) {
- uint32_t* ipv6 = addr->s6_addr32;
-
+int configure_packet_socket(const int sock, const in6_addr* const addr, const int ifindex) {
// clang-format off
struct sock_filter filter_code[] = {
- // Load the first four bytes of the IPv6 destination address (starts 24 bytes in).
- // Compare it against the first four bytes of our IPv6 address, in host byte order (BPF loads
- // are always in host byte order). If it matches, continue with next instruction (JMP 0). If it
- // doesn't match, jump ahead to statement that returns 0 (ignore packet). Repeat for the other
- // three words of the IPv6 address, and if they all match, return full packet (accept packet).
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 24),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[0]), 0, 7),
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 28),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[1]), 0, 5),
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 32),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[2]), 0, 3),
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 36),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[3]), 0, 1),
- BPF_STMT(BPF_RET | BPF_K, 0xFFFFFFFF),
- BPF_STMT(BPF_RET | BPF_K, 0),
+ BPF_LOAD_IPV6_BE32(daddr.s6_addr32[0]),
+ BPF2_REJECT_IF_NOT_EQUAL(ntohl(addr->s6_addr32[0])),
+ BPF_LOAD_IPV6_BE32(daddr.s6_addr32[1]),
+ BPF2_REJECT_IF_NOT_EQUAL(ntohl(addr->s6_addr32[1])),
+ BPF_LOAD_IPV6_BE32(daddr.s6_addr32[2]),
+ BPF2_REJECT_IF_NOT_EQUAL(ntohl(addr->s6_addr32[2])),
+ BPF_LOAD_IPV6_BE32(daddr.s6_addr32[3]),
+ BPF2_REJECT_IF_NOT_EQUAL(ntohl(addr->s6_addr32[3])),
+ BPF_ACCEPT,
};
// clang-format on
struct sock_fprog filter = {sizeof(filter_code) / sizeof(filter_code[0]), filter_code};
if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
- int res = errno;
- ALOGE("attach packet filter failed: %s", strerror(errno));
- return -res;
+ const int err = errno;
+ ALOGE("attach packet filter failed: %s", strerror(err));
+ return -err;
}
struct sockaddr_ll sll = {
@@ -257,9 +247,9 @@
PACKET_OTHERHOST, // The 464xlat IPv6 address is not assigned to the kernel.
};
if (bind(sock, (struct sockaddr*)&sll, sizeof(sll))) {
- int res = errno;
- ALOGE("binding packet socket: %s", strerror(errno));
- return -res;
+ const int err = errno;
+ ALOGE("binding packet socket: %s", strerror(err));
+ return -err;
}
return 0;
diff --git a/service/native/libs/libclat/clatutils_test.cpp b/service/native/libs/libclat/clatutils_test.cpp
index abd4e81..f4f97db 100644
--- a/service/native/libs/libclat/clatutils_test.cpp
+++ b/service/native/libs/libclat/clatutils_test.cpp
@@ -165,7 +165,7 @@
TunInterface v6Iface;
ASSERT_EQ(0, v6Iface.init());
- int s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IPV6));
+ const int s = socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC, htons(ETH_P_IPV6));
EXPECT_LE(0, s);
struct in6_addr addr6;
EXPECT_EQ(1, inet_pton(AF_INET6, "2001:db8::f00", &addr6));
diff --git a/service/native/libs/libclat/include/libclat/clatutils.h b/service/native/libs/libclat/include/libclat/clatutils.h
index 991b193..6e17e67 100644
--- a/service/native/libs/libclat/include/libclat/clatutils.h
+++ b/service/native/libs/libclat/include/libclat/clatutils.h
@@ -20,17 +20,19 @@
namespace net {
namespace clat {
-bool isIpv4AddressFree(in_addr_t addr);
-in_addr_t selectIpv4Address(const in_addr ip, int16_t prefixlen);
-void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix);
-int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix,
- in6_addr* v6, uint32_t mark);
-int detect_mtu(const struct in6_addr* plat_subnet, uint32_t plat_suffix, uint32_t mark);
-int configure_packet_socket(int sock, in6_addr* addr, int ifindex);
+bool isIpv4AddressFree(const in_addr_t addr);
+in_addr_t selectIpv4Address(const in_addr ip, const int16_t prefixlen);
+void makeChecksumNeutral(in6_addr* const v6, const in_addr v4, const in6_addr& nat64Prefix);
+int generateIpv6Address(const char* const iface, const in_addr v4, const in6_addr& nat64Prefix,
+ in6_addr* const v6, const uint32_t mark);
+int detect_mtu(const struct in6_addr* const plat_subnet, const uint32_t plat_suffix,
+ const uint32_t mark);
+int configure_packet_socket(const int sock, const in6_addr* const addr, const int ifindex);
// For testing
-typedef bool (*isIpv4AddrFreeFn)(in_addr_t);
-in_addr_t selectIpv4AddressInternal(const in_addr ip, int16_t prefixlen, isIpv4AddrFreeFn fn);
+typedef bool (*isIpv4AddrFreeFn)(const in_addr_t);
+in_addr_t selectIpv4AddressInternal(const in_addr ip, const int16_t prefixlen,
+ const isIpv4AddrFreeFn fn);
} // namespace clat
} // namespace net
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 4c55afe..e969cd6 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -911,7 +911,7 @@
// This is the cache for the packageName -> ApplicationSelfCertifiedNetworkCapabilities. This
// value can be accessed from both handler thread and any random binder thread. Therefore,
- // accessing this value requires holding a lock.
+ // accessing this value requires holding a lock. The cache is the same across all the users.
@GuardedBy("mSelfCertifiedCapabilityCache")
private final Map<String, ApplicationSelfCertifiedNetworkCapabilities>
mSelfCertifiedCapabilityCache = new HashMap<>();
@@ -3133,7 +3133,7 @@
optsShim.setDeliveryGroupPolicy(ConstantsShim.DELIVERY_GROUP_POLICY_MOST_RECENT);
optsShim.setDeliveryGroupMatchingKey(ConnectivityManager.CONNECTIVITY_ACTION,
createDeliveryGroupKeyForConnectivityAction(info));
- optsShim.setDeferUntilActive(true);
+ optsShim.setDeferralPolicy(ConstantsShim.DEFERRAL_POLICY_UNTIL_ACTIVE);
} catch (UnsupportedApiLevelException e) {
Log.wtf(TAG, "Using unsupported API" + e);
}
@@ -7001,6 +7001,7 @@
return;
}
ApplicationSelfCertifiedNetworkCapabilities applicationNetworkCapabilities;
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mSelfCertifiedCapabilityCache) {
applicationNetworkCapabilities = mSelfCertifiedCapabilityCache.get(
@@ -7027,6 +7028,8 @@
+ " property");
} catch (XmlPullParserException | IOException | InvalidTagException e) {
throw new SecurityException(e.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
applicationNetworkCapabilities.enforceSelfCertifiedNetworkCapabilitiesDeclared(
@@ -8467,6 +8470,7 @@
exemptUids[1] = nai.networkCapabilities.getOwnerUid();
UidRangeParcel[] ranges = toUidRangeStableParcels(uidRanges);
+ // Close sockets before modifying uid ranges so that RST packets can reach to the server.
maybeCloseSockets(nai, ranges, exemptUids);
try {
if (add) {
@@ -8480,6 +8484,7 @@
loge("Exception while " + (add ? "adding" : "removing") + " uid ranges " + uidRanges +
" on netId " + nai.network.netId + ". " + e);
}
+ // Close sockets that established connection while requesting netd.
maybeCloseSockets(nai, ranges, exemptUids);
}
diff --git a/tests/common/java/android/net/netstats/NetworkTemplateTest.kt b/tests/common/java/android/net/netstats/NetworkTemplateTest.kt
index c2eacbc..fb6759e 100644
--- a/tests/common/java/android/net/netstats/NetworkTemplateTest.kt
+++ b/tests/common/java/android/net/netstats/NetworkTemplateTest.kt
@@ -165,23 +165,6 @@
}
@Test
- fun testUnsupportedAppUsageConstructor() {
- val templateMobile = NetworkTemplate(MATCH_MOBILE, null /* subscriberId */,
- null /* wifiNetworkKey */)
- val templateMobileWildcard = NetworkTemplate(6 /* MATCH_MOBILE_WILDCARD */,
- null /* subscriberId */, null /* wifiNetworkKey */)
- val templateWifiWildcard = NetworkTemplate(7 /* MATCH_WIFI_WILDCARD */,
- null /* subscriberId */,
- null /* wifiNetworkKey */)
-
- assertEquals(NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES).build(),
- templateMobile)
- assertEquals(NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES).build(),
- templateMobileWildcard)
- assertEquals(NetworkTemplate.Builder(MATCH_WIFI).build(), templateWifiWildcard)
- }
-
- @Test
fun testBuilderWifiNetworkKeys() {
// Verify template builder which generates same template with the given different
// sequence keys.
diff --git a/tests/cts/hostside/TEST_MAPPING b/tests/cts/hostside/TEST_MAPPING
index ab6de82..2cfd7af 100644
--- a/tests/cts/hostside/TEST_MAPPING
+++ b/tests/cts/hostside/TEST_MAPPING
@@ -8,6 +8,9 @@
},
{
"exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
}
]
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
index a5bf000..b6902b5 100755
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -18,6 +18,8 @@
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
import static android.content.pm.PackageManager.FEATURE_WIFI;
import static android.net.ConnectivityManager.TYPE_VPN;
@@ -36,6 +38,12 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_DATA_RECEIVED;
+import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_ERROR;
+import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_PAUSED;
+import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_RESUMED;
+import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_STARTED;
+import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_STOPPED;
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN;
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE;
import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_EXPORTED;
@@ -64,6 +72,7 @@
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.IpSecManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
@@ -71,6 +80,7 @@
import android.net.NetworkRequest;
import android.net.Proxy;
import android.net.ProxyInfo;
+import android.net.SocketKeepalive;
import android.net.TestNetworkInterface;
import android.net.TestNetworkManager;
import android.net.TransportInfo;
@@ -79,6 +89,7 @@
import android.net.VpnService;
import android.net.VpnTransportInfo;
import android.net.cts.util.CtsNetUtils;
+import android.net.util.KeepaliveUtils;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Handler;
@@ -87,6 +98,7 @@
import android.os.Process;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
@@ -105,6 +117,8 @@
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
import com.android.modules.utils.build.SdkLevel;
+import com.android.net.module.util.ArrayTrackRecord;
+import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.PacketBuilder;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -141,6 +155,7 @@
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
@@ -190,6 +205,12 @@
public static int SOCKET_TIMEOUT_MS = 100;
public static String TEST_HOST = "connectivitycheck.gstatic.com";
+ private static final String AUTOMATIC_ON_OFF_KEEPALIVE_VERSION =
+ "automatic_on_off_keepalive_version";
+ // Enabled since version 1 means it's always enabled because the version is always above 1
+ private static final String AUTOMATIC_ON_OFF_KEEPALIVE_ENABLED = "1";
+ private static final long TEST_TCP_POLLING_TIMER_EXPIRED_PERIOD_MS = 60_000L;
+
private UiDevice mDevice;
private MyActivity mActivity;
private String mPackageName;
@@ -201,13 +222,15 @@
private Context mTestContext;
private Context mTargetContext;
Network mNetwork;
- NetworkCallback mCallback;
final Object mLock = new Object();
final Object mLockShutdown = new Object();
private String mOldPrivateDnsMode;
private String mOldPrivateDnsSpecifier;
+ // The registered callbacks.
+ private List<NetworkCallback> mRegisteredCallbacks = new ArrayList<>();
+
@Rule
public final DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
@@ -228,7 +251,6 @@
@Before
public void setUp() throws Exception {
mNetwork = null;
- mCallback = null;
mTestContext = getInstrumentation().getContext();
mTargetContext = getInstrumentation().getTargetContext();
storePrivateDnsSetting();
@@ -248,15 +270,40 @@
public void tearDown() throws Exception {
restorePrivateDnsSetting();
mRemoteSocketFactoryClient.unbind();
- if (mCallback != null) {
- mCM.unregisterNetworkCallback(mCallback);
- }
mCtsNetUtils.tearDown();
Log.i(TAG, "Stopping VPN");
stopVpn();
+ unregisterRegisteredCallbacks();
mActivity.finish();
}
+ private void registerNetworkCallback(NetworkRequest request, NetworkCallback callback) {
+ mCM.registerNetworkCallback(request, callback);
+ mRegisteredCallbacks.add(callback);
+ }
+
+ private void registerDefaultNetworkCallback(NetworkCallback callback) {
+ mCM.registerDefaultNetworkCallback(callback);
+ mRegisteredCallbacks.add(callback);
+ }
+
+ private void registerSystemDefaultNetworkCallback(NetworkCallback callback, Handler h) {
+ mCM.registerSystemDefaultNetworkCallback(callback, h);
+ mRegisteredCallbacks.add(callback);
+ }
+
+ private void registerDefaultNetworkCallbackForUid(int uid, NetworkCallback callback,
+ Handler h) {
+ mCM.registerDefaultNetworkCallbackForUid(uid, callback, h);
+ mRegisteredCallbacks.add(callback);
+ }
+
+ private void unregisterRegisteredCallbacks() {
+ for (NetworkCallback callback: mRegisteredCallbacks) {
+ mCM.unregisterNetworkCallback(callback);
+ }
+ }
+
private void prepareVpn() throws Exception {
final int REQUEST_ID = 42;
@@ -372,7 +419,7 @@
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
- mCallback = new NetworkCallback() {
+ final NetworkCallback callback = new NetworkCallback() {
public void onAvailable(Network network) {
synchronized (mLock) {
Log.i(TAG, "Got available callback for network=" + network);
@@ -381,7 +428,7 @@
}
}
};
- mCM.registerNetworkCallback(request, mCallback); // Unregistered in tearDown.
+ registerNetworkCallback(request, callback);
// Start the service and wait up for TIMEOUT_MS ms for the VPN to come up.
establishVpn(addresses, routes, excludedRoutes, allowedApplications, disallowedApplications,
@@ -406,7 +453,7 @@
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
- mCallback = new NetworkCallback() {
+ final NetworkCallback callback = new NetworkCallback() {
public void onLost(Network network) {
synchronized (mLockShutdown) {
Log.i(TAG, "Got lost callback for network=" + network
@@ -417,7 +464,7 @@
}
}
};
- mCM.registerNetworkCallback(request, mCallback); // Unregistered in tearDown.
+ registerNetworkCallback(request, callback);
// Simply calling mActivity.stopService() won't stop the service, because the system binds
// to the service for the purpose of sending it a revoke command if another VPN comes up,
// and stopping a bound service has no effect. Instead, "start" the service again with an
@@ -778,14 +825,10 @@
}
};
- mCM.registerNetworkCallback(request, callback);
+ registerNetworkCallback(request, callback);
- try {
- assertTrue("Private DNS hostname was not " + hostname + " after " + TIMEOUT_MS + "ms",
- latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- } finally {
- mCM.unregisterNetworkCallback(callback);
- }
+ assertTrue("Private DNS hostname was not " + hostname + " after " + TIMEOUT_MS + "ms",
+ latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
private void setAndVerifyPrivateDns(boolean strictMode) throws Exception {
@@ -872,7 +915,7 @@
false /* isAlwaysMetered */);
// Acquire the NETWORK_SETTINGS permission for getting the underlying networks.
runWithShellPermissionIdentity(() -> {
- mCM.registerNetworkCallback(makeVpnNetworkRequest(), callback);
+ registerNetworkCallback(makeVpnNetworkRequest(), callback);
// Check that this VPN doesn't have any underlying networks.
expectUnderlyingNetworks(callback, new ArrayList<Network>());
@@ -905,8 +948,6 @@
} else {
mCtsNetUtils.ensureWifiDisconnected(null);
}
- }, () -> {
- mCM.unregisterNetworkCallback(callback);
});
}
@@ -940,9 +981,9 @@
UserHandle.of(5 /* userId */).getUid(Process.FIRST_APPLICATION_UID);
final Handler h = new Handler(Looper.getMainLooper());
runWithShellPermissionIdentity(() -> {
- mCM.registerSystemDefaultNetworkCallback(systemDefaultCallback, h);
- mCM.registerDefaultNetworkCallbackForUid(otherUid, otherUidCallback, h);
- mCM.registerDefaultNetworkCallbackForUid(Process.myUid(), myUidCallback, h);
+ registerSystemDefaultNetworkCallback(systemDefaultCallback, h);
+ registerDefaultNetworkCallbackForUid(otherUid, otherUidCallback, h);
+ registerDefaultNetworkCallbackForUid(Process.myUid(), myUidCallback, h);
}, NETWORK_SETTINGS);
for (TestableNetworkCallback callback :
List.of(systemDefaultCallback, otherUidCallback, myUidCallback)) {
@@ -993,9 +1034,6 @@
// fail and could cause the default network to switch (e.g., from wifi to cellular).
systemDefaultCallback.assertNoCallback();
otherUidCallback.assertNoCallback();
- mCM.unregisterNetworkCallback(systemDefaultCallback);
- mCM.unregisterNetworkCallback(otherUidCallback);
- mCM.unregisterNetworkCallback(myUidCallback);
}
checkStrictModePrivateDns();
@@ -1024,6 +1062,183 @@
checkStrictModePrivateDns();
}
+ private int getSupportedKeepalives(NetworkCapabilities nc) throws Exception {
+ // Get number of supported concurrent keepalives for testing network.
+ final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(
+ mTargetContext);
+ return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
+ keepalivesPerTransport, nc);
+ }
+
+ // This class can't be private, otherwise the constants can't be static imported.
+ static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback {
+ // This must be larger than the alarm delay in AutomaticOnOffKeepaliveTracker.
+ private static final int KEEPALIVE_TIMEOUT_MS = 10_000;
+ public enum CallbackType {
+ ON_STARTED,
+ ON_RESUMED,
+ ON_STOPPED,
+ ON_PAUSED,
+ ON_ERROR,
+ ON_DATA_RECEIVED
+ }
+ private ArrayTrackRecord<CallbackType> mHistory = new ArrayTrackRecord<>();
+ private ArrayTrackRecord<CallbackType>.ReadHead mEvents = mHistory.newReadHead();
+
+ @Override
+ public void onStarted() {
+ mHistory.add(ON_STARTED);
+ }
+
+ @Override
+ public void onResumed() {
+ mHistory.add(ON_RESUMED);
+ }
+
+ @Override
+ public void onStopped() {
+ mHistory.add(ON_STOPPED);
+ }
+
+ @Override
+ public void onPaused() {
+ mHistory.add(ON_PAUSED);
+ }
+
+ @Override
+ public void onError(final int error) {
+ mHistory.add(ON_ERROR);
+ }
+
+ @Override
+ public void onDataReceived() {
+ mHistory.add(ON_DATA_RECEIVED);
+ }
+
+ public CallbackType poll() {
+ return mEvents.poll(KEEPALIVE_TIMEOUT_MS, it -> true);
+ }
+ }
+
+ private InetAddress getV4AddrByName(final String hostname) throws Exception {
+ final InetAddress[] allAddrs = InetAddress.getAllByName(hostname);
+ for (InetAddress addr : allAddrs) {
+ if (addr instanceof Inet4Address) return addr;
+ }
+ return null;
+ }
+
+ @Test
+ public void testAutomaticOnOffKeepaliveModeNoClose() throws Exception {
+ doTestAutomaticOnOffKeepaliveMode(false);
+ }
+
+ @Test
+ public void testAutomaticOnOffKeepaliveModeClose() throws Exception {
+ doTestAutomaticOnOffKeepaliveMode(true);
+ }
+
+ private void startKeepalive(SocketKeepalive kp, TestSocketKeepaliveCallback callback) {
+ runWithShellPermissionIdentity(() -> {
+ // Only SocketKeepalive.start() requires READ_DEVICE_CONFIG because feature is protected
+ // by a feature flag. But also verify ON_STARTED callback received here to ensure
+ // keepalive is indeed started because start() runs in the executor thread and shell
+ // permission may be dropped before reading DeviceConfig.
+ kp.start(10 /* intervalSec */, SocketKeepalive.FLAG_AUTOMATIC_ON_OFF, mNetwork);
+
+ // Verify callback status.
+ assertEquals(ON_STARTED, callback.poll());
+ }, READ_DEVICE_CONFIG);
+ }
+
+ private void doTestAutomaticOnOffKeepaliveMode(final boolean closeSocket) throws Exception {
+ assumeTrue(supportedHardware());
+
+ // Get default network first before starting VPN
+ final Network defaultNetwork = mCM.getActiveNetwork();
+ final TestableNetworkCallback cb = new TestableNetworkCallback();
+ registerDefaultNetworkCallback(cb);
+ cb.expect(CallbackEntry.AVAILABLE, defaultNetwork);
+ final NetworkCapabilities cap =
+ cb.expect(CallbackEntry.NETWORK_CAPS_UPDATED, defaultNetwork).getCaps();
+ final LinkProperties lp =
+ cb.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, defaultNetwork).getLp();
+ cb.expect(CallbackEntry.BLOCKED_STATUS, defaultNetwork);
+
+ // Setup VPN
+ final FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS);
+ final String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName;
+ startVpn(new String[]{"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
+ new String[]{"192.0.2.0/24", "2001:db8::/32"},
+ allowedApps, "" /* disallowedApplications */, null /* proxyInfo */,
+ null /* underlyingNetworks */, false /* isAlwaysMetered */);
+ assertSocketClosed(fd, TEST_HOST);
+
+ // Decrease the TCP polling timer for testing.
+ runWithShellPermissionIdentity(() -> mCM.setTestLowTcpPollingTimerForKeepalive(
+ System.currentTimeMillis() + TEST_TCP_POLLING_TIMER_EXPIRED_PERIOD_MS),
+ NETWORK_SETTINGS);
+
+ // Setup keepalive
+ final int supported = getSupportedKeepalives(cap);
+ assumeTrue("Network " + defaultNetwork + " does not support keepalive", supported != 0);
+ final InetAddress srcAddr = CollectionUtils.findFirst(lp.getAddresses(),
+ it -> it instanceof Inet4Address);
+ assumeTrue("This test requires native IPv4", srcAddr != null);
+
+ final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
+
+ final String origMode = runWithShellPermissionIdentity(() -> {
+ final String mode = DeviceConfig.getProperty(
+ DeviceConfig.NAMESPACE_CONNECTIVITY, AUTOMATIC_ON_OFF_KEEPALIVE_VERSION);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_CONNECTIVITY,
+ AUTOMATIC_ON_OFF_KEEPALIVE_VERSION,
+ AUTOMATIC_ON_OFF_KEEPALIVE_ENABLED, false /* makeDefault */);
+ return mode;
+ }, READ_DEVICE_CONFIG, WRITE_DEVICE_CONFIG);
+
+ final IpSecManager ipSec = mTargetContext.getSystemService(IpSecManager.class);
+ SocketKeepalive kp = null;
+ try (IpSecManager.UdpEncapsulationSocket nattSocket = ipSec.openUdpEncapsulationSocket()) {
+ final InetAddress dstAddr = getV4AddrByName(TEST_HOST);
+ assertNotNull(dstAddr);
+
+ // Start keepalive with dynamic keepalive mode enabled.
+ final Executor executor = mTargetContext.getMainExecutor();
+ kp = mCM.createSocketKeepalive(defaultNetwork, nattSocket,
+ srcAddr, dstAddr, executor, callback);
+ startKeepalive(kp, callback);
+
+ // There should be no open sockets on the VPN network, because any
+ // open sockets were closed when startVpn above was called. So the
+ // first TCP poll should trigger ON_PAUSED.
+ assertEquals(ON_PAUSED, callback.poll());
+
+ final Socket s = new Socket();
+ mNetwork.bindSocket(s);
+ s.connect(new InetSocketAddress(dstAddr, 80));
+ assertEquals(ON_RESUMED, callback.poll());
+
+ if (closeSocket) {
+ s.close();
+ assertEquals(ON_PAUSED, callback.poll());
+ }
+
+ kp.stop();
+ assertEquals(ON_STOPPED, callback.poll());
+ } finally {
+ if (kp != null) kp.stop();
+
+ runWithShellPermissionIdentity(() -> {
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_CONNECTIVITY,
+ AUTOMATIC_ON_OFF_KEEPALIVE_VERSION,
+ origMode, false);
+ mCM.setTestLowTcpPollingTimerForKeepalive(0);
+ }, WRITE_DEVICE_CONFIG, NETWORK_SETTINGS);
+ }
+ }
+
@Test
public void testAppDisallowed() throws Exception {
assumeTrue(supportedHardware());
@@ -1623,7 +1838,7 @@
testAndCleanup(() -> {
runWithShellPermissionIdentity(() -> {
- mCM.registerDefaultNetworkCallbackForUid(remoteUid, remoteUidCallback,
+ registerDefaultNetworkCallbackForUid(remoteUid, remoteUidCallback,
new Handler(Looper.getMainLooper()));
}, NETWORK_SETTINGS);
remoteUidCallback.expectAvailableCallbacksWithBlockedReasonNone(network);
@@ -1659,8 +1874,6 @@
checkBlockIncomingPacket(tunFd, remoteUdpFd, EXPECT_BLOCK);
}, /* cleanup */ () -> {
- mCM.unregisterNetworkCallback(remoteUidCallback);
- }, /* cleanup */ () -> {
Os.close(tunFd);
}, /* cleanup */ () -> {
Os.close(remoteUdpFd);
@@ -1684,7 +1897,7 @@
final int myUid = Process.myUid();
testAndCleanup(() -> {
- mCM.registerDefaultNetworkCallback(defaultNetworkCallback);
+ registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.expectAvailableCallbacks(defaultNetwork);
final Range<Integer> myUidRange = new Range<>(myUid, myUid);
@@ -1716,8 +1929,6 @@
defaultNetworkCallback.eventuallyExpect(CallbackEntry.AVAILABLE,
NETWORK_CALLBACK_TIMEOUT_MS,
entry -> defaultNetwork.equals(entry.getNetwork()));
- }, /* cleanup */ () -> {
- mCM.unregisterNetworkCallback(defaultNetworkCallback);
});
}
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 10a2821..603779d 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
@@ -16,6 +16,8 @@
package com.android.cts.net;
+import android.platform.test.annotations.RequiresDevice;
+
public class HostsideVpnTests extends HostsideNetworkTestCase {
@Override
@@ -89,6 +91,18 @@
TEST_PKG, TEST_PKG + ".VpnTest", "testAlwaysMeteredVpnWithNullUnderlyingNetwork");
}
+ @RequiresDevice // Keepalive is not supported on virtual hardware
+ public void testAutomaticOnOffKeepaliveModeClose() throws Exception {
+ runDeviceTests(
+ TEST_PKG, TEST_PKG + ".VpnTest", "testAutomaticOnOffKeepaliveModeClose");
+ }
+
+ @RequiresDevice // Keepalive is not supported on virtual hardware
+ public void testAutomaticOnOffKeepaliveModeNoClose() throws Exception {
+ runDeviceTests(
+ TEST_PKG, TEST_PKG + ".VpnTest", "testAutomaticOnOffKeepaliveModeNoClose");
+ }
+
public void testAlwaysMeteredVpnWithNonNullUnderlyingNetwork() throws Exception {
runDeviceTests(
TEST_PKG,
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index 7c24c95..dc22369 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
+++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -37,8 +37,6 @@
import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig
import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig
import android.net.cts.util.CtsNetUtils
-import com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTPS_URL
-import com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTP_URL
import android.platform.test.annotations.AppModeFull
import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY
@@ -47,28 +45,30 @@
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.runner.AndroidJUnit4
import com.android.modules.utils.build.SdkLevel.isAtLeastR
+import com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTPS_URL
+import com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTP_URL
import com.android.testutils.DeviceConfigRule
-import com.android.testutils.RecorderCallback
+import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
import com.android.testutils.TestHttpServer
import com.android.testutils.TestHttpServer.Request
import com.android.testutils.TestableNetworkCallback
import com.android.testutils.runAsShell
import fi.iki.elonen.NanoHTTPD.Response.Status
-import junit.framework.AssertionFailedError
-import org.junit.After
-import org.junit.Assume.assumeTrue
-import org.junit.Assume.assumeFalse
-import org.junit.Before
-import org.junit.BeforeClass
-import org.junit.Rule
-import org.junit.runner.RunWith
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
+import junit.framework.AssertionFailedError
import kotlin.test.Test
import kotlin.test.assertNotEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
+import org.junit.After
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Rule
+import org.junit.runner.RunWith
private const val TEST_HTTPS_URL_PATH = "/https_path"
private const val TEST_HTTP_URL_PATH = "/http_path"
@@ -151,8 +151,8 @@
.build()
val cellCb = TestableNetworkCallback(timeoutMs = TEST_TIMEOUT_MS)
cm.registerNetworkCallback(cellReq, cellCb)
- val cb = cellCb.eventuallyExpectOrNull<RecorderCallback.CallbackEntry.CapabilitiesChanged> {
- it.network == cellNetwork && it.caps.hasCapability(NET_CAPABILITY_VALIDATED)
+ val cb = cellCb.poll { it.network == cellNetwork &&
+ it is CapabilitiesChanged && it.caps.hasCapability(NET_CAPABILITY_VALIDATED)
}
assertNotNull(cb, "Mobile network $cellNetwork has no access to the internet. " +
"Check the mobile data connection.")
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 6925808..774176f 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -2434,11 +2434,11 @@
runWithShellPermissionIdentity(() -> registerDefaultNetworkCallbackForUid(
otherUid, otherUidCallback, handler), NETWORK_SETTINGS);
- final Network defaultNetwork = mCm.getActiveNetwork();
+ final Network defaultNetwork = myUidCallback.expect(CallbackEntry.AVAILABLE).getNetwork();
final List<DetailedBlockedStatusCallback> allCallbacks =
List.of(myUidCallback, otherUidCallback);
for (DetailedBlockedStatusCallback callback : allCallbacks) {
- callback.expectAvailableCallbacksWithBlockedReasonNone(defaultNetwork);
+ callback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
}
final Range<Integer> myUidRange = new Range<>(myUid, myUid);
@@ -3408,6 +3408,9 @@
private static final boolean EXPECT_PASS = false;
private static final boolean EXPECT_BLOCK = true;
+
+ // ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed
+ // DENYLIST means the firewall allows all by default, uids must be explicitly denyed
private static final boolean ALLOWLIST = true;
private static final boolean DENYLIST = false;
@@ -3473,17 +3476,49 @@
@Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
@AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testFirewallBlocking() {
- // ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed
+ public void testFirewallBlockingDozable() {
doTestFirewallBlocking(FIREWALL_CHAIN_DOZABLE, ALLOWLIST);
- doTestFirewallBlocking(FIREWALL_CHAIN_POWERSAVE, ALLOWLIST);
- doTestFirewallBlocking(FIREWALL_CHAIN_RESTRICTED, ALLOWLIST);
- doTestFirewallBlocking(FIREWALL_CHAIN_LOW_POWER_STANDBY, ALLOWLIST);
+ }
- // DENYLIST means the firewall allows all by default, uids must be explicitly denyed
+ @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
+ @AppModeFull(reason = "Socket cannot bind in instant app mode")
+ public void testFirewallBlockingPowersave() {
+ doTestFirewallBlocking(FIREWALL_CHAIN_POWERSAVE, ALLOWLIST);
+ }
+
+ @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
+ @AppModeFull(reason = "Socket cannot bind in instant app mode")
+ public void testFirewallBlockingRestricted() {
+ doTestFirewallBlocking(FIREWALL_CHAIN_RESTRICTED, ALLOWLIST);
+ }
+
+ @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
+ @AppModeFull(reason = "Socket cannot bind in instant app mode")
+ public void testFirewallBlockingLowPowerStandby() {
+ doTestFirewallBlocking(FIREWALL_CHAIN_LOW_POWER_STANDBY, ALLOWLIST);
+ }
+
+ @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
+ @AppModeFull(reason = "Socket cannot bind in instant app mode")
+ public void testFirewallBlockingStandby() {
doTestFirewallBlocking(FIREWALL_CHAIN_STANDBY, DENYLIST);
+ }
+
+ @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
+ @AppModeFull(reason = "Socket cannot bind in instant app mode")
+ public void testFirewallBlockingOemDeny1() {
doTestFirewallBlocking(FIREWALL_CHAIN_OEM_DENY_1, DENYLIST);
+ }
+
+ @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
+ @AppModeFull(reason = "Socket cannot bind in instant app mode")
+ public void testFirewallBlockingOemDeny2() {
doTestFirewallBlocking(FIREWALL_CHAIN_OEM_DENY_2, DENYLIST);
+ }
+
+ @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
+ @AppModeFull(reason = "Socket cannot bind in instant app mode")
+ public void testFirewallBlockingOemDeny3() {
doTestFirewallBlocking(FIREWALL_CHAIN_OEM_DENY_3, DENYLIST);
}
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index b924f65..67bdd17 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -644,10 +644,9 @@
val listener = EthernetStateListener()
addInterfaceStateListener(listener)
- // TODO(b/236895792): THIS IS A BUG! Existing server mode interfaces are not reported when
- // an InterfaceStateListener is registered.
// Note: using eventuallyExpect as there may be other interfaces present.
- // listener.eventuallyExpect(iface, STATE_LINK_UP, ROLE_SERVER)
+ listener.eventuallyExpect(InterfaceStateChanged(iface.name,
+ STATE_LINK_UP, ROLE_SERVER, /* IpConfiguration */ null))
releaseTetheredInterface()
listener.eventuallyExpect(iface, STATE_LINK_UP, ROLE_CLIENT)
diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
index 6ba0fda..805dd65 100644
--- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
+++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
@@ -60,7 +60,11 @@
import com.android.internal.util.HexDump;
import com.android.networkstack.apishim.ConstantsShim;
+import com.android.networkstack.apishim.Ikev2VpnProfileBuilderShimImpl;
+import com.android.networkstack.apishim.Ikev2VpnProfileShimImpl;
import com.android.networkstack.apishim.VpnManagerShimImpl;
+import com.android.networkstack.apishim.common.Ikev2VpnProfileBuilderShim;
+import com.android.networkstack.apishim.common.Ikev2VpnProfileShim;
import com.android.networkstack.apishim.common.VpnManagerShim;
import com.android.networkstack.apishim.common.VpnProfileStateShim;
import com.android.testutils.DevSdkIgnoreRule;
@@ -223,17 +227,28 @@
}
private Ikev2VpnProfile buildIkev2VpnProfileCommon(
- @NonNull Ikev2VpnProfile.Builder builder, boolean isRestrictedToTestNetworks,
- boolean requiresValidation) throws Exception {
+ @NonNull Ikev2VpnProfileBuilderShim builderShim, boolean isRestrictedToTestNetworks,
+ boolean requiresValidation, boolean automaticIpVersionSelectionEnabled,
+ boolean automaticNattKeepaliveTimerEnabled) throws Exception {
- builder.setBypassable(true)
+ builderShim.setBypassable(true)
.setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS)
.setProxy(TEST_PROXY_INFO)
.setMaxMtu(TEST_MTU)
.setMetered(false);
if (TestUtils.shouldTestTApis()) {
- builder.setRequiresInternetValidation(requiresValidation);
+ builderShim.setRequiresInternetValidation(requiresValidation);
}
+
+ if (TestUtils.shouldTestUApis()) {
+ builderShim.setAutomaticIpVersionSelectionEnabled(automaticIpVersionSelectionEnabled);
+ builderShim.setAutomaticNattKeepaliveTimerEnabled(automaticNattKeepaliveTimerEnabled);
+ }
+
+ // Convert shim back to Ikev2VpnProfile.Builder since restrictToTestNetworks is a hidden
+ // method and is not defined in shims.
+ // TODO: replace it in alternative way to remove the hidden method usage
+ final Ikev2VpnProfile.Builder builder = (Ikev2VpnProfile.Builder) builderShim.getBuilder();
if (isRestrictedToTestNetworks) {
builder.restrictToTestNetworks();
}
@@ -249,13 +264,16 @@
? IkeSessionTestUtils.IKE_PARAMS_V6 : IkeSessionTestUtils.IKE_PARAMS_V4,
IkeSessionTestUtils.CHILD_PARAMS);
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(params)
+ final Ikev2VpnProfileBuilderShim builderShim =
+ Ikev2VpnProfileBuilderShimImpl.newInstance(params)
.setRequiresInternetValidation(requiresValidation)
.setProxy(TEST_PROXY_INFO)
.setMaxMtu(TEST_MTU)
.setMetered(false);
-
+ // Convert shim back to Ikev2VpnProfile.Builder since restrictToTestNetworks is a hidden
+ // method and is not defined in shims.
+ // TODO: replace it in alternative way to remove the hidden method usage
+ final Ikev2VpnProfile.Builder builder = (Ikev2VpnProfile.Builder) builderShim.getBuilder();
if (isRestrictedToTestNetworks) {
builder.restrictToTestNetworks();
}
@@ -263,31 +281,35 @@
}
private Ikev2VpnProfile buildIkev2VpnProfilePsk(@NonNull String remote,
- boolean isRestrictedToTestNetworks, boolean requiresValidation) throws Exception {
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(remote, TEST_IDENTITY).setAuthPsk(TEST_PSK);
+ boolean isRestrictedToTestNetworks, boolean requiresValidation)
+ throws Exception {
+ final Ikev2VpnProfileBuilderShim builder =
+ Ikev2VpnProfileBuilderShimImpl.newInstance(remote, TEST_IDENTITY)
+ .setAuthPsk(TEST_PSK);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
- requiresValidation);
+ requiresValidation, false /* automaticIpVersionSelectionEnabled */,
+ false /* automaticNattKeepaliveTimerEnabled */);
}
private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks)
throws Exception {
-
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ final Ikev2VpnProfileBuilderShim builder =
+ Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
- false /* requiresValidation */);
+ false /* requiresValidation */, false /* automaticIpVersionSelectionEnabled */,
+ false /* automaticNattKeepaliveTimerEnabled */);
}
private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks)
throws Exception {
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ final Ikev2VpnProfileBuilderShim builder =
+ Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthDigitalSignature(
mUserCertKey.cert, mUserCertKey.key, mServerRootCa);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
- false /* requiresValidation */);
+ false /* requiresValidation */, false /* automaticIpVersionSelectionEnabled */,
+ false /* automaticNattKeepaliveTimerEnabled */);
}
private void checkBasicIkev2VpnProfile(@NonNull Ikev2VpnProfile profile) throws Exception {
@@ -687,6 +709,56 @@
true /* testSessionKey */, false /* testIkeTunConnParams */);
}
+ @Test
+ public void testBuildIkev2VpnProfileWithAutomaticNattKeepaliveTimerEnabled() throws Exception {
+ // Cannot use @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) because this test also requires API
+ // 34 shims, and @IgnoreUpTo does not check that.
+ assumeTrue(TestUtils.shouldTestUApis());
+
+ final Ikev2VpnProfile profileWithDefaultValue = buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6,
+ false /* isRestrictedToTestNetworks */, false /* requiresValidation */);
+ final Ikev2VpnProfileShim<Ikev2VpnProfile> shimWithDefaultValue =
+ Ikev2VpnProfileShimImpl.newInstance(profileWithDefaultValue);
+ assertFalse(shimWithDefaultValue.isAutomaticNattKeepaliveTimerEnabled());
+
+ final Ikev2VpnProfileBuilderShim builder =
+ Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ .setAuthPsk(TEST_PSK);
+ final Ikev2VpnProfile profile = buildIkev2VpnProfileCommon(builder,
+ false /* isRestrictedToTestNetworks */,
+ false /* requiresValidation */,
+ false /* automaticIpVersionSelectionEnabled */,
+ true /* automaticNattKeepaliveTimerEnabled */);
+ final Ikev2VpnProfileShim<Ikev2VpnProfile> shim =
+ Ikev2VpnProfileShimImpl.newInstance(profile);
+ assertTrue(shim.isAutomaticNattKeepaliveTimerEnabled());
+ }
+
+ @Test
+ public void testBuildIkev2VpnProfileWithAutomaticIpVersionSelectionEnabled() throws Exception {
+ // Cannot use @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) because this test also requires API
+ // 34 shims, and @IgnoreUpTo does not check that.
+ assumeTrue(TestUtils.shouldTestUApis());
+
+ final Ikev2VpnProfile profileWithDefaultValue = buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6,
+ false /* isRestrictedToTestNetworks */, false /* requiresValidation */);
+ final Ikev2VpnProfileShim<Ikev2VpnProfile> shimWithDefaultValue =
+ Ikev2VpnProfileShimImpl.newInstance(profileWithDefaultValue);
+ assertFalse(shimWithDefaultValue.isAutomaticIpVersionSelectionEnabled());
+
+ final Ikev2VpnProfileBuilderShim builder =
+ Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ .setAuthPsk(TEST_PSK);
+ final Ikev2VpnProfile profile = buildIkev2VpnProfileCommon(builder,
+ false /* isRestrictedToTestNetworks */,
+ false /* requiresValidation */,
+ true /* automaticIpVersionSelectionEnabled */,
+ false /* automaticNattKeepaliveTimerEnabled */);
+ final Ikev2VpnProfileShim<Ikev2VpnProfile> shim =
+ Ikev2VpnProfileShimImpl.newInstance(profile);
+ assertTrue(shim.isAutomaticIpVersionSelectionEnabled());
+ }
+
private static class CertificateAndKey {
public final X509Certificate cert;
public final PrivateKey key;
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index de5e46f..6fd2321 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -19,6 +19,8 @@
import android.app.compat.CompatChanges
import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback
+import android.net.InetAddresses.parseNumericAddress
+import android.net.LinkAddress
import android.net.LinkProperties
import android.net.LocalSocket
import android.net.LocalSocketAddress
@@ -27,6 +29,7 @@
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
+import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkRequest
import android.net.TestNetworkInterface
@@ -62,18 +65,29 @@
import android.os.HandlerThread
import android.os.Process.myTid
import android.platform.test.annotations.AppModeFull
+import android.system.ErrnoException
+import android.system.Os
+import android.system.OsConstants.AF_INET6
+import android.system.OsConstants.EADDRNOTAVAIL
+import android.system.OsConstants.ENETUNREACH
+import android.system.OsConstants.IPPROTO_UDP
+import android.system.OsConstants.SOCK_DGRAM
import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import com.android.compatibility.common.util.PollingCheck
import com.android.compatibility.common.util.PropertyUtil
+import com.android.modules.utils.build.SdkLevel.isAtLeastU
import com.android.net.module.util.ArrayTrackRecord
import com.android.net.module.util.TrackRecord
import com.android.networkstack.apishim.NsdShimImpl
import com.android.networkstack.apishim.common.NsdShim
import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
+import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
import com.android.testutils.TestableNetworkAgent
+import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated
import com.android.testutils.TestableNetworkCallback
import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk30
import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk33
@@ -82,6 +96,7 @@
import com.android.testutils.waitForIdle
import java.io.File
import java.io.IOException
+import java.net.NetworkInterface
import java.net.ServerSocket
import java.nio.charset.StandardCharsets
import java.util.Random
@@ -353,24 +368,56 @@
.build(), cb)
val agent = registerTestNetworkAgent(iface.interfaceName)
val network = agent.network ?: fail("Registered agent should have a network")
+
+ cb.eventuallyExpect<LinkPropertiesChanged>(TIMEOUT_MS) {
+ it.lp.linkAddresses.isNotEmpty()
+ }
+
// The network has no INTERNET capability, so will be marked validated immediately
- cb.expectAvailableThenValidatedCallbacks(network, TIMEOUT_MS)
+ // It does not matter if validated capabilities come before/after the link addresses change
+ cb.eventuallyExpect<CapabilitiesChanged>(TIMEOUT_MS, from = 0) {
+ it.caps.hasCapability(NET_CAPABILITY_VALIDATED)
+ }
return TestTapNetwork(iface, cb, agent, network)
}
private fun registerTestNetworkAgent(ifaceName: String): TestableNetworkAgent {
+ val lp = LinkProperties().apply {
+ interfaceName = ifaceName
+ }
+
val agent = TestableNetworkAgent(context, handlerThread.looper,
NetworkCapabilities().apply {
removeCapability(NET_CAPABILITY_TRUSTED)
addTransportType(TRANSPORT_TEST)
setNetworkSpecifier(TestNetworkSpecifier(ifaceName))
- },
- LinkProperties().apply {
- interfaceName = ifaceName
- },
- NetworkAgentConfig.Builder().build())
- agent.register()
+ }, lp, NetworkAgentConfig.Builder().build())
+ val network = agent.register()
agent.markConnected()
+ agent.expectCallback<OnNetworkCreated>()
+
+ // Wait until the link-local address can be used. Address flags are not available without
+ // elevated permissions, so check that bindSocket works.
+ PollingCheck.check("No usable v6 address on interface after $TIMEOUT_MS ms", TIMEOUT_MS) {
+ val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
+ tryTest {
+ network.bindSocket(sock)
+ Os.connect(sock, parseNumericAddress("ff02::fb%$ifaceName"), 12345)
+ true
+ }.catch<ErrnoException> {
+ if (it.errno != ENETUNREACH && it.errno != EADDRNOTAVAIL) {
+ throw it
+ }
+ false
+ } cleanup {
+ Os.close(sock)
+ }
+ }
+
+ lp.setLinkAddresses(NetworkInterface.getByName(ifaceName).interfaceAddresses.map {
+ LinkAddress(it.address, it.networkPrefixLength.toInt())
+ })
+ agent.sendLinkProperties(lp)
return agent
}
@@ -378,8 +425,9 @@
fun tearDown() {
if (TestUtils.shouldTestTApis()) {
runAsShell(MANAGE_TEST_NETWORKS) {
- testNetwork1.close(cm)
- testNetwork2.close(cm)
+ // Avoid throwing here if initializing failed in setUp
+ if (this::testNetwork1.isInitialized) testNetwork1.close(cm)
+ if (this::testNetwork2.isInitialized) testNetwork2.close(cm)
}
}
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -465,7 +513,12 @@
assertTrue(resolvedService.attributes.containsKey("nullBinaryDataAttr"))
assertNull(resolvedService.attributes["nullBinaryDataAttr"])
assertTrue(resolvedService.attributes.containsKey("emptyBinaryDataAttr"))
- assertNull(resolvedService.attributes["emptyBinaryDataAttr"])
+ // TODO: change the check to target SDK U when this is what the code implements
+ if (isAtLeastU()) {
+ assertArrayEquals(byteArrayOf(), resolvedService.attributes["emptyBinaryDataAttr"])
+ } else {
+ assertNull(resolvedService.attributes["emptyBinaryDataAttr"])
+ }
assertEquals(localPort, resolvedService.port)
// Unregister the service
@@ -879,12 +932,10 @@
@Test
fun testRegisterServiceInfoCallback() {
- // This test requires shims supporting U+ APIs (NsdManager.subscribeService)
+ // This test requires shims supporting U+ APIs (NsdManager.registerServiceInfoCallback)
assumeTrue(TestUtils.shouldTestUApis())
- // Ensure Wi-Fi network connected and get addresses
- val wifiNetwork = ctsNetUtils.ensureWifiConnected()
- val lp = cm.getLinkProperties(wifiNetwork)
+ val lp = cm.getLinkProperties(testNetwork1.network)
assertNotNull(lp)
val addresses = lp.addresses
assertFalse(addresses.isEmpty())
@@ -892,33 +943,31 @@
val si = NsdServiceInfo().apply {
serviceType = this@NsdManagerTest.serviceType
serviceName = this@NsdManagerTest.serviceName
- network = wifiNetwork
+ network = testNetwork1.network
port = 12345 // Test won't try to connect so port does not matter
}
- // Register service on Wi-Fi network
+ // Register service on the network
val registrationRecord = NsdRegistrationRecord()
registerService(registrationRecord, si)
val discoveryRecord = NsdDiscoveryRecord()
val cbRecord = NsdServiceInfoCallbackRecord()
tryTest {
- // Discover service on Wi-Fi network.
+ // Discover service on the network.
nsdShim.discoverServices(nsdManager, serviceType, NsdManager.PROTOCOL_DNS_SD,
- wifiNetwork, Executor { it.run() }, discoveryRecord)
+ testNetwork1.network, Executor { it.run() }, discoveryRecord)
val foundInfo = discoveryRecord.waitForServiceDiscovered(
- serviceName, wifiNetwork)
+ serviceName, testNetwork1.network)
- // Subscribe to service and check the addresses are the same as Wi-Fi addresses
+ // Register service callback and check the addresses are the same as network addresses
nsdShim.registerServiceInfoCallback(nsdManager, foundInfo, { it.run() }, cbRecord)
- for (i in addresses.indices) {
- val subscribeCb = cbRecord.expectCallback<ServiceUpdated>()
- assertEquals(foundInfo.serviceName, subscribeCb.serviceInfo.serviceName)
- val hostAddresses = subscribeCb.serviceInfo.hostAddresses
- assertEquals(i + 1, hostAddresses.size)
- for (hostAddress in hostAddresses) {
- assertTrue(addresses.contains(hostAddress))
- }
+ val serviceInfoCb = cbRecord.expectCallback<ServiceUpdated>()
+ assertEquals(foundInfo.serviceName, serviceInfoCb.serviceInfo.serviceName)
+ val hostAddresses = serviceInfoCb.serviceInfo.hostAddresses
+ assertEquals(addresses.size, hostAddresses.size)
+ for (hostAddress in hostAddresses) {
+ assertTrue(addresses.contains(hostAddress))
}
} cleanupStep {
nsdManager.unregisterService(registrationRecord)
diff --git a/tests/unit/java/android/net/NetworkTemplateTest.kt b/tests/unit/java/android/net/NetworkTemplateTest.kt
index edbcea9..fc25fd8 100644
--- a/tests/unit/java/android/net/NetworkTemplateTest.kt
+++ b/tests/unit/java/android/net/NetworkTemplateTest.kt
@@ -130,10 +130,17 @@
mockContext, buildWifiNetworkState(null, TEST_WIFI_KEY1), true, 0)
val identWifiImsi1Key1 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_WIFI_KEY1), true, 0)
+ // This identity with a null wifiNetworkKey is to test matchesWifiNetworkKey won't crash
+ // the system when a null wifiNetworkKey is provided, which happens because of a bug in wifi
+ // and it should still match the wifi wildcard template. See b/266598304.
+ val identWifiNullKey = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(null /* subscriberId */,
+ null /* wifiNetworkKey */), true, 0)
templateWifiWildcard.assertDoesNotMatch(identMobileImsi1)
templateWifiWildcard.assertMatches(identWifiImsiNullKey1)
templateWifiWildcard.assertMatches(identWifiImsi1Key1)
+ templateWifiWildcard.assertMatches(identWifiNullKey)
}
@Test
@@ -148,6 +155,9 @@
.setWifiNetworkKeys(setOf(TEST_WIFI_KEY1)).build()
val templateWifiKeyAllImsi1 = NetworkTemplate.Builder(MATCH_WIFI)
.setSubscriberIds(setOf(TEST_IMSI1)).build()
+ val templateNullWifiKey = NetworkTemplate(MATCH_WIFI,
+ emptyArray<String>() /* subscriberIds */, arrayOf(null) /* wifiNetworkKeys */,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL)
val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1),
false, TelephonyManager.NETWORK_TYPE_UMTS)
@@ -159,6 +169,12 @@
mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_WIFI_KEY1), true, 0)
val identWifiImsi1Key2 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_WIFI_KEY2), true, 0)
+ // This identity with a null wifiNetworkKey is to test the matchesWifiNetworkKey won't crash
+ // the system when a null wifiNetworkKey is provided, which would happen in some unknown
+ // cases, see b/266598304.
+ val identWifiNullKey = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(null /* subscriberId */,
+ null /* wifiNetworkKey */), true, 0)
// Verify that template with WiFi Network Key only matches any subscriberId and
// specific WiFi Network Key.
@@ -191,6 +207,12 @@
templateWifiKeyAllImsi1.assertMatches(identWifiImsi1Key1)
templateWifiKeyAllImsi1.assertDoesNotMatch(identWifiImsi2Key1)
templateWifiKeyAllImsi1.assertMatches(identWifiImsi1Key2)
+
+ // Test a network identity with null wifiNetworkKey won't crash.
+ // It should not match a template with wifiNetworkKeys is non-null.
+ // Also, it should not match a template with wifiNetworkKeys that contains null.
+ templateWifiKey1.assertDoesNotMatch(identWifiNullKey)
+ templateNullWifiKey.assertDoesNotMatch(identWifiNullKey)
}
@Test
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 1a358b2..c1c6a8a 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -864,7 +864,8 @@
verify(mBroadcastOptionsShim).setDeliveryGroupMatchingKey(
eq(CONNECTIVITY_ACTION),
eq(createDeliveryGroupKeyForConnectivityAction(ni)));
- verify(mBroadcastOptionsShim).setDeferUntilActive(eq(true));
+ verify(mBroadcastOptionsShim).setDeferralPolicy(
+ eq(ConstantsShim.DEFERRAL_POLICY_UNTIL_ACTIVE));
} catch (UnsupportedApiLevelException e) {
throw new RuntimeException(e);
}
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index 053212b..0b48e08 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -21,6 +21,7 @@
import static android.net.nsd.NsdManager.FAILURE_INTERNAL_ERROR;
import static android.net.nsd.NsdManager.FAILURE_OPERATION_NOT_RUNNING;
+import static com.android.server.NsdService.constructServiceType;
import static com.android.testutils.ContextUtils.mockService;
import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
@@ -100,6 +101,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;
@@ -703,119 +705,102 @@
}
private void verifyUpdatedServiceInfo(NsdServiceInfo info, String serviceName,
- String serviceType, String address, int port, int interfaceIndex, Network network) {
+ String serviceType, List<InetAddress> address, int port, int interfaceIndex,
+ Network network) {
assertEquals(serviceName, info.getServiceName());
assertEquals(serviceType, info.getServiceType());
- assertTrue(info.getHostAddresses().contains(parseNumericAddress(address)));
+ assertEquals(address, info.getHostAddresses());
assertEquals(port, info.getPort());
assertEquals(network, info.getNetwork());
assertEquals(interfaceIndex, info.getInterfaceIndex());
}
@Test
- public void testRegisterAndUnregisterServiceInfoCallback() throws RemoteException {
+ public void testRegisterAndUnregisterServiceInfoCallback() {
final NsdManager client = connectClient(mService);
final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE);
final NsdManager.ServiceInfoCallback serviceInfoCallback = mock(
NsdManager.ServiceInfoCallback.class);
+ final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local";
+ final Network network = new Network(999);
+ request.setNetwork(network);
client.registerServiceInfoCallback(request, Runnable::run, serviceInfoCallback);
waitForIdle();
+ // Verify the registration callback start.
+ final ArgumentCaptor<MdnsServiceBrowserListener> listenerCaptor =
+ ArgumentCaptor.forClass(MdnsServiceBrowserListener.class);
+ verify(mSocketProvider).startMonitoringSockets();
+ verify(mDiscoveryManager).registerListener(eq(serviceTypeWithLocalDomain),
+ listenerCaptor.capture(), argThat(options -> network.equals(options.getNetwork())));
- final IMDnsEventListener eventListener = getEventListener();
- final ArgumentCaptor<Integer> resolvIdCaptor = ArgumentCaptor.forClass(Integer.class);
- verify(mMockMDnsM).resolve(resolvIdCaptor.capture(), eq(SERVICE_NAME), eq(SERVICE_TYPE),
- eq("local.") /* domain */, eq(IFACE_IDX_ANY));
-
- // Resolve service successfully.
- final ResolutionInfo resolutionInfo = new ResolutionInfo(
- resolvIdCaptor.getValue(),
- IMDnsEventListener.SERVICE_RESOLVED,
- null /* serviceName */,
- null /* serviceType */,
- null /* domain */,
- SERVICE_FULL_NAME,
- DOMAIN_NAME,
+ final MdnsServiceBrowserListener listener = listenerCaptor.getValue();
+ final MdnsServiceInfo mdnsServiceInfo = new MdnsServiceInfo(
+ SERVICE_NAME,
+ serviceTypeWithLocalDomain.split("\\."),
+ List.of(), /* subtypes */
+ new String[]{"android", "local"}, /* hostName */
PORT,
- new byte[0] /* txtRecord */,
- IFACE_IDX_ANY);
- doReturn(true).when(mMockMDnsM).getServiceAddress(anyInt(), any(), anyInt());
- eventListener.onServiceResolutionStatus(resolutionInfo);
- waitForIdle();
+ List.of(IPV4_ADDRESS),
+ List.of(IPV6_ADDRESS),
+ List.of() /* textStrings */,
+ List.of() /* textEntries */,
+ 1234,
+ network);
- final ArgumentCaptor<Integer> getAddrIdCaptor = ArgumentCaptor.forClass(Integer.class);
- verify(mMockMDnsM).getServiceAddress(getAddrIdCaptor.capture(), eq(DOMAIN_NAME),
- eq(IFACE_IDX_ANY));
-
- // First address info
- final String v4Address = "192.0.2.1";
- final String v6Address = "2001:db8::";
- final GetAddressInfo addressInfo1 = new GetAddressInfo(
- getAddrIdCaptor.getValue(),
- IMDnsEventListener.SERVICE_GET_ADDR_SUCCESS,
- SERVICE_FULL_NAME,
- v4Address,
- IFACE_IDX_ANY,
- 999 /* netId */);
- eventListener.onGettingServiceAddressStatus(addressInfo1);
- waitForIdle();
-
+ // Verify onServiceFound callback
+ listener.onServiceFound(mdnsServiceInfo);
final ArgumentCaptor<NsdServiceInfo> updateInfoCaptor =
ArgumentCaptor.forClass(NsdServiceInfo.class);
verify(serviceInfoCallback, timeout(TIMEOUT_MS).times(1))
.onServiceUpdated(updateInfoCaptor.capture());
verifyUpdatedServiceInfo(updateInfoCaptor.getAllValues().get(0) /* info */, SERVICE_NAME,
- "." + SERVICE_TYPE, v4Address, PORT, IFACE_IDX_ANY, new Network(999));
+ SERVICE_TYPE,
+ List.of(parseNumericAddress(IPV4_ADDRESS), parseNumericAddress(IPV6_ADDRESS)),
+ PORT, IFACE_IDX_ANY, new Network(999));
- // Second address info
- final GetAddressInfo addressInfo2 = new GetAddressInfo(
- getAddrIdCaptor.getValue(),
- IMDnsEventListener.SERVICE_GET_ADDR_SUCCESS,
- SERVICE_FULL_NAME,
- v6Address,
- IFACE_IDX_ANY,
- 999 /* netId */);
- eventListener.onGettingServiceAddressStatus(addressInfo2);
- waitForIdle();
+ // Service addresses changed.
+ final String v4Address = "192.0.2.1";
+ final String v6Address = "2001:db8::1";
+ final MdnsServiceInfo updatedServiceInfo = new MdnsServiceInfo(
+ SERVICE_NAME,
+ serviceTypeWithLocalDomain.split("\\."),
+ List.of(), /* subtypes */
+ new String[]{"android", "local"}, /* hostName */
+ PORT,
+ List.of(v4Address),
+ List.of(v6Address),
+ List.of() /* textStrings */,
+ List.of() /* textEntries */,
+ 1234,
+ network);
+ // Verify onServiceUpdated callback.
+ listener.onServiceUpdated(updatedServiceInfo);
verify(serviceInfoCallback, timeout(TIMEOUT_MS).times(2))
.onServiceUpdated(updateInfoCaptor.capture());
- verifyUpdatedServiceInfo(updateInfoCaptor.getAllValues().get(1) /* info */, SERVICE_NAME,
- "." + SERVICE_TYPE, v6Address, PORT, IFACE_IDX_ANY, new Network(999));
+ verifyUpdatedServiceInfo(updateInfoCaptor.getAllValues().get(2) /* info */, SERVICE_NAME,
+ SERVICE_TYPE,
+ List.of(parseNumericAddress(v4Address), parseNumericAddress(v6Address)),
+ PORT, IFACE_IDX_ANY, new Network(999));
+ // Verify service callback unregistration.
client.unregisterServiceInfoCallback(serviceInfoCallback);
waitForIdle();
-
verify(serviceInfoCallback, timeout(TIMEOUT_MS)).onServiceInfoCallbackUnregistered();
}
@Test
- public void testRegisterServiceCallbackFailed() throws Exception {
+ public void testRegisterServiceCallbackFailed() {
final NsdManager client = connectClient(mService);
- final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE);
- final NsdManager.ServiceInfoCallback subscribeListener = mock(
+ final String invalidServiceType = "a_service";
+ final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, invalidServiceType);
+ final NsdManager.ServiceInfoCallback serviceInfoCallback = mock(
NsdManager.ServiceInfoCallback.class);
- client.registerServiceInfoCallback(request, Runnable::run, subscribeListener);
+ client.registerServiceInfoCallback(request, Runnable::run, serviceInfoCallback);
waitForIdle();
- final IMDnsEventListener eventListener = getEventListener();
- final ArgumentCaptor<Integer> resolvIdCaptor = ArgumentCaptor.forClass(Integer.class);
- verify(mMockMDnsM).resolve(resolvIdCaptor.capture(), eq(SERVICE_NAME), eq(SERVICE_TYPE),
- eq("local.") /* domain */, eq(IFACE_IDX_ANY));
-
- // Fail to resolve service.
- final ResolutionInfo resolutionFailedInfo = new ResolutionInfo(
- resolvIdCaptor.getValue(),
- IMDnsEventListener.SERVICE_RESOLUTION_FAILED,
- null /* serviceName */,
- null /* serviceType */,
- null /* domain */,
- null /* serviceFullName */,
- null /* domainName */,
- 0 /* port */,
- new byte[0] /* txtRecord */,
- IFACE_IDX_ANY);
- eventListener.onServiceResolutionStatus(resolutionFailedInfo);
- verify(subscribeListener, timeout(TIMEOUT_MS))
+ // Fail to register service callback.
+ verify(serviceInfoCallback, timeout(TIMEOUT_MS))
.onServiceInfoCallbackRegistrationFailed(eq(FAILURE_BAD_PARAMETERS));
}
@@ -895,8 +880,8 @@
List.of(), /* subtypes */
new String[] {"android", "local"}, /* hostName */
12345, /* port */
- IPV4_ADDRESS,
- IPV6_ADDRESS,
+ List.of(IPV4_ADDRESS),
+ List.of(IPV6_ADDRESS),
List.of(), /* textStrings */
List.of(), /* textEntries */
1234, /* interfaceIndex */
@@ -915,8 +900,8 @@
null, /* subtypes */
null, /* hostName */
0, /* port */
- null, /* ipv4Address */
- null, /* ipv6Address */
+ List.of(), /* ipv4Address */
+ List.of(), /* ipv6Address */
null, /* textStrings */
null, /* textEntries */
1234, /* interfaceIndex */
@@ -992,8 +977,8 @@
List.of(), /* subtypes */
new String[]{"android", "local"}, /* hostName */
PORT,
- IPV4_ADDRESS,
- IPV6_ADDRESS,
+ List.of(IPV4_ADDRESS),
+ List.of("2001:db8::1", "2001:db8::2"),
List.of() /* textStrings */,
List.of(MdnsServiceInfo.TextEntry.fromBytes(new byte[]{
'k', 'e', 'y', '=', (byte) 0xFF, (byte) 0xFE})) /* textEntries */,
@@ -1013,6 +998,11 @@
assertEquals(1, info.getAttributes().size());
assertArrayEquals(new byte[]{(byte) 0xFF, (byte) 0xFE}, info.getAttributes().get("key"));
assertEquals(parseNumericAddress(IPV4_ADDRESS), info.getHost());
+ assertEquals(3, info.getHostAddresses().size());
+ assertTrue(info.getHostAddresses().stream().anyMatch(
+ address -> address.equals(parseNumericAddress("2001:db8::1"))));
+ assertTrue(info.getHostAddresses().stream().anyMatch(
+ address -> address.equals(parseNumericAddress("2001:db8::2"))));
assertEquals(network, info.getNetwork());
// Verify the listener has been unregistered.
@@ -1057,6 +1047,54 @@
}
@Test
+ public void testTypeSpecificFeatureFlagging() {
+ doReturn("_type1._tcp:flag1,_type2._tcp:flag2").when(mDeps).getTypeAllowlistFlags();
+ doReturn(true).when(mDeps).isFeatureEnabled(any(),
+ eq("mdns_discovery_manager_allowlist_flag1_version"));
+ doReturn(true).when(mDeps).isFeatureEnabled(any(),
+ eq("mdns_advertiser_allowlist_flag2_version"));
+
+ final NsdManager client = connectClient(mService);
+ final NsdServiceInfo service1 = new NsdServiceInfo(SERVICE_NAME, "_type1._tcp");
+ service1.setHostAddresses(List.of(parseNumericAddress("2001:db8::123")));
+ service1.setPort(1234);
+ final NsdServiceInfo service2 = new NsdServiceInfo(SERVICE_NAME, "_type2._tcp");
+ service2.setHostAddresses(List.of(parseNumericAddress("2001:db8::123")));
+ service2.setPort(1234);
+
+ client.discoverServices(service1.getServiceType(),
+ NsdManager.PROTOCOL_DNS_SD, mock(DiscoveryListener.class));
+ client.discoverServices(service2.getServiceType(),
+ NsdManager.PROTOCOL_DNS_SD, mock(DiscoveryListener.class));
+ waitForIdle();
+
+ // The DiscoveryManager is enabled for _type1 but not _type2
+ verify(mDiscoveryManager).registerListener(eq("_type1._tcp.local"), any(), any());
+ verify(mDiscoveryManager, never()).registerListener(
+ eq("_type2._tcp.local"), any(), any());
+
+ client.resolveService(service1, mock(ResolveListener.class));
+ client.resolveService(service2, mock(ResolveListener.class));
+ waitForIdle();
+
+ // Same behavior for resolve
+ verify(mDiscoveryManager, times(2)).registerListener(
+ eq("_type1._tcp.local"), any(), any());
+ verify(mDiscoveryManager, never()).registerListener(
+ eq("_type2._tcp.local"), any(), any());
+
+ client.registerService(service1, NsdManager.PROTOCOL_DNS_SD,
+ mock(RegistrationListener.class));
+ client.registerService(service2, NsdManager.PROTOCOL_DNS_SD,
+ mock(RegistrationListener.class));
+ waitForIdle();
+
+ // The advertiser is enabled for _type2 but not _type1
+ verify(mAdvertiser, never()).addService(anyInt(), argThat(info -> matches(info, service1)));
+ verify(mAdvertiser).addService(anyInt(), argThat(info -> matches(info, service2)));
+ }
+
+ @Test
public void testAdvertiseWithMdnsAdvertiser() {
setMdnsAdvertiserEnabled();
@@ -1152,6 +1190,50 @@
argThat(info -> matches(info, new NsdServiceInfo(regInfo.getServiceName(), null))));
}
+ @Test
+ public void testStopServiceResolutionWithMdnsDiscoveryManager() {
+ setMdnsDiscoveryManagerEnabled();
+
+ final NsdManager client = connectClient(mService);
+ final ResolveListener resolveListener = mock(ResolveListener.class);
+ final Network network = new Network(999);
+ final String serviceType = "_nsd._service._tcp";
+ final String constructedServiceType = "_nsd._sub._service._tcp.local";
+ final ArgumentCaptor<MdnsServiceBrowserListener> listenerCaptor =
+ ArgumentCaptor.forClass(MdnsServiceBrowserListener.class);
+ final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, serviceType);
+ request.setNetwork(network);
+ client.resolveService(request, resolveListener);
+ waitForIdle();
+ verify(mSocketProvider).startMonitoringSockets();
+ verify(mDiscoveryManager).registerListener(eq(constructedServiceType),
+ listenerCaptor.capture(), argThat(options -> network.equals(options.getNetwork())));
+
+ client.stopServiceResolution(resolveListener);
+ waitForIdle();
+
+ // Verify the listener has been unregistered.
+ verify(mDiscoveryManager, timeout(TIMEOUT_MS))
+ .unregisterListener(eq(constructedServiceType), eq(listenerCaptor.getValue()));
+ verify(resolveListener, timeout(TIMEOUT_MS)).onResolutionStopped(argThat(ns ->
+ request.getServiceName().equals(ns.getServiceName())
+ && request.getServiceType().equals(ns.getServiceType())));
+ verify(mSocketProvider, timeout(CLEANUP_DELAY_MS + TIMEOUT_MS)).requestStopWhenInactive();
+ }
+
+ @Test
+ public void testConstructServiceType() {
+ final String serviceType1 = "test._tcp";
+ final String serviceType2 = "_test._quic";
+ final String serviceType3 = "_123._udp.";
+ final String serviceType4 = "_TEST._999._tcp.";
+
+ assertEquals(null, constructServiceType(serviceType1));
+ assertEquals(null, constructServiceType(serviceType2));
+ assertEquals("_123._udp", constructServiceType(serviceType3));
+ assertEquals("_TEST._sub._999._tcp", constructServiceType(serviceType4));
+ }
+
private void waitForIdle() {
HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
}
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index 2d87728..1f965d9 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -25,6 +25,8 @@
import static android.net.ConnectivityManager.NetworkCallback;
import static android.net.INetd.IF_STATE_DOWN;
import static android.net.INetd.IF_STATE_UP;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.VpnManager.TYPE_VPN_PLATFORM;
import static android.net.cts.util.IkeSessionTestUtils.CHILD_PARAMS;
@@ -36,6 +38,8 @@
import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO;
import static android.os.Build.VERSION_CODES.S_V2;
import static android.os.UserHandle.PER_USER_RANGE;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL;
+import static android.telephony.CarrierConfigManager.KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
import static com.android.server.connectivity.Vpn.AUTOMATIC_KEEPALIVE_DELAY_SECONDS;
@@ -107,6 +111,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
import android.net.RouteInfo;
+import android.net.TelephonyNetworkSpecifier;
import android.net.UidRangeParcel;
import android.net.VpnManager;
import android.net.VpnProfileState;
@@ -126,6 +131,7 @@
import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.net.ipsec.ike.exceptions.IkeTimeoutException;
+import android.net.wifi.WifiInfo;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.ConditionVariable;
@@ -139,6 +145,10 @@
import android.os.test.TestLooper;
import android.provider.Settings;
import android.security.Credentials;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
@@ -265,6 +275,9 @@
private static final Range<Integer> PRIMARY_USER_RANGE = uidRangeForUser(PRIMARY_USER.id);
// Same as IkeSessionParams#IKE_NATT_KEEPALIVE_DELAY_SEC_DEFAULT
private static final int IKE_NATT_KEEPALIVE_DELAY_SEC_DEFAULT = 10;
+ private static final int TEST_KEEPALIVE_TIMER = 800;
+ private static final int TEST_SUB_ID = 1234;
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
@Mock private UserManager mUserManager;
@Mock private PackageManager mPackageManager;
@@ -278,6 +291,10 @@
@Mock private Vpn.VpnNetworkAgentWrapper mMockNetworkAgent;
@Mock private ConnectivityManager mConnectivityManager;
@Mock private ConnectivityDiagnosticsManager mCdm;
+ @Mock private TelephonyManager mTelephonyManager;
+ @Mock private TelephonyManager mTmPerSub;
+ @Mock private CarrierConfigManager mConfigManager;
+ @Mock private SubscriptionManager mSubscriptionManager;
@Mock private IpSecService mIpSecService;
@Mock private VpnProfileStore mVpnProfileStore;
@Mock private ScheduledThreadPoolExecutor mExecutor;
@@ -286,7 +303,6 @@
private final VpnProfile mVpnProfile;
private IpSecManager mIpSecManager;
-
private TestDeps mTestDeps;
public VpnTest() throws Exception {
@@ -322,6 +338,11 @@
mockService(IpSecManager.class, Context.IPSEC_SERVICE, mIpSecManager);
mockService(ConnectivityDiagnosticsManager.class, Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
mCdm);
+ mockService(TelephonyManager.class, Context.TELEPHONY_SERVICE, mTelephonyManager);
+ mockService(CarrierConfigManager.class, Context.CARRIER_CONFIG_SERVICE, mConfigManager);
+ mockService(SubscriptionManager.class, Context.TELEPHONY_SUBSCRIPTION_SERVICE,
+ mSubscriptionManager);
+ doReturn(mTmPerSub).when(mTelephonyManager).createForSubscriptionId(anyInt());
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
@@ -1924,7 +1945,7 @@
}
@Test
- public void testMigrateIkeSessionFromIkeTunnConnParams_AutoTimerNoTimer()
+ public void testMigrateIkeSession_FromIkeTunnConnParams_AutoTimerNoTimer()
throws Exception {
doTestMigrateIkeSession_FromIkeTunnConnParams(
false /* isAutomaticIpVersionSelectionEnabled */,
@@ -1933,21 +1954,21 @@
}
@Test
- public void testMigrateIkeSessionFromIkeTunnConnParams_AutoTimerTimerSet()
+ public void testMigrateIkeSession_FromIkeTunnConnParams_AutoTimerTimerSet()
throws Exception {
doTestMigrateIkeSession_FromIkeTunnConnParams(
false /* isAutomaticIpVersionSelectionEnabled */,
true /* isAutomaticNattKeepaliveTimerEnabled */,
- 800 /* keepaliveTimeout */);
+ TEST_KEEPALIVE_TIMER);
}
@Test
- public void testMigrateIkeSessionFromIkeTunnConnParams_AutoIp()
+ public void testMigrateIkeSession_FromIkeTunnConnParams_AutoIp()
throws Exception {
doTestMigrateIkeSession_FromIkeTunnConnParams(
true /* isAutomaticIpVersionSelectionEnabled */,
false /* isAutomaticNattKeepaliveTimerEnabled */,
- TEST_KEEPALIVE_TIMEOUT_UNSET /* keepaliveTimeout */);
+ TEST_KEEPALIVE_TIMEOUT_UNSET);
}
@Test
@@ -2016,9 +2037,12 @@
verifySetupPlatformVpn(profile,
createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
false /* mtuSupportsIpv6 */);
- // Mock new network comes up and the cleanup task is cancelled
+ // Simulate a new network coming up
vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+ verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt());
+ vpnSnapShot.nwCb.onCapabilitiesChanged(
+ TEST_NETWORK_2, new NetworkCapabilities.Builder().build());
// Verify MOBIKE is triggered
verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2,
expectedIpVersion, expectedEncapType, expectedKeepalive);
@@ -2026,6 +2050,102 @@
vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
}
+ private void mockCarrierConfig(int subId, int keepaliveTimer, int simStatus) {
+ final SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
+ doReturn(subId).when(subscriptionInfo).getSubscriptionId();
+ doReturn(List.of(subscriptionInfo)).when(mSubscriptionManager)
+ .getActiveSubscriptionInfoList();
+
+ doReturn(simStatus).when(mTmPerSub).getSimApplicationState();
+
+ final PersistableBundle persistableBundle = new PersistableBundle();
+ persistableBundle.putInt(KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT, keepaliveTimer);
+ // For CarrierConfigManager.isConfigForIdentifiedCarrier check
+ persistableBundle.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+ doReturn(persistableBundle).when(mConfigManager).getConfigForSubId(subId);
+ }
+
+ private CarrierConfigManager.CarrierConfigChangeListener getCarrierConfigListener() {
+ final ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerCaptor =
+ ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+ verify(mConfigManager).registerCarrierConfigChangeListener(any(), listenerCaptor.capture());
+
+ return listenerCaptor.getValue();
+ }
+
+ @Test
+ public void testNattKeepaliveTimerFromCarrierConfig_noSubId() throws Exception {
+ doTestNattKeepaliveTimerFromCarrierConfig(new NetworkCapabilities(),
+ TelephonyManager.SIM_STATE_LOADED, AUTOMATIC_KEEPALIVE_DELAY_SECONDS);
+ }
+
+ @Test
+ public void testNattKeepaliveTimerFromCarrierConfig_simAbsent() throws Exception {
+ doTestNattKeepaliveTimerFromCarrierConfig(new NetworkCapabilities.Builder().build(),
+ TelephonyManager.SIM_STATE_ABSENT, AUTOMATIC_KEEPALIVE_DELAY_SECONDS);
+ }
+
+ @Test
+ public void testNattKeepaliveTimerFromCarrierConfig() throws Exception {
+ final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(TEST_SUB_ID)
+ .build())
+ .build();
+ doTestNattKeepaliveTimerFromCarrierConfig(nc,
+ TelephonyManager.SIM_STATE_LOADED, TEST_KEEPALIVE_TIMER);
+ }
+
+ @Test
+ public void testNattKeepaliveTimerFromCarrierConfig_NotCell() throws Exception {
+ final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .setTransportInfo(new WifiInfo.Builder().build())
+ .build();
+ doTestNattKeepaliveTimerFromCarrierConfig(nc,
+ TelephonyManager.SIM_STATE_LOADED, AUTOMATIC_KEEPALIVE_DELAY_SECONDS);
+ }
+
+ private void doTestNattKeepaliveTimerFromCarrierConfig(NetworkCapabilities nc, int simState,
+ int expectedKeepaliveTimer) throws Exception {
+ final Ikev2VpnProfile ikeProfile =
+ new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY)
+ .setAuthPsk(TEST_VPN_PSK)
+ .setBypassable(true /* isBypassable */)
+ .setAutomaticNattKeepaliveTimerEnabled(true)
+ .build();
+
+ final PlatformVpnSnapshot vpnSnapShot =
+ verifySetupPlatformVpn(ikeProfile.toVpnProfile(),
+ createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
+ false /* mtuSupportsIpv6 */);
+
+ final CarrierConfigManager.CarrierConfigChangeListener listener =
+ getCarrierConfigListener();
+
+ // Simulate a new network coming up
+ vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+ // Migration will not be started until receiving network capabilities change.
+ verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt());
+
+ reset(mIkeSessionWrapper);
+ mockCarrierConfig(TEST_SUB_ID, TEST_KEEPALIVE_TIMER, simState);
+ vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2, nc);
+ verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2,
+ ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, expectedKeepaliveTimer);
+
+ reset(mExecutor);
+ reset(mIkeSessionWrapper);
+
+ // Trigger carrier config change
+ listener.onCarrierConfigChanged(1 /* logicalSlotIndex */, TEST_SUB_ID,
+ -1 /* carrierId */, -1 /* specificCarrierId */);
+ verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2,
+ ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, expectedKeepaliveTimer);
+ }
+
@Test
public void testStartPlatformVpn_mtuDoesNotSupportIpv6() throws Exception {
final PlatformVpnSnapshot vpnSnapShot =
@@ -2051,7 +2171,10 @@
// Mock new network comes up and the cleanup task is cancelled
vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
verify(mScheduledFuture).cancel(anyBoolean());
+ verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt());
+ vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2,
+ new NetworkCapabilities.Builder().build());
// Verify MOBIKE is triggered
verify(mIkeSessionWrapper).setNetwork(eq(TEST_NETWORK_2),
eq(ESP_IP_VERSION_AUTO) /* ipVersion */,
@@ -2146,7 +2269,11 @@
// Mock network switch
vpnSnapShot.nwCb.onLost(TEST_NETWORK);
vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+ // The old IKE Session will not be killed until receiving network capabilities change.
+ verify(mIkeSessionWrapper, never()).kill();
+ vpnSnapShot.nwCb.onCapabilitiesChanged(
+ TEST_NETWORK_2, new NetworkCapabilities.Builder().build());
// Verify the old IKE Session is killed
verify(mIkeSessionWrapper).kill();
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 e6b8326..7e7e6a4 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
@@ -18,20 +18,25 @@
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
-import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.net.Network;
import android.text.TextUtils;
+import android.util.Pair;
+import com.android.server.connectivity.mdns.MdnsSocketClientBase.SocketCreationCallback;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -48,6 +53,10 @@
private static final String SERVICE_TYPE_1 = "_googlecast._tcp.local";
private static final String SERVICE_TYPE_2 = "_test._tcp.local";
+ private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_1 =
+ Pair.create(SERVICE_TYPE_1, null);
+ private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_2 =
+ Pair.create(SERVICE_TYPE_2, null);
@Mock private ExecutorProvider executorProvider;
@Mock private MdnsSocketClientBase socketClient;
@@ -69,10 +78,13 @@
discoveryManager = new MdnsDiscoveryManager(executorProvider, socketClient) {
@Override
- MdnsServiceTypeClient createServiceTypeClient(@NonNull String serviceType) {
- if (serviceType.equals(SERVICE_TYPE_1)) {
+ MdnsServiceTypeClient createServiceTypeClient(@NonNull String serviceType,
+ @Nullable Network network) {
+ final Pair<String, Network> perNetworkServiceType =
+ Pair.create(serviceType, network);
+ if (perNetworkServiceType.equals(PER_NETWORK_SERVICE_TYPE_1)) {
return mockServiceTypeClientOne;
- } else if (serviceType.equals(SERVICE_TYPE_2)) {
+ } else if (perNetworkServiceType.equals(PER_NETWORK_SERVICE_TYPE_2)) {
return mockServiceTypeClientTwo;
}
return null;
@@ -80,13 +92,23 @@
};
}
+ private void verifyListenerRegistration(String serviceType, MdnsServiceBrowserListener listener,
+ MdnsServiceTypeClient client) throws IOException {
+ final ArgumentCaptor<SocketCreationCallback> callbackCaptor =
+ ArgumentCaptor.forClass(SocketCreationCallback.class);
+ discoveryManager.registerListener(serviceType, listener,
+ MdnsSearchOptions.getDefaultOptions());
+ verify(socketClient).startDiscovery();
+ verify(socketClient).notifyNetworkRequested(
+ eq(listener), any(), callbackCaptor.capture());
+ final SocketCreationCallback callback = callbackCaptor.getValue();
+ callback.onSocketCreated(null /* network */);
+ verify(client).startSendAndReceive(listener, MdnsSearchOptions.getDefaultOptions());
+ }
+
@Test
public void registerListener_unregisterListener() throws IOException {
- discoveryManager.registerListener(
- SERVICE_TYPE_1, mockListenerOne, MdnsSearchOptions.getDefaultOptions());
- verify(socketClient).startDiscovery();
- verify(mockServiceTypeClientOne)
- .startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions());
+ verifyListenerRegistration(SERVICE_TYPE_1, mockListenerOne, mockServiceTypeClientOne);
when(mockServiceTypeClientOne.stopSendAndReceive(mockListenerOne)).thenReturn(true);
discoveryManager.unregisterListener(SERVICE_TYPE_1, mockListenerOne);
@@ -96,40 +118,30 @@
@Test
public void registerMultipleListeners() throws IOException {
- discoveryManager.registerListener(
- SERVICE_TYPE_1, mockListenerOne, MdnsSearchOptions.getDefaultOptions());
- verify(socketClient).startDiscovery();
- verify(mockServiceTypeClientOne)
- .startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions());
-
- discoveryManager.registerListener(
- SERVICE_TYPE_2, mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
- verify(mockServiceTypeClientTwo)
- .startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
+ verifyListenerRegistration(SERVICE_TYPE_1, mockListenerOne, mockServiceTypeClientOne);
+ verifyListenerRegistration(SERVICE_TYPE_2, mockListenerTwo, mockServiceTypeClientTwo);
}
@Test
- public void onResponseReceived() {
- discoveryManager.registerListener(
- SERVICE_TYPE_1, mockListenerOne, MdnsSearchOptions.getDefaultOptions());
- discoveryManager.registerListener(
- SERVICE_TYPE_2, mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
+ public void onResponseReceived() throws IOException {
+ verifyListenerRegistration(SERVICE_TYPE_1, mockListenerOne, mockServiceTypeClientOne);
+ verifyListenerRegistration(SERVICE_TYPE_2, mockListenerTwo, mockServiceTypeClientTwo);
MdnsPacket responseForServiceTypeOne = createMdnsPacket(SERVICE_TYPE_1);
final int ifIndex = 1;
- final Network network = mock(Network.class);
- discoveryManager.onResponseReceived(responseForServiceTypeOne, ifIndex, network);
+ discoveryManager.onResponseReceived(responseForServiceTypeOne, ifIndex, null /* network */);
verify(mockServiceTypeClientOne).processResponse(responseForServiceTypeOne, ifIndex,
- network);
+ null /* network */);
MdnsPacket responseForServiceTypeTwo = createMdnsPacket(SERVICE_TYPE_2);
- discoveryManager.onResponseReceived(responseForServiceTypeTwo, ifIndex, network);
+ discoveryManager.onResponseReceived(responseForServiceTypeTwo, ifIndex, null /* network */);
verify(mockServiceTypeClientTwo).processResponse(responseForServiceTypeTwo, ifIndex,
- network);
+ null /* network */);
MdnsPacket responseForSubtype = createMdnsPacket("subtype._sub._googlecast._tcp.local");
- discoveryManager.onResponseReceived(responseForSubtype, ifIndex, network);
- verify(mockServiceTypeClientOne).processResponse(responseForSubtype, ifIndex, network);
+ discoveryManager.onResponseReceived(responseForSubtype, ifIndex, null /* network */);
+ verify(mockServiceTypeClientOne).processResponse(responseForSubtype, ifIndex,
+ null /* network */);
}
private MdnsPacket createMdnsPacket(String serviceType) {
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java
index 1e322e4..90c43e5 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java
@@ -62,6 +62,7 @@
@Mock private MdnsInterfaceSocket mSocket;
@Mock private MdnsServiceBrowserListener mListener;
@Mock private MdnsSocketClientBase.Callback mCallback;
+ @Mock private MdnsSocketClientBase.SocketCreationCallback mSocketCreationCallback;
private MdnsMultinetworkSocketClient mSocketClient;
private Handler mHandler;
@@ -78,7 +79,8 @@
private SocketCallback expectSocketCallback() {
final ArgumentCaptor<SocketCallback> callbackCaptor =
ArgumentCaptor.forClass(SocketCallback.class);
- mHandler.post(() -> mSocketClient.notifyNetworkRequested(mListener, mNetwork));
+ mHandler.post(() -> mSocketClient.notifyNetworkRequested(
+ mListener, mNetwork, mSocketCreationCallback));
verify(mProvider, timeout(DEFAULT_TIMEOUT))
.requestSocket(eq(mNetwork), callbackCaptor.capture());
return callbackCaptor.getValue();
@@ -107,6 +109,7 @@
doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
// Notify socket created
callback.onSocketCreated(mNetwork, mSocket, List.of());
+ verify(mSocketCreationCallback).onSocketCreated(mNetwork);
// Send packet to IPv4 with target network and verify sending has been called.
mSocketClient.sendMulticastPacket(ipv4Packet, mNetwork);
@@ -138,6 +141,7 @@
doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
// Notify socket created
callback.onSocketCreated(mNetwork, mSocket, List.of());
+ verify(mSocketCreationCallback).onSocketCreated(mNetwork);
final ArgumentCaptor<PacketHandler> handlerCaptor =
ArgumentCaptor.forClass(PacketHandler.class);
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java
index d83c0dd..a80c078 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java
@@ -158,16 +158,16 @@
// MDNS record for name "testhost1" with an IPv4 address of 10.1.2.3
private static final byte[] DATAIN_IPV4_1 = HexDump.hexStringToByteArray(
- "0974657374686f73743100000100010000007800040a010203");
+ "0974657374686f73743100000180010000007800040a010203");
// MDNS record for name "testhost1" with an IPv4 address of 10.1.2.4
private static final byte[] DATAIN_IPV4_2 = HexDump.hexStringToByteArray(
- "0974657374686f73743100000100010000007800040a010204");
+ "0974657374686f73743100000180010000007800040a010204");
// MDNS record w/name "testhost1" & IPv6 address of aabb:ccdd:1122:3344:a0b0:c0d0:1020:3040
private static final byte[] DATAIN_IPV6_1 = HexDump.hexStringToByteArray(
- "0974657374686f73743100001c0001000000780010aabbccdd11223344a0b0c0d010203040");
+ "0974657374686f73743100001c8001000000780010aabbccdd11223344a0b0c0d010203040");
// MDNS record w/name "testhost1" & IPv6 address of aabb:ccdd:1122:3344:a0b0:c0d0:1020:3030
private static final byte[] DATAIN_IPV6_2 = HexDump.hexStringToByteArray(
- "0974657374686f73743100001c0001000000780010aabbccdd11223344a0b0c0d010203030");
+ "0974657374686f73743100001c8001000000780010aabbccdd11223344a0b0c0d010203030");
// MDNS record w/name "test" & PTR to foo.bar.quxx
private static final byte[] DATAIN_PTR_1 = HexDump.hexStringToByteArray(
"047465737400000C000100001194000E03666F6F03626172047175787800");
@@ -295,15 +295,15 @@
assertTrue(response.isComplete());
response = new MdnsResponse(responses.valueAt(0));
- response.setInet4AddressRecord(null);
+ response.clearInet4AddressRecords();
assertFalse(response.isComplete());
- response.setInet6AddressRecord(new MdnsInetAddressRecord(new String[] { "testhostname" },
+ response.addInet6AddressRecord(new MdnsInetAddressRecord(new String[] { "testhostname" },
0L /* receiptTimeMillis */, false /* cacheFlush */, 1234L /* ttlMillis */,
parseNumericAddress("2008:db1::123")));
assertTrue(response.isComplete());
- response.setInet6AddressRecord(null);
+ response.clearInet6AddressRecords();
assertFalse(response.isComplete());
response = new MdnsResponse(responses.valueAt(0));
@@ -356,10 +356,12 @@
assertTrue(response2.isComplete());
// And should both have the same IPv6 address:
- assertEquals(parseNumericAddress("2605:a601:a846:5700:3e61:5ff:fe0c:89f8"),
- response1.getInet6AddressRecord().getInet6Address());
- assertEquals(parseNumericAddress("2605:a601:a846:5700:3e61:5ff:fe0c:89f8"),
- response2.getInet6AddressRecord().getInet6Address());
+ assertTrue(response1.getInet6AddressRecords().stream().anyMatch(
+ record -> record.getInet6Address().equals(
+ parseNumericAddress("2605:a601:a846:5700:3e61:5ff:fe0c:89f8"))));
+ assertTrue(response2.getInet6AddressRecords().stream().anyMatch(
+ record -> record.getInet6Address().equals(
+ parseNumericAddress("2605:a601:a846:5700:3e61:5ff:fe0c:89f8"))));
}
@Test
@@ -514,9 +516,9 @@
reader.skip(2); // skip record type indication.
// Apply the right kind of record to the response.
if (responseData.recordClass == MdnsInet4AddressRecord.class) {
- response.setInet4AddressRecord(new MdnsInet4AddressRecord(name, reader));
+ response.addInet4AddressRecord(new MdnsInet4AddressRecord(name, reader));
} else if (responseData.recordClass == MdnsInet6AddressRecord.class) {
- response.setInet6AddressRecord(new MdnsInet6AddressRecord(name, reader));
+ response.addInet6AddressRecord(new MdnsInet6AddressRecord(name, reader));
} else if (responseData.recordClass == MdnsPointerRecord.class) {
response.addPointerRecord(new MdnsPointerRecord(name, reader));
} else if (responseData.recordClass == MdnsServiceRecord.class) {
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java
index 132a822..3f5e7a1 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java
@@ -108,10 +108,10 @@
0 /* serviceWeight */, 0 /* servicePort */, hostname));
response.setTextRecord(new MdnsTextRecord(serviceName, 0L /* receiptTimeMillis */,
true /* cacheFlush */, recordsTtlMillis, emptyList() /* entries */));
- response.setInet4AddressRecord(new MdnsInetAddressRecord(
+ response.addInet4AddressRecord(new MdnsInetAddressRecord(
hostname, 0L /* receiptTimeMillis */, true /* cacheFlush */,
recordsTtlMillis, parseNumericAddress("192.0.2.123")));
- response.setInet6AddressRecord(new MdnsInetAddressRecord(
+ response.addInet6AddressRecord(new MdnsInetAddressRecord(
hostname, 0L /* receiptTimeMillis */, true /* cacheFlush */,
recordsTtlMillis, parseNumericAddress("2001:db8::123")));
return response;
@@ -126,7 +126,7 @@
MdnsInetAddressRecord record = new MdnsInetAddressRecord(name, MdnsRecord.TYPE_A, reader);
MdnsResponse response = new MdnsResponse(0, TEST_SERVICE_NAME, INTERFACE_INDEX, mNetwork);
assertFalse(response.hasInet4AddressRecord());
- assertTrue(response.setInet4AddressRecord(record));
+ assertTrue(response.addInet4AddressRecord(record));
assertEquals(response.getInet4AddressRecord(), record);
}
@@ -140,7 +140,7 @@
new MdnsInetAddressRecord(name, MdnsRecord.TYPE_AAAA, reader);
MdnsResponse response = new MdnsResponse(0, TEST_SERVICE_NAME, INTERFACE_INDEX, mNetwork);
assertFalse(response.hasInet6AddressRecord());
- assertTrue(response.setInet6AddressRecord(record));
+ assertTrue(response.addInet6AddressRecord(record));
assertEquals(response.getInet6AddressRecord(), record);
}
@@ -228,8 +228,8 @@
final MdnsResponse response = makeCompleteResponse(TEST_TTL_MS);
assertFalse(response.addPointerRecord(response.getPointerRecords().get(0)));
- assertFalse(response.setInet6AddressRecord(response.getInet6AddressRecord()));
- assertFalse(response.setInet4AddressRecord(response.getInet4AddressRecord()));
+ assertFalse(response.addInet6AddressRecord(response.getInet6AddressRecord()));
+ assertFalse(response.addInet4AddressRecord(response.getInet4AddressRecord()));
assertFalse(response.setServiceRecord(response.getServiceRecord()));
assertFalse(response.setTextRecord(response.getTextRecord()));
}
@@ -245,12 +245,14 @@
assertTrue(response.getRecords().stream().anyMatch(r ->
r == response.getPointerRecords().get(0)));
- assertTrue(response.setInet6AddressRecord(ttlZeroResponse.getInet6AddressRecord()));
+ assertTrue(response.addInet6AddressRecord(ttlZeroResponse.getInet6AddressRecord()));
+ assertEquals(1, response.getInet6AddressRecords().size());
assertEquals(0, response.getInet6AddressRecord().getTtl());
assertTrue(response.getRecords().stream().anyMatch(r ->
r == response.getInet6AddressRecord()));
- assertTrue(response.setInet4AddressRecord(ttlZeroResponse.getInet4AddressRecord()));
+ assertTrue(response.addInet4AddressRecord(ttlZeroResponse.getInet4AddressRecord()));
+ assertEquals(1, response.getInet4AddressRecords().size());
assertEquals(0, response.getInet4AddressRecord().getTtl());
assertTrue(response.getRecords().stream().anyMatch(r ->
r == response.getInet4AddressRecord()));
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java
index 76728cf..e7d7a98 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java
@@ -119,6 +119,26 @@
}
@Test
+ public void constructor_createWithUppercaseKeys_correctAttributes() {
+ MdnsServiceInfo info =
+ new MdnsServiceInfo(
+ "my-mdns-service",
+ new String[] {"_testtype", "_tcp"},
+ List.of(),
+ new String[] {"my-host", "local"},
+ 12345,
+ "192.168.1.1",
+ "2001::1",
+ List.of("KEY=Value"),
+ /* textEntries= */ null);
+
+ assertEquals("Value", info.getAttributeByKey("key"));
+ assertEquals("Value", info.getAttributeByKey("KEY"));
+ assertEquals(1, info.getAttributes().size());
+ assertEquals("KEY", info.getAttributes().keySet().iterator().next());
+ }
+
+ @Test
public void getInterfaceIndex_constructorWithDefaultValues_returnsMinusOne() {
MdnsServiceInfo info =
new MdnsServiceInfo(
@@ -177,8 +197,8 @@
List.of(),
new String[] {"my-host", "local"},
12345,
- "192.168.1.1",
- "2001::1",
+ List.of("192.168.1.1"),
+ List.of("2001::1"),
List.of(),
/* textEntries= */ null,
/* interfaceIndex= */ 20,
@@ -197,8 +217,8 @@
List.of(),
new String[] {"my-host", "local"},
12345,
- "192.168.1.1",
- "2001::1",
+ List.of("192.168.1.1", "192.168.1.2"),
+ List.of("2001::1", "2001::2"),
List.of("vn=Alphabet Inc.", "mn=Google Nest Hub Max", "id=12345"),
List.of(
MdnsServiceInfo.TextEntry.fromString("vn=Google Inc."),
@@ -217,7 +237,9 @@
assertArrayEquals(beforeParcel.getHostName(), afterParcel.getHostName());
assertEquals(beforeParcel.getPort(), afterParcel.getPort());
assertEquals(beforeParcel.getIpv4Address(), afterParcel.getIpv4Address());
+ assertEquals(beforeParcel.getIpv4Addresses(), afterParcel.getIpv4Addresses());
assertEquals(beforeParcel.getIpv6Address(), afterParcel.getIpv6Address());
+ assertEquals(beforeParcel.getIpv6Addresses(), afterParcel.getIpv6Addresses());
assertEquals(beforeParcel.getAttributes(), afterParcel.getAttributes());
assertEquals(beforeParcel.getInterfaceIndex(), afterParcel.getInterfaceIndex());
assertEquals(beforeParcel.getNetwork(), afterParcel.getNetwork());
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 a5c6123..3e2ea35 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
@@ -166,7 +166,7 @@
client =
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
- mockDecoderClock) {
+ mockDecoderClock, mockNetwork) {
@Override
MdnsPacketWriter createMdnsPacketWriter() {
return mockPacketWriter;
@@ -420,13 +420,13 @@
}
private static void verifyServiceInfo(MdnsServiceInfo serviceInfo, String serviceName,
- String[] serviceType, String ipv4Address, String ipv6Address, int port,
+ String[] serviceType, List<String> ipv4Addresses, List<String> ipv6Addresses, int port,
List<String> subTypes, Map<String, String> attributes, int interfaceIndex,
Network network) {
assertEquals(serviceName, serviceInfo.getServiceInstanceName());
assertArrayEquals(serviceType, serviceInfo.getServiceType());
- assertEquals(ipv4Address, serviceInfo.getIpv4Address());
- assertEquals(ipv6Address, serviceInfo.getIpv6Address());
+ assertEquals(ipv4Addresses, serviceInfo.getIpv4Addresses());
+ assertEquals(ipv6Addresses, serviceInfo.getIpv6Addresses());
assertEquals(port, serviceInfo.getPort());
assertEquals(subTypes, serviceInfo.getSubtypes());
for (String key : attributes.keySet()) {
@@ -449,8 +449,8 @@
verifyServiceInfo(serviceInfoCaptor.getAllValues().get(0),
"service-instance-1",
SERVICE_TYPE_LABELS,
- /* ipv4Address= */ null,
- /* ipv6Address= */ null,
+ /* ipv4Address= */ List.of(),
+ /* ipv6Address= */ List.of(),
/* port= */ 0,
/* subTypes= */ List.of(),
Collections.emptyMap(),
@@ -484,8 +484,8 @@
verifyServiceInfo(serviceInfoCaptor.getAllValues().get(0),
"service-instance-1",
SERVICE_TYPE_LABELS,
- ipV4Address /* ipv4Address */,
- null /* ipv6Address */,
+ List.of(ipV4Address) /* ipv4Address */,
+ List.of() /* ipv6Address */,
5353 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
@@ -539,8 +539,8 @@
verifyServiceInfo(serviceInfoCaptor.getAllValues().get(0),
"service-instance-1",
SERVICE_TYPE_LABELS,
- null /* ipv4Address */,
- ipV6Address /* ipv6Address */,
+ List.of() /* ipv4Address */,
+ List.of(ipV6Address) /* ipv6Address */,
5353 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
@@ -638,8 +638,8 @@
verifyServiceInfo(serviceInfoCaptor.getAllValues().get(0),
"service-instance-1",
SERVICE_TYPE_LABELS,
- "192.168.1.1" /* ipv4Address */,
- null /* ipv6Address */,
+ List.of("192.168.1.1") /* ipv4Address */,
+ List.of() /* ipv6Address */,
5353 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
@@ -701,7 +701,7 @@
final String serviceInstanceName = "service-instance-1";
client =
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
- mockDecoderClock) {
+ mockDecoderClock, mockNetwork) {
@Override
MdnsPacketWriter createMdnsPacketWriter() {
return mockPacketWriter;
@@ -740,7 +740,7 @@
final String serviceInstanceName = "service-instance-1";
client =
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
- mockDecoderClock) {
+ mockDecoderClock, mockNetwork) {
@Override
MdnsPacketWriter createMdnsPacketWriter() {
return mockPacketWriter;
@@ -773,7 +773,7 @@
final String serviceInstanceName = "service-instance-1";
client =
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
- mockDecoderClock) {
+ mockDecoderClock, mockNetwork) {
@Override
MdnsPacketWriter createMdnsPacketWriter() {
return mockPacketWriter;
@@ -834,8 +834,8 @@
verifyServiceInfo(serviceInfoCaptor.getAllValues().get(0),
serviceName,
SERVICE_TYPE_LABELS,
- null /* ipv4Address */,
- null /* ipv6Address */,
+ List.of() /* ipv4Address */,
+ List.of() /* ipv6Address */,
5353 /* port */,
Collections.singletonList(subtype) /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
@@ -847,8 +847,8 @@
verifyServiceInfo(serviceInfoCaptor.getAllValues().get(1),
serviceName,
SERVICE_TYPE_LABELS,
- ipV4Address /* ipv4Address */,
- null /* ipv6Address */,
+ List.of(ipV4Address) /* ipv4Address */,
+ List.of() /* ipv6Address */,
5353 /* port */,
Collections.singletonList(subtype) /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
@@ -860,8 +860,8 @@
verifyServiceInfo(serviceInfoCaptor.getAllValues().get(2),
serviceName,
SERVICE_TYPE_LABELS,
- ipV4Address /* ipv4Address */,
- ipV6Address /* ipv6Address */,
+ List.of(ipV4Address) /* ipv4Address */,
+ List.of(ipV6Address) /* ipv6Address */,
5354 /* port */,
Collections.singletonList(subtype) /* subTypes */,
Collections.singletonMap("key", "value") /* attributes */,
@@ -873,8 +873,8 @@
verifyServiceInfo(serviceInfoCaptor.getAllValues().get(3),
serviceName,
SERVICE_TYPE_LABELS,
- ipV4Address /* ipv4Address */,
- ipV6Address /* ipv6Address */,
+ List.of(ipV4Address) /* ipv4Address */,
+ List.of(ipV6Address) /* ipv6Address */,
5354 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", "value") /* attributes */,
@@ -886,8 +886,8 @@
verifyServiceInfo(serviceInfoCaptor.getAllValues().get(4),
serviceName,
SERVICE_TYPE_LABELS,
- ipV4Address /* ipv4Address */,
- ipV6Address /* ipv6Address */,
+ List.of(ipV4Address) /* ipv4Address */,
+ List.of(ipV6Address) /* ipv6Address */,
5354 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", "value") /* attributes */,
@@ -897,7 +897,8 @@
@Test
public void testProcessResponse_Resolve() throws Exception {
- client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor);
+ client = new MdnsServiceTypeClient(
+ SERVICE_TYPE, mockSocketClient, currentThreadExecutor, mockNetwork);
final String instanceName = "service-instance";
final String[] hostname = new String[] { "testhost "};
@@ -982,8 +983,8 @@
verifyServiceInfo(serviceInfoCaptor.getValue(),
instanceName,
SERVICE_TYPE_LABELS,
- ipV4Address,
- ipV6Address,
+ List.of(ipV4Address),
+ List.of(ipV6Address),
1234 /* port */,
Collections.emptyList() /* subTypes */,
Collections.emptyMap() /* attributes */,
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
index 9048686..abb1747 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
@@ -412,7 +412,8 @@
mdnsClient.startDiscovery();
verify(mockCallback, timeout(TIMEOUT).atLeast(1))
- .onFailedToParseMdnsResponse(anyInt(), eq(MdnsResponseErrorCode.ERROR_END_OF_FILE));
+ .onFailedToParseMdnsResponse(
+ anyInt(), eq(MdnsResponseErrorCode.ERROR_END_OF_FILE), any());
mdnsClient.stopDiscovery();
}
@@ -433,7 +434,8 @@
mdnsClient.startDiscovery();
verify(mockCallback, timeout(TIMEOUT).atLeast(1))
- .onFailedToParseMdnsResponse(1, MdnsResponseErrorCode.ERROR_END_OF_FILE);
+ .onFailedToParseMdnsResponse(
+ eq(1), eq(MdnsResponseErrorCode.ERROR_END_OF_FILE), any());
mdnsClient.stopDiscovery();
}
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 13a6a6f..8046263 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -82,7 +82,6 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -395,10 +394,6 @@
verify(mNetd).registerUnsolicitedEventListener(alertObserver.capture());
mAlertObserver = alertObserver.getValue();
- // Make augmentWithStackedInterfaces returns the interfaces that was passed to it.
- doAnswer(inv -> ((String[]) inv.getArgument(0)).clone())
- .when(mStatsFactory).augmentWithStackedInterfaces(any());
-
// Catch TetheringEventCallback during systemReady().
ArgumentCaptor<TetheringManager.TetheringEventCallback> tetheringEventCbCaptor =
ArgumentCaptor.forClass(TetheringManager.TetheringEventCallback.class);
diff --git a/tools/gn2bp/Android.bp.swp b/tools/gn2bp/Android.bp.swp
index d22a576..83dd341 100644
--- a/tools/gn2bp/Android.bp.swp
+++ b/tools/gn2bp/Android.bp.swp
@@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-// This file is automatically generated by gen_android_bp. Do not edit.
+// This file is automatically generated by gn2bp/gen_android_bp. Do not edit.
build = ["Android.extras.bp"]
-// GN: PACKAGE
+// The actual license can be found in Android.extras.bp
package {
default_applicable_licenses: [
"external_cronet_license",
@@ -1378,6 +1378,8 @@
"base/vlog.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
],
@@ -1436,8 +1438,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -6561,6 +6561,8 @@
"components/cronet/android/cronet_jni.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libz",
@@ -6640,8 +6642,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_brotli_common",
"cronet_aml_third_party_brotli_dec",
"cronet_aml_third_party_icu_icui18n",
@@ -7873,6 +7873,8 @@
"components/cronet/android/url_request_error.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libz",
@@ -7949,8 +7951,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_brotli_common",
"cronet_aml_third_party_brotli_dec",
"cronet_aml_third_party_icu_icui18n",
@@ -8824,6 +8824,8 @@
"components/cronet/url_request_context_config.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libz",
@@ -8898,8 +8900,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_brotli_common",
"cronet_aml_third_party_brotli_dec",
"cronet_aml_third_party_icu_icui18n",
@@ -9648,6 +9648,8 @@
"components/cronet/metrics_util.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
],
@@ -9707,8 +9709,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -9968,6 +9968,8 @@
"components/metrics/library_support/histogram_manager.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libprotobuf-cpp-lite",
@@ -10028,8 +10030,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -10400,6 +10400,8 @@
"components/prefs/writeable_pref_store.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
],
@@ -10459,8 +10461,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -11023,6 +11023,8 @@
"crypto/unexportable_key_metrics.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
],
@@ -11082,8 +11084,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -12426,6 +12426,8 @@
"net/dns/test_dns_config_service.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libz",
@@ -12494,8 +12496,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_brotli_common",
"cronet_aml_third_party_brotli_dec",
"cronet_aml_third_party_icu_icui18n",
@@ -12835,6 +12835,8 @@
"net/dns/public/util.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libz",
@@ -12902,8 +12904,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_brotli_common",
"cronet_aml_third_party_brotli_dec",
"cronet_aml_third_party_icu_icui18n",
@@ -13634,6 +13634,8 @@
"net/http/transport_security_state.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libz",
@@ -13703,8 +13705,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_brotli_common",
"cronet_aml_third_party_brotli_dec",
"cronet_aml_third_party_icu_icui18n",
@@ -14648,6 +14648,8 @@
"net/url_request/websocket_handshake_userdata_key.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libz",
@@ -14718,8 +14720,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_brotli_common",
"cronet_aml_third_party_brotli_dec",
"cronet_aml_third_party_icu_icui18n",
@@ -15543,6 +15543,8 @@
":cronet_aml_net_isolation_info_proto_gen",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libprotobuf-cpp-lite",
@@ -15605,8 +15607,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_brotli_common",
"cronet_aml_third_party_brotli_dec",
"cronet_aml_third_party_icu_icui18n",
@@ -16218,6 +16218,8 @@
":cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libprotobuf-cpp-lite",
@@ -16283,8 +16285,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -16589,6 +16589,8 @@
"net/extras/preload_data/decoder.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
],
@@ -16648,8 +16650,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -17629,6 +17629,10 @@
"net/third_party/quiche/src/quiche/quic/core/proto/crypto_server_config.proto",
"net/third_party/quiche/src/quiche/quic/core/proto/source_address_token.proto",
],
+ shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
+ ],
tools: [
"cronet_aml_third_party_protobuf_protoc",
],
@@ -18039,6 +18043,8 @@
"net/third_party/quiche/src/quiche/spdy/core/spdy_simple_arena.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
"libprotobuf-cpp-lite",
@@ -18101,8 +18107,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -19419,6 +19423,8 @@
"net/traffic_annotation/network_traffic_annotation_android.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
],
@@ -19478,8 +19484,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -19749,6 +19753,8 @@
"net/third_party/uri_template/uri_template.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
],
@@ -19808,8 +19814,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -30095,350 +30099,6 @@
},
}
-// GN: //third_party/boringssl:boringssl
-cc_library_static {
- name: "cronet_aml_third_party_boringssl_boringssl",
- srcs: [
- "third_party/boringssl/err_data.c",
- "third_party/boringssl/src/crypto/asn1/a_bitstr.c",
- "third_party/boringssl/src/crypto/asn1/a_bool.c",
- "third_party/boringssl/src/crypto/asn1/a_d2i_fp.c",
- "third_party/boringssl/src/crypto/asn1/a_dup.c",
- "third_party/boringssl/src/crypto/asn1/a_gentm.c",
- "third_party/boringssl/src/crypto/asn1/a_i2d_fp.c",
- "third_party/boringssl/src/crypto/asn1/a_int.c",
- "third_party/boringssl/src/crypto/asn1/a_mbstr.c",
- "third_party/boringssl/src/crypto/asn1/a_object.c",
- "third_party/boringssl/src/crypto/asn1/a_octet.c",
- "third_party/boringssl/src/crypto/asn1/a_print.c",
- "third_party/boringssl/src/crypto/asn1/a_strex.c",
- "third_party/boringssl/src/crypto/asn1/a_strnid.c",
- "third_party/boringssl/src/crypto/asn1/a_time.c",
- "third_party/boringssl/src/crypto/asn1/a_type.c",
- "third_party/boringssl/src/crypto/asn1/a_utctm.c",
- "third_party/boringssl/src/crypto/asn1/a_utf8.c",
- "third_party/boringssl/src/crypto/asn1/asn1_lib.c",
- "third_party/boringssl/src/crypto/asn1/asn1_par.c",
- "third_party/boringssl/src/crypto/asn1/asn_pack.c",
- "third_party/boringssl/src/crypto/asn1/f_int.c",
- "third_party/boringssl/src/crypto/asn1/f_string.c",
- "third_party/boringssl/src/crypto/asn1/posix_time.c",
- "third_party/boringssl/src/crypto/asn1/tasn_dec.c",
- "third_party/boringssl/src/crypto/asn1/tasn_enc.c",
- "third_party/boringssl/src/crypto/asn1/tasn_fre.c",
- "third_party/boringssl/src/crypto/asn1/tasn_new.c",
- "third_party/boringssl/src/crypto/asn1/tasn_typ.c",
- "third_party/boringssl/src/crypto/asn1/tasn_utl.c",
- "third_party/boringssl/src/crypto/base64/base64.c",
- "third_party/boringssl/src/crypto/bio/bio.c",
- "third_party/boringssl/src/crypto/bio/bio_mem.c",
- "third_party/boringssl/src/crypto/bio/connect.c",
- "third_party/boringssl/src/crypto/bio/fd.c",
- "third_party/boringssl/src/crypto/bio/file.c",
- "third_party/boringssl/src/crypto/bio/hexdump.c",
- "third_party/boringssl/src/crypto/bio/pair.c",
- "third_party/boringssl/src/crypto/bio/printf.c",
- "third_party/boringssl/src/crypto/bio/socket.c",
- "third_party/boringssl/src/crypto/bio/socket_helper.c",
- "third_party/boringssl/src/crypto/blake2/blake2.c",
- "third_party/boringssl/src/crypto/bn_extra/bn_asn1.c",
- "third_party/boringssl/src/crypto/bn_extra/convert.c",
- "third_party/boringssl/src/crypto/buf/buf.c",
- "third_party/boringssl/src/crypto/bytestring/asn1_compat.c",
- "third_party/boringssl/src/crypto/bytestring/ber.c",
- "third_party/boringssl/src/crypto/bytestring/cbb.c",
- "third_party/boringssl/src/crypto/bytestring/cbs.c",
- "third_party/boringssl/src/crypto/bytestring/unicode.c",
- "third_party/boringssl/src/crypto/chacha/chacha.c",
- "third_party/boringssl/src/crypto/cipher_extra/cipher_extra.c",
- "third_party/boringssl/src/crypto/cipher_extra/derive_key.c",
- "third_party/boringssl/src/crypto/cipher_extra/e_aesctrhmac.c",
- "third_party/boringssl/src/crypto/cipher_extra/e_aesgcmsiv.c",
- "third_party/boringssl/src/crypto/cipher_extra/e_chacha20poly1305.c",
- "third_party/boringssl/src/crypto/cipher_extra/e_des.c",
- "third_party/boringssl/src/crypto/cipher_extra/e_null.c",
- "third_party/boringssl/src/crypto/cipher_extra/e_rc2.c",
- "third_party/boringssl/src/crypto/cipher_extra/e_rc4.c",
- "third_party/boringssl/src/crypto/cipher_extra/e_tls.c",
- "third_party/boringssl/src/crypto/cipher_extra/tls_cbc.c",
- "third_party/boringssl/src/crypto/conf/conf.c",
- "third_party/boringssl/src/crypto/cpu_aarch64_apple.c",
- "third_party/boringssl/src/crypto/cpu_aarch64_fuchsia.c",
- "third_party/boringssl/src/crypto/cpu_aarch64_linux.c",
- "third_party/boringssl/src/crypto/cpu_aarch64_win.c",
- "third_party/boringssl/src/crypto/cpu_arm.c",
- "third_party/boringssl/src/crypto/cpu_arm_linux.c",
- "third_party/boringssl/src/crypto/cpu_intel.c",
- "third_party/boringssl/src/crypto/cpu_ppc64le.c",
- "third_party/boringssl/src/crypto/crypto.c",
- "third_party/boringssl/src/crypto/curve25519/curve25519.c",
- "third_party/boringssl/src/crypto/curve25519/spake25519.c",
- "third_party/boringssl/src/crypto/des/des.c",
- "third_party/boringssl/src/crypto/dh_extra/dh_asn1.c",
- "third_party/boringssl/src/crypto/dh_extra/params.c",
- "third_party/boringssl/src/crypto/digest_extra/digest_extra.c",
- "third_party/boringssl/src/crypto/dsa/dsa.c",
- "third_party/boringssl/src/crypto/dsa/dsa_asn1.c",
- "third_party/boringssl/src/crypto/ec_extra/ec_asn1.c",
- "third_party/boringssl/src/crypto/ec_extra/ec_derive.c",
- "third_party/boringssl/src/crypto/ec_extra/hash_to_curve.c",
- "third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.c",
- "third_party/boringssl/src/crypto/ecdsa_extra/ecdsa_asn1.c",
- "third_party/boringssl/src/crypto/engine/engine.c",
- "third_party/boringssl/src/crypto/err/err.c",
- "third_party/boringssl/src/crypto/evp/evp.c",
- "third_party/boringssl/src/crypto/evp/evp_asn1.c",
- "third_party/boringssl/src/crypto/evp/evp_ctx.c",
- "third_party/boringssl/src/crypto/evp/p_dsa_asn1.c",
- "third_party/boringssl/src/crypto/evp/p_ec.c",
- "third_party/boringssl/src/crypto/evp/p_ec_asn1.c",
- "third_party/boringssl/src/crypto/evp/p_ed25519.c",
- "third_party/boringssl/src/crypto/evp/p_ed25519_asn1.c",
- "third_party/boringssl/src/crypto/evp/p_hkdf.c",
- "third_party/boringssl/src/crypto/evp/p_rsa.c",
- "third_party/boringssl/src/crypto/evp/p_rsa_asn1.c",
- "third_party/boringssl/src/crypto/evp/p_x25519.c",
- "third_party/boringssl/src/crypto/evp/p_x25519_asn1.c",
- "third_party/boringssl/src/crypto/evp/pbkdf.c",
- "third_party/boringssl/src/crypto/evp/print.c",
- "third_party/boringssl/src/crypto/evp/scrypt.c",
- "third_party/boringssl/src/crypto/evp/sign.c",
- "third_party/boringssl/src/crypto/ex_data.c",
- "third_party/boringssl/src/crypto/fipsmodule/bcm.c",
- "third_party/boringssl/src/crypto/fipsmodule/fips_shared_support.c",
- "third_party/boringssl/src/crypto/hkdf/hkdf.c",
- "third_party/boringssl/src/crypto/hpke/hpke.c",
- "third_party/boringssl/src/crypto/hrss/hrss.c",
- "third_party/boringssl/src/crypto/lhash/lhash.c",
- "third_party/boringssl/src/crypto/mem.c",
- "third_party/boringssl/src/crypto/obj/obj.c",
- "third_party/boringssl/src/crypto/obj/obj_xref.c",
- "third_party/boringssl/src/crypto/pem/pem_all.c",
- "third_party/boringssl/src/crypto/pem/pem_info.c",
- "third_party/boringssl/src/crypto/pem/pem_lib.c",
- "third_party/boringssl/src/crypto/pem/pem_oth.c",
- "third_party/boringssl/src/crypto/pem/pem_pk8.c",
- "third_party/boringssl/src/crypto/pem/pem_pkey.c",
- "third_party/boringssl/src/crypto/pem/pem_x509.c",
- "third_party/boringssl/src/crypto/pem/pem_xaux.c",
- "third_party/boringssl/src/crypto/pkcs7/pkcs7.c",
- "third_party/boringssl/src/crypto/pkcs7/pkcs7_x509.c",
- "third_party/boringssl/src/crypto/pkcs8/p5_pbev2.c",
- "third_party/boringssl/src/crypto/pkcs8/pkcs8.c",
- "third_party/boringssl/src/crypto/pkcs8/pkcs8_x509.c",
- "third_party/boringssl/src/crypto/poly1305/poly1305.c",
- "third_party/boringssl/src/crypto/poly1305/poly1305_arm.c",
- "third_party/boringssl/src/crypto/poly1305/poly1305_vec.c",
- "third_party/boringssl/src/crypto/pool/pool.c",
- "third_party/boringssl/src/crypto/rand_extra/deterministic.c",
- "third_party/boringssl/src/crypto/rand_extra/forkunsafe.c",
- "third_party/boringssl/src/crypto/rand_extra/fuchsia.c",
- "third_party/boringssl/src/crypto/rand_extra/passive.c",
- "third_party/boringssl/src/crypto/rand_extra/rand_extra.c",
- "third_party/boringssl/src/crypto/rand_extra/windows.c",
- "third_party/boringssl/src/crypto/rc4/rc4.c",
- "third_party/boringssl/src/crypto/refcount_c11.c",
- "third_party/boringssl/src/crypto/refcount_lock.c",
- "third_party/boringssl/src/crypto/rsa_extra/rsa_asn1.c",
- "third_party/boringssl/src/crypto/rsa_extra/rsa_print.c",
- "third_party/boringssl/src/crypto/siphash/siphash.c",
- "third_party/boringssl/src/crypto/stack/stack.c",
- "third_party/boringssl/src/crypto/thread.c",
- "third_party/boringssl/src/crypto/thread_none.c",
- "third_party/boringssl/src/crypto/thread_pthread.c",
- "third_party/boringssl/src/crypto/thread_win.c",
- "third_party/boringssl/src/crypto/trust_token/pmbtoken.c",
- "third_party/boringssl/src/crypto/trust_token/trust_token.c",
- "third_party/boringssl/src/crypto/trust_token/voprf.c",
- "third_party/boringssl/src/crypto/x509/a_digest.c",
- "third_party/boringssl/src/crypto/x509/a_sign.c",
- "third_party/boringssl/src/crypto/x509/a_verify.c",
- "third_party/boringssl/src/crypto/x509/algorithm.c",
- "third_party/boringssl/src/crypto/x509/asn1_gen.c",
- "third_party/boringssl/src/crypto/x509/by_dir.c",
- "third_party/boringssl/src/crypto/x509/by_file.c",
- "third_party/boringssl/src/crypto/x509/i2d_pr.c",
- "third_party/boringssl/src/crypto/x509/name_print.c",
- "third_party/boringssl/src/crypto/x509/rsa_pss.c",
- "third_party/boringssl/src/crypto/x509/t_crl.c",
- "third_party/boringssl/src/crypto/x509/t_req.c",
- "third_party/boringssl/src/crypto/x509/t_x509.c",
- "third_party/boringssl/src/crypto/x509/t_x509a.c",
- "third_party/boringssl/src/crypto/x509/x509.c",
- "third_party/boringssl/src/crypto/x509/x509_att.c",
- "third_party/boringssl/src/crypto/x509/x509_cmp.c",
- "third_party/boringssl/src/crypto/x509/x509_d2.c",
- "third_party/boringssl/src/crypto/x509/x509_def.c",
- "third_party/boringssl/src/crypto/x509/x509_ext.c",
- "third_party/boringssl/src/crypto/x509/x509_lu.c",
- "third_party/boringssl/src/crypto/x509/x509_obj.c",
- "third_party/boringssl/src/crypto/x509/x509_req.c",
- "third_party/boringssl/src/crypto/x509/x509_set.c",
- "third_party/boringssl/src/crypto/x509/x509_trs.c",
- "third_party/boringssl/src/crypto/x509/x509_txt.c",
- "third_party/boringssl/src/crypto/x509/x509_v3.c",
- "third_party/boringssl/src/crypto/x509/x509_vfy.c",
- "third_party/boringssl/src/crypto/x509/x509_vpm.c",
- "third_party/boringssl/src/crypto/x509/x509cset.c",
- "third_party/boringssl/src/crypto/x509/x509name.c",
- "third_party/boringssl/src/crypto/x509/x509rset.c",
- "third_party/boringssl/src/crypto/x509/x509spki.c",
- "third_party/boringssl/src/crypto/x509/x_algor.c",
- "third_party/boringssl/src/crypto/x509/x_all.c",
- "third_party/boringssl/src/crypto/x509/x_attrib.c",
- "third_party/boringssl/src/crypto/x509/x_crl.c",
- "third_party/boringssl/src/crypto/x509/x_exten.c",
- "third_party/boringssl/src/crypto/x509/x_info.c",
- "third_party/boringssl/src/crypto/x509/x_name.c",
- "third_party/boringssl/src/crypto/x509/x_pkey.c",
- "third_party/boringssl/src/crypto/x509/x_pubkey.c",
- "third_party/boringssl/src/crypto/x509/x_req.c",
- "third_party/boringssl/src/crypto/x509/x_sig.c",
- "third_party/boringssl/src/crypto/x509/x_spki.c",
- "third_party/boringssl/src/crypto/x509/x_val.c",
- "third_party/boringssl/src/crypto/x509/x_x509.c",
- "third_party/boringssl/src/crypto/x509/x_x509a.c",
- "third_party/boringssl/src/crypto/x509v3/pcy_cache.c",
- "third_party/boringssl/src/crypto/x509v3/pcy_data.c",
- "third_party/boringssl/src/crypto/x509v3/pcy_map.c",
- "third_party/boringssl/src/crypto/x509v3/pcy_node.c",
- "third_party/boringssl/src/crypto/x509v3/pcy_tree.c",
- "third_party/boringssl/src/crypto/x509v3/v3_akey.c",
- "third_party/boringssl/src/crypto/x509v3/v3_akeya.c",
- "third_party/boringssl/src/crypto/x509v3/v3_alt.c",
- "third_party/boringssl/src/crypto/x509v3/v3_bcons.c",
- "third_party/boringssl/src/crypto/x509v3/v3_bitst.c",
- "third_party/boringssl/src/crypto/x509v3/v3_conf.c",
- "third_party/boringssl/src/crypto/x509v3/v3_cpols.c",
- "third_party/boringssl/src/crypto/x509v3/v3_crld.c",
- "third_party/boringssl/src/crypto/x509v3/v3_enum.c",
- "third_party/boringssl/src/crypto/x509v3/v3_extku.c",
- "third_party/boringssl/src/crypto/x509v3/v3_genn.c",
- "third_party/boringssl/src/crypto/x509v3/v3_ia5.c",
- "third_party/boringssl/src/crypto/x509v3/v3_info.c",
- "third_party/boringssl/src/crypto/x509v3/v3_int.c",
- "third_party/boringssl/src/crypto/x509v3/v3_lib.c",
- "third_party/boringssl/src/crypto/x509v3/v3_ncons.c",
- "third_party/boringssl/src/crypto/x509v3/v3_ocsp.c",
- "third_party/boringssl/src/crypto/x509v3/v3_pci.c",
- "third_party/boringssl/src/crypto/x509v3/v3_pcia.c",
- "third_party/boringssl/src/crypto/x509v3/v3_pcons.c",
- "third_party/boringssl/src/crypto/x509v3/v3_pmaps.c",
- "third_party/boringssl/src/crypto/x509v3/v3_prn.c",
- "third_party/boringssl/src/crypto/x509v3/v3_purp.c",
- "third_party/boringssl/src/crypto/x509v3/v3_skey.c",
- "third_party/boringssl/src/crypto/x509v3/v3_utl.c",
- "third_party/boringssl/src/ssl/bio_ssl.cc",
- "third_party/boringssl/src/ssl/d1_both.cc",
- "third_party/boringssl/src/ssl/d1_lib.cc",
- "third_party/boringssl/src/ssl/d1_pkt.cc",
- "third_party/boringssl/src/ssl/d1_srtp.cc",
- "third_party/boringssl/src/ssl/dtls_method.cc",
- "third_party/boringssl/src/ssl/dtls_record.cc",
- "third_party/boringssl/src/ssl/encrypted_client_hello.cc",
- "third_party/boringssl/src/ssl/extensions.cc",
- "third_party/boringssl/src/ssl/handoff.cc",
- "third_party/boringssl/src/ssl/handshake.cc",
- "third_party/boringssl/src/ssl/handshake_client.cc",
- "third_party/boringssl/src/ssl/handshake_server.cc",
- "third_party/boringssl/src/ssl/s3_both.cc",
- "third_party/boringssl/src/ssl/s3_lib.cc",
- "third_party/boringssl/src/ssl/s3_pkt.cc",
- "third_party/boringssl/src/ssl/ssl_aead_ctx.cc",
- "third_party/boringssl/src/ssl/ssl_asn1.cc",
- "third_party/boringssl/src/ssl/ssl_buffer.cc",
- "third_party/boringssl/src/ssl/ssl_cert.cc",
- "third_party/boringssl/src/ssl/ssl_cipher.cc",
- "third_party/boringssl/src/ssl/ssl_file.cc",
- "third_party/boringssl/src/ssl/ssl_key_share.cc",
- "third_party/boringssl/src/ssl/ssl_lib.cc",
- "third_party/boringssl/src/ssl/ssl_privkey.cc",
- "third_party/boringssl/src/ssl/ssl_session.cc",
- "third_party/boringssl/src/ssl/ssl_stat.cc",
- "third_party/boringssl/src/ssl/ssl_transcript.cc",
- "third_party/boringssl/src/ssl/ssl_versions.cc",
- "third_party/boringssl/src/ssl/ssl_x509.cc",
- "third_party/boringssl/src/ssl/t1_enc.cc",
- "third_party/boringssl/src/ssl/tls13_both.cc",
- "third_party/boringssl/src/ssl/tls13_client.cc",
- "third_party/boringssl/src/ssl/tls13_enc.cc",
- "third_party/boringssl/src/ssl/tls13_server.cc",
- "third_party/boringssl/src/ssl/tls_method.cc",
- "third_party/boringssl/src/ssl/tls_record.cc",
- ],
- static_libs: [
- "cronet_aml_third_party_boringssl_boringssl_asm",
- ],
- defaults: [
- "cronet_aml_defaults",
- ],
- cflags: [
- "-DANDROID",
- "-DANDROID_NDK_VERSION_ROLL=r23_1",
- "-DBORINGSSL_ALLOW_CXX_RUNTIME",
- "-DBORINGSSL_IMPLEMENTATION",
- "-DBORINGSSL_NO_STATIC_INITIALIZER",
- "-DCR_CLANG_REVISION=\"llvmorg-16-init-6578-g0d30e92f-2\"",
- "-DCR_LIBCXX_REVISION=64d36e572d3f9719c5d75011a718f33f11126851",
- "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
- "-DHAVE_SYS_UIO_H",
- "-DNDEBUG",
- "-DNO_UNWIND_TABLES",
- "-DNVALGRIND",
- "-DOFFICIAL_BUILD",
- "-DOPENSSL_SMALL",
- "-D_GNU_SOURCE",
- "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
- "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
- "-Oz",
- "-fdata-sections",
- "-ffunction-sections",
- "-fno-asynchronous-unwind-tables",
- "-fno-unwind-tables",
- "-fvisibility-inlines-hidden",
- "-fvisibility=hidden",
- "-g1",
- ],
- local_include_dirs: [
- "./",
- "buildtools/third_party/libc++/",
- "buildtools/third_party/libc++/trunk/include",
- "buildtools/third_party/libc++abi/trunk/include",
- "third_party/boringssl/src/include/",
- ],
- cpp_std: "c++17",
- ldflags: [
- "-Wl,--as-needed",
- "-Wl,--gc-sections",
- "-Wl,--icf=all",
- ],
- target: {
- android_arm: {
- cflags: [
- "-fstack-protector",
- ],
- },
- android_arm64: {
- cflags: [
- "-fstack-protector",
- "-mno-outline",
- "-mno-outline-atomics",
- ],
- },
- android_x86: {
- cflags: [
- "-msse3",
- ],
- },
- android_x86_64: {
- cflags: [
- "-fstack-protector",
- "-msse3",
- ],
- },
- },
-}
-
// GN: //third_party/boringssl:boringssl__testing
cc_library_static {
name: "cronet_aml_third_party_boringssl_boringssl__testing",
@@ -30810,145 +30470,6 @@
},
}
-// GN: //third_party/boringssl:boringssl_asm
-cc_library_static {
- name: "cronet_aml_third_party_boringssl_boringssl_asm",
- defaults: [
- "cronet_aml_defaults",
- ],
- cflags: [
- "-DANDROID",
- "-DANDROID_NDK_VERSION_ROLL=r23_1",
- "-DCR_CLANG_REVISION=\"llvmorg-16-init-6578-g0d30e92f-2\"",
- "-DCR_LIBCXX_REVISION=64d36e572d3f9719c5d75011a718f33f11126851",
- "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
- "-DHAVE_SYS_UIO_H",
- "-DNDEBUG",
- "-DNO_UNWIND_TABLES",
- "-DNVALGRIND",
- "-DOFFICIAL_BUILD",
- "-D_FORTIFY_SOURCE=2",
- "-D_GNU_SOURCE",
- "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
- "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
- "-D__STDC_CONSTANT_MACROS",
- "-D__STDC_FORMAT_MACROS",
- "-Oz",
- "-fdata-sections",
- "-ffunction-sections",
- "-fno-asynchronous-unwind-tables",
- "-fno-unwind-tables",
- "-fvisibility-inlines-hidden",
- "-fvisibility=hidden",
- "-g1",
- ],
- local_include_dirs: [
- "./",
- "buildtools/third_party/libc++/",
- "buildtools/third_party/libc++/trunk/include",
- "buildtools/third_party/libc++abi/trunk/include",
- "third_party/boringssl/src/include/",
- ],
- cpp_std: "c++17",
- ldflags: [
- "-Wl,--as-needed",
- "-Wl,--gc-sections",
- "-Wl,--icf=all",
- ],
- target: {
- android_arm: {
- srcs: [
- "third_party/boringssl/linux-arm/crypto/chacha/chacha-armv4.S",
- "third_party/boringssl/linux-arm/crypto/fipsmodule/aesv8-armx32.S",
- "third_party/boringssl/linux-arm/crypto/fipsmodule/armv4-mont.S",
- "third_party/boringssl/linux-arm/crypto/fipsmodule/bsaes-armv7.S",
- "third_party/boringssl/linux-arm/crypto/fipsmodule/ghash-armv4.S",
- "third_party/boringssl/linux-arm/crypto/fipsmodule/ghashv8-armx32.S",
- "third_party/boringssl/linux-arm/crypto/fipsmodule/sha1-armv4-large.S",
- "third_party/boringssl/linux-arm/crypto/fipsmodule/sha256-armv4.S",
- "third_party/boringssl/linux-arm/crypto/fipsmodule/sha512-armv4.S",
- "third_party/boringssl/linux-arm/crypto/fipsmodule/vpaes-armv7.S",
- "third_party/boringssl/linux-arm/crypto/test/trampoline-armv4.S",
- "third_party/boringssl/src/crypto/curve25519/asm/x25519-asm-arm.S",
- "third_party/boringssl/src/crypto/poly1305/poly1305_arm_asm.S",
- ],
- cflags: [
- "-fstack-protector",
- ],
- },
- android_arm64: {
- srcs: [
- "third_party/boringssl/linux-aarch64/crypto/chacha/chacha-armv8.S",
- "third_party/boringssl/linux-aarch64/crypto/cipher_extra/chacha20_poly1305_armv8.S",
- "third_party/boringssl/linux-aarch64/crypto/fipsmodule/aesv8-armx64.S",
- "third_party/boringssl/linux-aarch64/crypto/fipsmodule/armv8-mont.S",
- "third_party/boringssl/linux-aarch64/crypto/fipsmodule/ghash-neon-armv8.S",
- "third_party/boringssl/linux-aarch64/crypto/fipsmodule/ghashv8-armx64.S",
- "third_party/boringssl/linux-aarch64/crypto/fipsmodule/p256-armv8-asm.S",
- "third_party/boringssl/linux-aarch64/crypto/fipsmodule/p256_beeu-armv8-asm.S",
- "third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha1-armv8.S",
- "third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha256-armv8.S",
- "third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha512-armv8.S",
- "third_party/boringssl/linux-aarch64/crypto/fipsmodule/vpaes-armv8.S",
- "third_party/boringssl/linux-aarch64/crypto/test/trampoline-armv8.S",
- ],
- cflags: [
- "-fstack-protector",
- "-mno-outline",
- "-mno-outline-atomics",
- ],
- },
- android_x86: {
- srcs: [
- "third_party/boringssl/linux-x86/crypto/chacha/chacha-x86.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/aesni-x86.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/bn-586.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/co-586.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/ghash-ssse3-x86.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/ghash-x86.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/md5-586.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/sha1-586.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/sha256-586.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/sha512-586.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/vpaes-x86.S",
- "third_party/boringssl/linux-x86/crypto/fipsmodule/x86-mont.S",
- "third_party/boringssl/linux-x86/crypto/test/trampoline-x86.S",
- ],
- cflags: [
- "-msse3",
- ],
- },
- android_x86_64: {
- srcs: [
- "third_party/boringssl/linux-x86_64/crypto/chacha/chacha-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/cipher_extra/aes128gcmsiv-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/cipher_extra/chacha20_poly1305_x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/aesni-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/ghash-ssse3-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/ghash-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/md5-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/p256-x86_64-asm.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/p256_beeu-x86_64-asm.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/rdrand-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/rsaz-avx2.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/sha1-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/sha256-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/sha512-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/vpaes-x86_64.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/x86_64-mont.S",
- "third_party/boringssl/linux-x86_64/crypto/fipsmodule/x86_64-mont5.S",
- "third_party/boringssl/linux-x86_64/crypto/test/trampoline-x86_64.S",
- "third_party/boringssl/src/crypto/hrss/asm/poly_rq_mul.S",
- ],
- cflags: [
- "-fstack-protector",
- "-msse3",
- ],
- },
- },
-}
-
// GN: //third_party/boringssl:boringssl_asm__testing
cc_library_static {
name: "cronet_aml_third_party_boringssl_boringssl_asm__testing",
@@ -34787,6 +34308,8 @@
"url/url_util.cc",
],
shared_libs: [
+ "//external/cronet/third_party/boringssl:libcrypto",
+ "//external/cronet/third_party/boringssl:libssl",
"libandroid",
"liblog",
],
@@ -34846,8 +34369,6 @@
"cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
"cronet_aml_third_party_android_ndk_cpu_features",
"cronet_aml_third_party_ashmem_ashmem",
- "cronet_aml_third_party_boringssl_boringssl",
- "cronet_aml_third_party_boringssl_boringssl_asm",
"cronet_aml_third_party_icu_icui18n",
"cronet_aml_third_party_icu_icuuc_private",
"cronet_aml_third_party_libevent_libevent",
@@ -35227,51 +34748,3 @@
],
}
-// GN: LICENSE
-license {
- name: "external_cronet_license",
- license_kinds: [
- "SPDX-license-identifier-AFL-2.0",
- "SPDX-license-identifier-Apache-2.0",
- "SPDX-license-identifier-BSD",
- "SPDX-license-identifier-BSL-1.0",
- "SPDX-license-identifier-ICU",
- "SPDX-license-identifier-ISC",
- "SPDX-license-identifier-MIT",
- "SPDX-license-identifier-MPL",
- "SPDX-license-identifier-MPL-1.1",
- "SPDX-license-identifier-MPL-2.0",
- "SPDX-license-identifier-NCSA",
- "SPDX-license-identifier-OpenSSL",
- "SPDX-license-identifier-Unicode-DFS",
- "legacy_unencumbered",
- ],
- license_text: [
- "LICENSE",
- "base/third_party/double_conversion/LICENSE",
- "base/third_party/dynamic_annotations/LICENSE",
- "base/third_party/icu/LICENSE",
- "base/third_party/nspr/LICENSE",
- "base/third_party/superfasthash/LICENSE",
- "base/third_party/symbolize/LICENSE",
- "base/third_party/valgrind/LICENSE",
- "base/third_party/xdg_user_dirs/LICENSE",
- "net/third_party/quiche/src/LICENSE",
- "net/third_party/uri_template/LICENSE",
- "third_party/abseil-cpp/LICENSE",
- "third_party/ashmem/LICENSE",
- "third_party/boringssl/src/LICENSE",
- "third_party/boringssl/src/third_party/fiat/LICENSE",
- "third_party/boringssl/src/third_party/googletest/LICENSE",
- "third_party/boringssl/src/third_party/wycheproof_testvectors/LICENSE",
- "third_party/brotli/LICENSE",
- "third_party/icu/LICENSE",
- "third_party/icu/scripts/LICENSE",
- "third_party/libevent/LICENSE",
- "third_party/metrics_proto/LICENSE",
- "third_party/modp_b64/LICENSE",
- "third_party/protobuf/LICENSE",
- "third_party/protobuf/third_party/utf8_range/LICENSE",
- ],
-}
-
diff --git a/tools/gn2bp/gen_android_bp b/tools/gn2bp/gen_android_bp
index d714a90..b48a05b 100755
--- a/tools/gn2bp/gen_android_bp
+++ b/tools/gn2bp/gen_android_bp
@@ -39,6 +39,8 @@
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+CRONET_LICENSE_NAME = "external_cronet_license"
+
# Default targets to translate to the blueprint file.
DEFAULT_TARGETS = [
'//components/cronet/android:cronet',
@@ -188,6 +190,9 @@
],
}
+def always_disable(module, arch):
+ return None
+
def enable_brotli(module, arch):
# Requires crrev/c/4111690
if arch is None:
@@ -213,25 +218,40 @@
else:
module.arch[arch].shared_libs.add('libz')
+def enable_boringssl(module, arch):
+ if arch is None:
+ shared_libs = module.shared_libs
+ else:
+ shared_libs = module.arch[arch].shared_libs
+ shared_libs.add('//external/cronet/third_party/boringssl:libcrypto')
+ shared_libs.add('//external/cronet/third_party/boringssl:libssl')
+
# Android equivalents for third-party libraries that the upstream project
# depends on.
builtin_deps = {
'//buildtools/third_party/libunwind:libunwind':
- lambda m, a: None, # disable libunwind
+ always_disable,
'//buildtools/third_party/libunwind:libunwind__testing':
- lambda m, a: None, # disable libunwind
+ always_disable,
'//net/data/ssl/chrome_root_store:gen_root_store_inc':
- lambda m, a: None,
+ always_disable,
'//net/data/ssl/chrome_root_store:gen_root_store_inc__testing':
- lambda m, a: None,
+ always_disable,
'//net/tools/root_store_tool:root_store_tool':
- lambda m, a: None,
+ always_disable,
'//net/tools/root_store_tool:root_store_tool__testing':
- lambda m, a: None,
+ always_disable,
'//third_party/zlib:zlib':
enable_zlib,
'//third_party/zlib:zlib__testing':
enable_zlib,
+ '//third_party/boringssl:boringssl':
+ enable_boringssl,
+ '//third_party/boringssl:boringssl_asm':
+ # Due to FIPS requirements, downstream BoringSSL has a different "shape" than upstream's.
+ # We're guaranteed that if X depends on :boringssl it will also depend on :boringssl_asm.
+ # Hence, always drop :boringssl_asm and handle the translation entirely in :boringssl.
+ always_disable,
}
experimental_android_deps = {
@@ -1764,54 +1784,10 @@
return blueprint
-def create_license_module(blueprint):
- module = Module("license", "external_cronet_license", "LICENSE")
- module.license_kinds.update({
- 'SPDX-license-identifier-MPL',
- 'SPDX-license-identifier-MPL-1.1',
- 'SPDX-license-identifier-ISC',
- 'SPDX-license-identifier-AFL-2.0',
- 'SPDX-license-identifier-MPL-2.0',
- 'SPDX-license-identifier-BSD',
- 'SPDX-license-identifier-Apache-2.0',
- 'SPDX-license-identifier-BSL-1.0',
- 'SPDX-license-identifier-Unicode-DFS',
- 'SPDX-license-identifier-NCSA',
- 'SPDX-license-identifier-OpenSSL',
- 'SPDX-license-identifier-MIT',
- "SPDX-license-identifier-ICU",
- 'legacy_unencumbered',
- })
- module.license_text.update({
- "LICENSE",
- "net/third_party/uri_template/LICENSE",
- "net/third_party/quiche/src/LICENSE",
- "base/third_party/symbolize/LICENSE",
- "base/third_party/superfasthash/LICENSE",
- "base/third_party/xdg_user_dirs/LICENSE",
- "base/third_party/double_conversion/LICENSE",
- "base/third_party/nspr/LICENSE",
- "base/third_party/dynamic_annotations/LICENSE",
- "base/third_party/icu/LICENSE",
- "base/third_party/valgrind/LICENSE",
- "third_party/brotli/LICENSE",
- "third_party/protobuf/LICENSE",
- "third_party/protobuf/third_party/utf8_range/LICENSE",
- "third_party/metrics_proto/LICENSE",
- "third_party/boringssl/src/LICENSE",
- "third_party/boringssl/src/third_party/googletest/LICENSE",
- "third_party/boringssl/src/third_party/wycheproof_testvectors/LICENSE",
- "third_party/boringssl/src/third_party/fiat/LICENSE",
- "third_party/libevent/LICENSE",
- "third_party/ashmem/LICENSE",
- "third_party/icu/LICENSE",
- "third_party/icu/scripts/LICENSE",
- "third_party/abseil-cpp/LICENSE",
- "third_party/modp_b64/LICENSE",
- })
+def create_default_license_module(blueprint):
default_license = Module("package", "", "PACKAGE")
- default_license.default_applicable_licenses.add(module.name)
- blueprint.add_module(module)
+ default_license.comment = "The actual license can be found in Android.extras.bp"
+ default_license.default_applicable_licenses.add(CRONET_LICENSE_NAME)
blueprint.add_module(default_license)
def main():
@@ -1866,7 +1842,7 @@
# Add any proto groups to the blueprint.
for l_name, t_names in proto_groups.items():
create_proto_group_modules(blueprint, gn, l_name, t_names)
- create_license_module(blueprint)
+ create_default_license_module(blueprint)
output = [
"""// Copyright (C) 2022 The Android Open Source Project
//