Merge "Add comment for per-app preference priority" into main
diff --git a/Cronet/tests/OWNERS b/Cronet/tests/OWNERS
deleted file mode 100644
index a35a789..0000000
--- a/Cronet/tests/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Bug component: 31808
-
-set noparent
-file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking_xts
-
-# TODO: Temp ownership to develop cronet CTS
-colibie@google.com #{LAST_RESORT_SUGGESTION}
-prohr@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/Cronet/tests/common/Android.bp b/Cronet/tests/common/Android.bp
deleted file mode 100644
index 703f544..0000000
--- a/Cronet/tests/common/Android.bp
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-//
-
-// Tests in this folder are included both in unit tests and CTS.
-// They must be fast and stable, and exercise public or test APIs.
-
-package {
- default_team: "trendy_team_fwk_core_networking",
- // See: http://go/android-license-faq
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-// TODO: Consider merging with ConnectivityCoverageTests which is a collection of all
-// Connectivity tests being used for coverage. This will depend on how far we decide to
-// go with merging NetHttp and Tethering targets.
-android_test {
- name: "NetHttpCoverageTests",
- enforce_default_target_sdk_version: true,
- min_sdk_version: "30",
- test_suites: [
- "general-tests",
- "mts-tethering",
- ],
- static_libs: [
- "modules-utils-native-coverage-listener",
- "CtsNetHttpTestsLib",
- "NetHttpTestsLibPreJarJar",
- ],
- jarjar_rules: ":net-http-test-jarjar-rules",
- compile_multilib: "both", // Include both the 32 and 64 bit versions
- jni_libs: [
- "cronet_aml_components_cronet_android_cronet_tests__testing",
- "cronet_aml_third_party_netty_tcnative_netty_tcnative_so__testing",
- "libnativecoverage",
- ],
- data: [":cronet_javatests_resources"],
-}
diff --git a/Cronet/tests/common/AndroidManifest.xml b/Cronet/tests/common/AndroidManifest.xml
deleted file mode 100644
index b00fc90..0000000
--- a/Cronet/tests/common/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- 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"
- android:label="NetHttp coverage tests">
- <uses-library android:name="android.test.runner" />
- </application>
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.net.http.tests.coverage"
- android:label="NetHttp coverage tests">
- </instrumentation>
-</manifest>
diff --git a/Cronet/tests/common/AndroidTest.xml b/Cronet/tests/common/AndroidTest.xml
deleted file mode 100644
index 7646a04..0000000
--- a/Cronet/tests/common/AndroidTest.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<!--
- ~ 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.
- -->
-<configuration description="Runs coverage tests for NetHttp">
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="test-file-name" value="NetHttpCoverageTests.apk" />
- <option name="install-arg" value="-t" />
- </target_preparer>
- <option name="test-tag" value="NetHttpCoverageTests" />
-
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="push-file" key="net" value="/storage/emulated/0/chromium_tests_root/net" />
- <option name="push-file" key="test_server" value="/storage/emulated/0/chromium_tests_root/components/cronet/testing/test_server" />
- </target_preparer>
- <!-- 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.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" />
- <!-- b/298380508 -->
- <option name="exclude-filter" value="org.chromium.net.CronetUrlRequestContextTest#testSetLibraryLoaderIsEnforcedByDefaultEmbeddedProvider" />
- <!-- b/316559294 -->
- <option name="exclude-filter" value="org.chromium.net.NQETest#testQuicDisabled" />
- <!-- b/316559294 -->
- <option name="exclude-filter" value="org.chromium.net.NQETest#testPrefsWriteRead" />
- <!-- b/316554711-->
- <option name="exclude-filter" value="org.chromium.net.NetworkChangesTest" />
- <!-- b/316550794 -->
- <option name="exclude-filter" value="org.chromium.net.impl.CronetLoggerTest#testEngineCreation" />
- <!-- b/327182569 -->
- <option name="exclude-filter" value="org.chromium.net.urlconnection.CronetURLStreamHandlerFactoryTest#testSetUrlStreamFactoryUsesCronetForNative" />
- <option name="hidden-api-checks" value="false"/>
- <option name="isolated-storage" value="false"/>
- <option name="orchestrator" value="true"/>
- <option
- name="device-listeners"
- value="com.android.modules.utils.testing.NativeCoverageHackInstrumentationListener" />
- </test>
-</configuration>
diff --git a/Cronet/tests/cts/Android.bp b/Cronet/tests/cts/Android.bp
deleted file mode 100644
index 92b73d9..0000000
--- a/Cronet/tests/cts/Android.bp
+++ /dev/null
@@ -1,71 +0,0 @@
-//
-// Copyright (C) 2019 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 {
- default_team: "trendy_team_fwk_core_networking",
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_library {
- name: "CtsNetHttpTestsLib",
- defaults: [
- "cts_defaults",
- ],
- sdk_version: "test_current",
- min_sdk_version: "30",
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ],
- static_libs: [
- "androidx.test.ext.junit",
- "ctstestrunner-axt",
- "ctstestserver",
- "hamcrest-library",
- "junit",
- "kotlin-test",
- "mockito-target",
- "net-tests-utils",
- "truth",
- ],
- libs: [
- "android.test.base",
- "androidx.annotation_annotation",
- "framework-connectivity",
- "org.apache.http.legacy",
- ],
- lint: {
- test: true,
- },
-}
-
-android_test {
- name: "CtsNetHttpTestCases",
- defaults: [
- "cts_defaults",
- ],
- enforce_default_target_sdk_version: true,
- sdk_version: "test_current",
- min_sdk_version: "30",
- static_libs: ["CtsNetHttpTestsLib"],
- // Tag this as a cts test artifact
- test_suites: [
- "cts",
- "general-tests",
- "mts-tethering",
- "mcts-tethering",
- ],
-}
diff --git a/Cronet/tests/cts/AndroidManifest.xml b/Cronet/tests/cts/AndroidManifest.xml
deleted file mode 100644
index 26900b2..0000000
--- a/Cronet/tests/cts/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.net.http.cts">
-
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
-
- <application android:networkSecurityConfig="@xml/network_security_config">
- <uses-library android:name="android.test.runner"/>
- </application>
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.net.http.cts"
- android:label="CTS tests of android.net.http">
- </instrumentation>
-</manifest>
diff --git a/Cronet/tests/cts/AndroidTest.xml b/Cronet/tests/cts/AndroidTest.xml
deleted file mode 100644
index e0421fd..0000000
--- a/Cronet/tests/cts/AndroidTest.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 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.
- -->
-<configuration description="Config for CTS Cronet test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="networking" />
- <!-- Instant apps cannot create sockets. See b/264248246 -->
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsNetHttpTestCases.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.net.http.cts" />
- <option name="runtime-hint" value="10s" />
- </test>
-
- <!-- Only run CtsNetHttpTestCases in MTS if the Tethering Mainline module is installed. -->
- <object type="module_controller"
- class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
- <option name="mainline-module-package-name" value="com.google.android.tethering" />
- </object>
-</configuration>
diff --git a/Cronet/tests/cts/assets/html/hello_world.html b/Cronet/tests/cts/assets/html/hello_world.html
deleted file mode 100644
index ea62ce2..0000000
--- a/Cronet/tests/cts/assets/html/hello_world.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- ~ Copyright (C) 2022 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.
- -->
-
-<html>
-<head>
- <title>hello world</title>
-</head>
-<body>
-<h3>hello world</h3><br>
-</body>
-</html>
\ No newline at end of file
diff --git a/Cronet/tests/cts/res/xml/network_security_config.xml b/Cronet/tests/cts/res/xml/network_security_config.xml
deleted file mode 100644
index 7d7530b..0000000
--- a/Cronet/tests/cts/res/xml/network_security_config.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2022 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.
- -->
-
-<network-security-config>
- <domain-config cleartextTrafficPermitted="true">
- <domain includeSubdomains="true">localhost</domain>
- </domain-config>
-</network-security-config>
\ No newline at end of file
diff --git a/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt b/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt
deleted file mode 100644
index 464862d..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * 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.BidirectionalStream
-import android.net.http.HttpEngine
-import android.net.http.cts.util.TestBidirectionalStreamCallback
-import android.net.http.cts.util.TestBidirectionalStreamCallback.ResponseStep
-import android.net.http.cts.util.assumeOKStatusCode
-import android.net.http.cts.util.skipIfNoInternetConnection
-import android.os.Build
-import androidx.test.core.app.ApplicationProvider
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import com.android.testutils.SkipPresubmit
-import com.google.common.truth.Truth.assertThat
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import org.hamcrest.MatcherAssert
-import org.hamcrest.Matchers
-import org.junit.After
-import org.junit.AssumptionViolatedException
-import org.junit.Before
-import org.junit.runner.RunWith
-
-private const val URL = "https://source.android.com"
-
-/**
- * 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.
- */
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-class BidirectionalStreamTest {
- private val context: Context = ApplicationProvider.getApplicationContext()
- private val callback = TestBidirectionalStreamCallback()
- private val httpEngine = HttpEngine.Builder(context).build()
- private var stream: BidirectionalStream? = null
-
- @Before
- fun setUp() {
- skipIfNoInternetConnection(context)
- }
-
- @After
- @Throws(Exception::class)
- fun tearDown() {
- httpEngine.shutdown()
- }
-
- private fun createBidirectionalStreamBuilder(url: String): BidirectionalStream.Builder {
- return httpEngine.newBidirectionalStreamBuilder(url, callback.executor, callback)
- }
-
- @Test
- @Throws(Exception::class)
- @SkipPresubmit(reason = "b/293141085 Confirm non-flaky and move to presubmit after SLO")
- fun testBidirectionalStream_GetStream_CompletesSuccessfully() {
- stream = createBidirectionalStreamBuilder(URL).setHttpMethod("GET").build()
- stream!!.start()
- // We call to a real server and hence the server may not be reachable, cancel this stream
- // and rethrow the exception before tearDown,
- // otherwise shutdown would fail with active request error.
- try {
- callback.assumeCallback(ResponseStep.ON_SUCCEEDED)
- } catch (e: AssumptionViolatedException) {
- stream!!.cancel()
- callback.blockForDone()
- throw e
- }
-
- val info = callback.mResponseInfo
- assumeOKStatusCode(info)
- MatcherAssert.assertThat(
- "Received byte count must be > 0", info.receivedByteCount, Matchers.greaterThan(0L))
- assertEquals("h2", info.negotiatedProtocol)
- }
-
- @Test
- @Throws(Exception::class)
- fun testBidirectionalStream_getHttpMethod() {
- val builder = createBidirectionalStreamBuilder(URL)
- val method = "GET"
-
- builder.setHttpMethod(method)
- stream = builder.build()
- assertThat(stream!!.getHttpMethod()).isEqualTo(method)
- }
-
- @Test
- @Throws(Exception::class)
- fun testBidirectionalStream_hasTrafficStatsTag() {
- val builder = createBidirectionalStreamBuilder(URL)
-
- builder.setTrafficStatsTag(10)
- stream = builder.build()
- assertThat(stream!!.hasTrafficStatsTag()).isTrue()
- }
-
- @Test
- @Throws(Exception::class)
- fun testBidirectionalStream_getTrafficStatsTag() {
- val builder = createBidirectionalStreamBuilder(URL)
- val trafficStatsTag = 10
-
- builder.setTrafficStatsTag(trafficStatsTag)
- stream = builder.build()
- assertThat(stream!!.getTrafficStatsTag()).isEqualTo(trafficStatsTag)
- }
-
- @Test
- @Throws(Exception::class)
- fun testBidirectionalStream_hasTrafficStatsUid() {
- val builder = createBidirectionalStreamBuilder(URL)
-
- builder.setTrafficStatsUid(10)
- stream = builder.build()
- assertThat(stream!!.hasTrafficStatsUid()).isTrue()
- }
-
- @Test
- @Throws(Exception::class)
- fun testBidirectionalStream_getTrafficStatsUid() {
- val builder = createBidirectionalStreamBuilder(URL)
- val trafficStatsUid = 10
-
- builder.setTrafficStatsUid(trafficStatsUid)
- stream = builder.build()
- assertThat(stream!!.getTrafficStatsUid()).isEqualTo(trafficStatsUid)
- }
-
- @Test
- @Throws(Exception::class)
- fun testBidirectionalStream_getHeaders_asList() {
- val builder = createBidirectionalStreamBuilder(URL)
- val expectedHeaders = mapOf(
- "Authorization" to "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
- "Max-Forwards" to "10",
- "X-Client-Data" to "random custom header content").entries.toList()
-
- for (header in expectedHeaders) {
- builder.addHeader(header.key, header.value)
- }
-
- stream = builder.build()
- assertThat(stream!!.getHeaders().getAsList()).containsAtLeastElementsIn(expectedHeaders)
- }
-
- @Test
- @Throws(Exception::class)
- fun testBidirectionalStream_getHeaders_asMap() {
- val builder = createBidirectionalStreamBuilder(URL)
- val expectedHeaders = mapOf(
- "Authorization" to listOf("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="),
- "Max-Forwards" to listOf("10"),
- "X-Client-Data" to listOf("random custom header content"))
-
- for (header in expectedHeaders) {
- builder.addHeader(header.key, header.value.get(0))
- }
-
- stream = builder.build()
- assertThat(stream!!.getHeaders().getAsMap()).containsAtLeastEntriesIn(expectedHeaders)
- }
-
- @Test
- @Throws(Exception::class)
- fun testBidirectionalStream_getPriority() {
- val builder = createBidirectionalStreamBuilder(URL)
- val priority = BidirectionalStream.STREAM_PRIORITY_LOW
-
- builder.setPriority(priority)
- stream = builder.build()
- assertThat(stream!!.getPriority()).isEqualTo(priority)
- }
-
- @Test
- @Throws(Exception::class)
- fun testBidirectionalStream_isDelayRequestHeadersUntilFirstFlushEnabled() {
- val builder = createBidirectionalStreamBuilder(URL)
-
- builder.setDelayRequestHeadersUntilFirstFlushEnabled(true)
- stream = builder.build()
- assertThat(stream!!.isDelayRequestHeadersUntilFirstFlushEnabled()).isTrue()
- }
-}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt
deleted file mode 100644
index 1405ed9..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.CallbackException
-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.FailureType
-import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep
-import android.os.Build
-import androidx.test.core.app.ApplicationProvider
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import kotlin.test.assertIs
-import kotlin.test.assertSame
-import kotlin.test.assertTrue
-import org.junit.runner.RunWith
-
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-class CallbackExceptionTest {
-
- @Test
- fun testCallbackException_returnsInputParameters() {
- val message = "failed"
- val cause = Throwable("exception")
- val callbackException = object : CallbackException(message, cause) {}
-
- assertEquals(message, callbackException.message)
- assertSame(cause, callbackException.cause)
- }
-
- @Test
- fun testCallbackException_thrownFromUrlRequest() {
- val context: Context = ApplicationProvider.getApplicationContext()
- val server = HttpCtsTestServer(context)
- val httpEngine = HttpEngine.Builder(context).build()
- val callback = TestUrlRequestCallback()
- callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_RESPONSE_STARTED)
- val request = httpEngine
- .newUrlRequestBuilder(server.successUrl, callback.executor, callback)
- .build()
-
- request.start()
- callback.blockForDone()
-
- assertTrue(request.isDone)
- assertIs<CallbackException>(callback.mError)
- server.shutdown()
- httpEngine.shutdown()
- }
-}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/ConnectionMigrationOptionsTest.kt b/Cronet/tests/cts/src/android/net/http/cts/ConnectionMigrationOptionsTest.kt
deleted file mode 100644
index 10c7f3c..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/ConnectionMigrationOptionsTest.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.ConnectionMigrationOptions
-import android.net.http.ConnectionMigrationOptions.MIGRATION_OPTION_ENABLED
-import android.net.http.ConnectionMigrationOptions.MIGRATION_OPTION_UNSPECIFIED
-import android.os.Build
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import org.junit.runner.RunWith
-
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-class ConnectionMigrationOptionsTest {
-
- @Test
- fun testConnectionMigrationOptions_defaultValues() {
- val options =
- ConnectionMigrationOptions.Builder().build()
-
- assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.allowNonDefaultNetworkUsage)
- assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.defaultNetworkMigration)
- assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.pathDegradationMigration)
- }
-
- @Test
- fun testConnectionMigrationOptions_enableDefaultNetworkMigration_returnSetValue() {
- val options =
- ConnectionMigrationOptions.Builder()
- .setDefaultNetworkMigration(MIGRATION_OPTION_ENABLED)
- .build()
-
- assertEquals(MIGRATION_OPTION_ENABLED, options.defaultNetworkMigration)
- }
-
- @Test
- fun testConnectionMigrationOptions_enablePathDegradationMigration_returnSetValue() {
- val options =
- ConnectionMigrationOptions.Builder()
- .setPathDegradationMigration(MIGRATION_OPTION_ENABLED)
- .build()
-
- assertEquals(MIGRATION_OPTION_ENABLED, options.pathDegradationMigration)
- }
-
- @Test
- fun testConnectionMigrationOptions_allowNonDefaultNetworkUsage_returnSetValue() {
- val options =
- ConnectionMigrationOptions.Builder()
- .setAllowNonDefaultNetworkUsage(MIGRATION_OPTION_ENABLED).build()
-
- assertEquals(MIGRATION_OPTION_ENABLED, options.allowNonDefaultNetworkUsage)
- }
-}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/DnsOptionsTest.kt b/Cronet/tests/cts/src/android/net/http/cts/DnsOptionsTest.kt
deleted file mode 100644
index 56802c6..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/DnsOptionsTest.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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.DnsOptions
-import android.net.http.DnsOptions.DNS_OPTION_ENABLED
-import android.net.http.DnsOptions.DNS_OPTION_UNSPECIFIED
-import android.os.Build
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import java.time.Duration
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import kotlin.test.assertNotNull
-import kotlin.test.assertNull
-import org.junit.runner.RunWith
-
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-class DnsOptionsTest {
-
- @Test
- fun testDnsOptions_defaultValues() {
- val options = DnsOptions.Builder().build()
-
- assertEquals(DNS_OPTION_UNSPECIFIED, options.persistHostCache)
- assertNull(options.persistHostCachePeriod)
- assertEquals(DNS_OPTION_UNSPECIFIED, options.staleDns)
- assertNull(options.staleDnsOptions)
- assertEquals(DNS_OPTION_UNSPECIFIED, options.useHttpStackDnsResolver)
- assertEquals(DNS_OPTION_UNSPECIFIED,
- options.preestablishConnectionsToStaleDnsResults)
- }
-
- @Test
- fun testDnsOptions_persistHostCache_returnSetValue() {
- val options = DnsOptions.Builder()
- .setPersistHostCache(DNS_OPTION_ENABLED)
- .build()
-
- assertEquals(DNS_OPTION_ENABLED, options.persistHostCache)
- }
-
- @Test
- fun testDnsOptions_persistHostCachePeriod_returnSetValue() {
- val period = Duration.ofMillis(12345)
- val options = DnsOptions.Builder().setPersistHostCachePeriod(period).build()
-
- assertEquals(period, options.persistHostCachePeriod)
- }
-
- @Test
- fun testDnsOptions_enableStaleDns_returnSetValue() {
- val options = DnsOptions.Builder()
- .setStaleDns(DNS_OPTION_ENABLED)
- .build()
-
- assertEquals(DNS_OPTION_ENABLED, options.staleDns)
- }
-
- @Test
- fun testDnsOptions_useHttpStackDnsResolver_returnsSetValue() {
- val options = DnsOptions.Builder()
- .setUseHttpStackDnsResolver(DNS_OPTION_ENABLED)
- .build()
-
- assertEquals(DNS_OPTION_ENABLED, options.useHttpStackDnsResolver)
- }
-
- @Test
- fun testDnsOptions_preestablishConnectionsToStaleDnsResults_returnsSetValue() {
- val options = DnsOptions.Builder()
- .setPreestablishConnectionsToStaleDnsResults(DNS_OPTION_ENABLED)
- .build()
-
- assertEquals(DNS_OPTION_ENABLED,
- options.preestablishConnectionsToStaleDnsResults)
- }
-
- @Test
- fun testDnsOptions_setStaleDnsOptions_returnsSetValues() {
- val staleOptions = DnsOptions.StaleDnsOptions.Builder()
- .setAllowCrossNetworkUsage(DNS_OPTION_ENABLED)
- .setFreshLookupTimeout(Duration.ofMillis(1234))
- .build()
- val options = DnsOptions.Builder()
- .setStaleDns(DNS_OPTION_ENABLED)
- .setStaleDnsOptions(staleOptions)
- .build()
-
- assertEquals(DNS_OPTION_ENABLED, options.staleDns)
- assertEquals(staleOptions, options.staleDnsOptions)
- }
-
- @Test
- fun testStaleDnsOptions_defaultValues() {
- val options = DnsOptions.StaleDnsOptions.Builder().build()
-
- assertEquals(DNS_OPTION_UNSPECIFIED, options.allowCrossNetworkUsage)
- assertNull(options.freshLookupTimeout)
- assertNull(options.maxExpiredDelay)
- assertEquals(DNS_OPTION_UNSPECIFIED, options.useStaleOnNameNotResolved)
- }
-
- @Test
- fun testStaleDnsOptions_allowCrossNetworkUsage_returnsSetValue() {
- val options = DnsOptions.StaleDnsOptions.Builder()
- .setAllowCrossNetworkUsage(DNS_OPTION_ENABLED).build()
-
- assertEquals(DNS_OPTION_ENABLED, options.allowCrossNetworkUsage)
- }
-
- @Test
- fun testStaleDnsOptions_freshLookupTimeout_returnsSetValue() {
- val duration = Duration.ofMillis(12345)
- val options = DnsOptions.StaleDnsOptions.Builder().setFreshLookupTimeout(duration).build()
-
- assertNotNull(options.freshLookupTimeout)
- assertEquals(duration, options.freshLookupTimeout!!)
- }
-
- @Test
- fun testStaleDnsOptions_useStaleOnNameNotResolved_returnsSetValue() {
- val options = DnsOptions.StaleDnsOptions.Builder()
- .setUseStaleOnNameNotResolved(DNS_OPTION_ENABLED)
- .build()
-
- assertEquals(DNS_OPTION_ENABLED, options.useStaleOnNameNotResolved)
- }
-
- @Test
- fun testStaleDnsOptions_maxExpiredDelayMillis_returnsSetValue() {
- val duration = Duration.ofMillis(12345)
- val options = DnsOptions.StaleDnsOptions.Builder().setMaxExpiredDelay(duration).build()
-
- 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
deleted file mode 100644
index f86ac29..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * 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 static android.net.http.cts.util.TestUtilsKt.assertOKStatusCode;
-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.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.net.Network;
-import android.net.http.ConnectionMigrationOptions;
-import android.net.http.DnsOptions;
-import android.net.http.HttpEngine;
-import android.net.http.QuicOptions;
-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;
-import android.os.Build;
-
-import androidx.test.core.app.ApplicationProvider;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRunner;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Set;
-
-@RunWith(DevSdkIgnoreRunner.class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-public class HttpEngineTest {
- private static final String HOST = "source.android.com";
- private static final String URL = "https://" + HOST;
-
- private HttpEngine.Builder mEngineBuilder;
- private TestUrlRequestCallback mCallback;
- private HttpCtsTestServer mTestServer;
- private UrlRequest mRequest;
- private HttpEngine mEngine;
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- mContext = ApplicationProvider.getApplicationContext();
- skipIfNoInternetConnection(mContext);
- mEngineBuilder = new HttpEngine.Builder(mContext);
- mCallback = new TestUrlRequestCallback();
- mTestServer = new HttpCtsTestServer(mContext);
- }
-
- @After
- public void tearDown() throws Exception {
- if (mRequest != null) {
- mRequest.cancel();
- mCallback.blockForDone();
- }
- if (mEngine != null) {
- mEngine.shutdown();
- }
- if (mTestServer != null) {
- mTestServer.shutdown();
- }
- }
-
- private boolean isQuic(String negotiatedProtocol) {
- return negotiatedProtocol.startsWith("http/2+quic") || negotiatedProtocol.startsWith("h3");
- }
-
- @Test
- public void testHttpEngine_Default() throws Exception {
- mEngine = mEngineBuilder.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;
- assertOKStatusCode(info);
- assertEquals("h2", info.getNegotiatedProtocol());
- }
-
- @Test
- public void testHttpEngine_EnableHttpCache() {
- String url = mTestServer.getCacheableTestDownloadUrl(
- /* downloadId */ "cacheable-download",
- /* numBytes */ 10);
- 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();
- mCallback.expectCallback(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.expectCallback(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.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;
- assertOKStatusCode(info);
- assertEquals("http/1.1", info.getNegotiatedProtocol());
- }
-
- @Test
- public void testHttpEngine_EnablePublicKeyPinningBypassForLocalTrustAnchors() {
- String url = mTestServer.getSuccessUrl();
- // 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.
- }
-
- private byte[] generateSha256() {
- byte[] sha256 = new byte[32];
- Arrays.fill(sha256, (byte) 58);
- return sha256;
- }
-
- private Instant instantInFuture(int secondsIntoFuture) {
- Calendar cal = Calendar.getInstance();
- cal.add(Calendar.SECOND, secondsIntoFuture);
- return cal.getTime().toInstant();
- }
-
- @Test
- public void testHttpEngine_AddPublicKeyPins() {
- // CtsTestServer, when set in SslMode.NO_CLIENT_AUTH (required to trigger
- // certificate verification, needed by this test), uses a certificate that
- // doesn't match the hostname. For this reason, CtsTestServer cannot be used
- // by this test.
- Instant expirationInstant = instantInFuture(/* secondsIntoFuture */ 100);
- boolean includeSubdomains = true;
- Set<byte[]> pinsSha256 = Set.of(generateSha256());
- mEngine = mEngineBuilder.addPublicKeyPins(
- HOST, pinsSha256, includeSubdomains, expirationInstant).build();
-
- UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback);
- mRequest = builder.build();
- mRequest.start();
- mCallback.expectCallback(ResponseStep.ON_FAILED);
- assertNotNull("Expected an error", mCallback.mError);
- }
-
- @Test
- public void testHttpEngine_EnableQuic() throws Exception {
- String url = mTestServer.getSuccessUrl();
- mEngine = mEngineBuilder.setEnableQuic(true).addQuicHint(HOST, 443, 443).build();
- UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback);
- mRequest = builder.build();
- mRequest.start();
-
- mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
- UrlResponseInfo info = mCallback.mResponseInfo;
- assertOKStatusCode(info);
- }
-
- @Test
- public void testHttpEngine_GetDefaultUserAgent() throws Exception {
- assertThat(mEngineBuilder.getDefaultUserAgent(), containsString("AndroidHttpClient"));
- assertThat(mEngineBuilder.getDefaultUserAgent()).contains(HttpEngine.getVersionString());
- }
-
- @Test
- public void testHttpEngine_requestUsesDefaultUserAgent() throws Exception {
- mEngine = mEngineBuilder.build();
-
- String url = mTestServer.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";
- mEngine =
- new HttpEngine.Builder(ApplicationProvider.getApplicationContext())
- .setUserAgent(userAgent)
- .build();
-
- String url = mTestServer.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>.*", "");
- }
-
- @Test
- public void testHttpEngine_bindToNetwork() throws Exception {
- // Create a fake Android.net.Network. Since that network doesn't exist, binding to
- // that should end up in a failed request.
- Network mockNetwork = Mockito.mock(Network.class);
- Mockito.when(mockNetwork.getNetworkHandle()).thenReturn(123L);
- String url = mTestServer.getSuccessUrl();
-
- mEngine = mEngineBuilder.build();
- mEngine.bindToNetwork(mockNetwork);
- UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback);
- mRequest = builder.build();
- mRequest.start();
-
- mCallback.expectCallback(ResponseStep.ON_FAILED);
- }
-
- @Test
- public void testHttpEngine_unbindFromNetwork() throws Exception {
- // Create a fake Android.net.Network. Since that network doesn't exist, binding to
- // that should end up in a failed request.
- Network mockNetwork = Mockito.mock(Network.class);
- Mockito.when(mockNetwork.getNetworkHandle()).thenReturn(123L);
- String url = mTestServer.getSuccessUrl();
-
- mEngine = mEngineBuilder.build();
- // Bind to the fake network but then unbind. This should result in a successful
- // request.
- mEngine.bindToNetwork(mockNetwork);
- mEngine.bindToNetwork(null);
- UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback);
- mRequest = builder.build();
- mRequest.start();
-
- mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
- UrlResponseInfo info = mCallback.mResponseInfo;
- assertOKStatusCode(info);
- }
-
- @Test
- public void testHttpEngine_setConnectionMigrationOptions_requestSucceeds() {
- ConnectionMigrationOptions options = new ConnectionMigrationOptions.Builder().build();
- mEngine = mEngineBuilder.setConnectionMigrationOptions(options).build();
- UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(
- mTestServer.getSuccessUrl(), mCallback.getExecutor(), mCallback);
- mRequest = builder.build();
- mRequest.start();
-
- mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
- UrlResponseInfo info = mCallback.mResponseInfo;
- assertOKStatusCode(info);
- }
-
- @Test
- public void testHttpEngine_setDnsOptions_requestSucceeds() {
- DnsOptions options = new DnsOptions.Builder().build();
- mEngine = mEngineBuilder.setDnsOptions(options).build();
- UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(
- mTestServer.getSuccessUrl(), mCallback.getExecutor(), mCallback);
- mRequest = builder.build();
- mRequest.start();
-
- mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
- UrlResponseInfo info = mCallback.mResponseInfo;
- assertOKStatusCode(info);
- }
-
- @Test
- public void getVersionString_notEmpty() {
- assertThat(HttpEngine.getVersionString()).isNotEmpty();
- }
-
- @Test
- public void testHttpEngine_SetQuicOptions_RequestSucceedsWithQuic() throws Exception {
- String url = mTestServer.getSuccessUrl();
- QuicOptions options = new QuicOptions.Builder().build();
- mEngine = mEngineBuilder
- .setEnableQuic(true)
- .addQuicHint(HOST, 443, 443)
- .setQuicOptions(options)
- .build();
- UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback);
- mRequest = builder.build();
- mRequest.start();
-
- mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
- UrlResponseInfo info = mCallback.mResponseInfo;
- assertOKStatusCode(info);
-
- }
-
- @Test
- public void testHttpEngine_enableBrotli_brotliAdvertised() {
- mEngine = mEngineBuilder.setEnableBrotli(true).build();
- mRequest =
- mEngine.newUrlRequestBuilder(
- mTestServer.getEchoHeadersUrl(), mCallback.getExecutor(), mCallback)
- .build();
- mRequest.start();
-
- mCallback.assumeCallback(ResponseStep.ON_SUCCEEDED);
- UrlResponseInfo info = mCallback.mResponseInfo;
- assertThat(info.getHeaders().getAsMap().get("x-request-header-Accept-Encoding").toString())
- .contains("br");
- assertOKStatusCode(info);
- }
-}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt
deleted file mode 100644
index cff54b3..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.HttpEngine
-import android.net.http.NetworkException
-import android.net.http.cts.util.TestUrlRequestCallback
-import android.os.Build
-import androidx.test.core.app.ApplicationProvider
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import kotlin.test.assertEquals
-import kotlin.test.assertIs
-import kotlin.test.assertSame
-import kotlin.test.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-class NetworkExceptionTest {
-
- @Test
- fun testNetworkException_returnsInputParameters() {
- val message = "failed"
- val cause = Throwable("thrown")
- val networkException =
- object : NetworkException(message, cause) {
- override fun getErrorCode() = 0
- override fun isImmediatelyRetryable() = false
- }
-
- assertEquals(message, networkException.message)
- assertSame(cause, networkException.cause)
- }
-
- @Test
- fun testNetworkException_thrownFromUrlRequest() {
- val httpEngine = HttpEngine.Builder(ApplicationProvider.getApplicationContext()).build()
- val callback = TestUrlRequestCallback()
- val request =
- httpEngine.newUrlRequestBuilder("http://localhost", callback.executor, callback).build()
-
- request.start()
- callback.blockForDone()
-
- assertTrue(request.isDone)
- assertIs<NetworkException>(callback.mError)
- httpEngine.shutdown()
- }
-}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/QuicExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/QuicExceptionTest.kt
deleted file mode 100644
index 2705fc3..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/QuicExceptionTest.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.QuicException
-import android.os.Build
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import org.junit.runner.RunWith
-
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-class QuicExceptionTest {
-
- @Test
- fun testQuicException_returnsInputParameters() {
- val message = "failed"
- val cause = Throwable("thrown")
- val quicException =
- object : QuicException(message, cause) {
- override fun getErrorCode() = 0
- override fun isImmediatelyRetryable() = false
- }
-
- assertEquals(message, quicException.message)
- assertEquals(cause, quicException.cause)
- }
-
- // TODO: add test for QuicException triggered from HttpEngine
-}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/QuicOptionsTest.kt b/Cronet/tests/cts/src/android/net/http/cts/QuicOptionsTest.kt
deleted file mode 100644
index da0b15c..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/QuicOptionsTest.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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 android.os.Build
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import com.google.common.truth.Truth.assertThat
-import java.time.Duration
-import kotlin.test.assertFailsWith
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-class QuicOptionsTest {
- @Test
- fun testQuicOptions_defaultValues() {
- val quicOptions = QuicOptions.Builder().build()
- assertThat(quicOptions.allowedQuicHosts).isEmpty()
- assertThat(quicOptions.handshakeUserAgent).isNull()
- assertThat(quicOptions.idleConnectionTimeout).isNull()
- assertFalse(quicOptions.hasInMemoryServerConfigsCacheSize())
- assertFailsWith(IllegalStateException::class) {
- quicOptions.inMemoryServerConfigsCacheSize
- }
- }
-
- @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()
- }
-
- @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()
- assertTrue(quicOptions.hasInMemoryServerConfigsCacheSize())
- assertThat(quicOptions.inMemoryServerConfigsCacheSize)
- .isEqualTo(42)
- }
-
- @Test
- fun testQuicOptions_handshakeUserAgent_returnsSetValue() {
- val userAgent = "test"
- val quicOptions = QuicOptions.Builder()
- .setHandshakeUserAgent(userAgent)
- .build()
- assertThat(quicOptions.handshakeUserAgent)
- .isEqualTo(userAgent)
- }
-}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java b/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java
deleted file mode 100644
index 3c4d134..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) 2019 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 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.HeaderBlock;
-import android.net.http.HttpEngine;
-import android.net.http.HttpException;
-import android.net.http.InlineExecutionProhibitedException;
-import android.net.http.UploadDataProvider;
-import android.net.http.UrlRequest;
-import android.net.http.UrlRequest.Status;
-import android.net.http.UrlResponseInfo;
-import android.net.http.cts.util.HttpCtsTestServer;
-import android.net.http.cts.util.TestStatusListener;
-import android.net.http.cts.util.TestUrlRequestCallback;
-import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep;
-import android.net.http.cts.util.UploadDataProviders;
-import android.os.Build;
-import android.webkit.cts.CtsTestServer;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.core.app.ApplicationProvider;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRunner;
-
-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.Arrays;
-import java.util.List;
-import java.util.Map;
-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;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-@RunWith(DevSdkIgnoreRunner.class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-public class UrlRequestTest {
- private static final Executor DIRECT_EXECUTOR = Runnable::run;
-
- private TestUrlRequestCallback mCallback;
- private HttpCtsTestServer mTestServer;
- private HttpEngine mHttpEngine;
-
- @Before
- public void setUp() throws Exception {
- Context context = ApplicationProvider.getApplicationContext();
- skipIfNoInternetConnection(context);
- HttpEngine.Builder builder = new HttpEngine.Builder(context);
- mHttpEngine = builder.build();
- mCallback = new TestUrlRequestCallback();
- mTestServer = new HttpCtsTestServer(context);
- }
-
- @After
- public void tearDown() throws Exception {
- if (mHttpEngine != null) {
- mHttpEngine.shutdown();
- }
- if (mTestServer != null) {
- mTestServer.shutdown();
- }
- }
-
- private UrlRequest.Builder createUrlRequestBuilder(String url) {
- return mHttpEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback);
- }
-
- @Test
- public void testUrlRequestGet_CompletesSuccessfully() throws Exception {
- String url = mTestServer.getSuccessUrl();
- UrlRequest request = createUrlRequestBuilder(url).build();
- request.start();
-
- mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
- UrlResponseInfo info = mCallback.mResponseInfo;
- assertOKStatusCode(info);
- assertThat("Received byte count must be > 0", info.getReceivedByteCount(), greaterThan(0L));
- }
-
- @Test
- public void testUrlRequestStatus_InvalidBeforeRequestStarts() throws Exception {
- UrlRequest request = createUrlRequestBuilder(mTestServer.getSuccessUrl()).build();
- // Calling before request is started should give Status.INVALID,
- // since the native adapter is not created.
- TestStatusListener statusListener = new TestStatusListener();
- request.getStatus(statusListener);
- statusListener.expectStatus(Status.INVALID);
- }
-
- @Test
- public void testUrlRequestCancel_CancelCalled() throws Exception {
- UrlRequest request = createUrlRequestBuilder(mTestServer.getSuccessUrl()).build();
- mCallback.setAutoAdvance(false);
-
- request.start();
- mCallback.waitForNextStep();
- assertSame(mCallback.mResponseStep, ResponseStep.ON_RESPONSE_STARTED);
-
- request.cancel();
- mCallback.expectCallback(ResponseStep.ON_CANCELED);
- }
-
- @Test
- public void testUrlRequestPost_EchoRequestBody() {
- String testData = "test";
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getEchoBodyUrl());
-
- UploadDataProvider dataProvider = UploadDataProviders.create(testData);
- builder.setUploadDataProvider(dataProvider, mCallback.getExecutor());
- builder.addHeader("Content-Type", "text/html");
- builder.build().start();
- mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
-
- assertOKStatusCode(mCallback.mResponseInfo);
- assertEquals(testData, mCallback.mResponseAsString);
- }
-
- @Test
- 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 = UploadDataProviders.create("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 = UploadDataProviders.create("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 = UploadDataProviders.create("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 testUrlRequest_redirects() throws Exception {
- int expectedNumRedirects = 5;
- String url =
- mTestServer.getRedirectingAssetUrl("html/hello_world.html", expectedNumRedirects);
-
- UrlRequest request = createUrlRequestBuilder(url).build();
- request.start();
-
- mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
- UrlResponseInfo info = mCallback.mResponseInfo;
- assertOKStatusCode(info);
- assertThat(mCallback.mResponseAsString).contains("hello world");
- assertThat(info.getUrlChain()).hasSize(expectedNumRedirects + 1);
- assertThat(info.getUrlChain().get(0)).isEqualTo(url);
- assertThat(info.getUrlChain().get(expectedNumRedirects)).isEqualTo(info.getUrl());
- }
-
- @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);
- }
-
- @Test
- public void testUrlRequest_customHeaders() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getEchoHeadersUrl());
-
- List<Map.Entry<String, String>> expectedHeaders = Arrays.asList(
- Map.entry("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="),
- Map.entry("Max-Forwards", "10"),
- Map.entry("X-Client-Data", "random custom header content"));
-
- for (Map.Entry<String, String> header : expectedHeaders) {
- builder.addHeader(header.getKey(), header.getValue());
- }
-
- builder.build().start();
- mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
-
- assertOKStatusCode(mCallback.mResponseInfo);
-
- List<Map.Entry<String, String>> echoedHeaders =
- extractEchoedHeaders(mCallback.mResponseInfo.getHeaders());
-
- // The implementation might decide to add more headers like accepted encodings it handles
- // internally so the server is likely to see more headers than explicitly set
- // by the developer.
- assertThat(echoedHeaders)
- .containsAtLeastElementsIn(expectedHeaders);
- }
-
- @Test
- public void testUrlRequest_getHttpMethod() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getSuccessUrl());
- final String method = "POST";
-
- builder.setHttpMethod(method);
- UrlRequest request = builder.build();
- assertThat(request.getHttpMethod()).isEqualTo(method);
- }
-
- @Test
- public void testUrlRequest_getHeaders_asList() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getSuccessUrl());
- final List<Map.Entry<String, String>> expectedHeaders = Arrays.asList(
- Map.entry("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="),
- Map.entry("Max-Forwards", "10"),
- Map.entry("X-Client-Data", "random custom header content"));
-
- for (Map.Entry<String, String> header : expectedHeaders) {
- builder.addHeader(header.getKey(), header.getValue());
- }
-
- UrlRequest request = builder.build();
- assertThat(request.getHeaders().getAsList()).containsAtLeastElementsIn(expectedHeaders);
- }
-
- @Test
- public void testUrlRequest_getHeaders_asMap() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getSuccessUrl());
- final Map<String, List<String>> expectedHeaders = Map.of(
- "Authorization", Arrays.asList("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="),
- "Max-Forwards", Arrays.asList("10"),
- "X-Client-Data", Arrays.asList("random custom header content"));
-
- for (Map.Entry<String, List<String>> header : expectedHeaders.entrySet()) {
- builder.addHeader(header.getKey(), header.getValue().get(0));
- }
-
- UrlRequest request = builder.build();
- assertThat(request.getHeaders().getAsMap()).containsAtLeastEntriesIn(expectedHeaders);
- }
-
- @Test
- public void testUrlRequest_isCacheDisabled() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getSuccessUrl());
- final boolean isCacheDisabled = true;
-
- builder.setCacheDisabled(isCacheDisabled);
- UrlRequest request = builder.build();
- assertThat(request.isCacheDisabled()).isEqualTo(isCacheDisabled);
- }
-
- @Test
- public void testUrlRequest_isDirectExecutorAllowed() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getSuccessUrl());
- final boolean isDirectExecutorAllowed = true;
-
- builder.setDirectExecutorAllowed(isDirectExecutorAllowed);
- UrlRequest request = builder.build();
- assertThat(request.isDirectExecutorAllowed()).isEqualTo(isDirectExecutorAllowed);
- }
-
- @Test
- public void testUrlRequest_getPriority() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getSuccessUrl());
- final int priority = UrlRequest.REQUEST_PRIORITY_LOW;
-
- builder.setPriority(priority);
- UrlRequest request = builder.build();
- assertThat(request.getPriority()).isEqualTo(priority);
- }
-
- @Test
- public void testUrlRequest_hasTrafficStatsTag() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getSuccessUrl());
-
- builder.setTrafficStatsTag(10);
- UrlRequest request = builder.build();
- assertThat(request.hasTrafficStatsTag()).isEqualTo(true);
- }
-
- @Test
- public void testUrlRequest_getTrafficStatsTag() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getSuccessUrl());
- final int trafficStatsTag = 10;
-
- builder.setTrafficStatsTag(trafficStatsTag);
- UrlRequest request = builder.build();
- assertThat(request.getTrafficStatsTag()).isEqualTo(trafficStatsTag);
- }
-
- @Test
- public void testUrlRequest_hasTrafficStatsUid() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getSuccessUrl());
-
- builder.setTrafficStatsUid(10);
- UrlRequest request = builder.build();
- assertThat(request.hasTrafficStatsUid()).isEqualTo(true);
- }
-
- @Test
- public void testUrlRequest_getTrafficStatsUid() throws Exception {
- UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getSuccessUrl());
- final int trafficStatsUid = 10;
-
- builder.setTrafficStatsUid(trafficStatsUid);
- UrlRequest request = builder.build();
- assertThat(request.getTrafficStatsUid()).isEqualTo(trafficStatsUid);
- }
-
- private static List<Map.Entry<String, String>> extractEchoedHeaders(HeaderBlock headers) {
- return headers.getAsList()
- .stream()
- .flatMap(input -> {
- if (input.getKey().startsWith(CtsTestServer.ECHOED_RESPONSE_HEADER_PREFIX)) {
- String strippedKey =
- input.getKey().substring(
- CtsTestServer.ECHOED_RESPONSE_HEADER_PREFIX.length());
- return Stream.of(Map.entry(strippedKey, input.getValue()));
- } else {
- return Stream.empty();
- }
- })
- .collect(Collectors.toList());
- }
-
- private static class StubUrlRequestCallback implements 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);
- }
-
- @Override
- public void onCanceled(@NonNull UrlRequest request, @Nullable UrlResponseInfo info) {
- throw new UnsupportedOperationException();
- }
- }
-}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/UrlResponseInfoTest.kt b/Cronet/tests/cts/src/android/net/http/cts/UrlResponseInfoTest.kt
deleted file mode 100644
index f1b57c6..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/UrlResponseInfoTest.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 android.os.Build
-import androidx.test.core.app.ApplicationProvider
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
-import org.junit.runner.RunWith
-
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-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/HttpCtsTestServer.kt b/Cronet/tests/cts/src/android/net/http/cts/util/HttpCtsTestServer.kt
deleted file mode 100644
index 5196544..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/util/HttpCtsTestServer.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2022 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.content.Context
-import android.webkit.cts.CtsTestServer
-import java.net.URI
-import org.apache.http.HttpEntityEnclosingRequest
-import org.apache.http.HttpRequest
-import org.apache.http.HttpResponse
-import org.apache.http.HttpStatus
-import org.apache.http.HttpVersion
-import org.apache.http.message.BasicHttpResponse
-
-private const val ECHO_BODY_PATH = "/echo_body"
-
-/** Extends CtsTestServer to handle POST requests and other test specific requests */
-class HttpCtsTestServer(context: Context) : CtsTestServer(context) {
-
- val echoBodyUrl: String = baseUri + ECHO_BODY_PATH
- val successUrl: String = getAssetUrl("html/hello_world.html")
-
- override fun onPost(req: HttpRequest): HttpResponse? {
- val path = URI.create(req.requestLine.uri).path
- var response: HttpResponse? = null
-
- if (path.startsWith(ECHO_BODY_PATH)) {
- if (req !is HttpEntityEnclosingRequest) {
- return BasicHttpResponse(
- HttpVersion.HTTP_1_0,
- HttpStatus.SC_INTERNAL_SERVER_ERROR,
- "Expected req to be of type HttpEntityEnclosingRequest but got ${req.javaClass}"
- )
- }
-
- response = BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, null)
- response.entity = req.entity
- response.addHeader("Content-Length", req.entity.contentLength.toString())
- }
-
- return response
- }
-}
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
deleted file mode 100644
index 1e7333c..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/util/TestBidirectionalStreamCallback.java
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * 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 static org.hamcrest.Matchers.equalTo;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeThat;
-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;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-
-/**
- * Callback that tracks information from different callbacks and has a method to block thread until
- * the stream completes on another thread. Allows to cancel, block stream or throw an exception from
- * an arbitrary step.
- */
-public class TestBidirectionalStreamCallback implements BidirectionalStream.Callback {
- private static final int TIMEOUT_MS = 12_000;
- public UrlResponseInfo mResponseInfo;
- public HttpException mError;
-
- public ResponseStep mResponseStep = ResponseStep.NOTHING;
-
- public boolean mOnErrorCalled;
- public boolean mOnCanceledCalled;
-
- public int mHttpResponseDataLength;
- public String mResponseAsString = "";
-
- public HeaderBlock mTrailers;
-
- private static final int READ_BUFFER_SIZE = 32 * 1024;
-
- // When false, the consumer is responsible for all calls into the stream
- // that advance it.
- private boolean mAutoAdvance = true;
-
- // Conditionally fail on certain steps.
- private FailureType mFailureType = FailureType.NONE;
- private ResponseStep mFailureStep = ResponseStep.NOTHING;
-
- // Signals when the stream is done either successfully or not.
- private final ConditionVariable mDone = new ConditionVariable();
-
- // Signaled on each step when mAutoAdvance is false.
- private final ConditionVariable mReadStepBlock = new ConditionVariable();
- private final ConditionVariable mWriteStepBlock = new ConditionVariable();
-
- // Executor Service for Cronet callbacks.
- private final ExecutorService mExecutorService =
- Executors.newSingleThreadExecutor(new ExecutorThreadFactory());
- private Thread mExecutorThread;
-
- // position() of ByteBuffer prior to read() call.
- private int mBufferPositionBeforeRead;
-
- // Data to write.
- private final ArrayList<WriteBuffer> mWriteBuffers = new ArrayList<WriteBuffer>();
-
- // Buffers that we yet to receive the corresponding onWriteCompleted callback.
- private final ArrayList<WriteBuffer> mWriteBuffersToBeAcked = new ArrayList<WriteBuffer>();
-
- // Whether to use a direct executor.
- private final boolean mUseDirectExecutor;
- private final DirectExecutor mDirectExecutor;
-
- private class ExecutorThreadFactory implements ThreadFactory {
- @Override
- public Thread newThread(Runnable r) {
- mExecutorThread = new Thread(r);
- return mExecutorThread;
- }
- }
-
- private static class WriteBuffer {
- final ByteBuffer mBuffer;
- final boolean mFlush;
-
- WriteBuffer(ByteBuffer buffer, boolean flush) {
- mBuffer = buffer;
- mFlush = flush;
- }
- }
-
- private static class DirectExecutor implements Executor {
- @Override
- public void execute(Runnable task) {
- task.run();
- }
- }
-
- public enum ResponseStep {
- NOTHING,
- ON_STREAM_READY,
- ON_RESPONSE_STARTED,
- ON_READ_COMPLETED,
- ON_WRITE_COMPLETED,
- ON_TRAILERS,
- ON_CANCELED,
- ON_FAILED,
- ON_SUCCEEDED,
- }
-
- public enum FailureType {
- NONE,
- CANCEL_SYNC,
- CANCEL_ASYNC,
- // Same as above, but continues to advance the stream after posting
- // the cancellation task.
- CANCEL_ASYNC_WITHOUT_PAUSE,
- THROW_SYNC
- }
-
- private boolean isTerminalCallback(ResponseStep step) {
- switch (step) {
- case ON_SUCCEEDED:
- case ON_CANCELED:
- case ON_FAILED:
- return true;
- default:
- return false;
- }
- }
-
- public TestBidirectionalStreamCallback() {
- mUseDirectExecutor = false;
- mDirectExecutor = null;
- }
-
- public TestBidirectionalStreamCallback(boolean useDirectExecutor) {
- mUseDirectExecutor = useDirectExecutor;
- mDirectExecutor = new DirectExecutor();
- }
-
- public void setAutoAdvance(boolean autoAdvance) {
- mAutoAdvance = autoAdvance;
- }
-
- public void setFailure(FailureType failureType, ResponseStep failureStep) {
- mFailureStep = failureStep;
- mFailureType = failureType;
- }
-
- public boolean blockForDone() {
- return mDone.block(TIMEOUT_MS);
- }
-
- /**
- * Waits for a terminal callback to complete execution before failing if the callback is not the
- * expected one
- *
- * @param expectedStep the expected callback step
- */
- public void expectCallback(ResponseStep expectedStep) {
- if (isTerminalCallback(expectedStep)) {
- assertTrue(String.format(
- "Request timed out. Expected %s callback. Current callback is %s",
- expectedStep, mResponseStep),
- blockForDone());
- }
- assertSame(expectedStep, mResponseStep);
- }
-
- /**
- * Waits for a terminal callback to complete execution before skipping the test if the callback
- * is not the expected one
- *
- * @param expectedStep the expected callback step
- */
- public void assumeCallback(ResponseStep expectedStep) {
- if (isTerminalCallback(expectedStep)) {
- assumeTrue(
- String.format(
- "Request timed out. Expected %s callback. Current callback is %s",
- expectedStep, mResponseStep),
- blockForDone());
- }
- assumeThat(expectedStep, equalTo(mResponseStep));
- }
-
- public void waitForNextReadStep() {
- mReadStepBlock.block();
- mReadStepBlock.close();
- }
-
- public void waitForNextWriteStep() {
- mWriteStepBlock.block();
- mWriteStepBlock.close();
- }
-
- public Executor getExecutor() {
- if (mUseDirectExecutor) {
- return mDirectExecutor;
- }
- return mExecutorService;
- }
-
- public void shutdownExecutor() {
- if (mUseDirectExecutor) {
- throw new UnsupportedOperationException("DirectExecutor doesn't support shutdown");
- }
- mExecutorService.shutdown();
- }
-
- public void addWriteData(byte[] data) {
- addWriteData(data, true);
- }
-
- public void addWriteData(byte[] data, boolean flush) {
- ByteBuffer writeBuffer = ByteBuffer.allocateDirect(data.length);
- writeBuffer.put(data);
- writeBuffer.flip();
- mWriteBuffers.add(new WriteBuffer(writeBuffer, flush));
- mWriteBuffersToBeAcked.add(new WriteBuffer(writeBuffer, flush));
- }
-
- @Override
- public void onStreamReady(BidirectionalStream stream) {
- checkOnValidThread();
- assertFalse(stream.isDone());
- assertEquals(ResponseStep.NOTHING, mResponseStep);
- assertNull(mError);
- mResponseStep = ResponseStep.ON_STREAM_READY;
- if (maybeThrowCancelOrPause(stream, mWriteStepBlock)) {
- return;
- }
- startNextWrite(stream);
- }
-
- @Override
- public void onResponseHeadersReceived(BidirectionalStream stream, UrlResponseInfo info) {
- checkOnValidThread();
- assertFalse(stream.isDone());
- assertTrue(
- mResponseStep == ResponseStep.NOTHING
- || mResponseStep == ResponseStep.ON_STREAM_READY
- || mResponseStep == ResponseStep.ON_WRITE_COMPLETED);
- assertNull(mError);
-
- mResponseStep = ResponseStep.ON_RESPONSE_STARTED;
- mResponseInfo = info;
- if (maybeThrowCancelOrPause(stream, mReadStepBlock)) {
- return;
- }
- startNextRead(stream);
- }
-
- @Override
- public void onReadCompleted(
- BidirectionalStream stream,
- UrlResponseInfo info,
- ByteBuffer byteBuffer,
- boolean endOfStream) {
- checkOnValidThread();
- assertFalse(stream.isDone());
- assertTrue(
- mResponseStep == ResponseStep.ON_RESPONSE_STARTED
- || mResponseStep == ResponseStep.ON_READ_COMPLETED
- || mResponseStep == ResponseStep.ON_WRITE_COMPLETED
- || mResponseStep == ResponseStep.ON_TRAILERS);
- assertNull(mError);
-
- mResponseStep = ResponseStep.ON_READ_COMPLETED;
- mResponseInfo = info;
-
- final int bytesRead = byteBuffer.position() - mBufferPositionBeforeRead;
- mHttpResponseDataLength += bytesRead;
- final byte[] lastDataReceivedAsBytes = new byte[bytesRead];
- // Rewind byteBuffer.position() to pre-read() position.
- byteBuffer.position(mBufferPositionBeforeRead);
- // This restores byteBuffer.position() to its value on entrance to
- // this function.
- byteBuffer.get(lastDataReceivedAsBytes);
-
- mResponseAsString += new String(lastDataReceivedAsBytes);
-
- if (maybeThrowCancelOrPause(stream, mReadStepBlock)) {
- return;
- }
- // Do not read if EOF has been reached.
- if (!endOfStream) {
- startNextRead(stream);
- }
- }
-
- @Override
- public void onWriteCompleted(
- BidirectionalStream stream,
- UrlResponseInfo info,
- ByteBuffer buffer,
- boolean endOfStream) {
- checkOnValidThread();
- assertFalse(stream.isDone());
- assertNull(mError);
- mResponseStep = ResponseStep.ON_WRITE_COMPLETED;
- mResponseInfo = info;
- if (!mWriteBuffersToBeAcked.isEmpty()) {
- assertEquals(buffer, mWriteBuffersToBeAcked.get(0).mBuffer);
- mWriteBuffersToBeAcked.remove(0);
- }
- if (maybeThrowCancelOrPause(stream, mWriteStepBlock)) {
- return;
- }
- startNextWrite(stream);
- }
-
- @Override
- public void onResponseTrailersReceived(
- BidirectionalStream stream,
- UrlResponseInfo info,
- HeaderBlock trailers) {
- checkOnValidThread();
- assertFalse(stream.isDone());
- assertNull(mError);
- mResponseStep = ResponseStep.ON_TRAILERS;
- mResponseInfo = info;
- mTrailers = trailers;
- if (maybeThrowCancelOrPause(stream, mReadStepBlock)) {
- return;
- }
- }
-
- @Override
- public void onSucceeded(BidirectionalStream stream, UrlResponseInfo info) {
- checkOnValidThread();
- assertTrue(stream.isDone());
- assertTrue(
- mResponseStep == ResponseStep.ON_RESPONSE_STARTED
- || mResponseStep == ResponseStep.ON_READ_COMPLETED
- || mResponseStep == ResponseStep.ON_WRITE_COMPLETED
- || mResponseStep == ResponseStep.ON_TRAILERS);
- assertFalse(mOnErrorCalled);
- assertFalse(mOnCanceledCalled);
- assertNull(mError);
- assertEquals(0, mWriteBuffers.size());
- assertEquals(0, mWriteBuffersToBeAcked.size());
-
- mResponseStep = ResponseStep.ON_SUCCEEDED;
- mResponseInfo = info;
- openDone();
- maybeThrowCancelOrPause(stream, mReadStepBlock);
- }
-
- @Override
- public void onFailed(BidirectionalStream stream, UrlResponseInfo info, HttpException error) {
- checkOnValidThread();
- assertTrue(stream.isDone());
- // Shouldn't happen after success.
- assertTrue(mResponseStep != ResponseStep.ON_SUCCEEDED);
- // Should happen at most once for a single stream.
- assertFalse(mOnErrorCalled);
- assertFalse(mOnCanceledCalled);
- assertNull(mError);
- mResponseStep = ResponseStep.ON_FAILED;
- mResponseInfo = info;
-
- mOnErrorCalled = true;
- mError = error;
- openDone();
- maybeThrowCancelOrPause(stream, mReadStepBlock);
- }
-
- @Override
- public void onCanceled(BidirectionalStream stream, UrlResponseInfo info) {
- checkOnValidThread();
- assertTrue(stream.isDone());
- // Should happen at most once for a single stream.
- assertFalse(mOnCanceledCalled);
- assertFalse(mOnErrorCalled);
- assertNull(mError);
- mResponseStep = ResponseStep.ON_CANCELED;
- mResponseInfo = info;
-
- mOnCanceledCalled = true;
- openDone();
- maybeThrowCancelOrPause(stream, mReadStepBlock);
- }
-
- public void startNextRead(BidirectionalStream stream) {
- startNextRead(stream, ByteBuffer.allocateDirect(READ_BUFFER_SIZE));
- }
-
- public void startNextRead(BidirectionalStream stream, ByteBuffer buffer) {
- mBufferPositionBeforeRead = buffer.position();
- stream.read(buffer);
- }
-
- public void startNextWrite(BidirectionalStream stream) {
- if (!mWriteBuffers.isEmpty()) {
- Iterator<WriteBuffer> iterator = mWriteBuffers.iterator();
- while (iterator.hasNext()) {
- WriteBuffer b = iterator.next();
- stream.write(b.mBuffer, !iterator.hasNext());
- iterator.remove();
- if (b.mFlush) {
- stream.flush();
- break;
- }
- }
- }
- }
-
- public boolean isDone() {
- // It's not mentioned by the Android docs, but block(0) seems to block
- // indefinitely, so have to block for one millisecond to get state
- // without blocking.
- return mDone.block(1);
- }
-
- /** Returns the number of pending Writes. */
- public int numPendingWrites() {
- return mWriteBuffers.size();
- }
-
- protected void openDone() {
- mDone.open();
- }
-
- /** Returns {@code false} if the callback should continue to advance the stream. */
- private boolean maybeThrowCancelOrPause(
- final BidirectionalStream stream, ConditionVariable stepBlock) {
- if (mResponseStep != mFailureStep || mFailureType == FailureType.NONE) {
- if (!mAutoAdvance) {
- stepBlock.open();
- return true;
- }
- return false;
- }
-
- if (mFailureType == FailureType.THROW_SYNC) {
- throw new IllegalStateException("Callback Exception.");
- }
- Runnable task =
- new Runnable() {
- @Override
- public void run() {
- stream.cancel();
- }
- };
- if (mFailureType == FailureType.CANCEL_ASYNC
- || mFailureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE) {
- getExecutor().execute(task);
- } else {
- task.run();
- }
- return mFailureType != FailureType.CANCEL_ASYNC_WITHOUT_PAUSE;
- }
-
- /** Checks whether callback methods are invoked on the correct thread. */
- private void checkOnValidThread() {
- if (!mUseDirectExecutor) {
- assertEquals(mExecutorThread, Thread.currentThread());
- }
- }
-}
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
deleted file mode 100644
index 3a4486f..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/util/TestStatusListener.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2022 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.UrlRequest.StatusListener
-import java.util.concurrent.CompletableFuture
-import java.util.concurrent.TimeUnit
-import org.junit.Assert.assertSame
-
-private const val TIMEOUT_MS = 12000L
-
-/** Test status listener for requests */
-class TestStatusListener : StatusListener {
- private val statusFuture = CompletableFuture<Int>()
-
- override fun onStatus(status: Int) {
- statusFuture.complete(status)
- }
-
- /** Fails if the expected status is not the returned status */
- fun expectStatus(expected: Int) {
- assertSame(expected, statusFuture.get(TIMEOUT_MS, TimeUnit.MILLISECONDS))
- }
-}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/util/TestUrlRequestCallback.java b/Cronet/tests/cts/src/android/net/http/cts/util/TestUrlRequestCallback.java
deleted file mode 100644
index 28443b7..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/util/TestUrlRequestCallback.java
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright (C) 2022 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 static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.core.AnyOf.anyOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeThat;
-import static org.junit.Assume.assumeTrue;
-
-import android.net.http.CallbackException;
-import android.net.http.HttpException;
-import android.net.http.InlineExecutionProhibitedException;
-import android.net.http.UrlRequest;
-import android.net.http.UrlResponseInfo;
-import android.os.ConditionVariable;
-import android.os.StrictMode;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Callback that tracks information from different callbacks and has a
- * method to block thread until the request completes on another thread.
- * Allows us to cancel, block request or throw an exception from an arbitrary step.
- */
-public class TestUrlRequestCallback implements UrlRequest.Callback {
- private static final int TIMEOUT_MS = 12_000;
- public ArrayList<UrlResponseInfo> mRedirectResponseInfoList = new ArrayList<>();
- public ArrayList<String> mRedirectUrlList = new ArrayList<>();
- public UrlResponseInfo mResponseInfo;
- public HttpException mError;
-
- public ResponseStep mResponseStep = ResponseStep.NOTHING;
-
- public int mRedirectCount;
- public boolean mOnErrorCalled;
- public boolean mOnCanceledCalled;
-
- public int mHttpResponseDataLength;
- public String mResponseAsString = "";
-
- public int mReadBufferSize = 32 * 1024;
-
- // When false, the consumer is responsible for all calls into the request
- // that advance it.
- private boolean mAutoAdvance = true;
- // Whether an exception is thrown by maybeThrowCancelOrPause().
- private boolean mCallbackExceptionThrown;
-
- // Whether to permit calls on the network thread.
- private boolean mAllowDirectExecutor;
-
- // Whether to stop the executor thread after reaching a terminal method.
- // Terminal methods are (onSucceeded, onFailed or onCancelled)
- private boolean mBlockOnTerminalState;
-
- // Conditionally fail on certain steps.
- private FailureType mFailureType = FailureType.NONE;
- private ResponseStep mFailureStep = ResponseStep.NOTHING;
-
- // Signals when request is done either successfully or not.
- private final ConditionVariable mDone = new ConditionVariable();
-
- // Hangs the calling thread until a terminal method has started executing.
- private final ConditionVariable mWaitForTerminalToStart = new ConditionVariable();
-
- // Signaled on each step when mAutoAdvance is false.
- private final ConditionVariable mStepBlock = new ConditionVariable();
-
- // Executor Service for Http callbacks.
- private final ExecutorService mExecutorService;
- private Thread mExecutorThread;
-
- // position() of ByteBuffer prior to read() call.
- private int mBufferPositionBeforeRead;
-
- private static class ExecutorThreadFactory implements ThreadFactory {
- @Override
- public Thread newThread(final Runnable r) {
- return new Thread(new Runnable() {
- @Override
- public void run() {
- StrictMode.ThreadPolicy threadPolicy = StrictMode.getThreadPolicy();
- try {
- StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
- .detectNetwork()
- .penaltyLog()
- .penaltyDeath()
- .build());
- r.run();
- } finally {
- StrictMode.setThreadPolicy(threadPolicy);
- }
- }
- });
- }
- }
-
- public enum ResponseStep {
- NOTHING,
- ON_RECEIVED_REDIRECT,
- ON_RESPONSE_STARTED,
- ON_READ_COMPLETED,
- ON_SUCCEEDED,
- ON_FAILED,
- ON_CANCELED,
- }
-
- public enum FailureType {
- NONE,
- CANCEL_SYNC,
- CANCEL_ASYNC,
- // Same as above, but continues to advance the request after posting
- // the cancellation task.
- CANCEL_ASYNC_WITHOUT_PAUSE,
- THROW_SYNC
- }
-
- private static void assertContains(String expectedSubstring, String actualString) {
- assertNotNull(actualString);
- assertTrue("String [" + actualString + "] doesn't contain substring [" + expectedSubstring
- + "]", actualString.contains(expectedSubstring));
-
- }
-
- /**
- * Set {@code mExecutorThread}.
- */
- private void fillInExecutorThread() {
- mExecutorService.execute(new Runnable() {
- @Override
- public void run() {
- mExecutorThread = Thread.currentThread();
- }
- });
- }
-
- private boolean isTerminalCallback(ResponseStep step) {
- switch (step) {
- case ON_SUCCEEDED:
- case ON_CANCELED:
- case ON_FAILED:
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Create a {@link TestUrlRequestCallback} with a new single-threaded executor.
- */
- public TestUrlRequestCallback() {
- this(Executors.newSingleThreadExecutor(new ExecutorThreadFactory()));
- }
-
- /**
- * Create a {@link TestUrlRequestCallback} using a custom single-threaded executor.
- */
- public TestUrlRequestCallback(ExecutorService executorService) {
- mExecutorService = executorService;
- fillInExecutorThread();
- }
-
- /**
- * This blocks the callback executor thread once it has reached a final state callback.
- * In order to continue execution, this method must be called again and providing {@code false}
- * to continue execution.
- *
- * @param blockOnTerminalState the state to set for the executor thread
- */
- public void setBlockOnTerminalState(boolean blockOnTerminalState) {
- mBlockOnTerminalState = blockOnTerminalState;
- if (!blockOnTerminalState) {
- mDone.open();
- }
- }
-
- public void setAutoAdvance(boolean autoAdvance) {
- mAutoAdvance = autoAdvance;
- }
-
- public void setAllowDirectExecutor(boolean allowed) {
- mAllowDirectExecutor = allowed;
- }
-
- public void setFailure(FailureType failureType, ResponseStep failureStep) {
- mFailureStep = failureStep;
- mFailureType = failureType;
- }
-
- /**
- * Blocks the calling thread till callback execution is done
- *
- * @return true if the condition was opened, false if the call returns because of the timeout.
- */
- public boolean blockForDone() {
- return mDone.block(TIMEOUT_MS);
- }
-
- /**
- * Waits for a terminal callback to complete execution before failing if the callback
- * is not the expected one
- *
- * @param expectedStep the expected callback step
- */
- public void expectCallback(ResponseStep expectedStep) {
- if (isTerminalCallback(expectedStep)) {
- assertTrue("Did not receive terminal callback before timeout", blockForDone());
- }
- assertSame(expectedStep, mResponseStep);
- }
-
- /**
- * Waits for a terminal callback to complete execution before skipping the test if the
- * callback is not the expected one
- *
- * @param expectedStep the expected callback step
- */
- public void assumeCallback(ResponseStep expectedStep) {
- if (isTerminalCallback(expectedStep)) {
- assumeTrue("Did not receive terminal callback before timeout", blockForDone());
- }
- assumeThat(expectedStep, equalTo(mResponseStep));
- }
-
- /**
- * Blocks the calling thread until one of the final states has been called.
- * This is called before the callback has finished executed.
- */
- public void waitForTerminalToStart() {
- mWaitForTerminalToStart.block();
- }
-
- public void waitForNextStep() {
- mStepBlock.block();
- mStepBlock.close();
- }
-
- public ExecutorService getExecutor() {
- return mExecutorService;
- }
-
- public void shutdownExecutor() {
- mExecutorService.shutdown();
- }
-
- /**
- * Shuts down the ExecutorService and waits until it executes all posted
- * tasks.
- */
- public void shutdownExecutorAndWait() {
- mExecutorService.shutdown();
- try {
- // Termination shouldn't take long. Use 1 min which should be more than enough.
- mExecutorService.awaitTermination(1, TimeUnit.MINUTES);
- } catch (InterruptedException e) {
- fail("ExecutorService is interrupted while waiting for termination");
- }
- assertTrue(mExecutorService.isTerminated());
- }
-
- @Override
- public void onRedirectReceived(
- UrlRequest request, UrlResponseInfo info, String newLocationUrl) {
- checkExecutorThread();
- assertFalse(request.isDone());
- assertThat(mResponseStep, anyOf(
- equalTo(ResponseStep.NOTHING),
- equalTo(ResponseStep.ON_RECEIVED_REDIRECT)));
- assertNull(mError);
-
- mResponseStep = ResponseStep.ON_RECEIVED_REDIRECT;
- mRedirectUrlList.add(newLocationUrl);
- mRedirectResponseInfoList.add(info);
- ++mRedirectCount;
- if (maybeThrowCancelOrPause(request)) {
- return;
- }
- request.followRedirect();
- }
-
- @Override
- public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
- checkExecutorThread();
- assertFalse(request.isDone());
- assertThat(mResponseStep, anyOf(
- equalTo(ResponseStep.NOTHING),
- equalTo(ResponseStep.ON_RECEIVED_REDIRECT)));
- assertNull(mError);
-
- mResponseStep = ResponseStep.ON_RESPONSE_STARTED;
- mResponseInfo = info;
- if (maybeThrowCancelOrPause(request)) {
- return;
- }
- startNextRead(request);
- }
-
- @Override
- public void onReadCompleted(UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) {
- checkExecutorThread();
- assertFalse(request.isDone());
- assertThat(mResponseStep, anyOf(
- equalTo(ResponseStep.ON_RESPONSE_STARTED),
- equalTo(ResponseStep.ON_READ_COMPLETED)));
- assertNull(mError);
-
- mResponseStep = ResponseStep.ON_READ_COMPLETED;
-
- final byte[] lastDataReceivedAsBytes;
- final int bytesRead = byteBuffer.position() - mBufferPositionBeforeRead;
- mHttpResponseDataLength += bytesRead;
- lastDataReceivedAsBytes = new byte[bytesRead];
- // Rewind |byteBuffer.position()| to pre-read() position.
- byteBuffer.position(mBufferPositionBeforeRead);
- // This restores |byteBuffer.position()| to its value on entrance to
- // this function.
- byteBuffer.get(lastDataReceivedAsBytes);
- mResponseAsString += new String(lastDataReceivedAsBytes);
-
- if (maybeThrowCancelOrPause(request)) {
- return;
- }
- startNextRead(request);
- }
-
- @Override
- public void onSucceeded(UrlRequest request, UrlResponseInfo info) {
- checkExecutorThread();
- assertTrue(request.isDone());
- assertThat(mResponseStep, anyOf(
- equalTo(ResponseStep.ON_RESPONSE_STARTED),
- equalTo(ResponseStep.ON_READ_COMPLETED)));
- assertFalse(mOnErrorCalled);
- assertFalse(mOnCanceledCalled);
- assertNull(mError);
-
- mResponseStep = ResponseStep.ON_SUCCEEDED;
- mResponseInfo = info;
- mWaitForTerminalToStart.open();
- if (mBlockOnTerminalState) mDone.block();
- openDone();
- maybeThrowCancelOrPause(request);
- }
-
- @Override
- public void onFailed(UrlRequest request, UrlResponseInfo info, HttpException error) {
- // If the failure is because of prohibited direct execution, the test shouldn't fail
- // since the request already did.
- if (error.getCause() instanceof InlineExecutionProhibitedException) {
- mAllowDirectExecutor = true;
- }
- checkExecutorThread();
- assertTrue(request.isDone());
- // Shouldn't happen after success.
- assertNotEquals(ResponseStep.ON_SUCCEEDED, mResponseStep);
- // Should happen at most once for a single request.
- assertFalse(mOnErrorCalled);
- assertFalse(mOnCanceledCalled);
- assertNull(mError);
- if (mCallbackExceptionThrown) {
- assertTrue(error instanceof CallbackException);
- assertContains("Exception received from UrlRequest.Callback", error.getMessage());
- assertNotNull(error.getCause());
- assertTrue(error.getCause() instanceof IllegalStateException);
- assertContains("Listener Exception.", error.getCause().getMessage());
- }
-
- mResponseStep = ResponseStep.ON_FAILED;
- mOnErrorCalled = true;
- mError = error;
- mWaitForTerminalToStart.open();
- if (mBlockOnTerminalState) mDone.block();
- openDone();
- maybeThrowCancelOrPause(request);
- }
-
- @Override
- public void onCanceled(UrlRequest request, UrlResponseInfo info) {
- checkExecutorThread();
- assertTrue(request.isDone());
- // Should happen at most once for a single request.
- assertFalse(mOnCanceledCalled);
- assertFalse(mOnErrorCalled);
- assertNull(mError);
-
- mResponseStep = ResponseStep.ON_CANCELED;
- mOnCanceledCalled = true;
- mWaitForTerminalToStart.open();
- if (mBlockOnTerminalState) mDone.block();
- openDone();
- maybeThrowCancelOrPause(request);
- }
-
- public void startNextRead(UrlRequest request) {
- startNextRead(request, ByteBuffer.allocateDirect(mReadBufferSize));
- }
-
- public void startNextRead(UrlRequest request, ByteBuffer buffer) {
- mBufferPositionBeforeRead = buffer.position();
- request.read(buffer);
- }
-
- public boolean isDone() {
- // It's not mentioned by the Android docs, but block(0) seems to block
- // indefinitely, so have to block for one millisecond to get state
- // without blocking.
- return mDone.block(1);
- }
-
- protected void openDone() {
- mDone.open();
- }
-
- private void checkExecutorThread() {
- if (!mAllowDirectExecutor) {
- assertEquals(mExecutorThread, Thread.currentThread());
- }
- }
-
- /**
- * Returns {@code false} if the listener should continue to advance the
- * request.
- */
- private boolean maybeThrowCancelOrPause(final UrlRequest request) {
- checkExecutorThread();
- if (mResponseStep != mFailureStep || mFailureType == FailureType.NONE) {
- if (!mAutoAdvance) {
- mStepBlock.open();
- return true;
- }
- return false;
- }
-
- if (mFailureType == FailureType.THROW_SYNC) {
- assertFalse(mCallbackExceptionThrown);
- mCallbackExceptionThrown = true;
- throw new IllegalStateException("Listener Exception.");
- }
- Runnable task = new Runnable() {
- @Override
- public void run() {
- request.cancel();
- }
- };
- if (mFailureType == FailureType.CANCEL_ASYNC
- || mFailureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE) {
- getExecutor().execute(task);
- } else {
- task.run();
- }
- return mFailureType != FailureType.CANCEL_ASYNC_WITHOUT_PAUSE;
- }
-}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/util/TestUtils.kt b/Cronet/tests/cts/src/android/net/http/cts/util/TestUtils.kt
deleted file mode 100644
index 7fc005a..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/util/TestUtils.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.content.Context
-import android.net.ConnectivityManager
-import android.net.http.UrlResponseInfo
-import org.hamcrest.Matchers.equalTo
-import org.junit.Assert.assertEquals
-import org.junit.Assume.assumeNotNull
-import org.junit.Assume.assumeThat
-
-fun skipIfNoInternetConnection(context: Context) {
- val connectivityManager = context.getSystemService(ConnectivityManager::class.java)
- assumeNotNull(
- "This test requires a working Internet connection", connectivityManager!!.activeNetwork
- )
-}
-
-fun assertOKStatusCode(info: UrlResponseInfo) {
- assertEquals("Status code must be 200 OK", 200, info.httpStatusCode)
-}
-
-fun assumeOKStatusCode(info: UrlResponseInfo) {
- assumeThat("Status code must be 200 OK", info.httpStatusCode, equalTo(200))
-}
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
deleted file mode 100644
index 3b90fa0..0000000
--- a/Cronet/tests/cts/src/android/net/http/cts/util/UploadDataProviders.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * 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;
-import java.nio.charset.StandardCharsets;
-
-/**
- * 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);
- }
-
- /**
- * Uploads the UTF-8 representation of {@code data}
- *
- * @param data String containing data to upload
- * @return A new UploadDataProvider for the given data
- */
- public static UploadDataProvider create(String data) {
- return create(data.getBytes(StandardCharsets.UTF_8));
- }
-
- 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
deleted file mode 100644
index 9486e1f..0000000
--- a/Cronet/tests/mts/Android.bp
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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 {
- default_team: "trendy_team_fwk_core_networking",
- // See: http://go/android-license-faq
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_genrule {
- name: "net-http-test-jarjar-rules",
- tool_files: [
- ":NetHttpTestsLibPreJarJar{.jar}",
- "jarjar_excludes.txt",
- ],
- tools: [
- "jarjar-rules-generator",
- ],
- out: ["net_http_test_jarjar_rules.txt"],
- cmd: "$(location jarjar-rules-generator) " +
- "$(location :NetHttpTestsLibPreJarJar{.jar}) " +
- "--prefix android.net.connectivity " +
- "--excludes $(location jarjar_excludes.txt) " +
- "--output $(out)",
-}
-
-// Library to be used in coverage tests. cronet_java_tests can't be used directly because the common
-// tests need to inherit the NetHttpTests manifest.
-android_library {
- name: "NetHttpTestsLibPreJarJar",
- static_libs: [
- "cronet_aml_api_java",
- "cronet_aml_java__testing",
- "cronet_java_tests",
- ],
- sdk_version: "module_current",
- min_sdk_version: "30",
-}
-
-android_test {
- name: "NetHttpTests",
- defaults: [
- "mts-target-sdk-version-current",
- ],
- static_libs: ["NetHttpTestsLibPreJarJar"],
- jarjar_rules: ":net-http-test-jarjar-rules",
- jni_libs: [
- "cronet_aml_components_cronet_android_cronet__testing",
- "cronet_aml_components_cronet_android_cronet_tests__testing",
- "cronet_aml_third_party_netty_tcnative_netty_tcnative_so__testing",
- ],
- test_suites: [
- "general-tests",
- "mts-tethering",
- ],
- data: [":cronet_javatests_resources"],
-}
diff --git a/Cronet/tests/mts/AndroidManifest.xml b/Cronet/tests/mts/AndroidManifest.xml
deleted file mode 100644
index 2c56e3a..0000000
--- a/Cronet/tests/mts/AndroidManifest.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.net.http.mts">
-
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.INTERNET"/>
-
- <application android:networkSecurityConfig="@xml/network_security_config">
- <uses-library android:name="android.test.runner" />
- </application>
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.net.http.mts"
- android:label="MTS tests of android.net.http">
- </instrumentation>
-
-</manifest>
\ No newline at end of file
diff --git a/Cronet/tests/mts/AndroidTest.xml b/Cronet/tests/mts/AndroidTest.xml
deleted file mode 100644
index a438e2e..0000000
--- a/Cronet/tests/mts/AndroidTest.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<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.Sdk31ModuleController" />
-
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="test-file-name" value="NetHttpTests.apk" />
- </target_preparer>
-
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="push-file" key="net" value="/storage/emulated/0/chromium_tests_root/net" />
- <option name="push-file" key="test_server" value="/storage/emulated/0/chromium_tests_root/components/cronet/testing/test_server" />
- </target_preparer>
-
- <option name="test-tag" value="NetHttpTests" />
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.net.http.mts" />
- <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <!-- b/298380508 -->
- <option name="exclude-filter" value="org.chromium.net.CronetUrlRequestContextTest#testSetLibraryLoaderIsEnforcedByDefaultEmbeddedProvider" />
- <!-- b/316559294 -->
- <option name="exclude-filter" value="org.chromium.net.NQETest#testQuicDisabled" />
- <!-- b/316559294 -->
- <option name="exclude-filter" value="org.chromium.net.NQETest#testPrefsWriteRead" />
- <!-- b/316554711-->
- <option name="exclude-filter" value="org.chromium.net.NetworkChangesTest" />
- <!-- b/316550794 -->
- <option name="exclude-filter" value="org.chromium.net.impl.CronetLoggerTest#testEngineCreation" />
- <!-- b/327182569 -->
- <option name="exclude-filter" value="org.chromium.net.urlconnection.CronetURLStreamHandlerFactoryTest#testSetUrlStreamFactoryUsesCronetForNative" />
- <option name="hidden-api-checks" value="false"/>
- <option name="isolated-storage" value="false"/>
- <option name="orchestrator" value="true"/>
- </test>
-
- <!-- Only run NetHttpTests in MTS if the Tethering Mainline module is installed. -->
- <object type="module_controller"
- class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
- <option name="mainline-module-package-name" value="com.google.android.tethering" />
- </object>
-</configuration>
diff --git a/Cronet/tests/mts/jarjar_excludes.txt b/Cronet/tests/mts/jarjar_excludes.txt
deleted file mode 100644
index b5cdf6e..0000000
--- a/Cronet/tests/mts/jarjar_excludes.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-# Exclude some test prefixes, as they can't be found after being jarjared.
-com\.android\.testutils\..+
-# jarjar-gen can't handle some kotlin object expression, exclude packages that include them
-androidx\..+
-# don't jarjar netty as it does JNI
-io\.netty\..+
-kotlin\.test\..+
-kotlin\.reflect\..+
-org\.mockito\..+
-# Do not jarjar the api classes
-android\.net\..+
-# cronet_tests.so is not jarjared and uses base classes. We can remove this when there's a
-# separate java base target to depend on.
-org\.chromium\.base\..+
-J\.cronet_tests_N(\$.+)?
-
-# don't jarjar automatically generated FooJni files.
-org\.chromium\.net\..+Jni(\$.+)?
-
-# Do not jarjar the tests and its utils as they also do JNI with cronet_tests.so
-org\.chromium\.net\..*Test.*(\$.+)?
-org\.chromium\.net\.NativeTestServer(\$.+)?
-org\.chromium\.net\.MockUrlRequestJobFactory(\$.+)?
-org\.chromium\.net\.QuicTestServer(\$.+)?
-org\.chromium\.net\.MockCertVerifier(\$.+)?
-org\.chromium\.net\.LogcatCapture(\$.+)?
-org\.chromium\.net\.ReportingCollector(\$.+)?
-org\.chromium\.net\.Http2TestServer(\$.+)?
-org\.chromium\.net\.Http2TestHandler(\$.+)?
\ No newline at end of file
diff --git a/Cronet/tests/mts/res/raw/quicroot.pem b/Cronet/tests/mts/res/raw/quicroot.pem
deleted file mode 100644
index af21b3e..0000000
--- a/Cronet/tests/mts/res/raw/quicroot.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIC/jCCAeagAwIBAgIUXOi6XoxnMUjJg4jeOwRhsdqEqEQwDQYJKoZIhvcNAQEL
-BQAwFzEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTIzMDYwMTExMjcwMFoXDTMz
-MDUyOTExMjcwMFowFzEVMBMGA1UEAwwMVGVzdCBSb290IENBMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl9xCMPMIvfmJWz25AG/VtgWbqNs67HXQbXWf
-pDF2wjQpHVOYbfl7Zgly5O+5es1aUbJaGyZ9G6xuYSXKFnnYLoP7M86O05fQQBAj
-K+IE5nO6136ksCAfxCFTFfn4vhPvK8Vba5rqox4WeIXYKvHYSoiHz0ELrnFOHcyN
-Innyze7bLtkMCA1ShHpmvDCR+U3Uj6JwOfoirn29jjU/48/ORha7dcJYtYXk2eGo
-RJfrtIx20tXAaKaGnXOCGYbEVXTeQkQPqKFVzqP7+KYS/Y8eNFV35ugpLNES+44T
-bQ2QruTZdrNRjJkEoyiB/E53a0OUltB/R7Z0L0xstnKfsAf3OwIDAQABo0IwQDAP
-BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUVdXNh2lk
-51/6hMmz0Z+OpIe8+f0wDQYJKoZIhvcNAQELBQADggEBADNg7G8n6DUrQ5doXzm9
-kOp5siX6iPs0zFReXKhIT1Gef63l3tb7AdPedF03aj9XkUt0shhNOGG5SK2k5KBQ
-MJc9muYRCAyo2xMr3rFUQdI5B51SCy5HeAMralgTHXN0Hv+TH04YfRrACVmr+5ke
-pH3bF1gYaT+Zy5/pHJnV5lcwS6/H44g9XXWIopjWCwbfzKxIuWofqL4fiToPSIYu
-MCUI4bKZipcJT5O6rdz/S9lbgYVjOJ4HAoT2icNQqNMMfULKevmF8SdJzfNd35yn
-tAKTROhIE2aQRVCclrjo/T3eyjWGGoJlGmxKbeCf/rXzcn1BRtk/UzLnbUFFlg5l
-axw=
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/Cronet/tests/mts/res/values/cronet-test-rule-configuration.xml b/Cronet/tests/mts/res/values/cronet-test-rule-configuration.xml
deleted file mode 100644
index 48ce420..0000000
--- a/Cronet/tests/mts/res/values/cronet-test-rule-configuration.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources>
- <bool name="is_running_in_aosp">true</bool>
-</resources>
\ No newline at end of file
diff --git a/Cronet/tests/mts/res/xml/network_security_config.xml b/Cronet/tests/mts/res/xml/network_security_config.xml
deleted file mode 100644
index 32b7171..0000000
--- a/Cronet/tests/mts/res/xml/network_security_config.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2022 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.
- -->
-
-<network-security-config>
- <base-config>
- <trust-anchors>
- <certificates src="@raw/quicroot"/>
- <certificates src="system"/>
- </trust-anchors>
- </base-config>
- <!-- Since Android 9 (API 28) cleartext support is disabled by default, this
- causes some of our tests to fail (see crbug/1220357).
- The following configs allow http requests for the domains used in these
- tests.
-
- TODO(stefanoduo): Figure out if we really need to use http for these tests
- -->
- <domain-config cleartextTrafficPermitted="true">
- <!-- Used as the base URL by native test server (net::EmbeddedTestServer) -->
- <domain includeSubdomains="true">127.0.0.1</domain>
- <!-- Used by CronetHttpURLConnectionTest#testIOExceptionInterruptRethrown -->
- <domain includeSubdomains="true">localhost</domain>
- <!-- Used by CronetHttpURLConnectionTest#testBadIP -->
- <domain includeSubdomains="true">0.0.0.0</domain>
- <!-- Used by CronetHttpURLConnectionTest#testSetUseCachesFalse -->
- <domain includeSubdomains="true">host-cache-test-host</domain>
- <!-- Used by CronetHttpURLConnectionTest#testBadHostname -->
- <domain includeSubdomains="true">this-weird-host-name-does-not-exist</domain>
- <!-- Used by CronetUrlRequestContextTest#testHostResolverRules -->
- <domain includeSubdomains="true">some-weird-hostname</domain>
- </domain-config>
-</network-security-config>
\ No newline at end of file
diff --git a/TEST_MAPPING b/TEST_MAPPING
index d8d4c21..375397b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,4 +1,152 @@
{
+ "captiveportal-networkstack-resolve-tethering-mainline-presubmit": [
+ {
+ "name": "CtsNetTestCasesLatestSdk",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "CtsNetTestCasesMaxTargetSdk30",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "CtsNetTestCasesMaxTargetSdk31",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "CtsNetTestCasesMaxTargetSdk33",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "bpf_existence_test"
+ },
+ {
+ "name": "connectivity_native_test"
+ },
+ {
+ "name": "netd_updatable_unit_test"
+ },
+ {
+ "name": "ConnectivityCoverageTests",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ }
+ ]
+ },
+ {
+ "name": "libnetworkstats_test"
+ },
+ {
+ "name": "NetHttpCoverageTests",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ // These sometimes take longer than 1 min which is the presubmit timeout
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsTetheringTestLatestSdk",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.NetworkStackModuleTest"
+ }
+ ]
+ }
+ ],
+ "captiveportal-networkstack-mainline-presubmit": [
+ // Test with APK modules only, in cases where APEX is not supported, or the other modules
+ // were simply not updated
+ {
+ "name": "CtsNetTestCasesLatestSdk",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.ConnectivityModuleTest"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.DnsResolverModuleTest"
+ }
+ ]
+ }
+ ],
+ "tethering-mainline-presubmit": [
+ // Test with connectivity/tethering module only, to catch integration issues with older versions
+ // of other modules. "new tethering + old NetworkStack" is not a configuration that should
+ // really exist in the field, but there is no strong guarantee, and it is required by MTS
+ // testing for module qualification, where modules are tested independently.
+ {
+ "name": "CtsNetTestCasesLatestSdk",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.SkipMainlinePresubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.DnsResolverModuleTest"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.NetworkStackModuleTest"
+ }
+ ]
+ }
+ ],
"presubmit": [
{
"name": "ConnectivityCoverageTests",
@@ -104,19 +252,6 @@
},
{
"name": "FrameworksNetIntegrationTests"
- },
- // Runs both NetHttpTests and CtsNetHttpTestCases
- {
- "name": "NetHttpCoverageTests",
- "options": [
- {
- "exclude-annotation": "com.android.testutils.SkipPresubmit"
- },
- {
- // These sometimes take longer than 1 min which is the presubmit timeout
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
}
],
"postsubmit": [
@@ -144,9 +279,6 @@
},
{
"name": "FrameworksNetTests"
- },
- {
- "name": "NetHttpCoverageTests"
}
],
"mainline-presubmit": [
@@ -273,18 +405,6 @@
"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]",
- "options": [
- {
- "exclude-annotation": "com.android.testutils.SkipPresubmit"
- },
- {
- // These sometimes take longer than 1 min which is the presubmit timeout
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
- },
- {
"name": "CtsTetheringTestLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]",
"options": [
{
@@ -332,6 +452,9 @@
"path": "packages/modules/CaptivePortalLogin"
},
{
+ "path": "external/cronet"
+ },
+ {
"path": "vendor/xts/gts-tests/hostsidetests/networkstack"
}
]
diff --git a/common/FlaggedApi.bp b/common/FlaggedApi.bp
index 56625c5..21be1d3 100644
--- a/common/FlaggedApi.bp
+++ b/common/FlaggedApi.bp
@@ -17,7 +17,7 @@
aconfig_declarations {
name: "com.android.net.flags-aconfig",
package: "com.android.net.flags",
- container: "system",
+ container: "com.android.tethering",
srcs: ["flags.aconfig"],
visibility: ["//packages/modules/Connectivity:__subpackages__"],
}
@@ -25,7 +25,7 @@
aconfig_declarations {
name: "com.android.net.thread.flags-aconfig",
package: "com.android.net.thread.flags",
- container: "system",
+ container: "com.android.tethering",
srcs: ["thread_flags.aconfig"],
visibility: ["//packages/modules/Connectivity:__subpackages__"],
}
@@ -33,7 +33,7 @@
aconfig_declarations {
name: "nearby_flags",
package: "com.android.nearby.flags",
- container: "system",
+ container: "com.android.tethering",
srcs: ["nearby_flags.aconfig"],
visibility: ["//packages/modules/Connectivity:__subpackages__"],
}
diff --git a/common/flags.aconfig b/common/flags.aconfig
index 512677a..55a96ac 100644
--- a/common/flags.aconfig
+++ b/common/flags.aconfig
@@ -1,5 +1,5 @@
package: "com.android.net.flags"
-container: "system"
+container: "com.android.tethering"
# This file contains aconfig flags for FlaggedAPI annotations
# Flags used from platform code must be in under frameworks
@@ -91,3 +91,11 @@
description: "Flag for metered network firewall chain API"
bug: "332628891"
}
+
+flag {
+ name: "blocked_reason_oem_deny_chains"
+ is_exported: true
+ namespace: "android_core_networking"
+ description: "Flag for oem deny chains blocked reasons API"
+ bug: "328732146"
+}
diff --git a/common/nearby_flags.aconfig b/common/nearby_flags.aconfig
index b733849..55a865b 100644
--- a/common/nearby_flags.aconfig
+++ b/common/nearby_flags.aconfig
@@ -1,5 +1,5 @@
package: "com.android.nearby.flags"
-container: "system"
+container: "com.android.tethering"
flag {
name: "powered_off_finding"
diff --git a/common/thread_flags.aconfig b/common/thread_flags.aconfig
index 43fc147..43acd1b 100644
--- a/common/thread_flags.aconfig
+++ b/common/thread_flags.aconfig
@@ -1,5 +1,5 @@
package: "com.android.net.thread.flags"
-container: "system"
+container: "com.android.tethering"
flag {
name: "thread_enabled"
diff --git a/framework-t/src/android/net/IpSecTransform.java b/framework-t/src/android/net/IpSecTransform.java
index 4e10a96..70c9bc8 100644
--- a/framework-t/src/android/net/IpSecTransform.java
+++ b/framework-t/src/android/net/IpSecTransform.java
@@ -124,7 +124,7 @@
private IpSecTransform activate()
throws IOException, IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException {
- synchronized (this) {
+ synchronized (mLock) {
try {
IpSecTransformResponse result = getIpSecManager(mContext).createTransform(
mConfig, new Binder(), mContext.getOpPackageName());
@@ -164,20 +164,23 @@
public void close() {
Log.d(TAG, "Removing Transform with Id " + mResourceId);
- // Always safe to attempt cleanup
- if (mResourceId == INVALID_RESOURCE_ID) {
- mCloseGuard.close();
- return;
- }
- try {
- getIpSecManager(mContext).deleteTransform(mResourceId);
- } catch (Exception e) {
- // On close we swallow all random exceptions since failure to close is not
- // actionable by the user.
- Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
- } finally {
- mResourceId = INVALID_RESOURCE_ID;
- mCloseGuard.close();
+ synchronized(mLock) {
+ // Always safe to attempt cleanup
+ if (mResourceId == INVALID_RESOURCE_ID) {
+ mCloseGuard.close();
+ return;
+ }
+
+ try {
+ getIpSecManager(mContext).deleteTransform(mResourceId);
+ } catch (Exception e) {
+ // On close we swallow all random exceptions since failure to close is not
+ // actionable by the user.
+ Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
+ } finally {
+ mResourceId = INVALID_RESOURCE_ID;
+ mCloseGuard.close();
+ }
}
}
@@ -196,14 +199,17 @@
}
private final IpSecConfig mConfig;
- private int mResourceId;
+ private final Object mLock = new Object();
+ private int mResourceId; // Partly guarded by mLock to ensure basic safety, not correctness
private final Context mContext;
private final CloseGuard mCloseGuard = CloseGuard.get();
/** @hide */
@VisibleForTesting
public int getResourceId() {
- return mResourceId;
+ synchronized(mLock) {
+ return mResourceId;
+ }
}
/**
@@ -224,8 +230,10 @@
// TODO: Consider adding check to prevent DDoS attack.
try {
- final IpSecTransformState ipSecTransformState =
- getIpSecManager(mContext).getTransformState(mResourceId);
+ IpSecTransformState ipSecTransformState;
+ synchronized(mLock) {
+ ipSecTransformState = getIpSecManager(mContext).getTransformState(mResourceId);
+ }
executor.execute(
() -> {
callback.onResult(ipSecTransformState);
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index b2aafa0..d233f3e 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -52,6 +52,7 @@
field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
field public static final int BLOCKED_REASON_LOW_POWER_STANDBY = 32; // 0x20
field public static final int BLOCKED_REASON_NONE = 0; // 0x0
+ field @FlaggedApi("com.android.net.flags.blocked_reason_oem_deny_chains") public static final int BLOCKED_REASON_OEM_DENY = 128; // 0x80
field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
field @FlaggedApi("com.android.net.flags.basic_background_restrictions_enabled") public static final int FIREWALL_CHAIN_BACKGROUND = 6; // 0x6
field public static final int FIREWALL_CHAIN_DOZABLE = 1; // 0x1
diff --git a/framework/src/android/net/BpfNetMapsUtils.java b/framework/src/android/net/BpfNetMapsUtils.java
index 4e01fee..4099e2a 100644
--- a/framework/src/android/net/BpfNetMapsUtils.java
+++ b/framework/src/android/net/BpfNetMapsUtils.java
@@ -37,6 +37,18 @@
import static android.net.BpfNetMapsConstants.RESTRICTED_MATCH;
import static android.net.BpfNetMapsConstants.STANDBY_MATCH;
import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_ADMIN_DISABLED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_BACKGROUND;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_OEM_DENY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_RESTRICTED_MODE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
@@ -238,6 +250,67 @@
}
/**
+ * Get blocked reasons for specified uid
+ *
+ * @param uid Target Uid
+ * @return Reasons of network access blocking for an UID
+ */
+ public static int getUidNetworkingBlockedReasons(final int uid,
+ IBpfMap<S32, U32> configurationMap,
+ IBpfMap<S32, UidOwnerValue> uidOwnerMap,
+ IBpfMap<S32, U8> dataSaverEnabledMap
+ ) {
+ final long uidRuleConfig;
+ final long uidMatch;
+ try {
+ uidRuleConfig = configurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val;
+ final UidOwnerValue value = uidOwnerMap.getValue(new Struct.S32(uid));
+ uidMatch = (value != null) ? value.rule : 0L;
+ } catch (ErrnoException e) {
+ throw new ServiceSpecificException(e.errno,
+ "Unable to get firewall chain status: " + Os.strerror(e.errno));
+ }
+ final long blockingMatches = (uidRuleConfig & ~uidMatch & sMaskDropIfUnset)
+ | (uidRuleConfig & uidMatch & sMaskDropIfSet);
+
+ int blockedReasons = BLOCKED_REASON_NONE;
+ if ((blockingMatches & POWERSAVE_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_BATTERY_SAVER;
+ }
+ if ((blockingMatches & DOZABLE_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_DOZE;
+ }
+ if ((blockingMatches & STANDBY_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_APP_STANDBY;
+ }
+ if ((blockingMatches & RESTRICTED_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
+ }
+ if ((blockingMatches & LOW_POWER_STANDBY_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_LOW_POWER_STANDBY;
+ }
+ if ((blockingMatches & BACKGROUND_MATCH) != 0) {
+ blockedReasons |= BLOCKED_REASON_APP_BACKGROUND;
+ }
+ if ((blockingMatches & (OEM_DENY_1_MATCH | OEM_DENY_2_MATCH | OEM_DENY_3_MATCH)) != 0) {
+ blockedReasons |= BLOCKED_REASON_OEM_DENY;
+ }
+
+ // Metered chains are not enabled by configuration map currently.
+ if ((uidMatch & PENALTY_BOX_USER_MATCH) != 0) {
+ blockedReasons |= BLOCKED_METERED_REASON_USER_RESTRICTED;
+ }
+ if ((uidMatch & PENALTY_BOX_ADMIN_MATCH) != 0) {
+ blockedReasons |= BLOCKED_METERED_REASON_ADMIN_DISABLED;
+ }
+ if ((uidMatch & HAPPY_BOX_MATCH) == 0 && getDataSaverEnabled(dataSaverEnabledMap)) {
+ blockedReasons |= BLOCKED_METERED_REASON_DATA_SAVER;
+ }
+
+ return blockedReasons;
+ }
+
+ /**
* Return whether the network is blocked by firewall chains for the given uid.
*
* Note that {@link #getDataSaverEnabled(IBpfMap)} has a latency before V.
@@ -263,27 +336,16 @@
return false;
}
- final long uidRuleConfig;
- final long uidMatch;
- try {
- uidRuleConfig = configurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val;
- final UidOwnerValue value = uidOwnerMap.getValue(new Struct.S32(uid));
- uidMatch = (value != null) ? value.rule : 0L;
- } catch (ErrnoException e) {
- throw new ServiceSpecificException(e.errno,
- "Unable to get firewall chain status: " + Os.strerror(e.errno));
+ final int blockedReasons = getUidNetworkingBlockedReasons(
+ uid,
+ configurationMap,
+ uidOwnerMap,
+ dataSaverEnabledMap);
+ if (isNetworkMetered) {
+ return blockedReasons != BLOCKED_REASON_NONE;
+ } else {
+ return (blockedReasons & ~BLOCKED_METERED_REASON_MASK) != BLOCKED_REASON_NONE;
}
-
- final boolean blockedByAllowChains = 0 != (uidRuleConfig & ~uidMatch & sMaskDropIfUnset);
- final boolean blockedByDenyChains = 0 != (uidRuleConfig & uidMatch & sMaskDropIfSet);
- if (blockedByAllowChains || blockedByDenyChains) {
- return true;
- }
-
- if (!isNetworkMetered) return false;
- if ((uidMatch & (PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH)) != 0) return true;
- if ((uidMatch & HAPPY_BOX_MATCH) != 0) return false;
- return getDataSaverEnabled(dataSaverEnabledMap);
}
/**
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 7823258..48ed732 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -130,6 +130,8 @@
"com.android.net.flags.basic_background_restrictions_enabled";
static final String METERED_NETWORK_FIREWALL_CHAINS =
"com.android.net.flags.metered_network_firewall_chains";
+ static final String BLOCKED_REASON_OEM_DENY_CHAINS =
+ "com.android.net.flags.blocked_reason_oem_deny_chains";
}
/**
@@ -913,6 +915,19 @@
public static final int BLOCKED_REASON_APP_BACKGROUND = 1 << 6;
/**
+ * Flag to indicate that an app is subject to OEM-specific application restrictions that would
+ * result in its network access being blocked.
+ *
+ * @see #FIREWALL_CHAIN_OEM_DENY_1
+ * @see #FIREWALL_CHAIN_OEM_DENY_2
+ * @see #FIREWALL_CHAIN_OEM_DENY_3
+ * @hide
+ */
+ @FlaggedApi(Flags.BLOCKED_REASON_OEM_DENY_CHAINS)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_OEM_DENY = 1 << 7;
+
+ /**
* Flag to indicate that an app is subject to Data saver restrictions that would
* result in its metered network access being blocked.
*
@@ -952,6 +967,7 @@
BLOCKED_REASON_LOCKDOWN_VPN,
BLOCKED_REASON_LOW_POWER_STANDBY,
BLOCKED_REASON_APP_BACKGROUND,
+ BLOCKED_REASON_OEM_DENY,
BLOCKED_METERED_REASON_DATA_SAVER,
BLOCKED_METERED_REASON_USER_RESTRICTED,
BLOCKED_METERED_REASON_ADMIN_DISABLED,
diff --git a/framework/src/android/net/apf/ApfCapabilities.java b/framework/src/android/net/apf/ApfCapabilities.java
index fae2499..8efb182 100644
--- a/framework/src/android/net/apf/ApfCapabilities.java
+++ b/framework/src/android/net/apf/ApfCapabilities.java
@@ -22,6 +22,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible
* way to drop unwanted network packets to save power.
@@ -102,6 +104,11 @@
&& apfPacketFormat == other.apfPacketFormat;
}
+ @Override
+ public int hashCode() {
+ return Objects.hash(apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
+ }
+
/**
* Determines whether the APF interpreter advertises support for the data buffer access opcodes
* LDDW (LoaD Data Word) and STDW (STore Data Word). Full LDDW (LoaD Data Word) and
diff --git a/framework/src/android/net/connectivity/ConnectivityCompatChanges.java b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
index a80db85..c726dab 100644
--- a/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
+++ b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
@@ -99,6 +99,28 @@
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public static final long ENABLE_MATCH_LOCAL_NETWORK = 319212206L;
+ /**
+ * On Android {@link android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM} or higher releases,
+ * network access from apps targeting Android 36 or higher that do not have the
+ * {@link android.Manifest.permission#INTERNET} permission is considered blocked.
+ * This results in API behaviors change for apps without
+ * {@link android.Manifest.permission#INTERNET} permission.
+ * {@link android.net.NetworkInfo} returned from {@link android.net.ConnectivityManager} APIs
+ * always has {@link android.net.NetworkInfo.DetailedState#BLOCKED}.
+ * {@link android.net.ConnectivityManager#getActiveNetwork()} always returns null.
+ * {@link android.net.ConnectivityManager.NetworkCallback#onBlockedStatusChanged()} is always
+ * called with blocked=true.
+ * <p>
+ * For backwards compatibility, apps running on older releases, or targeting older SDK levels,
+ * network access from apps without {@link android.Manifest.permission#INTERNET} permission is
+ * considered not blocked even though apps cannot access any networks.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ public static final long NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION = 333340911L;
+
private ConnectivityCompatChanges() {
}
}
diff --git a/netbpfload/NetBpfLoad.cpp b/netbpfload/NetBpfLoad.cpp
index 710782d..0e1da93 100644
--- a/netbpfload/NetBpfLoad.cpp
+++ b/netbpfload/NetBpfLoad.cpp
@@ -51,23 +51,22 @@
#include "bpf/BpfUtils.h"
#include "loader.h"
-using android::base::EndsWith;
-using android::bpf::domain;
+namespace android {
+namespace bpf {
+
+using base::EndsWith;
using std::string;
-bool exists(const char* const path) {
+static bool exists(const char* const path) {
int v = access(path, F_OK);
- if (!v) {
- ALOGI("%s exists.", path);
- return true;
- }
+ if (!v) return true;
if (errno == ENOENT) return false;
ALOGE("FATAL: access(%s, F_OK) -> %d [%d:%s]", path, v, errno, strerror(errno));
abort(); // can only hit this if permissions (likely selinux) are screwed up
}
-const android::bpf::Location locations[] = {
+const Location locations[] = {
// S+ Tethering mainline module (network_stack): tether offload
{
.dir = "/apex/com.android.tethering/etc/bpf/",
@@ -97,7 +96,7 @@
},
};
-int loadAllElfObjects(const unsigned int bpfloader_ver, const android::bpf::Location& location) {
+static int loadAllElfObjects(const unsigned int bpfloader_ver, const Location& location) {
int retVal = 0;
DIR* dir;
struct dirent* ent;
@@ -111,12 +110,12 @@
progPath += s;
bool critical;
- int ret = android::bpf::loadProg(progPath.c_str(), &critical, bpfloader_ver, location);
+ int ret = loadProg(progPath.c_str(), &critical, bpfloader_ver, location);
if (ret) {
if (critical) retVal = ret;
ALOGE("Failed to load object: %s, ret: %s", progPath.c_str(), std::strerror(-ret));
} else {
- ALOGI("Loaded object: %s", progPath.c_str());
+ ALOGD("Loaded object: %s", progPath.c_str());
}
}
closedir(dir);
@@ -124,7 +123,7 @@
return retVal;
}
-int createSysFsBpfSubDir(const char* const prefix) {
+static int createSysFsBpfSubDir(const char* const prefix) {
if (*prefix) {
mode_t prevUmask = umask(0);
@@ -147,8 +146,8 @@
// Technically 'value' doesn't need to be newline terminated, but it's best
// to include a newline to match 'echo "value" > /proc/sys/...foo' behaviour,
// which is usually how kernel devs test the actual sysctl interfaces.
-int writeProcSysFile(const char *filename, const char *value) {
- android::base::unique_fd fd(open(filename, O_WRONLY | O_CLOEXEC));
+static int writeProcSysFile(const char *filename, const char *value) {
+ base::unique_fd fd(open(filename, O_WRONLY | O_CLOEXEC));
if (fd < 0) {
const int err = errno;
ALOGE("open('%s', O_WRONLY | O_CLOEXEC) -> %s", filename, strerror(err));
@@ -172,7 +171,7 @@
#define APEX_MOUNT_POINT "/apex/com.android.tethering"
const char * const platformBpfLoader = "/system/bin/bpfloader";
-int logTetheringApexVersion(void) {
+static int logTetheringApexVersion(void) {
char * found_blockdev = NULL;
FILE * f = NULL;
char buf[4096];
@@ -198,7 +197,7 @@
f = NULL;
if (!found_blockdev) return 2;
- ALOGD("Found Tethering Apex mounted from blockdev %s", found_blockdev);
+ ALOGV("Found Tethering Apex mounted from blockdev %s", found_blockdev);
f = fopen("/proc/mounts", "re");
if (!f) { free(found_blockdev); return 3; }
@@ -224,12 +223,12 @@
return 0;
}
-int main(int argc, char** argv, char * const envp[]) {
- (void)argc;
- android::base::InitLogging(argv, &android::base::KernelLogger);
+static bool isGSI() {
+ // From //system/gsid/libgsi.cpp IsGsiRunning()
+ return !access("/metadata/gsi/dsu/booted", F_OK);
+}
- ALOGI("NetBpfLoad '%s' starting...", argv[0]);
-
+static int doLoad(char** argv, char * const envp[]) {
const int device_api_level = android_get_device_api_level();
const bool isAtLeastT = (device_api_level >= __ANDROID_API_T__);
const bool isAtLeastU = (device_api_level >= __ANDROID_API_U__);
@@ -240,9 +239,9 @@
// first in U QPR2 beta~2
const bool has_platform_netbpfload_rc = exists("/system/etc/init/netbpfload.rc");
- ALOGI("NetBpfLoad api:%d/%d kver:%07x rc:%d%d",
- android_get_application_target_sdk_version(), device_api_level,
- android::bpf::kernelVersion(),
+ ALOGI("NetBpfLoad (%s) api:%d/%d kver:%07x (%s) rc:%d%d",
+ argv[0], android_get_application_target_sdk_version(), device_api_level,
+ kernelVersion(), describeArch(),
has_platform_bpfloader_rc, has_platform_netbpfload_rc);
if (!has_platform_bpfloader_rc && !has_platform_netbpfload_rc) {
@@ -262,27 +261,56 @@
return 1;
}
- if (isAtLeastT && !android::bpf::isAtLeastKernelVersion(4, 9, 0)) {
+ if (isAtLeastT && !isAtLeastKernelVersion(4, 9, 0)) {
ALOGE("Android T requires kernel 4.9.");
return 1;
}
- if (isAtLeastU && !android::bpf::isAtLeastKernelVersion(4, 14, 0)) {
+ if (isAtLeastU && !isAtLeastKernelVersion(4, 14, 0)) {
ALOGE("Android U requires kernel 4.14.");
return 1;
}
- if (isAtLeastV && !android::bpf::isAtLeastKernelVersion(4, 19, 0)) {
+ if (isAtLeastV && !isAtLeastKernelVersion(4, 19, 0)) {
ALOGE("Android V requires kernel 4.19.");
return 1;
}
- if (isAtLeastV && android::bpf::isX86() && !android::bpf::isKernel64Bit()) {
+ if (isAtLeastV && isX86() && !isKernel64Bit()) {
ALOGE("Android V requires X86 kernel to be 64-bit.");
return 1;
}
- if (android::bpf::isUserspace32bit() && android::bpf::isAtLeastKernelVersion(6, 2, 0)) {
+ if (isAtLeastV) {
+ bool bad = false;
+
+ if (!isLtsKernel()) {
+ ALOGW("Android V only supports LTS kernels.");
+ bad = true;
+ }
+
+#define REQUIRE(maj, min, sub) \
+ if (isKernelVersion(maj, min) && !isAtLeastKernelVersion(maj, min, sub)) { \
+ ALOGW("Android V requires %d.%d kernel to be %d.%d.%d+.", maj, min, maj, min, sub); \
+ bad = true; \
+ }
+
+ REQUIRE(4, 19, 236)
+ REQUIRE(5, 4, 186)
+ REQUIRE(5, 10, 199)
+ REQUIRE(5, 15, 136)
+ REQUIRE(6, 1, 57)
+ REQUIRE(6, 6, 0)
+
+#undef REQUIRE
+
+ if (bad && !isGSI()) {
+ ALOGE("Unsupported kernel version (%07x).", kernelVersion());
+ sleep(60);
+ }
+ }
+
+ if (isUserspace32bit() && isAtLeastKernelVersion(6, 2, 0)) {
/* Android 14/U should only launch on 64-bit kernels
* T launches on 5.10/5.15
* U launches on 5.15/6.1
@@ -307,9 +335,9 @@
}
// Ensure we can determine the Android build type.
- if (!android::bpf::isEng() && !android::bpf::isUser() && !android::bpf::isUserdebug()) {
+ if (!isEng() && !isUser() && !isUserdebug()) {
ALOGE("Failed to determine the build type: got %s, want 'eng', 'user', or 'userdebug'",
- android::bpf::getBuildType().c_str());
+ getBuildType().c_str());
return 1;
}
@@ -319,7 +347,7 @@
// (this writeFile is known to fail on at least 4.19, but always defaults to 0 on
// pre-5.13, on 5.13+ it depends on CONFIG_BPF_UNPRIV_DEFAULT_OFF)
if (writeProcSysFile("/proc/sys/kernel/unprivileged_bpf_disabled", "0\n") &&
- android::bpf::isAtLeastKernelVersion(5, 13, 0)) return 1;
+ isAtLeastKernelVersion(5, 13, 0)) return 1;
}
if (isAtLeastU) {
@@ -373,9 +401,9 @@
int key = 1;
int value = 123;
- android::base::unique_fd map(
- android::bpf::createMap(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 2, 0));
- if (android::bpf::writeToMapEntry(map, &key, &value, BPF_ANY)) {
+ base::unique_fd map(
+ createMap(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 2, 0));
+ if (writeToMapEntry(map, &key, &value, BPF_ANY)) {
ALOGE("Critical kernel bug - failure to write into index 1 of 2 element bpf map array.");
return 1;
}
@@ -392,3 +420,21 @@
ALOGI("mainline done!");
return 0;
}
+
+} // namespace bpf
+} // namespace android
+
+int main(int argc, char** argv, char * const envp[]) {
+ android::base::InitLogging(argv, &android::base::KernelLogger);
+
+ if (argc == 2 && !strcmp(argv[1], "done")) {
+ // we're being re-exec'ed from platform bpfloader to 'finalize' things
+ if (!android::base::SetProperty("bpf.progs_loaded", "1")) {
+ ALOGE("Failed to set bpf.progs_loaded property to 1.");
+ return 125;
+ }
+ return 0;
+ }
+
+ return android::bpf::doLoad(argv, envp);
+}
diff --git a/netbpfload/loader.cpp b/netbpfload/loader.cpp
index 52428a3..2b5f5c7 100644
--- a/netbpfload/loader.cpp
+++ b/netbpfload/loader.cpp
@@ -512,7 +512,7 @@
ret = readSectionByIdx(elfFile, i, cs_temp.data);
if (ret) return ret;
- ALOGD("Loaded code section %d (%s)", i, name.c_str());
+ ALOGV("Loaded code section %d (%s)", i, name.c_str());
vector<string> csSymNames;
ret = getSectionSymNames(elfFile, oldName, csSymNames, STT_FUNC);
@@ -532,13 +532,13 @@
if (name == (".rel" + oldName)) {
ret = readSectionByIdx(elfFile, i + 1, cs_temp.rel_data);
if (ret) return ret;
- ALOGD("Loaded relo section %d (%s)", i, name.c_str());
+ ALOGV("Loaded relo section %d (%s)", i, name.c_str());
}
}
if (cs_temp.data.size() > 0) {
cs.push_back(std::move(cs_temp));
- ALOGD("Adding section %d to cs list", i);
+ ALOGV("Adding section %d to cs list", i);
}
}
return 0;
@@ -869,7 +869,7 @@
// Occasionally might be useful for relocation debugging, but pretty spammy
if (0) {
- ALOGD("applying relo to instruction at byte offset: %llu, "
+ ALOGV("applying relo to instruction at byte offset: %llu, "
"insn offset %d, insn %llx",
(unsigned long long)offset, insnIndex, *(unsigned long long*)insn);
}
@@ -1177,7 +1177,7 @@
}
for (int i = 0; i < (int)mapFds.size(); i++)
- ALOGD("map_fd found at %d is %d in %s", i, mapFds[i].get(), elfPath);
+ ALOGV("map_fd found at %d is %d in %s", i, mapFds[i].get(), elfPath);
applyMapRelo(elfFile, mapFds, cs);
diff --git a/service-t/src/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java
index ea91e64..54b9ced 100644
--- a/service-t/src/com/android/server/IpSecService.java
+++ b/service-t/src/com/android/server/IpSecService.java
@@ -1877,6 +1877,10 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "IpsecService#getTransformState");
+ if (transformId == INVALID_RESOURCE_ID) {
+ throw new IllegalStateException("This transform is already closed");
+ }
+
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
TransformRecord transformInfo =
userRecord.mTransformRecords.getResourceOrThrow(transformId);
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
index 39e8bcc..36f3982 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
@@ -34,6 +34,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.CollectionUtils;
@@ -87,6 +88,12 @@
private static final String[] DNS_SD_SERVICE_TYPE =
new String[] { "_services", "_dns-sd", "_udp", LOCAL_TLD };
+ private enum RecordConflictType {
+ NO_CONFLICT,
+ CONFLICT,
+ IDENTICAL
+ }
+
@NonNull
private final Random mDelayGenerator = new Random();
// Map of service unique ID -> records for service
@@ -1172,38 +1179,49 @@
* {@link MdnsInterfaceAdvertiser#CONFLICT_HOST}.
*/
public Map<Integer, Integer> getConflictingServices(MdnsPacket packet) {
- // Avoid allocating a new set for each incoming packet: use an empty set by default.
- Map<Integer, Integer> conflicting = Collections.emptyMap();
+ Map<Integer, Integer> conflicting = new ArrayMap<>();
for (MdnsRecord record : packet.answers) {
+ SparseIntArray conflictingWithRecord = new SparseIntArray();
for (int i = 0; i < mServices.size(); i++) {
final ServiceRegistration registration = mServices.valueAt(i);
if (registration.exiting) continue;
- int conflictType = 0;
+ final RecordConflictType conflictForService =
+ conflictForService(record, registration);
+ final RecordConflictType conflictForHost = conflictForHost(record, registration);
- if (conflictForService(record, registration)) {
- conflictType |= CONFLICT_SERVICE;
+ // Identical record is found in the repository so there won't be a conflict.
+ if (conflictForService == RecordConflictType.IDENTICAL
+ || conflictForHost == RecordConflictType.IDENTICAL) {
+ conflictingWithRecord.clear();
+ break;
}
- if (conflictForHost(record, registration)) {
+ int conflictType = 0;
+ if (conflictForService == RecordConflictType.CONFLICT) {
+ conflictType |= CONFLICT_SERVICE;
+ }
+ if (conflictForHost == RecordConflictType.CONFLICT) {
conflictType |= CONFLICT_HOST;
}
if (conflictType != 0) {
- if (conflicting.isEmpty()) {
- // Conflict was found: use a mutable set
- conflicting = new ArrayMap<>();
- }
final int serviceId = mServices.keyAt(i);
- conflicting.put(serviceId, conflictType);
+ conflictingWithRecord.put(serviceId, conflictType);
}
}
+ for (int i = 0; i < conflictingWithRecord.size(); i++) {
+ final int serviceId = conflictingWithRecord.keyAt(i);
+ final int conflictType = conflictingWithRecord.valueAt(i);
+ final int oldConflictType = conflicting.getOrDefault(serviceId, 0);
+ conflicting.put(serviceId, oldConflictType | conflictType);
+ }
}
return conflicting;
}
- private static boolean conflictForService(
+ private static RecordConflictType conflictForService(
@NonNull MdnsRecord record, @NonNull ServiceRegistration registration) {
String[] fullServiceName;
if (registration.srvRecord != null) {
@@ -1211,75 +1229,75 @@
} else if (registration.serviceKeyRecord != null) {
fullServiceName = registration.serviceKeyRecord.record.getName();
} else {
- return false;
+ return RecordConflictType.NO_CONFLICT;
}
if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(record.getName(), fullServiceName)) {
- return false;
+ return RecordConflictType.NO_CONFLICT;
}
// As per RFC6762 9., it's fine if the "conflict" is an identical record with same
// data.
if (record instanceof MdnsServiceRecord && equals(record, registration.srvRecord)) {
- return false;
+ return RecordConflictType.IDENTICAL;
}
if (record instanceof MdnsTextRecord && equals(record, registration.txtRecord)) {
- return false;
+ return RecordConflictType.IDENTICAL;
}
if (record instanceof MdnsKeyRecord && equals(record, registration.serviceKeyRecord)) {
- return false;
+ return RecordConflictType.IDENTICAL;
}
- return true;
+ return RecordConflictType.CONFLICT;
}
- private boolean conflictForHost(
+ private RecordConflictType conflictForHost(
@NonNull MdnsRecord record, @NonNull ServiceRegistration registration) {
// Only custom hosts are checked. When using the default host, the hostname is derived from
// a UUID and it's supposed to be unique.
if (registration.serviceInfo.getHostname() == null) {
- return false;
+ return RecordConflictType.NO_CONFLICT;
}
- // It cannot be a hostname conflict because not record is registered with the hostname.
+ // It cannot be a hostname conflict because no record is registered with the hostname.
if (registration.addressRecords.isEmpty() && registration.hostKeyRecord == null) {
- return false;
+ return RecordConflictType.NO_CONFLICT;
}
// The record's name cannot be registered by NsdManager so it's not a conflict.
if (record.getName().length != 2 || !record.getName()[1].equals(LOCAL_TLD)) {
- return false;
+ return RecordConflictType.NO_CONFLICT;
}
// Different names. There won't be a conflict.
if (!MdnsUtils.equalsIgnoreDnsCase(
record.getName()[0], registration.serviceInfo.getHostname())) {
- return false;
+ return RecordConflictType.NO_CONFLICT;
}
// As per RFC6762 9., it's fine if the "conflict" is an identical record with same
// data.
if (record instanceof MdnsInetAddressRecord
&& hasInetAddressRecord(registration, (MdnsInetAddressRecord) record)) {
- return false;
+ return RecordConflictType.IDENTICAL;
}
if (record instanceof MdnsKeyRecord && equals(record, registration.hostKeyRecord)) {
- return false;
+ return RecordConflictType.IDENTICAL;
}
// Per RFC 6762 8.1, when a record is being probed, any answer containing a record with that
// name, of any type, MUST be considered a conflicting response.
if (registration.isProbing) {
- return true;
+ return RecordConflictType.CONFLICT;
}
if (record instanceof MdnsInetAddressRecord && !registration.addressRecords.isEmpty()) {
- return true;
+ return RecordConflictType.CONFLICT;
}
if (record instanceof MdnsKeyRecord && registration.hostKeyRecord != null) {
- return true;
+ return RecordConflictType.CONFLICT;
}
- return false;
+ return RecordConflictType.NO_CONFLICT;
}
private List<RecordInfo<MdnsInetAddressRecord>> getInetAddressRecordsForHostname(
diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
index 92f1953..b8689d6 100644
--- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
+++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
@@ -108,11 +108,7 @@
PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG);
}
- // This causes thread-unsafe access on mIpConfigurations which might
- // race with calls to EthernetManager#updateConfiguration().
- // EthernetManager#getConfiguration() has been marked as
- // @UnsupportedAppUsage since Android R.
- return mTracker.getIpConfiguration(iface);
+ return new IpConfiguration(mTracker.getIpConfiguration(iface));
}
/**
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java
index a60592f..71f289e 100644
--- a/service-t/src/com/android/server/ethernet/EthernetTracker.java
+++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -31,6 +31,8 @@
import android.net.ITetheredInterfaceCallback;
import android.net.InterfaceConfigurationParcel;
import android.net.IpConfiguration;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
import android.net.LinkAddress;
import android.net.NetworkCapabilities;
import android.net.StaticIpConfiguration;
@@ -109,7 +111,6 @@
/** Mapping between {iface name | mac address} -> {NetworkCapabilities} */
private final ConcurrentHashMap<String, NetworkCapabilities> mNetworkCapabilities =
new ConcurrentHashMap<>();
- /** Mapping between {iface name | mac address} -> {IpConfiguration} */
private final ConcurrentHashMap<String, IpConfiguration> mIpConfigurations =
new ConcurrentHashMap<>();
@@ -297,7 +298,7 @@
}
private IpConfiguration getIpConfigurationForCallback(String iface, int state) {
- return (state == EthernetManager.STATE_ABSENT) ? null : getIpConfiguration(iface);
+ return (state == EthernetManager.STATE_ABSENT) ? null : getOrCreateIpConfiguration(iface);
}
private void ensureRunningOnEthernetServiceThread() {
@@ -390,83 +391,8 @@
mHandler.post(() -> setInterfaceAdministrativeState(iface, enabled, cb));
}
- private @Nullable String getHwAddress(String iface) {
- if (getInterfaceRole(iface) == EthernetManager.ROLE_SERVER) {
- return mTetheringInterfaceHwAddr;
- }
-
- return mFactory.getHwAddress(iface);
- }
-
- /**
- * Get the IP configuration of the interface, or the default if the interface doesn't exist.
- * @param iface the name of the interface to retrieve.
- *
- * @return The IP configuration
- */
- public IpConfiguration getIpConfiguration(String iface) {
- return getIpConfiguration(iface, getHwAddress(iface));
- }
-
- private IpConfiguration getIpConfiguration(String iface, @Nullable String hwAddress) {
- // Look up Ip configuration first by ifname, then by MAC address.
- IpConfiguration ipConfig = mIpConfigurations.get(iface);
- if (ipConfig != null) {
- return ipConfig;
- }
-
- if (hwAddress == null) {
- // should never happen.
- Log.wtf(TAG, "No hardware address for interface " + iface);
- } else {
- ipConfig = mIpConfigurations.get(hwAddress);
- }
-
- if (ipConfig == null) {
- ipConfig = new IpConfiguration.Builder().build();
- }
-
- return ipConfig;
- }
-
- private NetworkCapabilities getNetworkCapabilities(String iface) {
- return getNetworkCapabilities(iface, getHwAddress(iface));
- }
-
- private NetworkCapabilities getNetworkCapabilities(String iface, @Nullable String hwAddress) {
- // Look up network capabilities first by ifname, then by MAC address.
- NetworkCapabilities networkCapabilities = mNetworkCapabilities.get(iface);
- if (networkCapabilities != null) {
- return networkCapabilities;
- }
-
- if (hwAddress == null) {
- // should never happen.
- Log.wtf(TAG, "No hardware address for interface " + iface);
- } else {
- networkCapabilities = mNetworkCapabilities.get(hwAddress);
- }
-
- if (networkCapabilities != null) {
- return networkCapabilities;
- }
-
- final NetworkCapabilities.Builder builder = createNetworkCapabilities(
- false /* clear default capabilities */, null, null)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
-
- if (isValidTestInterface(iface)) {
- builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
- } else {
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- }
-
- return builder.build();
+ IpConfiguration getIpConfiguration(String iface) {
+ return mIpConfigurations.get(iface);
}
@VisibleForTesting(visibility = PACKAGE)
@@ -507,8 +433,8 @@
* NET_CAPABILITY_NOT_RESTRICTED) capability. Otherwise, returns false.
*/
boolean isRestrictedInterface(String iface) {
- final NetworkCapabilities nc = getNetworkCapabilities(iface);
- return !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ final NetworkCapabilities nc = mNetworkCapabilities.get(iface);
+ return nc != null && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
void addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks) {
@@ -697,9 +623,17 @@
return;
}
- final NetworkCapabilities nc = getNetworkCapabilities(iface, hwAddress);
- final IpConfiguration ipConfiguration = getIpConfiguration(iface, hwAddress);
+ NetworkCapabilities nc = mNetworkCapabilities.get(iface);
+ if (nc == null) {
+ // Try to resolve using mac address
+ nc = mNetworkCapabilities.get(hwAddress);
+ if (nc == null) {
+ final boolean isTestIface = iface.matches(TEST_IFACE_REGEXP);
+ nc = createDefaultNetworkCapabilities(isTestIface);
+ }
+ }
+ IpConfiguration ipConfiguration = getOrCreateIpConfiguration(iface);
Log.d(TAG, "Tracking interface in client mode: " + iface);
mFactory.addInterface(iface, hwAddress, ipConfiguration, nc);
@@ -839,6 +773,25 @@
return new EthernetTrackerConfig(configString.split(";", /* limit of tokens */ 4));
}
+ private static NetworkCapabilities createDefaultNetworkCapabilities(boolean isTestIface) {
+ NetworkCapabilities.Builder builder = createNetworkCapabilities(
+ false /* clear default capabilities */, null, null)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+
+ if (isTestIface) {
+ builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
+ } else {
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ }
+
+ return builder.build();
+ }
+
/**
* Parses a static list of network capabilities
*
@@ -973,6 +926,15 @@
return new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build();
}
+ private IpConfiguration getOrCreateIpConfiguration(String iface) {
+ IpConfiguration ret = mIpConfigurations.get(iface);
+ if (ret != null) return ret;
+ ret = new IpConfiguration();
+ ret.setIpAssignment(IpAssignment.DHCP);
+ ret.setProxySettings(ProxySettings.NONE);
+ return ret;
+ }
+
private boolean isValidEthernetInterface(String iface) {
return iface.matches(mIfaceMatch) || isValidTestInterface(iface);
}
@@ -1059,7 +1021,7 @@
pw.println("IP Configurations:");
pw.increaseIndent();
for (String iface : mIpConfigurations.keySet()) {
- pw.println(iface + ": " + getIpConfiguration(iface));
+ pw.println(iface + ": " + mIpConfigurations.get(iface));
}
pw.decreaseIndent();
pw.println();
@@ -1067,7 +1029,7 @@
pw.println("Network Capabilities:");
pw.increaseIndent();
for (String iface : mNetworkCapabilities.keySet()) {
- pw.println(iface + ": " + getNetworkCapabilities(iface));
+ pw.println(iface + ": " + mNetworkCapabilities.get(iface));
}
pw.decreaseIndent();
pw.println();
diff --git a/service/Android.bp b/service/Android.bp
index 1d74efc..1dd09a9 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -188,7 +188,7 @@
"androidx.annotation_annotation",
"connectivity-net-module-utils-bpf",
"connectivity_native_aidl_interface-lateststable-java",
- "dnsresolver_aidl_interface-V14-java",
+ "dnsresolver_aidl_interface-V15-java",
"modules-utils-shell-command-handler",
"net-utils-device-common",
"net-utils-device-common-ip",
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 04d8ea4..23af0f8 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -32,6 +32,8 @@
import static android.net.BpfNetMapsUtils.getMatchByFirewallChain;
import static android.net.BpfNetMapsUtils.isFirewallAllowList;
import static android.net.BpfNetMapsUtils.matchToString;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
import static android.net.INetd.PERMISSION_INTERNET;
@@ -804,6 +806,25 @@
}
/**
+ * Get granted permissions for specified uid. If uid is not in the map, this method returns
+ * {@link android.net.INetd.PERMISSION_INTERNET} since this is a default permission.
+ * See {@link #setNetPermForUids}
+ *
+ * @param uid target uid
+ * @return granted permissions.
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public int getNetPermForUid(final int uid) {
+ try {
+ final U8 permissions = sUidPermissionMap.getValue(new S32(uid));
+ return permissions != null ? permissions.val : PERMISSION_INTERNET;
+ } catch (ErrnoException e) {
+ Log.wtf(TAG, "Failed to get permission for uid: " + uid);
+ return PERMISSION_INTERNET;
+ }
+ }
+
+ /**
* Set Data Saver enabled or disabled
*
* @param enable whether Data Saver is enabled or disabled.
@@ -863,6 +884,49 @@
}
}
+ /**
+ * Get blocked reasons for specified uid
+ *
+ * @param uid Target Uid
+ * @return Reasons of network access blocking for an UID
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public int getUidNetworkingBlockedReasons(final int uid) {
+ return BpfNetMapsUtils.getUidNetworkingBlockedReasons(uid,
+ sConfigurationMap, sUidOwnerMap, sDataSaverEnabledMap);
+ }
+
+ /**
+ * Return whether the network access of specified uid is blocked on metered networks
+ *
+ * @param uid The target uid.
+ * @return True if the network access is blocked on metered networks. Otherwise, false
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public boolean isUidRestrictedOnMeteredNetworks(final int uid) {
+ final int blockedReasons = getUidNetworkingBlockedReasons(uid);
+ return (blockedReasons & BLOCKED_METERED_REASON_MASK) != BLOCKED_REASON_NONE;
+ }
+
+ /*
+ * Return whether the network is blocked by firewall chains for the given uid.
+ *
+ * Note that {@link #getDataSaverEnabled()} has a latency before V.
+ *
+ * @param uid The target uid.
+ * @param isNetworkMetered Whether the target network is metered.
+ *
+ * @return True if the network is blocked. Otherwise, false.
+ * @throws ServiceSpecificException if the read fails.
+ *
+ * @hide
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public boolean isUidNetworkingBlocked(final int uid, boolean isNetworkMetered) {
+ return BpfNetMapsUtils.isUidNetworkingBlocked(uid, isNetworkMetered,
+ sConfigurationMap, sUidOwnerMap, sDataSaverEnabledMap);
+ }
+
/** Register callback for statsd to pull atom. */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public void setPullAtomCallback(final Context context) {
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index dc91f7d..fff809e 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -64,6 +64,7 @@
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.INetd.PERMISSION_INTERNET;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_SKIPPED;
@@ -101,6 +102,7 @@
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY;
import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_MATCH_LOCAL_NETWORK;
import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_SELF_CERTIFIED_CAPABILITIES_DECLARATION;
+import static android.net.connectivity.ConnectivityCompatChanges.NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION;
import static android.os.Process.INVALID_UID;
import static android.os.Process.VPN_UID;
import static android.system.OsConstants.ETH_P_ALL;
@@ -2229,6 +2231,11 @@
return nai;
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private boolean hasInternetPermission(final int uid) {
+ return (mBpfNetMaps.getNetPermForUid(uid) & PERMISSION_INTERNET) != 0;
+ }
+
/**
* Check if UID should be blocked from using the specified network.
*/
@@ -2242,7 +2249,17 @@
final long ident = Binder.clearCallingIdentity();
try {
final boolean metered = nc == null ? true : nc.isMetered();
- return mPolicyManager.isUidNetworkingBlocked(uid, metered);
+ if (mDeps.isAtLeastV()) {
+ final boolean hasInternetPermission = hasInternetPermission(uid);
+ final boolean blockedByUidRules = mBpfNetMaps.isUidNetworkingBlocked(uid, metered);
+ if (mDeps.isChangeEnabled(NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION, uid)) {
+ return blockedByUidRules || !hasInternetPermission;
+ } else {
+ return hasInternetPermission && blockedByUidRules;
+ }
+ } else {
+ return mPolicyManager.isUidNetworkingBlocked(uid, metered);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2320,7 +2337,7 @@
final int uid = mDeps.getCallingUid();
final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
if (nai == null) return null;
- final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false);
+ final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false /* ignoreBlocked */);
maybeLogBlockedNetworkInfo(networkInfo, uid);
return networkInfo;
}
@@ -7953,6 +7970,13 @@
// Policy already enforced.
return;
}
+ if (mDeps.isAtLeastV()) {
+ if (mBpfNetMaps.isUidRestrictedOnMeteredNetworks(uid)) {
+ // If UID is restricted, don't allow them to bring up metered APNs.
+ networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ }
+ return;
+ }
final long ident = Binder.clearCallingIdentity();
try {
if (mPolicyManager.isUidRestrictedOnMeteredNetworks(uid)) {
@@ -12737,8 +12761,8 @@
if (um.isManagedProfile(profile.getIdentifier())) {
return true;
}
- if (mDeps.isAtLeastT() && dpm.getDeviceOwner() != null) return true;
- return false;
+
+ return mDeps.isAtLeastT() && dpm.getDeviceOwnerComponentOnAnyUser() != null;
}
/**
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index eea16bf..634a8fa 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -399,6 +399,10 @@
mCookieTagMap = mDeps.getBpfCookieTagMap();
}
+ // Note that this may only be called on a brand new v4-* interface,
+ // because it uses bpfmap.insertEntry() which fails if entry exists,
+ // and because the value includes (initialized to 0) byte/packet
+ // counters, so a replace (instead of insert) would wipe those stats.
private void maybeStartBpf(final ClatdTracker tracker) {
if (mIngressMap == null || mEgressMap == null) return;
@@ -520,31 +524,6 @@
}
}
- private void maybeCleanUp(ParcelFileDescriptor tunFd, ParcelFileDescriptor readSock6,
- ParcelFileDescriptor writeSock6) {
- if (tunFd != null) {
- try {
- tunFd.close();
- } catch (IOException e) {
- Log.e(TAG, "Fail to close tun file descriptor " + e);
- }
- }
- if (readSock6 != null) {
- try {
- readSock6.close();
- } catch (IOException e) {
- Log.e(TAG, "Fail to close read socket " + e);
- }
- }
- if (writeSock6 != null) {
- try {
- writeSock6.close();
- } catch (IOException e) {
- Log.e(TAG, "Fail to close write socket " + e);
- }
- }
- }
-
private void tagSocketAsClat(long cookie) throws IOException {
if (mCookieTagMap == null) {
throw new IOException("Cookie tag map is not initialized");
@@ -600,42 +579,6 @@
throw new IOException("Prefix must be 96 bits long: " + nat64Prefix);
}
- // [1] Pick an IPv4 address from 192.0.0.4, 192.0.0.5, 192.0.0.6 ..
- final String v4Str;
- try {
- v4Str = mDeps.selectIpv4Address(INIT_V4ADDR_STRING, INIT_V4ADDR_PREFIX_LEN);
- } catch (IOException e) {
- throw new IOException("no IPv4 addresses were available for clat: " + e);
- }
-
- final Inet4Address v4;
- try {
- v4 = (Inet4Address) InetAddresses.parseNumericAddress(v4Str);
- } catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
- throw new IOException("Invalid IPv4 address " + v4Str);
- }
-
- // [2] Generate a checksum-neutral IID.
- final Integer fwmark = getFwmark(netId);
- final String pfx96Str = nat64Prefix.getAddress().getHostAddress();
- final String v6Str;
- try {
- v6Str = mDeps.generateIpv6Address(iface, v4Str, pfx96Str, fwmark);
- } catch (IOException e) {
- throw new IOException("no IPv6 addresses were available for clat: " + e);
- }
-
- final Inet6Address pfx96 = (Inet6Address) nat64Prefix.getAddress();
- final Inet6Address v6;
- try {
- v6 = (Inet6Address) InetAddresses.parseNumericAddress(v6Str);
- } catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
- throw new IOException("Invalid IPv6 address " + v6Str);
- }
-
- // [3] Open, configure and bring up the tun interface.
- // Create the v4-... tun interface.
-
// Initialize all required file descriptors with null pointer. This makes the following
// error handling easier. Simply always call #maybeCleanUp for closing file descriptors,
// if any valid ones, in error handling.
@@ -643,145 +586,112 @@
ParcelFileDescriptor readSock6 = null;
ParcelFileDescriptor writeSock6 = null;
- final String tunIface = CLAT_PREFIX + iface;
- try {
- tunFd = mDeps.adoptFd(mDeps.createTunInterface(tunIface));
- } catch (IOException e) {
- throw new IOException("Create tun interface " + tunIface + " failed: " + e);
- }
+ long cookie = 0;
+ boolean isSocketTagged = false;
- final int tunIfIndex = mDeps.getInterfaceIndex(tunIface);
- if (tunIfIndex == INVALID_IFINDEX) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Fail to get interface index for interface " + tunIface);
- }
+ try {
+ // [1] Pick an IPv4 address from 192.0.0.4, 192.0.0.5, 192.0.0.6 ..
+ final String v4Str = mDeps.selectIpv4Address(INIT_V4ADDR_STRING,
+ INIT_V4ADDR_PREFIX_LEN);
+ final Inet4Address v4 = (Inet4Address) InetAddresses.parseNumericAddress(v4Str);
- // disable IPv6 on it - failing to do so is not a critical error
- try {
- mNetd.interfaceSetEnableIPv6(tunIface, false /* enabled */);
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Disable IPv6 on " + tunIface + " failed: " + e);
- }
+ // [2] Generate a checksum-neutral IID.
+ final Integer fwmark = getFwmark(netId);
+ final String pfx96Str = nat64Prefix.getAddress().getHostAddress();
+ final String v6Str = mDeps.generateIpv6Address(iface, v4Str, pfx96Str, fwmark);
+ final Inet6Address pfx96 = (Inet6Address) nat64Prefix.getAddress();
+ final Inet6Address v6 = (Inet6Address) InetAddresses.parseNumericAddress(v6Str);
- // Detect ipv4 mtu.
- final int detectedMtu;
- try {
- detectedMtu = mDeps.detectMtu(pfx96Str,
- ByteBuffer.wrap(GOOGLE_DNS_4.getAddress()).getInt(), fwmark);
- } catch (IOException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Detect MTU on " + tunIface + " failed: " + e);
- }
- final int mtu = adjustMtu(detectedMtu);
- Log.i(TAG, "detected ipv4 mtu of " + detectedMtu + " adjusted to " + mtu);
+ // [3] Open and configure local 464xlat read/write sockets.
+ // Opens a packet socket to receive IPv6 packets in clatd.
- // Config tun interface mtu, address and bring up.
- try {
- mNetd.interfaceSetMtu(tunIface, mtu);
- } catch (RemoteException | ServiceSpecificException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Set MTU " + mtu + " on " + tunIface + " failed: " + e);
- }
- final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
- ifConfig.ifName = tunIface;
- ifConfig.ipv4Addr = v4Str;
- ifConfig.prefixLength = 32;
- ifConfig.hwAddr = "";
- ifConfig.flags = new String[] {IF_STATE_UP};
- try {
- mNetd.interfaceSetCfg(ifConfig);
- } catch (RemoteException | ServiceSpecificException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Setting IPv4 address to " + ifConfig.ipv4Addr + "/"
- + ifConfig.prefixLength + " failed on " + ifConfig.ifName + ": " + e);
- }
-
- // [4] Open and configure local 464xlat read/write sockets.
- // Opens a packet socket to receive IPv6 packets in clatd.
- try {
// Use a JNI call to get native file descriptor instead of Os.socket() because we would
// like to use ParcelFileDescriptor to manage file descriptor. But ctor
// ParcelFileDescriptor(FileDescriptor fd) is a @hide function. Need to use native file
// descriptor to initialize ParcelFileDescriptor object instead.
readSock6 = mDeps.adoptFd(mDeps.openPacketSocket());
- } catch (IOException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Open packet socket failed: " + e);
- }
- // Opens a raw socket with a given fwmark to send IPv6 packets in clatd.
- try {
+ // Opens a raw socket with a given fwmark to send IPv6 packets in clatd.
// Use a JNI call to get native file descriptor instead of Os.socket(). See above
// reason why we use jniOpenPacketSocket6().
writeSock6 = mDeps.adoptFd(mDeps.openRawSocket6(fwmark));
- } catch (IOException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Open raw socket failed: " + e);
- }
- final int ifIndex = mDeps.getInterfaceIndex(iface);
- if (ifIndex == INVALID_IFINDEX) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Fail to get interface index for interface " + iface);
- }
+ final int ifIndex = mDeps.getInterfaceIndex(iface);
+ if (ifIndex == INVALID_IFINDEX) {
+ throw new IOException("Fail to get interface index for interface " + iface);
+ }
- // Start translating packets to the new prefix.
- try {
+ // Start translating packets to the new prefix.
mDeps.addAnycastSetsockopt(writeSock6.getFileDescriptor(), v6Str, ifIndex);
- } catch (IOException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("add anycast sockopt failed: " + e);
- }
-
- // Tag socket as AID_CLAT to avoid duplicated CLAT data usage accounting.
- final long cookie;
- try {
+ // Tag socket as AID_CLAT to avoid duplicated CLAT data usage accounting.
cookie = mDeps.getSocketCookie(writeSock6.getFileDescriptor());
tagSocketAsClat(cookie);
- } catch (IOException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("tag raw socket failed: " + e);
- }
-
- // Update our packet socket filter to reflect the new 464xlat IP address.
- try {
+ isSocketTagged = true;
+ // Update our packet socket filter to reflect the new 464xlat IP address.
mDeps.configurePacketSocket(readSock6.getFileDescriptor(), v6Str, ifIndex);
- } catch (IOException e) {
- try {
- untagSocket(cookie);
- } catch (IOException e2) {
- Log.e(TAG, "untagSocket cookie " + cookie + " failed: " + e2);
+
+ // [4] Open, configure and bring up the tun interface.
+ // Create the v4-... tun interface.
+ final String tunIface = CLAT_PREFIX + iface;
+ tunFd = mDeps.adoptFd(mDeps.createTunInterface(tunIface));
+ final int tunIfIndex = mDeps.getInterfaceIndex(tunIface);
+ if (tunIfIndex == INVALID_IFINDEX) {
+ throw new IOException("Fail to get interface index for interface " + tunIface);
}
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("configure packet socket failed: " + e);
- }
+ // disable IPv6 on it - failing to do so is not a critical error
+ mNetd.interfaceSetEnableIPv6(tunIface, false /* enabled */);
+ // Detect ipv4 mtu.
+ final int detectedMtu = mDeps.detectMtu(pfx96Str,
+ ByteBuffer.wrap(GOOGLE_DNS_4.getAddress()).getInt(), fwmark);
+ final int mtu = adjustMtu(detectedMtu);
+ Log.i(TAG, "detected ipv4 mtu of " + detectedMtu + " adjusted to " + mtu);
+ // Config tun interface mtu, address and bring up.
+ mNetd.interfaceSetMtu(tunIface, mtu);
+ final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
+ ifConfig.ifName = tunIface;
+ ifConfig.ipv4Addr = v4Str;
+ ifConfig.prefixLength = 32;
+ ifConfig.hwAddr = "";
+ ifConfig.flags = new String[] {IF_STATE_UP};
+ mNetd.interfaceSetCfg(ifConfig);
- // [5] Start clatd.
- final int pid;
- try {
- pid = mDeps.startClatd(tunFd.getFileDescriptor(), readSock6.getFileDescriptor(),
- writeSock6.getFileDescriptor(), iface, pfx96Str, v4Str, v6Str);
- } catch (IOException e) {
- try {
- untagSocket(cookie);
- } catch (IOException e2) {
- Log.e(TAG, "untagSocket cookie " + cookie + " failed: " + e2);
+ // [5] Start clatd.
+ final int pid = mDeps.startClatd(tunFd.getFileDescriptor(),
+ readSock6.getFileDescriptor(), writeSock6.getFileDescriptor(), iface, pfx96Str,
+ v4Str, v6Str);
+
+ // [6] Initialize and store clatd tracker object.
+ mClatdTracker = new ClatdTracker(iface, ifIndex, tunIface, tunIfIndex, v4, v6, pfx96,
+ pid, cookie);
+
+ // [7] Start BPF
+ maybeStartBpf(mClatdTracker);
+
+ return v6Str;
+ } catch (IOException | RemoteException | ServiceSpecificException | ClassCastException
+ | IllegalArgumentException | NullPointerException e) {
+ if (isSocketTagged) {
+ try {
+ untagSocket(cookie);
+ } catch (IOException e2) {
+ Log.e(TAG, "untagSocket cookie " + cookie + " failed: " + e2);
+ }
}
- throw new IOException("Error start clatd on " + iface + ": " + e);
- } finally {
- // The file descriptors have been duplicated (dup2) to clatd in native_startClatd().
- // Close these file descriptor stubs which are unused anymore.
- maybeCleanUp(tunFd, readSock6, writeSock6);
+ try {
+ if (tunFd != null) {
+ tunFd.close();
+ }
+ if (readSock6 != null) {
+ readSock6.close();
+ }
+ if (writeSock6 != null) {
+ writeSock6.close();
+ }
+ } catch (IOException e2) {
+ Log.e(TAG, "Fail to cleanup fd ", e);
+ }
+ throw new IOException("Failed to start clat ", e);
}
-
- // [6] Initialize and store clatd tracker object.
- mClatdTracker = new ClatdTracker(iface, ifIndex, tunIface, tunIfIndex, v4, v6, pfx96,
- pid, cookie);
-
- // [7] Start BPF
- maybeStartBpf(mClatdTracker);
-
- return v6Str;
}
private void maybeStopBpf(final ClatdTracker tracker) {
diff --git a/service/src/com/android/server/connectivity/DnsManager.java b/service/src/com/android/server/connectivity/DnsManager.java
index 8e6854a..ac02229 100644
--- a/service/src/com/android/server/connectivity/DnsManager.java
+++ b/service/src/com/android/server/connectivity/DnsManager.java
@@ -390,6 +390,7 @@
: new String[0]; // Off
paramsParcel.transportTypes = nc.getTransportTypes();
paramsParcel.meteredNetwork = nc.isMetered();
+ paramsParcel.interfaceNames = lp.getAllInterfaceNames().toArray(new String[0]);
// Prepare to track the validation status of the DNS servers in the
// resolver config when private DNS is in opportunistic or strict mode.
if (useTls) {
@@ -403,13 +404,14 @@
}
Log.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
- + "%d, %d, %s, %s, %s, %b)", paramsParcel.netId,
+ + "%d, %d, %s, %s, %s, %b, %s)", paramsParcel.netId,
Arrays.toString(paramsParcel.servers), Arrays.toString(paramsParcel.domains),
paramsParcel.sampleValiditySeconds, paramsParcel.successThreshold,
paramsParcel.minSamples, paramsParcel.maxSamples, paramsParcel.baseTimeoutMsec,
paramsParcel.retryCount, paramsParcel.tlsName,
Arrays.toString(paramsParcel.tlsServers),
- Arrays.toString(paramsParcel.transportTypes), paramsParcel.meteredNetwork));
+ Arrays.toString(paramsParcel.transportTypes), paramsParcel.meteredNetwork,
+ Arrays.toString(paramsParcel.interfaceNames)));
try {
mDnsResolver.setResolverConfiguration(paramsParcel);
diff --git a/service/src/com/android/server/connectivity/DscpPolicyTracker.java b/service/src/com/android/server/connectivity/DscpPolicyTracker.java
index 15d6adb..9c2b9e8 100644
--- a/service/src/com/android/server/connectivity/DscpPolicyTracker.java
+++ b/service/src/com/android/server/connectivity/DscpPolicyTracker.java
@@ -64,6 +64,8 @@
return "/sys/fs/bpf/net_shared/map_" + which + "_map";
}
+ private final boolean mHaveProgram = TcUtils.isBpfProgramUsable(PROG_PATH);
+
private Set<String> mAttachedIfaces;
private final BpfMap<Struct.S32, DscpPolicyValue> mBpfDscpIpv4Policies;
@@ -325,6 +327,7 @@
* Attach BPF program
*/
private boolean attachProgram(@NonNull String iface) {
+ if (!mHaveProgram) return false;
try {
NetworkInterface netIface = NetworkInterface.getByName(iface);
TcUtils.tcFilterAddDevBpf(netIface.getIndex(), false, PRIO_DSCP, (short) ETH_P_ALL,
diff --git a/service/src/com/android/server/connectivity/Nat464Xlat.java b/service/src/com/android/server/connectivity/Nat464Xlat.java
index 065922d..489dab5 100644
--- a/service/src/com/android/server/connectivity/Nat464Xlat.java
+++ b/service/src/com/android/server/connectivity/Nat464Xlat.java
@@ -202,13 +202,13 @@
try {
addrStr = mClatCoordinator.clatStart(baseIface, getNetId(), mNat64PrefixInUse);
} catch (IOException e) {
- Log.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
+ Log.e(TAG, "Error starting clatd on " + baseIface, e);
}
} else {
try {
addrStr = mNetd.clatdStart(baseIface, mNat64PrefixInUse.toString());
} catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
+ Log.e(TAG, "Error starting clatd on " + baseIface, e);
}
}
mIface = CLAT_PREFIX + baseIface;
@@ -217,7 +217,7 @@
try {
mIPv6Address = (Inet6Address) InetAddresses.parseNumericAddress(addrStr);
} catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
- Log.e(TAG, "Invalid IPv6 address " + addrStr);
+ Log.e(TAG, "Invalid IPv6 address " + addrStr , e);
}
if (mPrefixDiscoveryRunning && !isPrefixDiscoveryNeeded()) {
stopPrefixDiscovery();
diff --git a/staticlibs/device/com/android/net/module/util/TcUtils.java b/staticlibs/device/com/android/net/module/util/TcUtils.java
index 9d2fb7f..a6b222f 100644
--- a/staticlibs/device/com/android/net/module/util/TcUtils.java
+++ b/staticlibs/device/com/android/net/module/util/TcUtils.java
@@ -101,4 +101,12 @@
* @throws IOException
*/
public static native void tcQdiscAddDevClsact(int ifIndex) throws IOException;
+
+ /**
+ * Attempt to fetch a bpf program from a path.
+ * Return true on success, false on non-existence or any other failure.
+ *
+ * @param bpfProgPath
+ */
+ public static native boolean isBpfProgramUsable(String bpfProgPath);
}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
index 92ec0c4..df7010e 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
@@ -41,6 +41,10 @@
public static final short IFLA_ADDRESS = 1;
public static final short IFLA_IFNAME = 3;
public static final short IFLA_MTU = 4;
+ public static final short IFLA_INET6_ADDR_GEN_MODE = 8;
+ public static final short IFLA_AF_SPEC = 26;
+
+ public static final short IN6_ADDR_GEN_MODE_NONE = 1;
private int mMtu;
@NonNull
diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java
index 02d1574..28eeaea 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java
@@ -49,7 +49,7 @@
@Field(order = 4, type = Type.U32)
public final long change;
- StructIfinfoMsg(short family, int type, int index, long flags, long change) {
+ public StructIfinfoMsg(short family, int type, int index, long flags, long change) {
this.family = family;
this.type = type;
this.index = index;
diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
index 7c4abe0..19d8bbe 100644
--- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
+++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
@@ -179,6 +179,7 @@
public static final int ICMPV6_RA_HEADER_LEN = 16;
public static final int ICMPV6_NS_HEADER_LEN = 24;
public static final int ICMPV6_NA_HEADER_LEN = 24;
+ public static final int ICMPV6_ND_OPTION_TLLA_LEN = 8;
public static final int NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER = 1 << 31;
public static final int NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED = 1 << 30;
diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h
index 59257b8..417a5c4 100644
--- a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h
+++ b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h
@@ -42,10 +42,26 @@
return kver;
}
-static inline __unused bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) {
+static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) {
return kernelVersion() >= KVER(major, minor, sub);
}
+static inline bool isKernelVersion(unsigned major, unsigned minor) {
+ return isAtLeastKernelVersion(major, minor, 0) && !isAtLeastKernelVersion(major, minor + 1, 0);
+}
+
+static inline bool __unused isLtsKernel() {
+ return isKernelVersion(4, 4) || // minimum for Android R
+ isKernelVersion(4, 9) || // minimum for Android S & T
+ isKernelVersion(4, 14) || // minimum for Android U
+ isKernelVersion(4, 19) || // minimum for Android V
+ isKernelVersion(5, 4) || // first supported in Android R
+ isKernelVersion(5, 10) || // first supported in Android S
+ isKernelVersion(5, 15) || // first supported in Android T
+ isKernelVersion(6, 1) || // first supported in Android U
+ isKernelVersion(6, 6); // first supported in Android V
+}
+
// Figure out the bitness of userspace.
// Trivial and known at compile time.
static constexpr bool isUserspace32bit() {
diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
index 9995cb9..cb02de8 100644
--- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
+++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
@@ -148,6 +148,13 @@
return bpfFdGet(pathname, BPF_F_RDONLY);
}
+inline bool usableProgram(const char* pathname) {
+ int fd = retrieveProgram(pathname);
+ bool ok = (fd >= 0);
+ if (ok) close(fd);
+ return ok;
+}
+
inline int attachProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd,
const BPF_FD_TYPE cg_fd, uint32_t flags = 0) {
return bpf(BPF_PROG_ATTACH, {
diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp
index ab83da6..2a587b6 100644
--- a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp
+++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp
@@ -19,6 +19,9 @@
#include <nativehelper/scoped_utf_chars.h>
#include <tcutils/tcutils.h>
+#define BPF_FD_JUST_USE_INT
+#include "BpfSyscallWrappers.h"
+
namespace android {
static void throwIOException(JNIEnv *env, const char *msg, int error) {
@@ -96,6 +99,14 @@
}
}
+static jboolean com_android_net_module_util_TcUtils_isBpfProgramUsable(JNIEnv *env,
+ jclass clazz,
+ jstring bpfProgPath) {
+ ScopedUtfChars pathname(env, bpfProgPath);
+ return bpf::usableProgram(pathname.c_str());
+}
+
+
/*
* JNI registration.
*/
@@ -111,6 +122,8 @@
(void *)com_android_net_module_util_TcUtils_tcFilterDelDev},
{"tcQdiscAddDevClsact", "(I)V",
(void *)com_android_net_module_util_TcUtils_tcQdiscAddDevClsact},
+ {"isBpfProgramUsable", "(Ljava/lang/String;)Z",
+ (void *)com_android_net_module_util_TcUtils_isBpfProgramUsable},
};
int register_com_android_net_module_util_TcUtils(JNIEnv *env,
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt
index 4185b05..d5e91c2 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt
@@ -24,6 +24,7 @@
* A JUnit Rule that sets feature flags based on `@FeatureFlag` annotations.
*
* This rule enables dynamic control of feature flag states during testing.
+ * And restores the original values after performing tests.
*
* **Usage:**
* ```kotlin
@@ -31,6 +32,8 @@
* @get:Rule
* val setFeatureFlagsRule = SetFeatureFlagsRule(setFlagsMethod = (name, enabled) -> {
* // Custom handling code.
+ * }, (name) -> {
+ * // Custom getter code to retrieve the original values.
* })
*
* // ... test methods with @FeatureFlag annotations
@@ -41,7 +44,10 @@
* }
* ```
*/
-class SetFeatureFlagsRule(val setFlagsMethod: (name: String, enabled: Boolean) -> Unit) : TestRule {
+class SetFeatureFlagsRule(
+ val setFlagsMethod: (name: String, enabled: Boolean?) -> Unit,
+ val getFlagsMethod: (name: String) -> Boolean?
+) : TestRule {
/**
* This annotation marks a test method as requiring a specific feature flag to be configured.
*
@@ -69,13 +75,20 @@
FeatureFlag::class.java
)
+ val valuesToBeRestored = mutableMapOf<String, Boolean?>()
for (featureFlagAnnotation in featureFlagAnnotations) {
+ valuesToBeRestored[featureFlagAnnotation.name] =
+ getFlagsMethod(featureFlagAnnotation.name)
setFlagsMethod(featureFlagAnnotation.name, featureFlagAnnotation.enabled)
}
// Execute the test method, which includes methods annotated with
// @Before, @Test and @After.
base.evaluate()
+
+ valuesToBeRestored.forEach {
+ setFlagsMethod(it.key, it.value)
+ }
}
}
}
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt
index 05c0444..f76916a 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt
@@ -91,6 +91,7 @@
override val network: Network,
val reason: Int
) : CallbackEntry()
+
// Convenience constants for expecting a type
companion object {
@JvmField
@@ -216,7 +217,11 @@
) : this(null, timeoutMs, noCallbackTimeoutMs, waiterFunc)
fun createLinkedCopy() = TestableNetworkCallback(
- this, defaultTimeoutMs, defaultNoCallbackTimeoutMs, waiterFunc)
+ this,
+ defaultTimeoutMs,
+ defaultNoCallbackTimeoutMs,
+ waiterFunc
+ )
// The last available network, or null if any network was lost since the last call to
// onAvailable. TODO : fix this by fixing the tests that rely on this behavior
@@ -402,8 +407,11 @@
from: Int = mark,
crossinline predicate: (T) -> Boolean = { true }
): T = history.poll(timeoutMs, from) { it is T && predicate(it) }.also {
- assertNotNull(it, "Callback ${T::class} not received within ${timeoutMs}ms. " +
- "Got ${history.backtrace()}")
+ assertNotNull(
+ it,
+ "Callback ${T::class} not received within ${timeoutMs}ms. " +
+ "Got ${history.backtrace()}"
+ )
} as T
@JvmOverloads
@@ -412,8 +420,11 @@
timeoutMs: Long = defaultTimeoutMs,
predicate: (cb: T) -> Boolean = { true }
) = history.poll(timeoutMs) { type.java.isInstance(it) && predicate(it as T) }.also {
- assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms. " +
- "Got ${history.backtrace()}")
+ assertNotNull(
+ it,
+ "Callback ${type.java} not received within ${timeoutMs}ms. " +
+ "Got ${history.backtrace()}"
+ )
} as T
fun <T : CallbackEntry> eventuallyExpect(
@@ -422,8 +433,11 @@
from: Int = mark,
predicate: (cb: T) -> Boolean = { true }
) = history.poll(timeoutMs, from) { type.java.isInstance(it) && predicate(it as T) }.also {
- assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms. " +
- "Got ${history.backtrace()}")
+ assertNotNull(
+ it,
+ "Callback ${type.java} not received within ${timeoutMs}ms. " +
+ "Got ${history.backtrace()}"
+ )
} as T
// Expects onAvailable and the callbacks that follow it. These are:
@@ -534,8 +548,13 @@
blockedReason: Int,
tmt: Long = defaultTimeoutMs
) {
- expectAvailableCallbacks(net, validated = false, suspended = false,
- blockedReason = blockedReason, tmt = tmt)
+ expectAvailableCallbacks(
+ net,
+ validated = false,
+ suspended = false,
+ blockedReason = blockedReason,
+ tmt = tmt
+ )
expectCaps(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) }
}
diff --git a/tests/cts/hostside-network-policy/Android.bp b/tests/cts/hostside-network-policy/Android.bp
new file mode 100644
index 0000000..c3ce0b9
--- /dev/null
+++ b/tests/cts/hostside-network-policy/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2024 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 {
+ default_team: "trendy_team_framework_backstage_power",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_test_host {
+ name: "CtsHostsideNetworkPolicyTests",
+ defaults: ["cts_defaults"],
+ // Only compile source java files in this apk.
+ srcs: [
+ "src/**/*.java",
+ ":ArgumentConstants",
+ ],
+ libs: [
+ "cts-tradefed",
+ "tradefed",
+ ],
+ static_libs: [
+ "modules-utils-build-testing",
+ ],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ ],
+ data: [
+ ":CtsHostsideNetworkPolicyTestsApp",
+ ":CtsHostsideNetworkPolicyTestsApp2",
+ ],
+ per_testcase_directory: true,
+}
diff --git a/tests/cts/hostside-network-policy/AndroidTest.xml b/tests/cts/hostside-network-policy/AndroidTest.xml
new file mode 100644
index 0000000..44f77f8
--- /dev/null
+++ b/tests/cts/hostside-network-policy/AndroidTest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+<configuration description="Config for CTS network policy host test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="networking" />
+ <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
+ <target_preparer class="com.android.cts.netpolicy.NetworkPolicyTestsPreparer" />
+
+ <!-- Enabling change id ALLOW_TEST_API_ACCESS allows that package to access @TestApi methods -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="am compat enable ALLOW_TEST_API_ACCESS com.android.cts.netpolicy.hostside.app2" />
+ <option name="teardown-command" value="am compat reset ALLOW_TEST_API_ACCESS com.android.cts.netpolicy.hostside.app2" />
+ <option name="teardown-command" value="cmd power set-mode 0" />
+ <option name="teardown-command" value="cmd battery reset" />
+ <option name="teardown-command" value="cmd netpolicy stop-watching" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" />
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="set-global-setting" key="low_power_standby_enabled" value="0" />
+ </target_preparer>
+
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsHostsideNetworkPolicyTests.jar" />
+ <option name="runtime-hint" value="3m56s" />
+ </test>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/sdcard/CtsHostsideNetworkPolicyTests" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/tests/cts/hostside-network-policy/OWNERS b/tests/cts/hostside-network-policy/OWNERS
new file mode 100644
index 0000000..ea83e61
--- /dev/null
+++ b/tests/cts/hostside-network-policy/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 61373
+# Inherits parent owners
+include platform/frameworks/base:/services/core/java/com/android/server/net/OWNERS
diff --git a/tests/cts/hostside-network-policy/TEST_MAPPING b/tests/cts/hostside-network-policy/TEST_MAPPING
new file mode 100644
index 0000000..57ac4f7
--- /dev/null
+++ b/tests/cts/hostside-network-policy/TEST_MAPPING
@@ -0,0 +1,27 @@
+{
+ "presubmit-large": [
+ {
+ "name": "CtsHostsideNetworkPolicyTests",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ // Postsubmit on virtual devices to monitor flakiness of all tests that don't require a
+ // physical device
+ "name": "CtsHostsideNetworkPolicyTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/cts/hostside-network-policy/aidl/Android.bp b/tests/cts/hostside-network-policy/aidl/Android.bp
new file mode 100644
index 0000000..b182090
--- /dev/null
+++ b/tests/cts/hostside-network-policy/aidl/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2024 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 {
+ default_team: "trendy_team_framework_backstage_power",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_test_helper_library {
+ name: "CtsHostsideNetworkPolicyTestsAidl",
+ sdk_version: "current",
+ srcs: [
+ "com/android/cts/netpolicy/hostside/*.aidl",
+ ],
+}
diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl b/tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/IMyService.aidl
similarity index 86%
rename from tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl
rename to tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/IMyService.aidl
index 906024b..068d9d8 100644
--- a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl
+++ b/tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/IMyService.aidl
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import android.app.job.JobInfo;
-import com.android.cts.net.hostside.INetworkCallback;
-import com.android.cts.net.hostside.NetworkCheckResult;
+import com.android.cts.netpolicy.hostside.INetworkCallback;
+import com.android.cts.netpolicy.hostside.NetworkCheckResult;
interface IMyService {
void registerBroadcastReceiver();
diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl b/tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/INetworkCallback.aidl
similarity index 95%
rename from tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl
rename to tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/INetworkCallback.aidl
index 2048bab..38efc7b 100644
--- a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl
+++ b/tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/INetworkCallback.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import android.net.Network;
import android.net.NetworkCapabilities;
diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl b/tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/INetworkStateObserver.aidl
similarity index 89%
rename from tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
rename to tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/INetworkStateObserver.aidl
index 8ef4659..c6b7a1c 100644
--- a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
+++ b/tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/INetworkStateObserver.aidl
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import android.net.NetworkInfo;
-import com.android.cts.net.hostside.NetworkCheckResult;
+import com.android.cts.netpolicy.hostside.NetworkCheckResult;
interface INetworkStateObserver {
void onNetworkStateChecked(int resultCode, in NetworkCheckResult networkCheckResult);
diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/NetworkCheckResult.aidl b/tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/NetworkCheckResult.aidl
similarity index 94%
rename from tests/cts/hostside/aidl/com/android/cts/net/hostside/NetworkCheckResult.aidl
rename to tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/NetworkCheckResult.aidl
index cdd6b70..7aac2ab 100644
--- a/tests/cts/hostside/aidl/com/android/cts/net/hostside/NetworkCheckResult.aidl
+++ b/tests/cts/hostside-network-policy/aidl/com/android/cts/netpolicy/hostside/NetworkCheckResult.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import android.net.NetworkInfo;
diff --git a/tests/cts/hostside-network-policy/app/Android.bp b/tests/cts/hostside-network-policy/app/Android.bp
new file mode 100644
index 0000000..a31c843
--- /dev/null
+++ b/tests/cts/hostside-network-policy/app/Android.bp
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2024 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 {
+ default_team: "trendy_team_framework_backstage_power",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_defaults {
+ name: "CtsHostsideNetworkPolicyTestsAppDefaults",
+ platform_apis: true,
+ static_libs: [
+ "CtsHostsideNetworkPolicyTestsAidl",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "compatibility-device-util-axt",
+ "cts-net-utils",
+ "ctstestrunner-axt",
+ "modules-utils-build",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ":ArgumentConstants",
+ ],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "general-tests",
+ "sts",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsHostsideNetworkPolicyTestsApp",
+ defaults: [
+ "cts_support_defaults",
+ "framework-connectivity-test-defaults",
+ "CtsHostsideNetworkPolicyTestsAppDefaults",
+ ],
+}
diff --git a/tests/cts/hostside-network-policy/app/AndroidManifest.xml b/tests/cts/hostside-network-policy/app/AndroidManifest.xml
new file mode 100644
index 0000000..f19e35f
--- /dev/null
+++ b/tests/cts/hostside-network-policy/app/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.netpolicy.hostside">
+
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <application android:requestLegacyExternalStorage="true">
+ <uses-library android:name="android.test.runner"/>
+ <service android:name=".MyNotificationListenerService"
+ android:label="MyNotificationListenerService"
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationListenerService"/>
+ </intent-filter>
+ </service>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.netpolicy.hostside"/>
+
+</manifest>
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractAppIdleTestCase.java
similarity index 96%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractAppIdleTestCase.java
index d9ff539..19e4364 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractAppIdleTestCase.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE;
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.APP_STANDBY_MODE;
+import static com.android.cts.netpolicy.hostside.Property.BATTERY_SAVER_MODE;
import static org.junit.Assert.assertEquals;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractBatterySaverModeTestCase.java
similarity index 96%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractBatterySaverModeTestCase.java
index 0d7365f..ae226e2 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractBatterySaverModeTestCase.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.BATTERY_SAVER_MODE;
import org.junit.After;
import org.junit.Before;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDefaultRestrictionsTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractDefaultRestrictionsTest.java
similarity index 98%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDefaultRestrictionsTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractDefaultRestrictionsTest.java
index 8a3e790..da633c0 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDefaultRestrictionsTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractDefaultRestrictionsTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractDozeModeTestCase.java
similarity index 95%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractDozeModeTestCase.java
index b037953..0c8cb70 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractDozeModeTestCase.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
-import static com.android.cts.net.hostside.Property.DOZE_MODE;
-import static com.android.cts.net.hostside.Property.NOT_LOW_RAM_DEVICE;
+import static com.android.cts.netpolicy.hostside.Property.DOZE_MODE;
+import static com.android.cts.netpolicy.hostside.Property.NOT_LOW_RAM_DEVICE;
import android.os.SystemClock;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractExpeditedJobTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractExpeditedJobTest.java
similarity index 88%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractExpeditedJobTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractExpeditedJobTest.java
index 7cac2af..5435920 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractExpeditedJobTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractExpeditedJobTest.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
-import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE;
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DOZE_MODE;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.setRestrictBackground;
+import static com.android.cts.netpolicy.hostside.Property.APP_STANDBY_MODE;
+import static com.android.cts.netpolicy.hostside.Property.BATTERY_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.DATA_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.DOZE_MODE;
+import static com.android.cts.netpolicy.hostside.Property.METERED_NETWORK;
import org.junit.After;
import org.junit.Before;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractRestrictBackgroundNetworkTestCase.java
similarity index 96%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 4437986..d0203c5 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
@@ -23,18 +23,18 @@
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
import static android.os.BatteryManager.BATTERY_PLUGGED_ANY;
-import static com.android.cts.net.arguments.InstrumentationArguments.ARG_CONNECTION_CHECK_CUSTOM_URL;
-import static com.android.cts.net.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCommand;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.forceRunJob;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getConnectivityManager;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getContext;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getInstrumentation;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isAppStandbySupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isBatterySaverSupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackgroundInternal;
+import static com.android.cts.netpolicy.arguments.InstrumentationArguments.ARG_CONNECTION_CHECK_CUSTOM_URL;
+import static com.android.cts.netpolicy.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.executeShellCommand;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.forceRunJob;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.getConnectivityManager;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.getContext;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.getInstrumentation;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.isAppStandbySupported;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.isBatterySaverSupported;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.isDozeModeSupported;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.setRestrictBackgroundInternal;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -93,8 +93,8 @@
public abstract class AbstractRestrictBackgroundNetworkTestCase {
public static final String TAG = "RestrictBackgroundNetworkTests";
- protected static final String TEST_PKG = "com.android.cts.net.hostside";
- protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2";
+ protected static final String TEST_PKG = "com.android.cts.netpolicy.hostside";
+ protected static final String TEST_APP2_PKG = "com.android.cts.netpolicy.hostside.app2";
// TODO(b/321797685): Configure it via device-config once it is available.
protected static final long PROCESS_STATE_TRANSITION_DELAY_MS = TimeUnit.SECONDS.toMillis(5);
@@ -112,17 +112,17 @@
private static final String MANIFEST_RECEIVER = "ManifestReceiver";
private static final String DYNAMIC_RECEIVER = "DynamicReceiver";
private static final String ACTION_FINISH_ACTIVITY =
- "com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY";
+ "com.android.cts.netpolicy.hostside.app2.action.FINISH_ACTIVITY";
private static final String ACTION_FINISH_JOB =
- "com.android.cts.net.hostside.app2.action.FINISH_JOB";
+ "com.android.cts.netpolicy.hostside.app2.action.FINISH_JOB";
// Copied from com.android.server.net.NetworkPolicyManagerService class
private static final String ACTION_SNOOZE_WARNING =
"com.android.server.net.action.SNOOZE_WARNING";
private static final String ACTION_RECEIVER_READY =
- "com.android.cts.net.hostside.app2.action.RECEIVER_READY";
+ "com.android.cts.netpolicy.hostside.app2.action.RECEIVER_READY";
static final String ACTION_SHOW_TOAST =
- "com.android.cts.net.hostside.app2.action.SHOW_TOAST";
+ "com.android.cts.netpolicy.hostside.app2.action.SHOW_TOAST";
protected static final String NOTIFICATION_TYPE_CONTENT = "CONTENT";
protected static final String NOTIFICATION_TYPE_DELETE = "DELETE";
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AppIdleMeteredTest.java
similarity index 85%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AppIdleMeteredTest.java
index f1858d6..6b802f6 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AppIdleMeteredTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.METERED_NETWORK;
@RequiredProperties({METERED_NETWORK})
public class AppIdleMeteredTest extends AbstractAppIdleTestCase {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AppIdleNonMeteredTest.java
similarity index 85%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AppIdleNonMeteredTest.java
index e737a6d..2e725ae 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/AppIdleNonMeteredTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.NON_METERED_NETWORK;
@RequiredProperties({NON_METERED_NETWORK})
public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/BatterySaverModeMeteredTest.java
similarity index 85%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/BatterySaverModeMeteredTest.java
index c78ca2e..2e421f6 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/BatterySaverModeMeteredTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.METERED_NETWORK;
@RequiredProperties({METERED_NETWORK})
public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/BatterySaverModeNonMeteredTest.java
similarity index 85%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/BatterySaverModeNonMeteredTest.java
index fb52a54..0be5644 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/BatterySaverModeNonMeteredTest.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.NON_METERED_NETWORK;
@RequiredProperties({NON_METERED_NETWORK})
public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnOnActivityStartTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/ConnOnActivityStartTest.java
similarity index 85%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnOnActivityStartTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/ConnOnActivityStartTest.java
index 3e22a23..811190f 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnOnActivityStartTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/ConnOnActivityStartTest.java
@@ -14,20 +14,20 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getUiDevice;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
-import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE;
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DOZE_MODE;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.getUiDevice;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.setRestrictBackground;
+import static com.android.cts.netpolicy.hostside.Property.APP_STANDBY_MODE;
+import static com.android.cts.netpolicy.hostside.Property.BATTERY_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.DATA_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.DOZE_MODE;
+import static com.android.cts.netpolicy.hostside.Property.METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.NON_METERED_NETWORK;
import static org.junit.Assume.assumeTrue;
@@ -53,6 +53,7 @@
@After
public final void tearDown() throws Exception {
super.tearDown();
+ finishActivity();
resetDeviceState();
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DataSaverModeTest.java
similarity index 95%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DataSaverModeTest.java
index 790e031..66e0d00 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DataSaverModeTest.java
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
import static com.android.compatibility.common.util.FeatureUtil.isTV;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
-import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-import static com.android.cts.net.hostside.Property.NO_DATA_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.setRestrictBackground;
+import static com.android.cts.netpolicy.hostside.Property.DATA_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.NO_DATA_SAVER_MODE;
import static org.junit.Assert.fail;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataWarningReceiverTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DataWarningReceiverTest.java
similarity index 96%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/DataWarningReceiverTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DataWarningReceiverTest.java
index 13bbab6..69ca206 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataWarningReceiverTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DataWarningReceiverTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.clearSnoozeTimestamps;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.clearSnoozeTimestamps;
import android.content.pm.PackageManager;
import android.telephony.SubscriptionManager;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DefaultRestrictionsMeteredTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DefaultRestrictionsMeteredTest.java
similarity index 86%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/DefaultRestrictionsMeteredTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DefaultRestrictionsMeteredTest.java
index f3a1026..810fd19 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DefaultRestrictionsMeteredTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DefaultRestrictionsMeteredTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.METERED_NETWORK;
@RequiredProperties({METERED_NETWORK})
public class DefaultRestrictionsMeteredTest extends AbstractDefaultRestrictionsTest {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DefaultRestrictionsNonMeteredTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DefaultRestrictionsNonMeteredTest.java
similarity index 85%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/DefaultRestrictionsNonMeteredTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DefaultRestrictionsNonMeteredTest.java
index 5651dd0..fef546c 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DefaultRestrictionsNonMeteredTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DefaultRestrictionsNonMeteredTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.NON_METERED_NETWORK;
@RequiredProperties({NON_METERED_NETWORK})
public class DefaultRestrictionsNonMeteredTest extends AbstractDefaultRestrictionsTest {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DozeModeMeteredTest.java
similarity index 85%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DozeModeMeteredTest.java
index 4306c99..741dd7e 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DozeModeMeteredTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.METERED_NETWORK;
@RequiredProperties({METERED_NETWORK})
public class DozeModeMeteredTest extends AbstractDozeModeTestCase {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DozeModeNonMeteredTest.java
similarity index 85%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DozeModeNonMeteredTest.java
index 1e89f15..f343df5 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DozeModeNonMeteredTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.NON_METERED_NETWORK;
@RequiredProperties({NON_METERED_NETWORK})
public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DumpOnFailureRule.java
similarity index 92%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DumpOnFailureRule.java
index 07434b1..2dc6cc4 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/DumpOnFailureRule.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_APP2_PKG;
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG;
+import static com.android.cts.netpolicy.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
+import static com.android.cts.netpolicy.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_APP2_PKG;
+import static com.android.cts.netpolicy.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG;
import android.os.Environment;
import android.os.FileUtils;
@@ -42,7 +42,7 @@
public class DumpOnFailureRule extends OnFailureRule {
private File mDumpDir = new File(Environment.getExternalStorageDirectory(),
- "CtsHostsideNetworkTests");
+ "CtsHostsideNetworkPolicyTests");
@Override
public void onTestFailure(Statement base, Description description, Throwable throwable) {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ExpeditedJobMeteredTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/ExpeditedJobMeteredTest.java
similarity index 85%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/ExpeditedJobMeteredTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/ExpeditedJobMeteredTest.java
index 3809534..d56a50b 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ExpeditedJobMeteredTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/ExpeditedJobMeteredTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.METERED_NETWORK;
@RequiredProperties({METERED_NETWORK})
public class ExpeditedJobMeteredTest extends AbstractExpeditedJobTest {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ExpeditedJobNonMeteredTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/ExpeditedJobNonMeteredTest.java
similarity index 85%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/ExpeditedJobNonMeteredTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/ExpeditedJobNonMeteredTest.java
index 6596269..0a776ee 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ExpeditedJobNonMeteredTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/ExpeditedJobNonMeteredTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.NON_METERED_NETWORK;
@RequiredProperties({NON_METERED_NETWORK})
public class ExpeditedJobNonMeteredTest extends AbstractExpeditedJobTest {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MeterednessConfigurationRule.java
similarity index 86%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MeterednessConfigurationRule.java
index 5c99c67..4f4e68e 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MeterednessConfigurationRule.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setupActiveNetworkMeteredness;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.setupActiveNetworkMeteredness;
+import static com.android.cts.netpolicy.hostside.Property.METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.NON_METERED_NETWORK;
import android.util.ArraySet;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MixedModesTest.java
similarity index 95%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MixedModesTest.java
index c9edda6..b0fa106 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MixedModesTest.java
@@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
-import static com.android.cts.net.hostside.Property.APP_STANDBY_MODE;
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DOZE_MODE;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.setRestrictBackground;
+import static com.android.cts.netpolicy.hostside.Property.APP_STANDBY_MODE;
+import static com.android.cts.netpolicy.hostside.Property.BATTERY_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.DATA_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.DOZE_MODE;
+import static com.android.cts.netpolicy.hostside.Property.METERED_NETWORK;
+import static com.android.cts.netpolicy.hostside.Property.NON_METERED_NETWORK;
import android.os.SystemClock;
import android.util.Log;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MyNotificationListenerService.java
similarity index 98%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MyNotificationListenerService.java
index 0132536..6dc9921 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MyNotificationListenerService.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import android.app.Notification;
import android.app.PendingIntent;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MyServiceClient.java
similarity index 98%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MyServiceClient.java
index 494192f..71b28f6 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/MyServiceClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import android.app.job.JobInfo;
import android.content.ComponentName;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkCallbackTest.java
similarity index 96%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkCallbackTest.java
index 5552b8f..7038d02 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkCallbackTest.java
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getActiveNetworkCapabilities;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.getActiveNetworkCapabilities;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.setRestrictBackground;
+import static com.android.cts.netpolicy.hostside.Property.BATTERY_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.DATA_SAVER_MODE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkPolicyManagerTest.java
similarity index 95%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkPolicyManagerTest.java
index 968e270..9b3fe9f 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkPolicyManagerTest.java
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
import static android.os.Process.SYSTEM_UID;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.assertIsUidRestrictedOnMeteredNetworks;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.assertNetworkingBlockedStatusForUid;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isUidNetworkingBlocked;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
-import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.assertIsUidRestrictedOnMeteredNetworks;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.assertNetworkingBlockedStatusForUid;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.isUidNetworkingBlocked;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.setRestrictBackground;
+import static com.android.cts.netpolicy.hostside.Property.BATTERY_SAVER_MODE;
+import static com.android.cts.netpolicy.hostside.Property.DATA_SAVER_MODE;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkPolicyTestRunner.java
similarity index 96%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkPolicyTestRunner.java
index f340907..0207b00 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestRunner.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkPolicyTestRunner.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkPolicyTestUtils.java
similarity index 98%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkPolicyTestUtils.java
index 5331601..26a88f2 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/NetworkPolicyTestUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
@@ -26,7 +26,7 @@
import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
+import static com.android.cts.netpolicy.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/Property.java
similarity index 72%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/Property.java
index 18805f9..a03833f 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/Property.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/Property.java
@@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isAppStandbySupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isBatterySaverSupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDataSaverSupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isLowRamDevice;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.isAppStandbySupported;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.isBatterySaverSupported;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.isDataSaverSupported;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.isDozeModeSupported;
+import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.isLowRamDevice;
public enum Property {
BATTERY_SAVER_MODE(1 << 0) {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/RequiredProperties.java
similarity index 95%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/RequiredProperties.java
index 96838bb..799a513 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredProperties.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/RequiredProperties.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/RequiredPropertiesRule.java
similarity index 95%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/RequiredPropertiesRule.java
index 01f9f3e..5dea67c 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RequiredPropertiesRule.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/RequiredPropertiesRule.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
+import static com.android.cts.netpolicy.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
import android.text.TextUtils;
import android.util.ArraySet;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/RestrictedModeTest.java
similarity index 97%
rename from tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java
rename to tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/RestrictedModeTest.java
index 4777bf4..f183f4e 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java
+++ b/tests/cts/hostside-network-policy/app/src/com/android/cts/netpolicy/hostside/RestrictedModeTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside;
+package com.android.cts.netpolicy.hostside;
import org.junit.After;
import org.junit.Before;
diff --git a/tests/cts/hostside-network-policy/app2/Android.bp b/tests/cts/hostside-network-policy/app2/Android.bp
new file mode 100644
index 0000000..6ef0b06
--- /dev/null
+++ b/tests/cts/hostside-network-policy/app2/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2024 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 {
+ default_team: "trendy_team_framework_backstage_power",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsHostsideNetworkPolicyTestsApp2",
+ defaults: ["cts_support_defaults"],
+ platform_apis: true,
+ static_libs: [
+ "androidx.annotation_annotation",
+ "CtsHostsideNetworkPolicyTestsAidl",
+ "modules-utils-build",
+ ],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ ],
+ certificate: ":cts-netpolicy-app",
+}
diff --git a/tests/cts/hostside-network-policy/app2/AndroidManifest.xml b/tests/cts/hostside-network-policy/app2/AndroidManifest.xml
new file mode 100644
index 0000000..668f2da
--- /dev/null
+++ b/tests/cts/hostside-network-policy/app2/AndroidManifest.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.netpolicy.hostside.app2">
+
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+
+ <!--
+ This application is used to listen to RESTRICT_BACKGROUND_CHANGED intents and store
+ them in a shared preferences which is then read by the test app. These broadcasts are
+ handled by 2 listeners, one defined the manifest and another dynamically registered by
+ a service.
+
+ The manifest-defined listener also handles ordered broadcasts used to share data with the
+ test app.
+
+ This application also provides a service, RemoteSocketFactoryService, that the test app can
+ use to open sockets to remote hosts as a different user ID.
+ -->
+ <application android:usesCleartextTraffic="true"
+ android:testOnly="true"
+ android:debuggable="true">
+
+ <activity android:name=".MyActivity"
+ android:exported="true"/>
+ <service android:name=".MyService"
+ android:exported="true"/>
+ <service android:name=".MyForegroundService"
+ android:foregroundServiceType="specialUse"
+ android:exported="true">
+ <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
+ android:value="Connectivity" />
+ </service>
+ <receiver android:name=".MyBroadcastReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.net.conn.RESTRICT_BACKGROUND_CHANGED"/>
+ <action android:name="com.android.cts.netpolicy.hostside.app2.action.GET_COUNTERS"/>
+ <action android:name="com.android.cts.netpolicy.hostside.app2.action.GET_RESTRICT_BACKGROUND_STATUS"/>
+ <action android:name="com.android.cts.netpolicy.hostside.app2.action.CHECK_NETWORK"/>
+ <action android:name="com.android.cts.netpolicy.hostside.app2.action.SEND_NOTIFICATION"/>
+ <action android:name="com.android.cts.netpolicy.hostside.app2.action.SHOW_TOAST"/>
+ </intent-filter>
+ </receiver>
+ <service android:name=".MyJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
+ </application>
+
+ <!--
+ Adding this to make sure that receiving the broadcast is not restricted by
+ package visibility restrictions.
+ -->
+ <queries>
+ <package android:name="android" />
+ </queries>
+
+</manifest>
diff --git a/tests/cts/hostside/app2/res/drawable/ic_notification.png b/tests/cts/hostside-network-policy/app2/res/drawable/ic_notification.png
similarity index 100%
rename from tests/cts/hostside/app2/res/drawable/ic_notification.png
rename to tests/cts/hostside-network-policy/app2/res/drawable/ic_notification.png
Binary files differ
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/Common.java
similarity index 91%
rename from tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
rename to tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/Common.java
index 1c45579..1719f9b 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
+++ b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/Common.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside.app2;
+package com.android.cts.netpolicy.hostside.app2;
-import static com.android.cts.net.hostside.INetworkStateObserver.RESULT_ERROR_OTHER;
-import static com.android.cts.net.hostside.INetworkStateObserver.RESULT_ERROR_UNEXPECTED_CAPABILITIES;
-import static com.android.cts.net.hostside.INetworkStateObserver.RESULT_ERROR_UNEXPECTED_PROC_STATE;
+import static com.android.cts.netpolicy.hostside.INetworkStateObserver.RESULT_ERROR_OTHER;
+import static com.android.cts.netpolicy.hostside.INetworkStateObserver.RESULT_ERROR_UNEXPECTED_CAPABILITIES;
+import static com.android.cts.netpolicy.hostside.INetworkStateObserver.RESULT_ERROR_UNEXPECTED_PROC_STATE;
import android.app.ActivityManager;
import android.content.Context;
@@ -31,8 +31,8 @@
import android.os.RemoteException;
import android.util.Log;
-import com.android.cts.net.hostside.INetworkStateObserver;
-import com.android.cts.net.hostside.NetworkCheckResult;
+import com.android.cts.netpolicy.hostside.INetworkStateObserver;
+import com.android.cts.netpolicy.hostside.NetworkCheckResult;
import java.net.HttpURLConnection;
import java.net.InetAddress;
@@ -49,13 +49,13 @@
static final String DYNAMIC_RECEIVER = "DynamicReceiver";
static final String ACTION_RECEIVER_READY =
- "com.android.cts.net.hostside.app2.action.RECEIVER_READY";
+ "com.android.cts.netpolicy.hostside.app2.action.RECEIVER_READY";
static final String ACTION_FINISH_ACTIVITY =
- "com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY";
+ "com.android.cts.netpolicy.hostside.app2.action.FINISH_ACTIVITY";
static final String ACTION_FINISH_JOB =
- "com.android.cts.net.hostside.app2.action.FINISH_JOB";
+ "com.android.cts.netpolicy.hostside.app2.action.FINISH_JOB";
static final String ACTION_SHOW_TOAST =
- "com.android.cts.net.hostside.app2.action.SHOW_TOAST";
+ "com.android.cts.netpolicy.hostside.app2.action.SHOW_TOAST";
// Copied from com.android.server.net.NetworkPolicyManagerService class
static final String ACTION_SNOOZE_WARNING =
"com.android.server.net.action.SNOOZE_WARNING";
@@ -71,7 +71,7 @@
static final String NOTIFICATION_TYPE_ACTION_BUNDLE = "ACTION_BUNDLE";
static final String NOTIFICATION_TYPE_ACTION_REMOTE_INPUT = "ACTION_REMOTE_INPUT";
- static final String TEST_PKG = "com.android.cts.net.hostside";
+ static final String TEST_PKG = "com.android.cts.netpolicy.hostside";
static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
static final String KEY_SKIP_VALIDATION_CHECKS = TEST_PKG + ".skip_validation_checks";
static final String KEY_CUSTOM_URL = TEST_PKG + ".custom_url";
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyActivity.java
similarity index 90%
rename from tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
rename to tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyActivity.java
index aa58ff9..d274c50 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
+++ b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyActivity.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside.app2;
+package com.android.cts.netpolicy.hostside.app2;
-import static com.android.cts.net.hostside.app2.Common.ACTION_FINISH_ACTIVITY;
-import static com.android.cts.net.hostside.app2.Common.TAG;
-import static com.android.cts.net.hostside.app2.Common.TYPE_COMPONENT_ACTIVTY;
+import static com.android.cts.netpolicy.hostside.app2.Common.ACTION_FINISH_ACTIVITY;
+import static com.android.cts.netpolicy.hostside.app2.Common.TAG;
+import static com.android.cts.netpolicy.hostside.app2.Common.TYPE_COMPONENT_ACTIVTY;
import android.app.Activity;
import android.content.BroadcastReceiver;
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyBroadcastReceiver.java
similarity index 86%
rename from tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
rename to tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyBroadcastReceiver.java
index 1fd3745..27aec8c 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
+++ b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyBroadcastReceiver.java
@@ -14,22 +14,22 @@
* limitations under the License.
*/
-package com.android.cts.net.hostside.app2;
+package com.android.cts.netpolicy.hostside.app2;
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
-import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY;
-import static com.android.cts.net.hostside.app2.Common.ACTION_SHOW_TOAST;
-import static com.android.cts.net.hostside.app2.Common.ACTION_SNOOZE_WARNING;
-import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_BUNDLE;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_REMOTE_INPUT;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_BUNDLE;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_CONTENT;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_DELETE;
-import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_FULL_SCREEN;
-import static com.android.cts.net.hostside.app2.Common.TAG;
+import static com.android.cts.netpolicy.hostside.app2.Common.ACTION_RECEIVER_READY;
+import static com.android.cts.netpolicy.hostside.app2.Common.ACTION_SHOW_TOAST;
+import static com.android.cts.netpolicy.hostside.app2.Common.ACTION_SNOOZE_WARNING;
+import static com.android.cts.netpolicy.hostside.app2.Common.MANIFEST_RECEIVER;
+import static com.android.cts.netpolicy.hostside.app2.Common.NOTIFICATION_TYPE_ACTION;
+import static com.android.cts.netpolicy.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_BUNDLE;
+import static com.android.cts.netpolicy.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_REMOTE_INPUT;
+import static com.android.cts.netpolicy.hostside.app2.Common.NOTIFICATION_TYPE_BUNDLE;
+import static com.android.cts.netpolicy.hostside.app2.Common.NOTIFICATION_TYPE_CONTENT;
+import static com.android.cts.netpolicy.hostside.app2.Common.NOTIFICATION_TYPE_DELETE;
+import static com.android.cts.netpolicy.hostside.app2.Common.NOTIFICATION_TYPE_FULL_SCREEN;
+import static com.android.cts.netpolicy.hostside.app2.Common.TAG;
import android.app.Notification;
import android.app.Notification.Action;
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyForegroundService.java
similarity index 87%
rename from tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
rename to tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyForegroundService.java
index b55761c..54cee3c 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
+++ b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyForegroundService.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside.app2;
+package com.android.cts.netpolicy.hostside.app2;
-import static com.android.cts.net.hostside.app2.Common.TAG;
-import static com.android.cts.net.hostside.app2.Common.TEST_PKG;
-import static com.android.cts.net.hostside.app2.Common.TYPE_COMPONENT_FOREGROUND_SERVICE;
+import static com.android.cts.netpolicy.hostside.app2.Common.TAG;
+import static com.android.cts.netpolicy.hostside.app2.Common.TEST_PKG;
+import static com.android.cts.netpolicy.hostside.app2.Common.TYPE_COMPONENT_FOREGROUND_SERVICE;
import android.R;
import android.app.Notification;
@@ -31,7 +31,7 @@
import android.os.RemoteException;
import android.util.Log;
-import com.android.cts.net.hostside.INetworkStateObserver;
+import com.android.cts.netpolicy.hostside.INetworkStateObserver;
/**
* Service used to change app state to FOREGROUND_SERVICE.
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyJobService.java
similarity index 90%
rename from tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java
rename to tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyJobService.java
index 8c112b6..eba55ed 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java
+++ b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyJobService.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside.app2;
+package com.android.cts.netpolicy.hostside.app2;
-import static com.android.cts.net.hostside.app2.Common.ACTION_FINISH_JOB;
-import static com.android.cts.net.hostside.app2.Common.TAG;
-import static com.android.cts.net.hostside.app2.Common.TYPE_COMPONENT_EXPEDITED_JOB;
+import static com.android.cts.netpolicy.hostside.app2.Common.ACTION_FINISH_JOB;
+import static com.android.cts.netpolicy.hostside.app2.Common.TAG;
+import static com.android.cts.netpolicy.hostside.app2.Common.TYPE_COMPONENT_EXPEDITED_JOB;
import android.app.job.JobParameters;
import android.app.job.JobService;
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyService.java
similarity index 92%
rename from tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java
rename to tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyService.java
index 5010234..71bcead 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java
+++ b/tests/cts/hostside-network-policy/app2/src/com/android/cts/netpolicy/hostside/app2/MyService.java
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net.hostside.app2;
+package com.android.cts.netpolicy.hostside.app2;
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
-import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY;
-import static com.android.cts.net.hostside.app2.Common.ACTION_SNOOZE_WARNING;
-import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER;
-import static com.android.cts.net.hostside.app2.Common.TAG;
+import static com.android.cts.netpolicy.hostside.app2.Common.ACTION_RECEIVER_READY;
+import static com.android.cts.netpolicy.hostside.app2.Common.ACTION_SNOOZE_WARNING;
+import static com.android.cts.netpolicy.hostside.app2.Common.DYNAMIC_RECEIVER;
+import static com.android.cts.netpolicy.hostside.app2.Common.TAG;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -38,9 +38,9 @@
import android.os.RemoteException;
import android.util.Log;
-import com.android.cts.net.hostside.IMyService;
-import com.android.cts.net.hostside.INetworkCallback;
-import com.android.cts.net.hostside.NetworkCheckResult;
+import com.android.cts.netpolicy.hostside.IMyService;
+import com.android.cts.netpolicy.hostside.INetworkCallback;
+import com.android.cts.netpolicy.hostside.NetworkCheckResult;
import com.android.modules.utils.build.SdkLevel;
/**
diff --git a/tests/cts/hostside-network-policy/certs/Android.bp b/tests/cts/hostside-network-policy/certs/Android.bp
new file mode 100644
index 0000000..bfbc341
--- /dev/null
+++ b/tests/cts/hostside-network-policy/certs/Android.bp
@@ -0,0 +1,9 @@
+package {
+ default_team: "trendy_team_framework_backstage_power",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app_certificate {
+ name: "cts-netpolicy-app",
+ certificate: "cts-net-app",
+}
diff --git a/tests/cts/hostside/certs/README b/tests/cts/hostside-network-policy/certs/README
similarity index 100%
rename from tests/cts/hostside/certs/README
rename to tests/cts/hostside-network-policy/certs/README
diff --git a/tests/cts/hostside/certs/cts-net-app.pk8 b/tests/cts/hostside-network-policy/certs/cts-net-app.pk8
similarity index 100%
rename from tests/cts/hostside/certs/cts-net-app.pk8
rename to tests/cts/hostside-network-policy/certs/cts-net-app.pk8
Binary files differ
diff --git a/tests/cts/hostside/certs/cts-net-app.x509.pem b/tests/cts/hostside-network-policy/certs/cts-net-app.x509.pem
similarity index 100%
rename from tests/cts/hostside/certs/cts-net-app.x509.pem
rename to tests/cts/hostside-network-policy/certs/cts-net-app.x509.pem
diff --git a/tests/cts/hostside/instrumentation_arguments/Android.bp b/tests/cts/hostside-network-policy/instrumentation_arguments/Android.bp
similarity index 100%
rename from tests/cts/hostside/instrumentation_arguments/Android.bp
rename to tests/cts/hostside-network-policy/instrumentation_arguments/Android.bp
diff --git a/tests/cts/hostside/instrumentation_arguments/src/com/android/cts/net/arguments/InstrumentationArguments.java b/tests/cts/hostside-network-policy/instrumentation_arguments/src/com/android/cts/netpolicy/arguments/InstrumentationArguments.java
similarity index 94%
rename from tests/cts/hostside/instrumentation_arguments/src/com/android/cts/net/arguments/InstrumentationArguments.java
rename to tests/cts/hostside-network-policy/instrumentation_arguments/src/com/android/cts/netpolicy/arguments/InstrumentationArguments.java
index 911b129..0fe98e9 100644
--- a/tests/cts/hostside/instrumentation_arguments/src/com/android/cts/net/arguments/InstrumentationArguments.java
+++ b/tests/cts/hostside-network-policy/instrumentation_arguments/src/com/android/cts/netpolicy/arguments/InstrumentationArguments.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.net.arguments;
+package com.android.cts.netpolicy.arguments;
public interface InstrumentationArguments {
String ARG_WAIVE_BIND_PRIORITY = "waive_bind_priority";
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideConnOnActivityStartTest.java b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideConnOnActivityStartTest.java
similarity index 91%
rename from tests/cts/hostside/src/com/android/cts/net/HostsideConnOnActivityStartTest.java
rename to tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideConnOnActivityStartTest.java
index fff716d..422231d 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideConnOnActivityStartTest.java
+++ b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideConnOnActivityStartTest.java
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package com.android.cts.net;
+package com.android.cts.netpolicy;
-import static com.android.cts.net.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
+import static com.android.cts.netpolicy.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
import android.platform.test.annotations.FlakyTest;
-import com.android.testutils.SkipPresubmit;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.invoker.TestInformation;
import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
@@ -30,8 +29,8 @@
import java.util.Map;
-@SkipPresubmit(reason = "Out of SLO flakiness")
-public class HostsideConnOnActivityStartTest extends HostsideNetworkTestCase {
+@FlakyTest(bugId = 288324467)
+public class HostsideConnOnActivityStartTest extends HostsideNetworkPolicyTestCase {
private static final String TEST_CLASS = TEST_PKG + ".ConnOnActivityStartTest";
@BeforeClassWithInfo
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideDefaultNetworkRestrictionsTests.java b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideDefaultNetworkRestrictionsTests.java
similarity index 92%
rename from tests/cts/hostside/src/com/android/cts/net/HostsideDefaultNetworkRestrictionsTests.java
rename to tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideDefaultNetworkRestrictionsTests.java
index faabbef..62952bb 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideDefaultNetworkRestrictionsTests.java
+++ b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideDefaultNetworkRestrictionsTests.java
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package com.android.cts.net;
+package com.android.cts.netpolicy;
-import static com.android.cts.net.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
+import static com.android.cts.netpolicy.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
-import com.android.testutils.SkipPresubmit;
+import android.platform.test.annotations.FlakyTest;
+
import com.android.tradefed.device.DeviceNotAvailableException;
import org.junit.After;
@@ -28,8 +29,8 @@
import java.util.Map;
// TODO(b/321848487): Annotate with @RequiresFlagsEnabled to mirror the device-side tests.
-@SkipPresubmit(reason = "Monitoring for flakiness")
-public class HostsideDefaultNetworkRestrictionsTests extends HostsideNetworkTestCase {
+@FlakyTest(bugId = 288324467)
+public class HostsideDefaultNetworkRestrictionsTests extends HostsideNetworkPolicyTestCase {
private static final String METERED_TEST_CLASS = TEST_PKG + ".DefaultRestrictionsMeteredTest";
private static final String NON_METERED_TEST_CLASS =
TEST_PKG + ".DefaultRestrictionsNonMeteredTest";
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideNetworkCallbackTests.java
similarity index 88%
rename from tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java
rename to tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideNetworkCallbackTests.java
index c4bcdfd..2c2b118 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java
+++ b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideNetworkCallbackTests.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net;
+package com.android.cts.netpolicy;
-import static com.android.cts.net.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
+import static com.android.cts.netpolicy.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
-import com.android.testutils.SkipPresubmit;
+import android.platform.test.annotations.FlakyTest;
import org.junit.After;
import org.junit.Before;
@@ -25,8 +25,8 @@
import java.util.Map;
-@SkipPresubmit(reason = "Out of SLO flakiness")
-public class HostsideNetworkCallbackTests extends HostsideNetworkTestCase {
+@FlakyTest(bugId = 288324467)
+public class HostsideNetworkCallbackTests extends HostsideNetworkPolicyTestCase {
@Before
public void setUp() throws Exception {
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideNetworkPolicyManagerTests.java
similarity index 94%
rename from tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java
rename to tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideNetworkPolicyManagerTests.java
index 4730b14..8ffe360 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java
+++ b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideNetworkPolicyManagerTests.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.net;
+package com.android.cts.netpolicy;
-import static com.android.cts.net.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
+import static com.android.cts.netpolicy.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
import org.junit.After;
import org.junit.Before;
@@ -24,7 +24,7 @@
import java.util.Map;
-public class HostsideNetworkPolicyManagerTests extends HostsideNetworkTestCase {
+public class HostsideNetworkPolicyManagerTests extends HostsideNetworkPolicyTestCase {
@Before
public void setUp() throws Exception {
uninstallPackage(TEST_APP2_PKG, false);
diff --git a/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideNetworkPolicyTestCase.java b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideNetworkPolicyTestCase.java
new file mode 100644
index 0000000..6de6b17
--- /dev/null
+++ b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideNetworkPolicyTestCase.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.netpolicy;
+
+import static com.android.cts.netpolicy.arguments.InstrumentationArguments.ARG_CONNECTION_CHECK_CUSTOM_URL;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import com.android.ddmlib.Log;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.invoker.TestInformation;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.targetprep.suite.SuiteApkInstaller;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
+import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
+import com.android.tradefed.util.RunUtil;
+
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+abstract class HostsideNetworkPolicyTestCase extends BaseHostJUnit4Test {
+ protected static final boolean DEBUG = false;
+ protected static final String TAG = "HostsideNetworkPolicyTests";
+ protected static final String TEST_PKG = "com.android.cts.netpolicy.hostside";
+ protected static final String TEST_APK = "CtsHostsideNetworkPolicyTestsApp.apk";
+ protected static final String TEST_APP2_PKG = "com.android.cts.netpolicy.hostside.app2";
+ protected static final String TEST_APP2_APK = "CtsHostsideNetworkPolicyTestsApp2.apk";
+
+ @Option(name = "custom-url", importance = Option.Importance.IF_UNSET,
+ description = "A custom url to use for testing network connections")
+ protected String mCustomUrl;
+
+ @BeforeClassWithInfo
+ public static void setUpOnceBase(TestInformation testInfo) throws Exception {
+ uninstallPackage(testInfo, TEST_PKG, false);
+ installPackage(testInfo, TEST_APK);
+ }
+
+ @AfterClassWithInfo
+ public static void tearDownOnceBase(TestInformation testInfo)
+ throws DeviceNotAvailableException {
+ uninstallPackage(testInfo, TEST_PKG, true);
+ }
+
+ // Custom static method to install the specified package, this is used to bypass auto-cleanup
+ // per test in BaseHostJUnit4.
+ protected static void installPackage(TestInformation testInfo, String apk)
+ throws DeviceNotAvailableException, TargetSetupError {
+ assertNotNull(testInfo);
+ final int userId = testInfo.getDevice().getCurrentUser();
+ final SuiteApkInstaller installer = new SuiteApkInstaller();
+ // Force the apk clean up
+ installer.setCleanApk(true);
+ installer.addTestFileName(apk);
+ installer.setUserId(userId);
+ installer.setShouldGrantPermission(true);
+ installer.addInstallArg("-t");
+ try {
+ installer.setUp(testInfo);
+ } catch (BuildError e) {
+ throw new TargetSetupError(
+ e.getMessage(), e, testInfo.getDevice().getDeviceDescriptor(), e.getErrorId());
+ }
+ }
+
+ protected void installPackage(String apk) throws DeviceNotAvailableException, TargetSetupError {
+ installPackage(getTestInformation(), apk);
+ }
+
+ protected static void uninstallPackage(TestInformation testInfo, String packageName,
+ boolean shouldSucceed)
+ throws DeviceNotAvailableException {
+ assertNotNull(testInfo);
+ final String result = testInfo.getDevice().uninstallPackage(packageName);
+ if (shouldSucceed) {
+ assertNull("uninstallPackage(" + packageName + ") failed: " + result, result);
+ }
+ }
+
+ protected void uninstallPackage(String packageName,
+ boolean shouldSucceed)
+ throws DeviceNotAvailableException {
+ uninstallPackage(getTestInformation(), packageName, shouldSucceed);
+ }
+
+ protected void assertPackageUninstalled(String packageName) throws DeviceNotAvailableException {
+ final String command = "cmd package list packages " + packageName;
+ final int max_tries = 5;
+ for (int i = 1; i <= max_tries; i++) {
+ final String result = runCommand(command);
+ if (result.trim().isEmpty()) {
+ return;
+ }
+ // 'list packages' filters by substring, so we need to iterate with the results
+ // and check one by one, otherwise 'com.android.cts.netpolicy.hostside' could return
+ // 'com.android.cts.netpolicy.hostside.app2'
+ boolean found = false;
+ for (String line : result.split("[\\r\\n]+")) {
+ if (line.endsWith(packageName)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return;
+ }
+ Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result
+ + "); sleeping 1s before polling again");
+ RunUtil.getDefault().sleep(1000);
+ }
+ fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds");
+ }
+
+ protected int getUid(String packageName) throws DeviceNotAvailableException {
+ final int currentUser = getDevice().getCurrentUser();
+ final String uidLines = runCommand(
+ "cmd package list packages -U --user " + currentUser + " " + packageName);
+ for (String uidLine : uidLines.split("\n")) {
+ if (uidLine.startsWith("package:" + packageName + " uid:")) {
+ final String[] uidLineParts = uidLine.split(":");
+ // 3rd entry is package uid
+ return Integer.parseInt(uidLineParts[2].trim());
+ }
+ }
+ throw new IllegalStateException("Failed to find the test app on the device; pkg="
+ + packageName + ", u=" + currentUser);
+ }
+
+ protected boolean runDeviceTestsWithCustomOptions(String packageName, String className)
+ throws DeviceNotAvailableException {
+ return runDeviceTestsWithCustomOptions(packageName, className, null);
+ }
+
+ protected boolean runDeviceTestsWithCustomOptions(String packageName, String className,
+ String methodName) throws DeviceNotAvailableException {
+ return runDeviceTestsWithCustomOptions(packageName, className, methodName, null);
+ }
+
+ protected boolean runDeviceTestsWithCustomOptions(String packageName, String className,
+ String methodName, Map<String, String> testArgs) throws DeviceNotAvailableException {
+ final DeviceTestRunOptions deviceTestRunOptions = new DeviceTestRunOptions(packageName)
+ .setTestClassName(className)
+ .setTestMethodName(methodName);
+
+ // Currently there is only one custom option that the test exposes.
+ if (mCustomUrl != null) {
+ deviceTestRunOptions.addInstrumentationArg(ARG_CONNECTION_CHECK_CUSTOM_URL, mCustomUrl);
+ }
+ // Pass over any test specific arguments.
+ if (testArgs != null) {
+ for (Map.Entry<String, String> arg : testArgs.entrySet()) {
+ deviceTestRunOptions.addInstrumentationArg(arg.getKey(), arg.getValue());
+ }
+ }
+ return runDeviceTests(deviceTestRunOptions);
+ }
+
+ protected String runCommand(String command) throws DeviceNotAvailableException {
+ Log.d(TAG, "Command: '" + command + "'");
+ final String output = getDevice().executeShellCommand(command);
+ if (DEBUG) Log.v(TAG, "Output: " + output.trim());
+ return output;
+ }
+}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideRestrictBackgroundNetworkTests.java
similarity index 98%
rename from tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
rename to tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideRestrictBackgroundNetworkTests.java
index 7b9d3b5..0261c7d 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/HostsideRestrictBackgroundNetworkTests.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.cts.net;
+package com.android.cts.netpolicy;
import static org.junit.Assert.fail;
+import android.platform.test.annotations.FlakyTest;
import android.platform.test.annotations.SecurityTest;
import com.android.ddmlib.Log;
-import com.android.testutils.SkipPresubmit;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.util.RunUtil;
@@ -29,8 +29,8 @@
import org.junit.Before;
import org.junit.Test;
-@SkipPresubmit(reason = "Out of SLO flakiness")
-public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase {
+@FlakyTest(bugId = 288324467)
+public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkPolicyTestCase {
@Before
public void setUp() throws Exception {
diff --git a/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/NetworkPolicyTestsPreparer.java
similarity index 98%
rename from tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java
rename to tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/NetworkPolicyTestsPreparer.java
index 23aca24..cbf2f4d 100644
--- a/tests/cts/hostside/src/com/android/cts/net/NetworkPolicyTestsPreparer.java
+++ b/tests/cts/hostside-network-policy/src/com/android/cts/netpolicy/NetworkPolicyTestsPreparer.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.net;
+package com.android.cts.netpolicy;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp
index f6c0430..14d5d54 100644
--- a/tests/cts/hostside/Android.bp
+++ b/tests/cts/hostside/Android.bp
@@ -29,7 +29,6 @@
// Only compile source java files in this apk.
srcs: [
"src/**/*.java",
- ":ArgumentConstants",
],
libs: [
"net-tests-utils-host-device-common",
diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml
index 0ffe81e..ea6b078 100644
--- a/tests/cts/hostside/AndroidTest.xml
+++ b/tests/cts/hostside/AndroidTest.xml
@@ -22,7 +22,6 @@
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
- <target_preparer class="com.android.cts.net.NetworkPolicyTestsPreparer" />
<!-- Enabling change id ALLOW_TEST_API_ACCESS allows that package to access @TestApi methods -->
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
@@ -30,7 +29,6 @@
<option name="teardown-command" value="am compat reset ALLOW_TEST_API_ACCESS com.android.cts.net.hostside.app2" />
<option name="teardown-command" value="cmd power set-mode 0" />
<option name="teardown-command" value="cmd battery reset" />
- <option name="teardown-command" value="cmd netpolicy stop-watching" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
diff --git a/tests/cts/hostside/OWNERS b/tests/cts/hostside/OWNERS
deleted file mode 100644
index 20bc55e..0000000
--- a/tests/cts/hostside/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 61373
-# Inherits parent owners
-sudheersai@google.com
-jchalard@google.com
diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp
index cf4afa9..919e025 100644
--- a/tests/cts/hostside/app/Android.bp
+++ b/tests/cts/hostside/app/Android.bp
@@ -38,7 +38,6 @@
],
srcs: [
"src/**/*.java",
- ":ArgumentConstants",
],
// Tag this module as a cts test artifact
test_suites: [
diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml
index ca3397b..e0f4cdc 100644
--- a/tests/cts/hostside/app/AndroidManifest.xml
+++ b/tests/cts/hostside/app/AndroidManifest.xml
@@ -43,14 +43,6 @@
<action android:name="android.net.VpnService"/>
</intent-filter>
</service>
- <service android:name=".MyNotificationListenerService"
- android:label="MyNotificationListenerService"
- android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
- android:exported="true">
- <intent-filter>
- <action android:name="android.service.notification.NotificationListenerService"/>
- </intent-filter>
- </service>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
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 8e7b3d4..50d6e76 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
@@ -124,6 +124,7 @@
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.PacketBuilder;
import com.android.testutils.AutoReleaseNetworkCallbackRule;
+import com.android.testutils.ConnectUtil;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.RecorderCallback;
@@ -221,6 +222,7 @@
private WifiManager mWifiManager;
private RemoteSocketFactoryClient mRemoteSocketFactoryClient;
private CtsNetUtils mCtsNetUtils;
+ private ConnectUtil mConnectUtil;
private PackageManager mPackageManager;
private Context mTestContext;
private Context mTargetContext;
@@ -270,6 +272,7 @@
mRemoteSocketFactoryClient.bind();
mDevice.waitForIdle();
mCtsNetUtils = new CtsNetUtils(mTestContext);
+ mConnectUtil = new ConnectUtil(mTestContext);
mPackageManager = mTestContext.getPackageManager();
assumeTrue(supportedHardware());
}
@@ -893,7 +896,7 @@
final boolean isWifiEnabled = mWifiManager.isWifiEnabled();
testAndCleanup(() -> {
// Ensure both of wifi and mobile data are connected.
- final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+ final Network wifiNetwork = mConnectUtil.ensureWifiValidated();
final Network cellNetwork = mNetworkCallbackRule.requestCell();
// Store current default network.
final Network defaultNetwork = mCM.getActiveNetwork();
@@ -1940,7 +1943,7 @@
.build();
final CtsNetUtils.TestNetworkCallback callback = new CtsNetUtils.TestNetworkCallback();
mCM.requestNetwork(request, callback);
- final FileDescriptor srcTunFd = runWithShellPermissionIdentity(() -> {
+ final ParcelFileDescriptor srcTunFd = runWithShellPermissionIdentity(() -> {
final TestNetworkManager tnm = mTestContext.getSystemService(TestNetworkManager.class);
List<LinkAddress> linkAddresses = duplicatedAddress
? List.of(new LinkAddress("192.0.2.2/24"),
@@ -1949,7 +1952,7 @@
new LinkAddress("2001:db8:3:4::ffe/64"));
final TestNetworkInterface iface = tnm.createTunInterface(linkAddresses);
tnm.setupTestNetwork(iface.getInterfaceName(), new Binder());
- return iface.getFileDescriptor().getFileDescriptor();
+ return iface.getFileDescriptor();
}, MANAGE_TEST_NETWORKS);
final Network testNetwork = callback.waitForAvailable();
assertNotNull(testNetwork);
@@ -1963,11 +1966,11 @@
false /* isAlwaysMetered */);
final FileDescriptor dstUdpFd = dstSock.getFileDescriptor$();
- checkBlockUdp(srcTunFd, dstUdpFd,
+ checkBlockUdp(srcTunFd.getFileDescriptor(), dstUdpFd,
InetAddresses.parseNumericAddress("192.0.2.2") /* dstAddress */,
InetAddresses.parseNumericAddress("192.0.2.1") /* srcAddress */,
duplicatedAddress ? EXPECT_PASS : EXPECT_BLOCK);
- checkBlockUdp(srcTunFd, dstUdpFd,
+ checkBlockUdp(srcTunFd.getFileDescriptor(), dstUdpFd,
InetAddresses.parseNumericAddress("2001:db8:1:2::ffe") /* dstAddress */,
InetAddresses.parseNumericAddress("2001:db8:1:2::ffa") /* srcAddress */,
duplicatedAddress ? EXPECT_PASS : EXPECT_BLOCK);
@@ -1975,7 +1978,7 @@
// Traffic on VPN should not be affected
checkTrafficOnVpn();
}, /* cleanup */ () -> {
- Os.close(srcTunFd);
+ srcTunFd.close();
dstSock.close();
}, /* cleanup */ () -> {
runWithShellPermissionIdentity(() -> {
diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp
index c526172..ad25562 100644
--- a/tests/cts/hostside/app2/Android.bp
+++ b/tests/cts/hostside/app2/Android.bp
@@ -35,5 +35,4 @@
"general-tests",
"sts",
],
- certificate: ":cts-net-app",
}
diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml
index 2c2d957..412b307 100644
--- a/tests/cts/hostside/app2/AndroidManifest.xml
+++ b/tests/cts/hostside/app2/AndroidManifest.xml
@@ -40,33 +40,8 @@
<application android:usesCleartextTraffic="true"
android:testOnly="true"
android:debuggable="true">
-
- <activity android:name=".MyActivity"
- android:exported="true"/>
- <service android:name=".MyService"
- android:exported="true"/>
- <service android:name=".MyForegroundService"
- android:foregroundServiceType="specialUse"
- android:exported="true">
- <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
- android:value="Connectivity" />
- </service>
<service android:name=".RemoteSocketFactoryService"
android:exported="true"/>
-
- <receiver android:name=".MyBroadcastReceiver"
- android:exported="true">
- <intent-filter>
- <action android:name="android.net.conn.RESTRICT_BACKGROUND_CHANGED"/>
- <action android:name="com.android.cts.net.hostside.app2.action.GET_COUNTERS"/>
- <action android:name="com.android.cts.net.hostside.app2.action.GET_RESTRICT_BACKGROUND_STATUS"/>
- <action android:name="com.android.cts.net.hostside.app2.action.CHECK_NETWORK"/>
- <action android:name="com.android.cts.net.hostside.app2.action.SEND_NOTIFICATION"/>
- <action android:name="com.android.cts.net.hostside.app2.action.SHOW_TOAST"/>
- </intent-filter>
- </receiver>
- <service android:name=".MyJobService"
- android:permission="android.permission.BIND_JOB_SERVICE" />
</application>
<!--
diff --git a/tests/cts/hostside/certs/Android.bp b/tests/cts/hostside/certs/Android.bp
deleted file mode 100644
index 301973e..0000000
--- a/tests/cts/hostside/certs/Android.bp
+++ /dev/null
@@ -1,9 +0,0 @@
-package {
- default_team: "trendy_team_fwk_core_networking",
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_app_certificate {
- name: "cts-net-app",
- certificate: "cts-net-app",
-}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java
index d7dfa80..69d61b3 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java
@@ -16,15 +16,10 @@
package com.android.cts.net;
-import static com.android.cts.net.arguments.InstrumentationArguments.ARG_CONNECTION_CHECK_CUSTOM_URL;
-
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-import com.android.ddmlib.Log;
import com.android.modules.utils.build.testing.DeviceSdkLevel;
-import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.invoker.TestInformation;
import com.android.tradefed.targetprep.BuildError;
@@ -34,27 +29,17 @@
import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
-import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
-import com.android.tradefed.util.RunUtil;
import org.junit.runner.RunWith;
-import java.util.Map;
-
@RunWith(DeviceJUnit4ClassRunner.class)
abstract class HostsideNetworkTestCase extends BaseHostJUnit4Test {
- protected static final boolean DEBUG = false;
- protected static final String TAG = "HostsideNetworkTests";
protected static final String TEST_PKG = "com.android.cts.net.hostside";
protected static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk";
protected static final String TEST_APK_NEXT = "CtsHostsideNetworkTestsAppNext.apk";
protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2";
protected static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk";
- @Option(name = "custom-url", importance = Option.Importance.IF_UNSET,
- description = "A custom url to use for testing network connections")
- protected String mCustomUrl;
-
@BeforeClassWithInfo
public static void setUpOnceBase(TestInformation testInfo) throws Exception {
DeviceSdkLevel deviceSdkLevel = new DeviceSdkLevel(testInfo.getDevice());
@@ -110,85 +95,4 @@
throws DeviceNotAvailableException {
uninstallPackage(getTestInformation(), packageName, shouldSucceed);
}
-
- protected void assertPackageUninstalled(String packageName) throws DeviceNotAvailableException,
- InterruptedException {
- final String command = "cmd package list packages " + packageName;
- final int max_tries = 5;
- for (int i = 1; i <= max_tries; i++) {
- final String result = runCommand(command);
- if (result.trim().isEmpty()) {
- return;
- }
- // 'list packages' filters by substring, so we need to iterate with the results
- // and check one by one, otherwise 'com.android.cts.net.hostside' could return
- // 'com.android.cts.net.hostside.app2'
- boolean found = false;
- for (String line : result.split("[\\r\\n]+")) {
- if (line.endsWith(packageName)) {
- found = true;
- break;
- }
- }
- if (!found) {
- return;
- }
- i++;
- Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result
- + "); sleeping 1s before polling again");
- RunUtil.getDefault().sleep(1000);
- }
- fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds");
- }
-
- protected int getUid(String packageName) throws DeviceNotAvailableException {
- final int currentUser = getDevice().getCurrentUser();
- final String uidLines = runCommand(
- "cmd package list packages -U --user " + currentUser + " " + packageName);
- for (String uidLine : uidLines.split("\n")) {
- if (uidLine.startsWith("package:" + packageName + " uid:")) {
- final String[] uidLineParts = uidLine.split(":");
- // 3rd entry is package uid
- return Integer.parseInt(uidLineParts[2].trim());
- }
- }
- throw new IllegalStateException("Failed to find the test app on the device; pkg="
- + packageName + ", u=" + currentUser);
- }
-
- protected boolean runDeviceTestsWithCustomOptions(String packageName, String className)
- throws DeviceNotAvailableException {
- return runDeviceTestsWithCustomOptions(packageName, className, null);
- }
-
- protected boolean runDeviceTestsWithCustomOptions(String packageName, String className,
- String methodName) throws DeviceNotAvailableException {
- return runDeviceTestsWithCustomOptions(packageName, className, methodName, null);
- }
-
- protected boolean runDeviceTestsWithCustomOptions(String packageName, String className,
- String methodName, Map<String, String> testArgs) throws DeviceNotAvailableException {
- final DeviceTestRunOptions deviceTestRunOptions = new DeviceTestRunOptions(packageName)
- .setTestClassName(className)
- .setTestMethodName(methodName);
-
- // Currently there is only one custom option that the test exposes.
- if (mCustomUrl != null) {
- deviceTestRunOptions.addInstrumentationArg(ARG_CONNECTION_CHECK_CUSTOM_URL, mCustomUrl);
- }
- // Pass over any test specific arguments.
- if (testArgs != null) {
- for (Map.Entry<String, String> arg : testArgs.entrySet()) {
- deviceTestRunOptions.addInstrumentationArg(arg.getKey(), arg.getValue());
- }
- }
- return runDeviceTests(deviceTestRunOptions);
- }
-
- protected String runCommand(String command) throws DeviceNotAvailableException {
- Log.d(TAG, "Command: '" + command + "'");
- final String output = getDevice().executeShellCommand(command);
- if (DEBUG) Log.v(TAG, "Output: " + output.trim());
- return output;
- }
}
diff --git a/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt b/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt
index c883b78..258648f 100644
--- a/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt
+++ b/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt
@@ -64,9 +64,7 @@
fun hasTelephonyFeature() = pm.hasSystemFeature(FEATURE_TELEPHONY)
@Rpc(description = "Check whether the device supporters AP + STA concurrency.")
- fun isStaApConcurrencySupported() {
- wifiManager.isStaApConcurrencySupported()
- }
+ fun isStaApConcurrencySupported() = wifiManager.isStaApConcurrencySupported()
@Rpc(description = "Request cellular connection and ensure it is the default network.")
fun requestCellularAndEnsureDefault() {
diff --git a/tests/cts/net/native/src/BpfCompatTest.cpp b/tests/cts/net/native/src/BpfCompatTest.cpp
index 5c02b0d..e2fdd3d 100644
--- a/tests/cts/net/native/src/BpfCompatTest.cpp
+++ b/tests/cts/net/native/src/BpfCompatTest.cpp
@@ -27,35 +27,32 @@
using namespace android::bpf;
-void doBpfStructSizeTest(const char *elfPath) {
+void doBpfStructSizeTest(const char *elfPath, unsigned mapSz, unsigned progSz) {
std::ifstream elfFile(elfPath, std::ios::in | std::ios::binary);
ASSERT_TRUE(elfFile.is_open());
- if (android::modules::sdklevel::IsAtLeastU()) {
- EXPECT_EQ(120, readSectionUint("size_of_bpf_map_def", elfFile, 0));
- EXPECT_EQ(92, readSectionUint("size_of_bpf_prog_def", elfFile, 0));
- } else if (android::modules::sdklevel::IsAtLeastT()) {
- EXPECT_EQ(116, readSectionUint("size_of_bpf_map_def", elfFile, 0));
- EXPECT_EQ(92, readSectionUint("size_of_bpf_prog_def", elfFile, 0));
- } else {
- EXPECT_EQ(48, readSectionUint("size_of_bpf_map_def", elfFile, 0));
- EXPECT_EQ(28, readSectionUint("size_of_bpf_prog_def", elfFile, 0));
- }
-}
-
-TEST(BpfTest, bpfStructSizeTestPreT) {
- if (android::modules::sdklevel::IsAtLeastT()) GTEST_SKIP() << "T+ device.";
- doBpfStructSizeTest("/system/etc/bpf/netd.o");
- doBpfStructSizeTest("/system/etc/bpf/clatd.o");
+ EXPECT_EQ(mapSz, readSectionUint("size_of_bpf_map_def", elfFile, 0));
+ EXPECT_EQ(progSz, readSectionUint("size_of_bpf_prog_def", elfFile, 0));
}
TEST(BpfTest, bpfStructSizeTest) {
- if (android::modules::sdklevel::IsAtLeastU()) {
- doBpfStructSizeTest("/system/etc/bpf/gpuMem.o");
- doBpfStructSizeTest("/system/etc/bpf/timeInState.o");
+ if (android::modules::sdklevel::IsAtLeastV()) {
+ // Due to V+ using mainline netbpfload, there is no longer a need to
+ // enforce consistency between platform and mainline bpf .o files.
+ GTEST_SKIP() << "V+ device.";
+ } else if (android::modules::sdklevel::IsAtLeastU()) {
+ doBpfStructSizeTest("/system/etc/bpf/gpuMem.o", 120, 92);
+ doBpfStructSizeTest("/system/etc/bpf/timeInState.o", 120, 92);
+ } else if (android::modules::sdklevel::IsAtLeastT()) {
+ doBpfStructSizeTest("/system/etc/bpf/gpu_mem.o", 116, 92);
+ doBpfStructSizeTest("/system/etc/bpf/time_in_state.o", 116, 92);
+ } else if (android::modules::sdklevel::IsAtLeastS()) {
+ // These files were moved to mainline in Android T
+ doBpfStructSizeTest("/system/etc/bpf/netd.o", 48, 28);
+ doBpfStructSizeTest("/system/etc/bpf/clatd.o", 48, 28);
} else {
- doBpfStructSizeTest("/system/etc/bpf/gpu_mem.o");
- doBpfStructSizeTest("/system/etc/bpf/time_in_state.o");
+ // There is no mainline bpf code before S.
+ GTEST_SKIP() << "R- device.";
}
}
diff --git a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
index 1a535b4..a679498 100644
--- a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
+++ b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
@@ -26,9 +26,9 @@
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.net.apf.ApfCapabilities
-import android.net.apf.ApfConstant.ETH_ETHERTYPE_OFFSET
-import android.net.apf.ApfConstant.ICMP6_TYPE_OFFSET
-import android.net.apf.ApfConstant.IPV6_NEXT_HEADER_OFFSET
+import android.net.apf.ApfConstants.ETH_ETHERTYPE_OFFSET
+import android.net.apf.ApfConstants.ICMP6_TYPE_OFFSET
+import android.net.apf.ApfConstants.IPV6_NEXT_HEADER_OFFSET
import android.net.apf.ApfV4Generator
import android.net.apf.BaseApfGenerator
import android.net.apf.BaseApfGenerator.MemorySlot
@@ -313,18 +313,20 @@
// - [GMS-VSR-5.3.12-004] MUST indicate at least 1024 bytes of usable memory from calls to
// the getApfPacketFilterCapabilities HAL method.
// TODO: check whether above text should be changed "34 or higher"
- // This should assert apfVersionSupported >= 4 as per the VSR requirements, but there are
- // currently no tests for APFv6 and there cannot be a valid implementation as the
- // interpreter has yet to be finalized.
- assertThat(caps.apfVersionSupported).isEqualTo(4)
+ assertThat(caps.apfVersionSupported).isAtLeast(4)
assertThat(caps.maximumApfProgramSize).isAtLeast(1024)
+ if (caps.apfVersionSupported > 4) {
+ assertThat(caps.maximumApfProgramSize).isAtLeast(2048)
+ assertThat(caps.apfVersionSupported).isEqualTo(6000) // v6.0000
+ }
+
// DEVICEs launching with Android 15 (AOSP experimental) or higher with CHIPSETs that set
// ro.board.first_api_level or ro.board.api_level to 202404 or higher:
- // - [GMS-VSR-5.3.12-009] MUST indicate at least 2000 bytes of usable memory from calls to
+ // - [GMS-VSR-5.3.12-009] MUST indicate at least 2048 bytes of usable memory from calls to
// the getApfPacketFilterCapabilities HAL method.
if (getVsrApiLevel() >= 202404) {
- assertThat(caps.maximumApfProgramSize).isAtLeast(2000)
+ assertThat(caps.maximumApfProgramSize).isAtLeast(2048)
}
}
@@ -419,14 +421,15 @@
packetReader.expectPingDropped()
}
+ fun clearApfMemory() = installProgram(ByteArray(caps.maximumApfProgramSize))
+
// APF integration is mostly broken before V
@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Test
fun testPrefilledMemorySlotsV4() {
// Test v4 memory slots on both v4 and v6 interpreters.
assumeApfVersionSupportAtLeast(4)
- // Clear the entire memory before starting this test
- installProgram(ByteArray(caps.maximumApfProgramSize))
+ clearApfMemory()
val gen = ApfV4Generator(4)
// If not ICMPv6 Echo Reply -> PASS
@@ -457,8 +460,7 @@
packetReader.expectPingReply()
val readResult = readProgram()
- val buffer = ByteBuffer.wrap(readResult)
- buffer.position(counterRegion)
+ val buffer = ByteBuffer.wrap(readResult, counterRegion, 20 /* length */)
expect.withMessage("PROGRAM_SIZE").that(buffer.getInt()).isEqualTo(program.size)
expect.withMessage("RAM_LEN").that(buffer.getInt()).isEqualTo(caps.maximumApfProgramSize)
expect.withMessage("IPV4_HEADER_SIZE").that(buffer.getInt()).isEqualTo(0)
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
index b703f77..b5f43d3 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -69,9 +69,11 @@
import android.net.IpSecManager.SecurityParameterIndex;
import android.net.IpSecManager.UdpEncapsulationSocket;
import android.net.IpSecTransform;
+import android.net.IpSecTransformState;
import android.net.NetworkUtils;
import android.net.TrafficStats;
import android.os.Build;
+import android.os.OutcomeReceiver;
import android.platform.test.annotations.AppModeFull;
import android.system.ErrnoException;
import android.system.Os;
@@ -101,6 +103,9 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
@ConnectivityModuleTest
@RunWith(AndroidJUnit4.class)
@@ -1654,4 +1659,37 @@
newReplayBitmap(expectedPacketCount));
}
}
+
+ @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Test
+ public void testRequestIpSecTransformStateOnClosedTransform() throws Exception {
+ assumeRequestIpSecTransformStateSupported();
+
+ final InetAddress localAddr = InetAddresses.parseNumericAddress(IPV6_LOOPBACK);
+ final CompletableFuture<RuntimeException> futureError = new CompletableFuture<>();
+
+ try (SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(localAddr);
+ IpSecTransform transform =
+ buildTransportModeTransform(spi, localAddr, null /* encapSocket*/)) {
+ transform.close();
+
+ transform.requestIpSecTransformState(
+ Executors.newSingleThreadExecutor(),
+ new OutcomeReceiver<IpSecTransformState, RuntimeException>() {
+ @Override
+ public void onResult(IpSecTransformState state) {
+ fail("Expect to fail but received a state");
+ }
+
+ @Override
+ public void onError(RuntimeException error) {
+ futureError.complete(error);
+ }
+ });
+
+ assertTrue(
+ futureError.get(SOCK_TIMEOUT, TimeUnit.MILLISECONDS)
+ instanceof IllegalStateException);
+ }
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java
index 6ec4e62..5b53839 100644
--- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java
+++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java
@@ -68,6 +68,7 @@
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -511,7 +512,7 @@
assertArrayEquals(netCapabilities, nr.getCapabilities());
}
- @Test @IgnoreUpTo(VANILLA_ICE_CREAM)
+ @Test @IgnoreUpTo(VANILLA_ICE_CREAM) @Ignore("b/338200742")
public void testDefaultCapabilities() {
final NetworkRequest defaultNR = new NetworkRequest.Builder().build();
assertTrue(defaultNR.hasForbiddenCapability(NET_CAPABILITY_LOCAL_NETWORK));
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index 670889f..0dd2a23 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -93,7 +93,7 @@
private static final int SOCKET_TIMEOUT_MS = 10_000;
private static final int PRIVATE_DNS_PROBE_MS = 1_000;
- private static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 10_000;
+ private static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 30_000;
private static final int CONNECTIVITY_CHANGE_TIMEOUT_SECS = 30;
private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index fa79795..cbc060a 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.net.BpfNetMapsConstants.ALLOW_CHAINS;
+import static android.net.BpfNetMapsConstants.BACKGROUND_MATCH;
import static android.net.BpfNetMapsConstants.CURRENT_STATS_MAP_CONFIGURATION_KEY;
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY;
import static android.net.BpfNetMapsConstants.DATA_SAVER_DISABLED;
@@ -37,6 +38,14 @@
import static android.net.BpfNetMapsConstants.RESTRICTED_MATCH;
import static android.net.BpfNetMapsConstants.STANDBY_MATCH;
import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_ADMIN_DISABLED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_OEM_DENY;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
@@ -839,6 +848,21 @@
}
@Test
+ @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
+ public void testGetNetPermFoUid() throws Exception {
+ mUidPermissionMap.deleteEntry(new S32(TEST_UID));
+ assertEquals(PERMISSION_INTERNET, mBpfNetMaps.getNetPermForUid(TEST_UID));
+
+ mUidPermissionMap.updateEntry(new S32(TEST_UID), new U8((short) PERMISSION_NONE));
+ assertEquals(PERMISSION_NONE, mBpfNetMaps.getNetPermForUid(TEST_UID));
+
+ mUidPermissionMap.updateEntry(new S32(TEST_UID),
+ new U8((short) (PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)));
+ assertEquals(PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS,
+ mBpfNetMaps.getNetPermForUid(TEST_UID));
+ }
+
+ @Test
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testSwapActiveStatsMap() throws Exception {
mConfigurationMap.updateEntry(
@@ -1150,4 +1174,138 @@
assertDumpContains(dump, TEST_V6_ADDRESS.getHostAddress());
assertDumpContains(dump, TEST_IF_INDEX + "(" + TEST_IF_NAME + ")");
}
+
+ private void doTestGetUidNetworkingBlockedReasons(
+ final long configurationMatches,
+ final long uidRules,
+ final short dataSaverStatus,
+ final int expectedBlockedReasons
+ ) throws Exception {
+ mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(configurationMatches));
+ mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(NULL_IIF, uidRules));
+ mDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(dataSaverStatus));
+
+ assertEquals(expectedBlockedReasons, mBpfNetMaps.getUidNetworkingBlockedReasons(TEST_UID));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testGetUidNetworkingBlockedReasons() throws Exception {
+ doTestGetUidNetworkingBlockedReasons(
+ NO_MATCH,
+ NO_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_REASON_NONE
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ DOZABLE_MATCH,
+ NO_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_REASON_DOZE
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ DOZABLE_MATCH | POWERSAVE_MATCH | STANDBY_MATCH,
+ DOZABLE_MATCH | STANDBY_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_APP_STANDBY
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ OEM_DENY_1_MATCH | OEM_DENY_2_MATCH | OEM_DENY_3_MATCH,
+ OEM_DENY_1_MATCH | OEM_DENY_3_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_REASON_OEM_DENY
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ DOZABLE_MATCH,
+ DOZABLE_MATCH | BACKGROUND_MATCH | STANDBY_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_REASON_NONE
+ );
+
+ // Note that HAPPY_BOX and PENALTY_BOX are not disabled by configuration map
+ doTestGetUidNetworkingBlockedReasons(
+ NO_MATCH,
+ PENALTY_BOX_USER_MATCH,
+ DATA_SAVER_DISABLED,
+ BLOCKED_METERED_REASON_USER_RESTRICTED
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ NO_MATCH,
+ PENALTY_BOX_ADMIN_MATCH,
+ DATA_SAVER_ENABLED,
+ BLOCKED_METERED_REASON_ADMIN_DISABLED | BLOCKED_METERED_REASON_DATA_SAVER
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ NO_MATCH,
+ PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH | HAPPY_BOX_MATCH,
+ DATA_SAVER_ENABLED,
+ BLOCKED_METERED_REASON_USER_RESTRICTED | BLOCKED_METERED_REASON_ADMIN_DISABLED
+ );
+ doTestGetUidNetworkingBlockedReasons(
+ STANDBY_MATCH,
+ STANDBY_MATCH | PENALTY_BOX_USER_MATCH | HAPPY_BOX_MATCH,
+ DATA_SAVER_ENABLED,
+ BLOCKED_REASON_APP_STANDBY | BLOCKED_METERED_REASON_USER_RESTRICTED
+ );
+ }
+
+ private void doTestIsUidRestrictedOnMeteredNetworks(
+ final long enabledMatches,
+ final long uidRules,
+ final short dataSaver,
+ final boolean expectedRestricted
+ ) throws Exception {
+ mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(enabledMatches));
+ mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(NULL_IIF, uidRules));
+ mDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(dataSaver));
+
+ assertEquals(expectedRestricted, mBpfNetMaps.isUidRestrictedOnMeteredNetworks(TEST_UID));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testIsUidRestrictedOnMeteredNetworks() throws Exception {
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ NO_MATCH,
+ DATA_SAVER_DISABLED,
+ false /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ DOZABLE_MATCH | POWERSAVE_MATCH | STANDBY_MATCH,
+ DOZABLE_MATCH | STANDBY_MATCH ,
+ DATA_SAVER_DISABLED,
+ false /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ PENALTY_BOX_USER_MATCH,
+ DATA_SAVER_DISABLED,
+ true /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ PENALTY_BOX_ADMIN_MATCH,
+ DATA_SAVER_DISABLED,
+ true /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH | HAPPY_BOX_MATCH,
+ DATA_SAVER_DISABLED,
+ true /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ NO_MATCH,
+ DATA_SAVER_ENABLED,
+ true /* expectRestricted */
+ );
+ doTestIsUidRestrictedOnMeteredNetworks(
+ NO_MATCH,
+ HAPPY_BOX_MATCH,
+ DATA_SAVER_ENABLED,
+ false /* expectRestricted */
+ );
+ }
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index aee40c8..b6cb09b 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -87,6 +87,7 @@
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.INetd.PERMISSION_INTERNET;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
@@ -151,6 +152,7 @@
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
import static android.net.Proxy.PROXY_CHANGE_ACTION;
import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.net.connectivity.ConnectivityCompatChanges.NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
@@ -803,8 +805,10 @@
// This relies on all contexts for a given user returning the same UM mock
final DevicePolicyManager dpmMock = createContextAsUser(userHandle, 0 /* flags */)
.getSystemService(DevicePolicyManager.class);
- doReturn(value).when(dpmMock).getDeviceOwner();
- doReturn(value).when(mDevicePolicyManager).getDeviceOwner();
+ ComponentName componentName = value == null
+ ? null : new ComponentName(value, "deviceOwnerClass");
+ doReturn(componentName).when(dpmMock).getDeviceOwnerComponentOnAnyUser();
+ doReturn(componentName).when(mDevicePolicyManager).getDeviceOwnerComponentOnAnyUser();
}
@Override
@@ -1725,6 +1729,8 @@
private void mockUidNetworkingBlocked() {
doAnswer(i -> isUidBlocked(mBlockedReasons, i.getArgument(1))
).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
+ doAnswer(i -> isUidBlocked(mBlockedReasons, i.getArgument(1))
+ ).when(mBpfNetMaps).isUidNetworkingBlocked(anyInt(), anyBoolean());
}
private boolean isUidBlocked(int blockedReasons, boolean meteredNetwork) {
@@ -1941,6 +1947,10 @@
setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
setAlwaysOnNetworks(false);
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
+
+ mDeps.setChangeIdEnabled(
+ true, NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION, Process.myUid());
+ doReturn(PERMISSION_INTERNET).when(mBpfNetMaps).getNetPermForUid(anyInt());
// Note : Please do not add any new instrumentation here. If you need new instrumentation,
// please add it in CSTest and use subclasses of CSTest instead of adding more
// tools in ConnectivityServiceTest.
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index da7fda3..72dde7f 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -38,6 +38,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -418,21 +419,6 @@
inOrder.verify(mDeps).generateIpv6Address(eq(BASE_IFACE),
eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(NAT64_PREFIX_STRING), eq(MARK));
- // Open, configure and bring up the tun interface.
- inOrder.verify(mDeps).createTunInterface(eq(STACKED_IFACE));
- inOrder.verify(mDeps).adoptFd(eq(TUN_FD));
- inOrder.verify(mDeps).getInterfaceIndex(eq(STACKED_IFACE));
- inOrder.verify(mNetd).interfaceSetEnableIPv6(eq(STACKED_IFACE), eq(false /* enable */));
- inOrder.verify(mDeps).detectMtu(eq(NAT64_PREFIX_STRING), eq(GOOGLE_DNS_4), eq(MARK));
- inOrder.verify(mNetd).interfaceSetMtu(eq(STACKED_IFACE),
- eq(1472 /* ETHER_MTU(1500) - MTU_DELTA(28) */));
- inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
- STACKED_IFACE.equals(cfg.ifName)
- && XLAT_LOCAL_IPV4ADDR_STRING.equals(cfg.ipv4Addr)
- && (32 == cfg.prefixLength)
- && "".equals(cfg.hwAddr)
- && assertContainsFlag(cfg.flags, IF_STATE_UP)));
-
// Open and configure 464xlat read/write sockets.
inOrder.verify(mDeps).openPacketSocket();
inOrder.verify(mDeps).adoptFd(eq(PACKET_SOCK_FD));
@@ -449,6 +435,21 @@
argThat(fd -> Objects.equals(PACKET_SOCK_PFD.getFileDescriptor(), fd)),
eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(BASE_IFINDEX));
+ // Open, configure and bring up the tun interface.
+ inOrder.verify(mDeps).createTunInterface(eq(STACKED_IFACE));
+ inOrder.verify(mDeps).adoptFd(eq(TUN_FD));
+ inOrder.verify(mDeps).getInterfaceIndex(eq(STACKED_IFACE));
+ inOrder.verify(mNetd).interfaceSetEnableIPv6(eq(STACKED_IFACE), eq(false /* enable */));
+ inOrder.verify(mDeps).detectMtu(eq(NAT64_PREFIX_STRING), eq(GOOGLE_DNS_4), eq(MARK));
+ inOrder.verify(mNetd).interfaceSetMtu(eq(STACKED_IFACE),
+ eq(1472 /* ETHER_MTU(1500) - MTU_DELTA(28) */));
+ inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
+ STACKED_IFACE.equals(cfg.ifName)
+ && XLAT_LOCAL_IPV4ADDR_STRING.equals(cfg.ipv4Addr)
+ && (32 == cfg.prefixLength)
+ && "".equals(cfg.hwAddr)
+ && assertContainsFlag(cfg.flags, IF_STATE_UP)));
+
// Start clatd.
inOrder.verify(mDeps).startClatd(
argThat(fd -> Objects.equals(TUN_PFD.getFileDescriptor(), fd)),
@@ -630,9 +631,13 @@
public int createTunInterface(@NonNull String tuniface) throws IOException {
throw new IOException();
}
+ @Override
+ public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
+ return mock(IBpfMap.class);
+ }
}
checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
- false /* needToClosePacketSockFd */, false /* needToCloseRawSockFd */);
+ true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
@Test
@@ -643,9 +648,14 @@
throws IOException {
throw new IOException();
}
+
+ @Override
+ public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
+ return mock(IBpfMap.class);
+ }
}
checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
- false /* needToClosePacketSockFd */, false /* needToCloseRawSockFd */);
+ true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
@Test
@@ -656,7 +666,7 @@
throw new IOException();
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
false /* needToClosePacketSockFd */, false /* needToCloseRawSockFd */);
}
@@ -668,7 +678,7 @@
throw new IOException();
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
true /* needToClosePacketSockFd */, false /* needToCloseRawSockFd */);
}
@@ -681,7 +691,7 @@
throw new IOException();
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
@@ -694,7 +704,7 @@
throw new IOException();
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
@@ -721,7 +731,7 @@
throw new IOException();
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
@@ -733,7 +743,7 @@
return null;
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
}
diff --git a/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java b/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
index 44512bb..ea3d2dd 100644
--- a/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
@@ -29,8 +29,6 @@
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
-import static com.android.testutils.MiscAsserts.assertContainsExactly;
-import static com.android.testutils.MiscAsserts.assertContainsStringsExactly;
import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
import static org.junit.Assert.assertEquals;
@@ -38,12 +36,12 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.net.ConnectivitySettingsManager;
@@ -74,7 +72,6 @@
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;
@@ -122,29 +119,6 @@
assertFieldCountEquals(3, ResolverOptionsParcel.class);
}
- private void assertResolverParamsEquals(@NonNull ResolverParamsParcel actual,
- @NonNull ResolverParamsParcel expected) {
- assertEquals(actual.netId, expected.netId);
- assertEquals(actual.sampleValiditySeconds, expected.sampleValiditySeconds);
- assertEquals(actual.successThreshold, expected.successThreshold);
- assertEquals(actual.minSamples, expected.minSamples);
- assertEquals(actual.maxSamples, expected.maxSamples);
- assertEquals(actual.baseTimeoutMsec, expected.baseTimeoutMsec);
- assertEquals(actual.retryCount, expected.retryCount);
- assertContainsStringsExactly(actual.servers, expected.servers);
- assertContainsStringsExactly(actual.domains, expected.domains);
- assertEquals(actual.tlsName, expected.tlsName);
- assertContainsStringsExactly(actual.tlsServers, expected.tlsServers);
- assertContainsStringsExactly(actual.tlsFingerprints, expected.tlsFingerprints);
- assertEquals(actual.caCertificate, expected.caCertificate);
- assertEquals(actual.tlsConnectTimeoutMs, expected.tlsConnectTimeoutMs);
- assertResolverOptionsEquals(actual.resolverOptions, expected.resolverOptions);
- assertContainsExactly(actual.transportTypes, expected.transportTypes);
- assertEquals(actual.meteredNetwork, expected.meteredNetwork);
- assertEquals(actual.dohParams, expected.dohParams);
- assertFieldCountEquals(18, ResolverParamsParcel.class);
- }
-
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -365,11 +339,6 @@
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
mDnsManager.flushVmDnsCache();
- final ArgumentCaptor<ResolverParamsParcel> resolverParamsParcelCaptor =
- ArgumentCaptor.forClass(ResolverParamsParcel.class);
- verify(mMockDnsResolver, times(1)).setResolverConfiguration(
- resolverParamsParcelCaptor.capture());
- final ResolverParamsParcel actualParams = resolverParamsParcelCaptor.getValue();
final ResolverParamsParcel expectedParams = new ResolverParamsParcel();
expectedParams.netId = TEST_NETID;
expectedParams.sampleValiditySeconds = TEST_DEFAULT_SAMPLE_VALIDITY_SECONDS;
@@ -384,7 +353,8 @@
expectedParams.resolverOptions = null;
expectedParams.meteredNetwork = true;
expectedParams.dohParams = null;
- assertResolverParamsEquals(actualParams, expectedParams);
+ expectedParams.interfaceNames = new String[]{TEST_IFACENAME};
+ verify(mMockDnsResolver, times(1)).setResolverConfiguration(eq(expectedParams));
}
@Test
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
index d735dc6..2cb97c9 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
@@ -1625,6 +1625,44 @@
}
@Test
+ fun testGetConflictingServices_multipleRegistrationsForHostKey_noConflict() {
+ val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
+
+ repository.addServiceAndFinishProbing(TEST_SERVICE_ID_1, NsdServiceInfo().apply {
+ hostname = "MyHost"
+ hostAddresses = listOf(
+ parseNumericAddress("2001:db8::1"),
+ parseNumericAddress("2001:db8::2"))
+ publicKey = TEST_PUBLIC_KEY
+ })
+ repository.addService(TEST_SERVICE_ID_2, NsdServiceInfo().apply {
+ serviceType = "_testservice._tcp"
+ serviceName = "MyTestService"
+ port = TEST_PORT
+ hostname = "MyHost"
+ publicKey = TEST_PUBLIC_KEY
+ }, null /* ttl */)
+
+ // Although there's a KEY RR in the second registration being probed, it shouldn't conflict
+ // with an address record which is from a probed registration in the repository.
+ val otherTtlMillis = 1234L
+ val packet = MdnsPacket(
+ 0 /* flags */,
+ emptyList() /* questions */,
+ listOf(
+ MdnsInetAddressRecord(
+ arrayOf("MyHost", "local"),
+ 0L /* receiptTimeMillis */, true /* cacheFlush */,
+ otherTtlMillis,
+ parseNumericAddress("2001:db8::1"))
+ ) /* answers */,
+ emptyList() /* authorityRecords */,
+ emptyList() /* additionalRecords */)
+
+ assertEquals(mapOf(), repository.getConflictingServices(packet))
+ }
+
+ @Test
fun testGetConflictingServices_IdenticalService() {
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* ttl */)
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSActiveNetworkInfoTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSActiveNetworkInfoTest.kt
new file mode 100644
index 0000000..360a298
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivityservice/CSActiveNetworkInfoTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server
+
+import android.net.INetd.PERMISSION_INTERNET
+import android.net.INetd.PERMISSION_NONE
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.NetworkInfo.DetailedState.BLOCKED
+import android.net.NetworkInfo.DetailedState.CONNECTED
+import android.net.connectivity.ConnectivityCompatChanges.NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import com.android.testutils.DevSdkIgnoreRunner
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mockito.doReturn
+
+private fun nc() = NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build()
+
+@RunWith(DevSdkIgnoreRunner::class)
+@SmallTest
+@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class CSActiveNetworkInfoTest : CSTest() {
+
+ fun doTestGetActiveNetworkInfo(
+ changeEnabled: Boolean,
+ permissions: Int,
+ expectBlocked: Boolean
+ ) {
+ deps.setChangeIdEnabled(changeEnabled, NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION)
+ doReturn(permissions).`when`(bpfNetMaps).getNetPermForUid(anyInt())
+
+ val agent = Agent(nc = nc())
+ agent.connect()
+
+ val networkInfo = cm.activeNetworkInfo
+ assertNotNull(networkInfo)
+ if (expectBlocked) {
+ assertEquals(BLOCKED, networkInfo.detailedState)
+ } else {
+ assertEquals(CONNECTED, networkInfo.detailedState)
+ }
+ assertEquals(expectBlocked, cm.activeNetwork == null)
+ agent.disconnect()
+ }
+
+ @Test
+ fun testGetActiveNetworkInfo() {
+ doReturn(true).`when`(bpfNetMaps).isUidNetworkingBlocked(anyInt(), anyBoolean())
+ doTestGetActiveNetworkInfo(
+ changeEnabled = true,
+ permissions = PERMISSION_NONE,
+ expectBlocked = true
+ )
+ doTestGetActiveNetworkInfo(
+ changeEnabled = false,
+ permissions = PERMISSION_INTERNET,
+ expectBlocked = true
+ )
+ // Network access is considered not blocked if the compat change is disabled and an app
+ // does not have PERMISSION_INTERNET
+ doTestGetActiveNetworkInfo(
+ changeEnabled = false,
+ permissions = PERMISSION_NONE,
+ expectBlocked = false
+ )
+ }
+}
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 6425daa..9026481 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -314,7 +314,7 @@
new SetFeatureFlagsRule((name, enabled) -> {
mFeatureFlags.put(name, enabled);
return null;
- });
+ }, (name) -> mFeatureFlags.getOrDefault(name, false));
private class MockContext extends BroadcastInterceptingContext {
private final Context mBaseContext;
diff --git a/thread/TEST_MAPPING b/thread/TEST_MAPPING
index ebbb9af..34d67bb 100644
--- a/thread/TEST_MAPPING
+++ b/thread/TEST_MAPPING
@@ -11,5 +11,8 @@
}
],
"postsubmit": [
+ {
+ "name": "ThreadNetworkMultiDeviceTests"
+ }
]
}
diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
index 0559499..0c200fd 100644
--- a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
+++ b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
@@ -106,6 +106,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.Log;
import android.util.SparseArray;
@@ -121,6 +122,7 @@
import com.android.server.thread.openthread.IOtStatusReceiver;
import com.android.server.thread.openthread.Ipv6AddressInfo;
import com.android.server.thread.openthread.MeshcopTxtAttributes;
+import com.android.server.thread.openthread.OnMeshPrefixConfig;
import com.android.server.thread.openthread.OtDaemonState;
import libcore.util.HexEncoding;
@@ -199,6 +201,7 @@
private final ThreadPersistentSettings mPersistentSettings;
private final UserManager mUserManager;
private boolean mUserRestricted;
+ private boolean mAirplaneModeOn;
private boolean mForceStopOtDaemonEnabled;
private BorderRouterConfigurationParcel mBorderRouterConfig;
@@ -282,7 +285,7 @@
}
private void maybeInitializeOtDaemon() {
- if (!isEnabled()) {
+ if (!shouldEnableThread()) {
return;
}
@@ -317,7 +320,7 @@
otDaemon.initialize(
mTunIfController.getTunFd(),
- isEnabled(),
+ shouldEnableThread(),
mNsdPublisher,
getMeshcopTxtAttributes(mResources.get()),
mOtDaemonCallbackProxy,
@@ -382,7 +385,7 @@
Log.d(
TAG,
"Initializing Thread system service: Thread is "
- + (isEnabled() ? "enabled" : "disabled"));
+ + (shouldEnableThread() ? "enabled" : "disabled"));
try {
mTunIfController.createTunInterface();
} catch (IOException e) {
@@ -394,6 +397,8 @@
requestThreadNetwork();
mUserRestricted = isThreadUserRestricted();
registerUserRestrictionsReceiver();
+ mAirplaneModeOn = isAirplaneModeOn();
+ registerAirplaneModeReceiver();
maybeInitializeOtDaemon();
});
}
@@ -474,6 +479,15 @@
// the otDaemon set enabled state operation succeeded or not, so that it can recover
// to the desired value after reboot.
mPersistentSettings.put(ThreadPersistentSettings.THREAD_ENABLED.key, isEnabled);
+
+ // Remember whether the user wanted to keep Thread enabled in airplane mode. If once
+ // the user disabled Thread again in airplane mode, the persistent settings state is
+ // reset (so that Thread will be auto-disabled again when airplane mode is turned on).
+ // This behavior is consistent with Wi-Fi and bluetooth.
+ if (mAirplaneModeOn) {
+ mPersistentSettings.put(
+ ThreadPersistentSettings.THREAD_ENABLED_IN_AIRPLANE_MODE.key, isEnabled);
+ }
}
try {
@@ -510,36 +524,30 @@
+ newUserRestrictedState);
mUserRestricted = newUserRestrictedState;
- final boolean isEnabled = isEnabled();
+ final boolean shouldEnableThread = shouldEnableThread();
final IOperationReceiver receiver =
new IOperationReceiver.Stub() {
@Override
public void onSuccess() {
Log.d(
TAG,
- (isEnabled ? "Enabled" : "Disabled")
+ (shouldEnableThread ? "Enabled" : "Disabled")
+ " Thread due to user restriction change");
}
@Override
- public void onError(int otError, String messages) {
+ public void onError(int errorCode, String errorMessage) {
Log.e(
TAG,
"Failed to "
- + (isEnabled ? "enable" : "disable")
+ + (shouldEnableThread ? "enable" : "disable")
+ " Thread for user restriction change");
}
};
// Do not save the user restriction state to persistent settings so that the user
// configuration won't be overwritten
- setEnabledInternal(isEnabled, false /* persist */, new OperationReceiverWrapper(receiver));
- }
-
- /** Returns {@code true} if Thread is set enabled. */
- private boolean isEnabled() {
- return !mForceStopOtDaemonEnabled
- && !mUserRestricted
- && mPersistentSettings.get(ThreadPersistentSettings.THREAD_ENABLED);
+ setEnabledInternal(
+ shouldEnableThread, false /* persist */, new OperationReceiverWrapper(receiver));
}
/** Returns {@code true} if Thread has been restricted for the user. */
@@ -547,6 +555,74 @@
return mUserManager.hasUserRestriction(DISALLOW_THREAD_NETWORK);
}
+ private void registerAirplaneModeReceiver() {
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ onAirplaneModeChanged(isAirplaneModeOn());
+ }
+ },
+ new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED),
+ null /* broadcastPermission */,
+ mHandler);
+ }
+
+ private void onAirplaneModeChanged(boolean newAirplaneModeOn) {
+ checkOnHandlerThread();
+ if (mAirplaneModeOn == newAirplaneModeOn) {
+ return;
+ }
+ Log.i(TAG, "Airplane mode changed: " + mAirplaneModeOn + " -> " + newAirplaneModeOn);
+ mAirplaneModeOn = newAirplaneModeOn;
+
+ final boolean shouldEnableThread = shouldEnableThread();
+ final IOperationReceiver receiver =
+ new IOperationReceiver.Stub() {
+ @Override
+ public void onSuccess() {
+ Log.d(
+ TAG,
+ (shouldEnableThread ? "Enabled" : "Disabled")
+ + " Thread due to airplane mode change");
+ }
+
+ @Override
+ public void onError(int errorCode, String errorMessage) {
+ Log.e(
+ TAG,
+ "Failed to "
+ + (shouldEnableThread ? "enable" : "disable")
+ + " Thread for airplane mode change");
+ }
+ };
+ // Do not save the user restriction state to persistent settings so that the user
+ // configuration won't be overwritten
+ setEnabledInternal(
+ shouldEnableThread, false /* persist */, new OperationReceiverWrapper(receiver));
+ }
+
+ /** Returns {@code true} if Airplane mode has been turned on. */
+ private boolean isAirplaneModeOn() {
+ return Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0)
+ == 1;
+ }
+
+ /**
+ * Returns {@code true} if Thread should be enabled based on current settings, runtime user
+ * restriction and airplane mode state.
+ */
+ private boolean shouldEnableThread() {
+ final boolean enabledInAirplaneMode =
+ mPersistentSettings.get(ThreadPersistentSettings.THREAD_ENABLED_IN_AIRPLANE_MODE);
+
+ return !mForceStopOtDaemonEnabled
+ && !mUserRestricted
+ && (!mAirplaneModeOn || enabledInAirplaneMode)
+ && mPersistentSettings.get(ThreadPersistentSettings.THREAD_ENABLED);
+ }
+
private void requestUpstreamNetwork() {
if (mUpstreamNetworkCallback != null) {
throw new AssertionError("The upstream network request is already there.");
@@ -1018,7 +1094,7 @@
checkOnHandlerThread();
// Fails early to avoid waking up ot-daemon by the ThreadNetworkCountryCode class
- if (!isEnabled()) {
+ if (!shouldEnableThread()) {
receiver.onError(
ERROR_THREAD_DISABLED, "Can't set country code when Thread is disabled");
return;
@@ -1159,6 +1235,18 @@
}
}
+ private void handlePrefixChanged(List<OnMeshPrefixConfig> onMeshPrefixConfigList) {
+ checkOnHandlerThread();
+
+ mTunIfController.updatePrefixes(onMeshPrefixConfigList);
+
+ // The OT daemon can send link property updates before the networkAgent is
+ // registered
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendLinkProperties(mTunIfController.getLinkProperties());
+ }
+ }
+
private void sendLocalNetworkConfig() {
if (mNetworkAgent == null) {
return;
@@ -1283,7 +1371,6 @@
private void notifyThreadEnabledUpdated(IStateCallback callback, int enabledState) {
try {
callback.onThreadEnableStateChanged(enabledState);
- Log.i(TAG, "onThreadEnableStateChanged " + enabledState);
} catch (RemoteException ignored) {
// do nothing if the client is dead
}
@@ -1507,5 +1594,10 @@
public void onBackboneRouterStateChanged(BackboneRouterState state) {
mHandler.post(() -> handleMulticastForwardingChanged(state));
}
+
+ @Override
+ public void onPrefixChanged(List<OnMeshPrefixConfig> onMeshPrefixConfigList) {
+ mHandler.post(() -> handlePrefixChanged(onMeshPrefixConfigList));
+ }
}
}
diff --git a/thread/service/java/com/android/server/thread/ThreadPersistentSettings.java b/thread/service/java/com/android/server/thread/ThreadPersistentSettings.java
index 8aaff60..f18aac9 100644
--- a/thread/service/java/com/android/server/thread/ThreadPersistentSettings.java
+++ b/thread/service/java/com/android/server/thread/ThreadPersistentSettings.java
@@ -63,6 +63,14 @@
/** Stores the Thread feature toggle state, true for enabled and false for disabled. */
public static final Key<Boolean> THREAD_ENABLED = new Key<>("thread_enabled", true);
+ /**
+ * Indicates that Thread was enabled (i.e. via the setEnabled() API) when the airplane mode is
+ * turned on in settings. When this value is {@code true}, the current airplane mode state will
+ * be ignored when evaluating the Thread enabled state.
+ */
+ public static final Key<Boolean> THREAD_ENABLED_IN_AIRPLANE_MODE =
+ new Key<>("thread_enabled_in_airplane_mode", false);
+
/** Stores the Thread country code, null if no country code is stored. */
public static final Key<String> THREAD_COUNTRY_CODE = new Key<>("thread_country_code", null);
diff --git a/thread/service/java/com/android/server/thread/TunInterfaceController.java b/thread/service/java/com/android/server/thread/TunInterfaceController.java
index dec72b2..976f93d 100644
--- a/thread/service/java/com/android/server/thread/TunInterfaceController.java
+++ b/thread/service/java/com/android/server/thread/TunInterfaceController.java
@@ -16,29 +16,40 @@
package com.android.server.thread;
+import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.EADDRINUSE;
+import static android.system.OsConstants.IFF_MULTICAST;
+import static android.system.OsConstants.IFF_NOARP;
+import static android.system.OsConstants.NETLINK_ROUTE;
+
+import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWLINK;
+import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_AF_SPEC;
+import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_INET6_ADDR_GEN_MODE;
+import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IN6_ADDR_GEN_MODE_NONE;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
import android.annotation.Nullable;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
-import android.net.util.SocketUtils;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.Os;
-import android.system.OsConstants;
import android.util.Log;
+import com.android.net.module.util.HexDump;
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.net.module.util.netlink.NetlinkUtils;
-import com.android.net.module.util.netlink.RtNetlinkAddressMessage;
+import com.android.net.module.util.netlink.StructIfinfoMsg;
+import com.android.net.module.util.netlink.StructNlAttr;
+import com.android.net.module.util.netlink.StructNlMsgHdr;
import com.android.server.thread.openthread.Ipv6AddressInfo;
+import com.android.server.thread.openthread.OnMeshPrefixConfig;
-import java.io.FileDescriptor;
import java.io.IOException;
-import java.io.InterruptedIOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -46,12 +57,15 @@
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
/** Controller for virtual/tunnel network interfaces. */
public class TunInterfaceController {
private static final String TAG = "TunIfController";
+ private static final boolean DBG = false;
private static final long INFINITE_LIFETIME = 0xffffffffL;
static final int MTU = 1280;
@@ -61,12 +75,12 @@
private final String mIfName;
private final LinkProperties mLinkProperties = new LinkProperties();
- private ParcelFileDescriptor mParcelTunFd;
- private FileDescriptor mNetlinkSocket;
- private static int sNetlinkSeqNo = 0;
private final MulticastSocket mMulticastSocket; // For join group and leave group
+ private final List<InetAddress> mMulticastAddresses = new ArrayList<>();
+ private final List<RouteInfo> mNetDataPrefixes = new ArrayList<>();
+
+ private ParcelFileDescriptor mParcelTunFd;
private NetworkInterface mNetworkInterface;
- private List<InetAddress> mMulticastAddresses = new ArrayList<>();
/** Creates a new {@link TunInterfaceController} instance for given interface. */
public TunInterfaceController(String interfaceName) {
@@ -89,26 +103,21 @@
public void createTunInterface() throws IOException {
mParcelTunFd = ParcelFileDescriptor.adoptFd(nativeCreateTunInterface(mIfName, MTU));
try {
- mNetlinkSocket = NetlinkUtils.netlinkSocketForProto(OsConstants.NETLINK_ROUTE);
- } catch (ErrnoException e) {
- throw new IOException("Failed to create netlink socket", e);
- }
- try {
mNetworkInterface = NetworkInterface.getByName(mIfName);
} catch (SocketException e) {
throw new IOException("Failed to get NetworkInterface", e);
}
+
+ setAddrGenModeToNone();
}
public void destroyTunInterface() {
try {
mParcelTunFd.close();
- SocketUtils.closeSocket(mNetlinkSocket);
} catch (IOException e) {
// Should never fail
}
mParcelTunFd = null;
- mNetlinkSocket = null;
mNetworkInterface = null;
}
@@ -126,6 +135,10 @@
for (LinkAddress address : mLinkProperties.getAllLinkAddresses()) {
removeAddress(address);
}
+ for (RouteInfo route : mLinkProperties.getAllRoutes()) {
+ mLinkProperties.removeRoute(route);
+ }
+ mNetDataPrefixes.clear();
}
nativeSetInterfaceUp(mIfName, isUp);
}
@@ -136,14 +149,14 @@
public void addAddress(LinkAddress address) {
Log.d(TAG, "Adding address " + address + " with flags: " + address.getFlags());
- long validLifetimeSeconds;
long preferredLifetimeSeconds;
+ long validLifetimeSeconds;
if (address.getDeprecationTime() == LinkAddress.LIFETIME_PERMANENT
|| address.getDeprecationTime() == LinkAddress.LIFETIME_UNKNOWN) {
- validLifetimeSeconds = INFINITE_LIFETIME;
+ preferredLifetimeSeconds = INFINITE_LIFETIME;
} else {
- validLifetimeSeconds =
+ preferredLifetimeSeconds =
Math.max(
(address.getDeprecationTime() - SystemClock.elapsedRealtime()) / 1000L,
0L);
@@ -151,28 +164,23 @@
if (address.getExpirationTime() == LinkAddress.LIFETIME_PERMANENT
|| address.getExpirationTime() == LinkAddress.LIFETIME_UNKNOWN) {
- preferredLifetimeSeconds = INFINITE_LIFETIME;
+ validLifetimeSeconds = INFINITE_LIFETIME;
} else {
- preferredLifetimeSeconds =
+ validLifetimeSeconds =
Math.max(
(address.getExpirationTime() - SystemClock.elapsedRealtime()) / 1000L,
0L);
}
- byte[] message =
- RtNetlinkAddressMessage.newRtmNewAddressMessage(
- sNetlinkSeqNo++,
- address.getAddress(),
- (short) address.getPrefixLength(),
- address.getFlags(),
- (byte) address.getScope(),
- Os.if_nametoindex(mIfName),
- validLifetimeSeconds,
- preferredLifetimeSeconds);
- try {
- Os.write(mNetlinkSocket, message, 0, message.length);
- } catch (ErrnoException | InterruptedIOException e) {
- Log.e(TAG, "Failed to add address " + address, e);
+ if (!NetlinkUtils.sendRtmNewAddressRequest(
+ Os.if_nametoindex(mIfName),
+ address.getAddress(),
+ (short) address.getPrefixLength(),
+ address.getFlags(),
+ (byte) address.getScope(),
+ preferredLifetimeSeconds,
+ validLifetimeSeconds)) {
+ Log.w(TAG, "Failed to add address " + address.getAddress().getHostAddress());
return;
}
mLinkProperties.addLinkAddress(address);
@@ -182,22 +190,17 @@
/** Removes an address from the interface. */
public void removeAddress(LinkAddress address) {
Log.d(TAG, "Removing address " + address);
- byte[] message =
- RtNetlinkAddressMessage.newRtmDelAddressMessage(
- sNetlinkSeqNo++,
- address.getAddress(),
- (short) address.getPrefixLength(),
- Os.if_nametoindex(mIfName));
// Intentionally update the mLinkProperties before send netlink message because the
// address is already removed from ot-daemon and apps can't reach to the address even
// when the netlink request below fails
mLinkProperties.removeLinkAddress(address);
mLinkProperties.removeRoute(getRouteForAddress(address));
- try {
- Os.write(mNetlinkSocket, message, 0, message.length);
- } catch (ErrnoException | InterruptedIOException e) {
- Log.e(TAG, "Failed to remove address " + address, e);
+ if (!NetlinkUtils.sendRtmDelAddressRequest(
+ Os.if_nametoindex(mIfName),
+ (Inet6Address) address.getAddress(),
+ (short) address.getPrefixLength())) {
+ Log.w(TAG, "Failed to remove address " + address.getAddress().getHostAddress());
}
}
@@ -243,13 +246,40 @@
mMulticastAddresses.addAll(newMulticastAddresses);
}
+ public void updatePrefixes(List<OnMeshPrefixConfig> onMeshPrefixConfigList) {
+ final List<RouteInfo> newNetDataPrefixes = new ArrayList<>();
+
+ for (OnMeshPrefixConfig onMeshPrefixConfig : onMeshPrefixConfigList) {
+ newNetDataPrefixes.add(getRouteForOnMeshPrefix(onMeshPrefixConfig));
+ }
+
+ final CompareResult<RouteInfo> prefixDiff =
+ new CompareResult<>(mNetDataPrefixes, newNetDataPrefixes);
+ for (RouteInfo routeRemoved : prefixDiff.removed) {
+ mLinkProperties.removeRoute(routeRemoved);
+ }
+ for (RouteInfo routeAdded : prefixDiff.added) {
+ mLinkProperties.addRoute(routeAdded);
+ }
+
+ mNetDataPrefixes.clear();
+ mNetDataPrefixes.addAll(newNetDataPrefixes);
+ }
+
private RouteInfo getRouteForAddress(LinkAddress linkAddress) {
- return new RouteInfo(
- new IpPrefix(linkAddress.getAddress(), linkAddress.getPrefixLength()),
- null,
- mIfName,
- RouteInfo.RTN_UNICAST,
- MTU);
+ return getRouteForIpPrefix(
+ new IpPrefix(linkAddress.getAddress(), linkAddress.getPrefixLength()));
+ }
+
+ private RouteInfo getRouteForOnMeshPrefix(OnMeshPrefixConfig onMeshPrefixConfig) {
+ return getRouteForIpPrefix(
+ new IpPrefix(
+ bytesToInet6Address(onMeshPrefixConfig.prefix),
+ onMeshPrefixConfig.prefixLength));
+ }
+
+ private RouteInfo getRouteForIpPrefix(IpPrefix ipPrefix) {
+ return new RouteInfo(ipPrefix, null, mIfName, RouteInfo.RTN_UNICAST, MTU);
}
/** Called by {@link ThreadNetworkControllerService} to do clean up when ot-daemon is dead. */
@@ -333,4 +363,66 @@
Log.e(TAG, "failed to leave group " + address.getHostAddress(), e);
}
}
+
+ /**
+ * Sets the address generation mode to {@code IN6_ADDR_GEN_MODE_NONE}.
+ *
+ * <p>So that the "thread-wpan" interface has only one IPv6 link local address which is
+ * generated by OpenThread.
+ */
+ private void setAddrGenModeToNone() {
+ StructNlMsgHdr header = new StructNlMsgHdr();
+ header.nlmsg_type = RTM_NEWLINK;
+ header.nlmsg_pid = 0;
+ header.nlmsg_seq = 0;
+ header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+ StructIfinfoMsg ifInfo =
+ new StructIfinfoMsg(
+ (short) 0 /* family */,
+ 0 /* type */,
+ Os.if_nametoindex(mIfName),
+ (IFF_MULTICAST | IFF_NOARP) /* flags */,
+ 0xffffffff /* change */);
+
+ // Nested attributes
+ // IFLA_AF_SPEC
+ // AF_INET6
+ // IFLA_INET6_ADDR_GEN_MODE
+ StructNlAttr addrGenMode =
+ new StructNlAttr(IFLA_INET6_ADDR_GEN_MODE, (byte) IN6_ADDR_GEN_MODE_NONE);
+ StructNlAttr afInet6 = new StructNlAttr((short) AF_INET6, addrGenMode);
+ StructNlAttr afSpec = new StructNlAttr(IFLA_AF_SPEC, afInet6);
+
+ final int msgLength =
+ StructNlMsgHdr.STRUCT_SIZE
+ + StructIfinfoMsg.STRUCT_SIZE
+ + afSpec.getAlignedLength();
+ byte[] msg = new byte[msgLength];
+ ByteBuffer buf = ByteBuffer.wrap(msg);
+ buf.order(ByteOrder.nativeOrder());
+
+ header.nlmsg_len = msgLength;
+ header.pack(buf);
+ ifInfo.pack(buf);
+ afSpec.pack(buf);
+
+ if (buf.position() != msgLength) {
+ throw new AssertionError(
+ String.format(
+ "Unexpected netlink message size (actual = %d, expected = %d)",
+ buf.position(), msgLength));
+ }
+
+ if (DBG) {
+ Log.d(TAG, "ADDR_GEN_MODE message is:");
+ Log.d(TAG, HexDump.dumpHexString(msg));
+ }
+
+ try {
+ NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to set ADDR_GEN_MODE to NONE", e);
+ }
+ }
}
diff --git a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
index e211e22..61b6eac 100644
--- a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
+++ b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
@@ -22,6 +22,8 @@
import static android.net.thread.utils.IntegrationTestUtils.CALLBACK_TIMEOUT;
import static android.net.thread.utils.IntegrationTestUtils.RESTART_JOIN_TIMEOUT;
import static android.net.thread.utils.IntegrationTestUtils.getIpv6LinkAddresses;
+import static android.net.thread.utils.IntegrationTestUtils.getPrefixesFromNetData;
+import static android.net.thread.utils.IntegrationTestUtils.getThreadNetwork;
import static android.net.thread.utils.IntegrationTestUtils.isInMulticastGroup;
import static android.net.thread.utils.IntegrationTestUtils.waitFor;
@@ -31,11 +33,14 @@
import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.LinkAddress;
+import android.net.LinkProperties;
import android.net.thread.utils.FullThreadDevice;
import android.net.thread.utils.OtDaemonController;
import android.net.thread.utils.ThreadFeatureCheckerRule;
@@ -75,6 +80,9 @@
// The maximum time for OT addresses to be propagated to the TUN interface "thread-wpan"
private static final Duration TUN_ADDR_UPDATE_TIMEOUT = Duration.ofSeconds(1);
+ // The maximum time for changes to be propagated to netdata.
+ private static final Duration NET_DATA_UPDATE_TIMEOUT = Duration.ofSeconds(1);
+
// A valid Thread Active Operational Dataset generated from OpenThread CLI "dataset init new".
private static final byte[] DEFAULT_DATASET_TLVS =
base16().decode(
@@ -89,6 +97,10 @@
private static final Inet6Address GROUP_ADDR_ALL_ROUTERS =
(Inet6Address) InetAddresses.parseNumericAddress("ff02::2");
+ private static final String TEST_NO_SLAAC_PREFIX = "9101:dead:beef:cafe::/64";
+ private static final InetAddress TEST_NO_SLAAC_PREFIX_ADDRESS =
+ InetAddresses.parseNumericAddress("9101:dead:beef:cafe::");
+
@Rule public final ThreadFeatureCheckerRule mThreadRule = new ThreadFeatureCheckerRule();
private ExecutorService mExecutor;
@@ -164,7 +176,7 @@
// TODO (b/323300829): add test for removing an OT address
@Test
- public void tunInterface_joinedNetwork_otAddressesAddedToTunInterface() throws Exception {
+ public void tunInterface_joinedNetwork_otAndTunAddressesMatch() throws Exception {
mController.joinAndWait(DEFAULT_DATASET);
List<Inet6Address> otAddresses = mOtCtl.getAddresses();
@@ -173,9 +185,12 @@
// that we can write assertThat() in the Predicate
waitFor(
() -> {
- String ifconfig = runShellCommand("ifconfig thread-wpan");
- return otAddresses.stream()
- .allMatch(addr -> ifconfig.contains(addr.getHostAddress()));
+ List<Inet6Address> tunAddresses =
+ getIpv6LinkAddresses("thread-wpan").stream()
+ .map(linkAddr -> (Inet6Address) linkAddr.getAddress())
+ .toList();
+ return otAddresses.containsAll(tunAddresses)
+ && tunAddresses.containsAll(otAddresses);
},
TUN_ADDR_UPDATE_TIMEOUT);
}
@@ -237,6 +252,81 @@
assertTunInterfaceMemberOfGroup(GROUP_ADDR_ALL_ROUTERS);
}
+ @Test
+ public void edPingsMeshLocalAddresses_oneReplyPerRequest() throws Exception {
+ mController.joinAndWait(DEFAULT_DATASET);
+ startFtdChild(mFtd, DEFAULT_DATASET);
+ List<Inet6Address> meshLocalAddresses = mOtCtl.getMeshLocalAddresses();
+
+ for (Inet6Address address : meshLocalAddresses) {
+ assertWithMessage(
+ "There may be duplicated replies of ping request to "
+ + address.getHostAddress())
+ .that(mFtd.ping(address, 2))
+ .isEqualTo(2);
+ }
+ }
+
+ @Test
+ public void addPrefixToNetData_routeIsAddedToTunInterface() throws Exception {
+ ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+ mController.joinAndWait(DEFAULT_DATASET);
+
+ // Ftd child doesn't have the ability to add a prefix, so let BR itself add a prefix.
+ mOtCtl.executeCommand("prefix add " + TEST_NO_SLAAC_PREFIX + " pros med");
+ mOtCtl.executeCommand("netdata register");
+ waitFor(
+ () -> {
+ String netData = mOtCtl.executeCommand("netdata show");
+ return getPrefixesFromNetData(netData).contains(TEST_NO_SLAAC_PREFIX);
+ },
+ NET_DATA_UPDATE_TIMEOUT);
+
+ LinkProperties lp = cm.getLinkProperties(getThreadNetwork(CALLBACK_TIMEOUT));
+ assertThat(lp).isNotNull();
+ assertThat(lp.getRoutes().stream().anyMatch(r -> r.matches(TEST_NO_SLAAC_PREFIX_ADDRESS)))
+ .isTrue();
+ }
+
+ @Test
+ public void removePrefixFromNetData_routeIsRemovedFromTunInterface() throws Exception {
+ ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+ mController.joinAndWait(DEFAULT_DATASET);
+ mOtCtl.executeCommand("prefix add " + TEST_NO_SLAAC_PREFIX + " pros med");
+ mOtCtl.executeCommand("netdata register");
+
+ mOtCtl.executeCommand("prefix remove " + TEST_NO_SLAAC_PREFIX);
+ mOtCtl.executeCommand("netdata register");
+ waitFor(
+ () -> {
+ String netData = mOtCtl.executeCommand("netdata show");
+ return !getPrefixesFromNetData(netData).contains(TEST_NO_SLAAC_PREFIX);
+ },
+ NET_DATA_UPDATE_TIMEOUT);
+
+ LinkProperties lp = cm.getLinkProperties(getThreadNetwork(CALLBACK_TIMEOUT));
+ assertThat(lp).isNotNull();
+ assertThat(lp.getRoutes().stream().anyMatch(r -> r.matches(TEST_NO_SLAAC_PREFIX_ADDRESS)))
+ .isFalse();
+ }
+
+ @Test
+ public void toggleThreadNetwork_routeFromPreviousNetDataIsRemoved() throws Exception {
+ ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+ mController.joinAndWait(DEFAULT_DATASET);
+ mOtCtl.executeCommand("prefix add " + TEST_NO_SLAAC_PREFIX + " pros med");
+ mOtCtl.executeCommand("netdata register");
+
+ mController.leaveAndWait();
+ mOtCtl.factoryReset();
+ mController.joinAndWait(DEFAULT_DATASET);
+
+ LinkProperties lp = cm.getLinkProperties(getThreadNetwork(CALLBACK_TIMEOUT));
+ assertThat(lp).isNotNull();
+ assertThat(lp.getRoutes().stream().anyMatch(r -> r.matches(TEST_NO_SLAAC_PREFIX_ADDRESS)))
+ .isFalse();
+ }
+
// TODO (b/323300829): add more tests for integration with linux platform and
// ConnectivityService
diff --git a/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java b/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
index 5e70f6c..46cf562 100644
--- a/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
+++ b/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
@@ -57,7 +57,9 @@
private static final int PING_SIZE = 100;
// There may not be a response for the ping command, using a short timeout to keep the tests
// short.
- private static final float PING_TIMEOUT_SECONDS = 0.1f;
+ private static final float PING_TIMEOUT_0_1_SECOND = 0.1f;
+ // 1 second timeout should be used when response is expected.
+ private static final float PING_TIMEOUT_1_SECOND = 1f;
private final Process mProcess;
private final BufferedReader mReader;
@@ -78,9 +80,10 @@
*/
public FullThreadDevice(int nodeId) {
try {
- mProcess = Runtime.getRuntime().exec("/system/bin/ot-cli-ftd " + nodeId);
+ mProcess = Runtime.getRuntime().exec("/system/bin/ot-cli-ftd -Leth1 " + nodeId);
} catch (IOException e) {
- throw new IllegalStateException("Failed to start ot-cli-ftd (id=" + nodeId + ")", e);
+ throw new IllegalStateException(
+ "Failed to start ot-cli-ftd -Leth1 (id=" + nodeId + ")", e);
}
mReader = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
mWriter = new BufferedWriter(new OutputStreamWriter(mProcess.getOutputStream()));
@@ -408,7 +411,7 @@
1 /* count */,
PING_INTERVAL,
HOP_LIMIT,
- PING_TIMEOUT_SECONDS);
+ PING_TIMEOUT_0_1_SECOND);
}
public void ping(Inet6Address address) {
@@ -419,10 +422,24 @@
1 /* count */,
PING_INTERVAL,
HOP_LIMIT,
- PING_TIMEOUT_SECONDS);
+ PING_TIMEOUT_0_1_SECOND);
}
- private void ping(
+ /** Returns the number of ping reply packets received. */
+ public int ping(Inet6Address address, int count) {
+ List<String> output =
+ ping(
+ address,
+ null,
+ PING_SIZE,
+ count,
+ PING_INTERVAL,
+ HOP_LIMIT,
+ PING_TIMEOUT_1_SECOND);
+ return getReceivedPacketsCount(output);
+ }
+
+ private List<String> ping(
Inet6Address address,
Inet6Address source,
int size,
@@ -445,7 +462,21 @@
+ hopLimit
+ " "
+ timeout;
- executeCommand(cmd);
+ return executeCommand(cmd);
+ }
+
+ private int getReceivedPacketsCount(List<String> stringList) {
+ Pattern pattern = Pattern.compile("([\\d]+) packets received");
+
+ for (String message : stringList) {
+ Matcher matcher = pattern.matcher(message);
+ if (matcher.find()) {
+ String packetCountStr = matcher.group(1);
+ return Integer.parseInt(packetCountStr);
+ }
+ }
+ // No match found
+ return -1;
}
@FormatMethod
diff --git a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
index 9be9566..ada46c8 100644
--- a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
+++ b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
@@ -15,6 +15,7 @@
*/
package android.net.thread.utils;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK;
import static android.system.OsConstants.IPPROTO_ICMPV6;
import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
@@ -24,17 +25,24 @@
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import android.net.ConnectivityManager;
import android.net.InetAddresses;
import android.net.LinkAddress;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.net.TestNetworkInterface;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.net.thread.ThreadNetworkController;
+import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import androidx.annotation.NonNull;
+import androidx.test.core.app.ApplicationProvider;
import com.android.net.module.util.Struct;
import com.android.net.module.util.structs.Icmpv6Header;
@@ -293,7 +301,7 @@
return false;
}
- public static List<LinkAddress> getIpv6LinkAddresses(String interfaceName) throws IOException {
+ public static List<LinkAddress> getIpv6LinkAddresses(String interfaceName) {
List<LinkAddress> addresses = new ArrayList<>();
final String cmd = " ip -6 addr show dev " + interfaceName;
final String output = runShellCommandOrThrow(cmd);
@@ -375,6 +383,36 @@
}
}
+ public static String getPrefixesFromNetData(String netData) {
+ int startIdx = netData.indexOf("Prefixes:");
+ int endIdx = netData.indexOf("Routes:");
+ return netData.substring(startIdx, endIdx);
+ }
+
+ public static Network getThreadNetwork(Duration timeout) throws Exception {
+ CompletableFuture<Network> networkFuture = new CompletableFuture<>();
+ ConnectivityManager cm =
+ ApplicationProvider.getApplicationContext()
+ .getSystemService(ConnectivityManager.class);
+ NetworkRequest.Builder networkRequestBuilder =
+ new NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_THREAD);
+ // Before V, we need to explicitly set `NET_CAPABILITY_LOCAL_NETWORK` capability to request
+ // a Thread network.
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ networkRequestBuilder.addCapability(NET_CAPABILITY_LOCAL_NETWORK);
+ }
+ NetworkRequest networkRequest = networkRequestBuilder.build();
+ ConnectivityManager.NetworkCallback networkCallback =
+ new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onAvailable(Network network) {
+ networkFuture.complete(network);
+ }
+ };
+ cm.registerNetworkCallback(networkRequest, networkCallback);
+ return networkFuture.get(timeout.toSeconds(), SECONDS);
+ }
+
private static class DefaultDiscoveryListener implements NsdManager.DiscoveryListener {
@Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {}
diff --git a/thread/tests/multidevices/Android.bp b/thread/tests/multidevices/Android.bp
new file mode 100644
index 0000000..050caa8
--- /dev/null
+++ b/thread/tests/multidevices/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2024 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 {
+ default_team: "trendy_team_fwk_thread_network",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_test_host {
+ name: "ThreadNetworkMultiDeviceTests",
+ main: "thread_network_multi_device_test.py",
+ srcs: ["thread_network_multi_device_test.py"],
+ test_config: "AndroidTest.xml",
+ libs: [
+ "mobly",
+ ],
+ test_options: {
+ unit_test: false,
+ tags: ["mobly"],
+ },
+ test_suites: [
+ "mts-tethering",
+ "general-tests",
+ ],
+ version: {
+ py3: {
+ embedded_launcher: true,
+ },
+ },
+}
diff --git a/thread/tests/multidevices/AndroidTest.xml b/thread/tests/multidevices/AndroidTest.xml
new file mode 100644
index 0000000..a2ea9aa
--- /dev/null
+++ b/thread/tests/multidevices/AndroidTest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 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.
+ -->
+
+<configuration description="Config for Thread Multi-device test cases">
+ <option name="config-descriptor:metadata" key="component" value="threadnetwork" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.tethering.apex" />
+
+ <object class="com.android.tradefed.testtype.suite.module.DeviceFeatureModuleController"
+ type="module_controller">
+ <option name="required-feature" value="android.hardware.thread_network" />
+ </object>
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.tethering" />
+ </object>
+ <!--
+ Only run tests if the device under test is SDK version 34 (Android 14) or above.
+ -->
+ <object type="module_controller"
+ class="com.android.tradefed.testtype.suite.module.Sdk34ModuleController" />
+
+ <device name="device1">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ </device>
+ <device name="device2">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ </device>
+
+ <test class="com.android.tradefed.testtype.mobly.MoblyBinaryHostTest">
+ <!-- The mobly-par-file-name should match the module name -->
+ <option name="mobly-par-file-name" value="ThreadMultiDeviceTestCases" />
+ <!-- Timeout limit in milliseconds for all test cases of the python binary -->
+ <option name="mobly-test-timeout" value="180000" />
+ </test>
+</configuration>
diff --git a/thread/tests/multidevices/thread_network_multi_device_test.py b/thread/tests/multidevices/thread_network_multi_device_test.py
new file mode 100644
index 0000000..652576b
--- /dev/null
+++ b/thread/tests/multidevices/thread_network_multi_device_test.py
@@ -0,0 +1,67 @@
+# Copyright (C) 2024 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.
+
+# Lint as: python3
+
+import logging
+import time
+
+from mobly import asserts
+from mobly import base_test
+from mobly import test_runner
+from mobly.controllers import android_device
+
+class ThreadNetworkMultiDeviceTest(base_test.BaseTestClass):
+ def setup_class(self):
+ self.node_a, self.node_b = self.register_controller(
+ android_device, min_number=2)
+ self.node_a.adb.shell([
+ 'ot-ctl', 'factoryreset',
+ ])
+ self.node_b.adb.shell([
+ 'ot-ctl', 'factoryreset',
+ ])
+ time.sleep(1)
+
+ def ot_ctl(self, node, cmd, expect_done=True):
+ args = cmd.split(' ')
+ args = ['ot-ctl'] + args
+ stdout = node.adb.shell(args).decode('utf-8')
+ if expect_done:
+ asserts.assert_in('Done', stdout)
+ return stdout
+
+ def test_b_should_be_able_to_discover_a(self):
+ self.ot_ctl(self.node_a, 'dataset init new')
+ self.ot_ctl(self.node_a, 'dataset commit active')
+ self.ot_ctl(self.node_a, 'ifconfig up')
+ self.ot_ctl(self.node_a, 'thread start')
+ self.ot_ctl(self.node_a, 'state leader')
+ stdout = self.ot_ctl(self.node_a, 'extaddr')
+ extaddr = stdout.splitlines()[0]
+ logging.info('node a extaddr: %s', extaddr)
+ asserts.assert_equal(len(extaddr), 16)
+
+ stdout = self.ot_ctl(self.node_b, 'scan')
+ asserts.assert_in(extaddr, stdout)
+ logging.info('discovered node a')
+
+
+if __name__ == '__main__':
+ # Take test args
+ if '--' in sys.argv:
+ index = sys.argv.index('--')
+ sys.argv = sys.argv[:1] + sys.argv[index + 1:]
+
+ test_runner.main()
diff --git a/thread/tests/unit/AndroidManifest.xml b/thread/tests/unit/AndroidManifest.xml
index ace7c52..8442e80 100644
--- a/thread/tests/unit/AndroidManifest.xml
+++ b/thread/tests/unit/AndroidManifest.xml
@@ -19,6 +19,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="android.net.thread.unittests">
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
index 493058f..52a9dd9 100644
--- a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
+++ b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
@@ -26,6 +26,7 @@
import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_PRIVILEGED;
import static com.android.server.thread.ThreadNetworkCountryCode.DEFAULT_COUNTRY_CODE;
+import static com.android.server.thread.ThreadPersistentSettings.THREAD_ENABLED_IN_AIRPLANE_MODE;
import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_INVALID_STATE;
import static com.google.common.io.BaseEncoding.base16;
@@ -35,6 +36,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
@@ -64,6 +66,8 @@
import android.os.RemoteException;
import android.os.UserManager;
import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.util.AtomicFile;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -75,7 +79,9 @@
import com.android.server.thread.openthread.testing.FakeOtDaemon;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
@@ -133,7 +139,6 @@
@Mock private TunInterfaceController mMockTunIfController;
@Mock private ParcelFileDescriptor mMockTunFd;
@Mock private InfraInterfaceController mMockInfraIfController;
- @Mock private ThreadPersistentSettings mMockPersistentSettings;
@Mock private NsdPublisher mMockNsdPublisher;
@Mock private UserManager mMockUserManager;
@Mock private IBinder mIBinder;
@@ -143,11 +148,15 @@
private Context mContext;
private TestLooper mTestLooper;
private FakeOtDaemon mFakeOtDaemon;
+ private ThreadPersistentSettings mPersistentSettings;
private ThreadNetworkControllerService mService;
@Captor private ArgumentCaptor<ActiveOperationalDataset> mActiveDatasetCaptor;
+ @Rule(order = 1)
+ public final TemporaryFolder tempFolder = new TemporaryFolder();
+
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
@@ -164,10 +173,12 @@
mFakeOtDaemon = new FakeOtDaemon(handler);
when(mMockTunIfController.getTunFd()).thenReturn(mMockTunFd);
- when(mMockPersistentSettings.get(any())).thenReturn(true);
when(mMockUserManager.hasUserRestriction(eq(DISALLOW_THREAD_NETWORK))).thenReturn(false);
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+
when(mConnectivityResources.get()).thenReturn(mResources);
+ when(mResources.getBoolean(eq(R.bool.config_thread_default_enabled))).thenReturn(true);
when(mResources.getString(eq(R.string.config_thread_vendor_name)))
.thenReturn(TEST_VENDOR_NAME);
when(mResources.getString(eq(R.string.config_thread_vendor_oui)))
@@ -175,6 +186,10 @@
when(mResources.getString(eq(R.string.config_thread_model_name)))
.thenReturn(TEST_MODEL_NAME);
+ final AtomicFile storageFile = new AtomicFile(tempFolder.newFile("thread_settings.xml"));
+ mPersistentSettings = new ThreadPersistentSettings(storageFile, mConnectivityResources);
+ mPersistentSettings.initialize();
+
mService =
new ThreadNetworkControllerService(
mContext,
@@ -184,7 +199,7 @@
mMockConnectivityManager,
mMockTunIfController,
mMockInfraIfController,
- mMockPersistentSettings,
+ mPersistentSettings,
mMockNsdPublisher,
mMockUserManager,
mConnectivityResources,
@@ -343,15 +358,9 @@
@Test
public void userRestriction_userBecomesRestricted_stateIsDisabledButNotPersisted() {
- AtomicReference<BroadcastReceiver> receiverRef = new AtomicReference<>();
when(mMockUserManager.hasUserRestriction(eq(DISALLOW_THREAD_NETWORK))).thenReturn(false);
- doAnswer(
- invocation -> {
- receiverRef.set((BroadcastReceiver) invocation.getArguments()[0]);
- return null;
- })
- .when(mContext)
- .registerReceiver(any(BroadcastReceiver.class), any(), any(), any());
+ AtomicReference<BroadcastReceiver> receiverRef =
+ captureBroadcastReceiver(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
mService.initialize();
mTestLooper.dispatchAll();
@@ -360,21 +369,14 @@
mTestLooper.dispatchAll();
assertThat(mFakeOtDaemon.getEnabledState()).isEqualTo(STATE_DISABLED);
- verify(mMockPersistentSettings, never())
- .put(eq(ThreadPersistentSettings.THREAD_ENABLED.key), eq(false));
+ assertThat(mPersistentSettings.get(ThreadPersistentSettings.THREAD_ENABLED)).isTrue();
}
@Test
- public void userRestriction_userBecomesNotRestricted_stateIsEnabledButNotPersisted() {
- AtomicReference<BroadcastReceiver> receiverRef = new AtomicReference<>();
+ public void userRestriction_userBecomesNotRestricted_stateIsEnabled() {
when(mMockUserManager.hasUserRestriction(eq(DISALLOW_THREAD_NETWORK))).thenReturn(true);
- doAnswer(
- invocation -> {
- receiverRef.set((BroadcastReceiver) invocation.getArguments()[0]);
- return null;
- })
- .when(mContext)
- .registerReceiver(any(BroadcastReceiver.class), any(), any(), any());
+ AtomicReference<BroadcastReceiver> receiverRef =
+ captureBroadcastReceiver(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
mService.initialize();
mTestLooper.dispatchAll();
@@ -383,8 +385,6 @@
mTestLooper.dispatchAll();
assertThat(mFakeOtDaemon.getEnabledState()).isEqualTo(STATE_ENABLED);
- verify(mMockPersistentSettings, never())
- .put(eq(ThreadPersistentSettings.THREAD_ENABLED.key), eq(true));
}
@Test
@@ -401,6 +401,118 @@
assertThat(failure.getErrorCode()).isEqualTo(ERROR_FAILED_PRECONDITION);
}
+ @Test
+ public void airplaneMode_initWithAirplaneModeOn_otDaemonNotStarted() {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+
+ mService.initialize();
+ mTestLooper.dispatchAll();
+
+ assertThat(mFakeOtDaemon.isInitialized()).isFalse();
+ }
+
+ @Test
+ public void airplaneMode_initWithAirplaneModeOff_threadIsEnabled() {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+
+ mService.initialize();
+ mTestLooper.dispatchAll();
+
+ assertThat(mFakeOtDaemon.getEnabledState()).isEqualTo(STATE_ENABLED);
+ }
+
+ @Test
+ public void airplaneMode_changesFromOffToOn_stateIsDisabled() {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+ AtomicReference<BroadcastReceiver> receiverRef =
+ captureBroadcastReceiver(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ mService.initialize();
+ mTestLooper.dispatchAll();
+
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ receiverRef.get().onReceive(mContext, new Intent());
+ mTestLooper.dispatchAll();
+
+ assertThat(mFakeOtDaemon.getEnabledState()).isEqualTo(STATE_DISABLED);
+ }
+
+ @Test
+ public void airplaneMode_changesFromOnToOff_stateIsEnabled() {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ AtomicReference<BroadcastReceiver> receiverRef =
+ captureBroadcastReceiver(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ mService.initialize();
+ mTestLooper.dispatchAll();
+
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+ receiverRef.get().onReceive(mContext, new Intent());
+ mTestLooper.dispatchAll();
+
+ assertThat(mFakeOtDaemon.getEnabledState()).isEqualTo(STATE_ENABLED);
+ }
+
+ @Test
+ public void airplaneMode_setEnabledWhenAirplaneModeIsOn_WillNotAutoDisableSecondTime() {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ AtomicReference<BroadcastReceiver> receiverRef =
+ captureBroadcastReceiver(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ CompletableFuture<Void> setEnabledFuture = new CompletableFuture<>();
+ mService.initialize();
+
+ mService.setEnabled(true, newOperationReceiver(setEnabledFuture));
+ mTestLooper.dispatchAll();
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+ receiverRef.get().onReceive(mContext, new Intent());
+ mTestLooper.dispatchAll();
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ receiverRef.get().onReceive(mContext, new Intent());
+ mTestLooper.dispatchAll();
+
+ assertThat(mFakeOtDaemon.getEnabledState()).isEqualTo(STATE_ENABLED);
+ assertThat(mPersistentSettings.get(THREAD_ENABLED_IN_AIRPLANE_MODE)).isTrue();
+ }
+
+ @Test
+ public void airplaneMode_setDisabledWhenAirplaneModeIsOn_WillAutoDisableSecondTime() {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ AtomicReference<BroadcastReceiver> receiverRef =
+ captureBroadcastReceiver(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ CompletableFuture<Void> setEnabledFuture = new CompletableFuture<>();
+ mService.initialize();
+ mService.setEnabled(true, newOperationReceiver(setEnabledFuture));
+ mTestLooper.dispatchAll();
+
+ mService.setEnabled(false, newOperationReceiver(setEnabledFuture));
+ mTestLooper.dispatchAll();
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+ receiverRef.get().onReceive(mContext, new Intent());
+ mTestLooper.dispatchAll();
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ receiverRef.get().onReceive(mContext, new Intent());
+ mTestLooper.dispatchAll();
+
+ assertThat(mFakeOtDaemon.getEnabledState()).isEqualTo(STATE_DISABLED);
+ assertThat(mPersistentSettings.get(THREAD_ENABLED_IN_AIRPLANE_MODE)).isFalse();
+ }
+
+ private AtomicReference<BroadcastReceiver> captureBroadcastReceiver(String action) {
+ AtomicReference<BroadcastReceiver> receiverRef = new AtomicReference<>();
+
+ doAnswer(
+ invocation -> {
+ receiverRef.set((BroadcastReceiver) invocation.getArguments()[0]);
+ return null;
+ })
+ .when(mContext)
+ .registerReceiver(
+ any(BroadcastReceiver.class),
+ argThat(actualIntentFilter -> actualIntentFilter.hasAction(action)),
+ any(),
+ any());
+
+ return receiverRef;
+ }
+
private static IOperationReceiver newOperationReceiver(CompletableFuture<Void> future) {
return new IOperationReceiver.Stub() {
@Override
diff --git a/tools/aospify_device.sh b/tools/aospify_device.sh
new file mode 100755
index 0000000..f25ac9d
--- /dev/null
+++ b/tools/aospify_device.sh
@@ -0,0 +1,164 @@
+#!/bin/bash
+
+# Script to swap core networking modules in a GMS userdebug device to AOSP modules, by remounting
+# the system partition and replacing module prebuilts. This is only to be used for local testing,
+# and should only be used on userdebug devices that support "adb root" and remounting the system
+# partition using overlayfs.
+#
+# Usage: aospify_device.sh [device_serial]
+# Reset by wiping data (adb reboot bootloader && fastboot erase userdata && fastboot reboot).
+#
+# This applies to NetworkStack, CaptivePortalLogin, dnsresolver, tethering, cellbroadcast modules,
+# which generally need to be preloaded together (core networking modules + cellbroadcast which
+# shares its certificates with NetworkStack and CaptivePortalLogin)
+#
+# This allows device manufacturers to test their changes in AOSP modules, running them on their
+# own device builds, before contributing contributing the patches to AOSP. After running this script
+# once AOSP modules can be quickly built and updated on the prepared device with:
+# m NetworkStack
+# adb install --staged $ANDROID_PRODUCT_OUT/system/priv-app/NetworkStack/NetworkStack.apk \
+# adb reboot
+# or for APEX modules:
+# m com.android.tethering deapexer
+# $ANDROID_HOST_OUT/bin/deapexer decompress --input $ANDROID_PRODUCT_OUT/system/apex/com.android.tethering.capex --output /tmp/decompressed.apex
+# adb install /tmp/decompressed.apex && adb reboot
+#
+# This has been tested on Android T and Android U Pixel devices. On recent (U+) devices, it requires
+# setting a released target SDK (for example target_sdk_version: "34") in
+# packages/modules/Connectivity/service/ServiceConnectivityResources/Android.bp before building.
+set -e
+
+function push_apex {
+ local original_apex_name=$1
+ local aosp_apex_name=$2
+ if $ADB_CMD shell ls /system/apex/$original_apex_name.capex 1>/dev/null 2>/dev/null; then
+ $ADB_CMD shell rm /system/apex/$original_apex_name.capex
+ $ADB_CMD push $ANDROID_PRODUCT_OUT/system/apex/$aosp_apex_name.capex /system/apex/
+ else
+ rm -f /tmp/decompressed_$aosp_apex_name.apex
+ $ANDROID_HOST_OUT/bin/deapexer decompress --input $ANDROID_PRODUCT_OUT/system/apex/$aosp_apex_name.capex --output /tmp/decompressed_$aosp_apex_name.apex
+ $ADB_CMD shell rm /system/apex/$original_apex_name.apex
+ $ADB_CMD push /tmp/decompressed_$aosp_apex_name.apex /system/apex/$aosp_apex_name.apex
+ rm /tmp/decompressed_$aosp_apex_name.apex
+ fi
+}
+
+function push_apk {
+ local app_type=$1
+ local original_apk_name=$2
+ local aosp_apk_name=$3
+ $ADB_CMD shell rm /system/$app_type/$original_apk_name/$original_apk_name.apk
+ $ADB_CMD push $ANDROID_PRODUCT_OUT/system/$app_type/$aosp_apk_name/$aosp_apk_name.apk /system/$app_type/$original_apk_name/
+}
+
+NETWORKSTACK_AOSP_SEPOLICY_KEY="<signer signature=\"308205dc308203c4a003020102020900fc6cb0d8a6fdd16\
+8300d06092a864886f70d01010b0500308181310b30090603550406130255533113301106035504080c0a43616c69666f72\
+6e69613116301406035504070c0d4d6f756e7461696e20566965773110300e060355040a0c07416e64726f69643110300e0\
+60355040b0c07416e64726f69643121301f06035504030c18636f6d2e616e64726f69642e6e6574776f726b737461636b30\
+20170d3139303231323031343632305a180f34373537303130383031343632305a308181310b30090603550406130255533\
+113301106035504080c0a43616c69666f726e69613116301406035504070c0d4d6f756e7461696e20566965773110300e06\
+0355040a0c07416e64726f69643110300e060355040b0c07416e64726f69643121301f06035504030c18636f6d2e616e647\
+26f69642e6e6574776f726b737461636b30820222300d06092a864886f70d01010105000382020f003082020a0282020100\
+bb71f5137ff0b2d757acc2ca3d378e0f8de11090d5caf3d49e314d35c283b778b02d792d8eba440364ca970985441660f0b\
+c00afbc63dd611b1bf51ad28a1edd21e0048f548b80f8bd113e25682822f57dab8273afaf12c64d19a0c6be238f3e66ddc7\
+9b10fd926931e3ee60a7bf618644da3c2c4fc428139d45d27beda7fe45e30075b493ead6ec01cdd55d931c0a657e2e59742\
+ca632b6dc3842a2deb7d22443c809291d7a549203ae6ae356582a4ca23f30f0549c4ec8408a75278e95c69e8390ad5280bc\
+efaef6f1309a41bd9f3bfb5d12dca7e79ec6fd6848193fa9ab728224887b4f93e985ec7cbf6401b0e863a4b91c05d046f04\
+0fe954004b1645954fcb4114cee1e8b64b47d719a19ef4c001cb183f7f3e166e43f56d68047c3440da34fdf529d44274b8b\
+2f6afb345091ad8ad4b93bd5c55d52286a5d3c157465db8ddf62e7cdb6b10fb18888046afdd263ae6f2125d9065759c7e42\
+f8610a6746edbdc547d4301612eeec3c3cbd124dececc8d38b20e73b13f24ee7ca13a98c5f61f0c81b07d2b519749bc2bcb\
+9e0949aef6c118a3e8125e6ab57fce46bb091a66740e10b31c740b891900c0ecda9cc69ecb4f3369998b175106dd0a4ffd7\
+024eb7e75fedd1a5b131d0bb2b40c63491e3cf86b8957b21521b3a96ed1376a51a6ac697866b0256dee1bcd9ab9a188bf4c\
+ed80b59a5f24c2da9a55eb7b0e502116e30203010001a3533051301d0603551d0e041604149383c92cfbf099d5c47b0c365\
+7d8622a084b72e1301f0603551d230418301680149383c92cfbf099d5c47b0c3657d8622a084b72e1300f0603551d130101\
+ff040530030101ff300d06092a864886f70d01010b050003820201006a0501382fde2a6b8f70c60cd1b8ee4f788718c288b\
+170258ef3a96230b65005650d6a4c42a59a97b2ddec502413e7b438fbd060363d74b74a232382a7f77fd3da34e38f79fad0\
+35a8b472c5cff365818a0118d87fa1e31cc7ed4befd27628760c290980c3cc3b7ff0cfd01b75ff1fcc83e981b5b25a54d85\
+b68a80424ac26015fb3a4c754969a71174c0bc283f6c88191dced609e245f5938ffd0ad799198e2d0bf6342221c1b0a5d33\
+2ed2fffc668982cabbcb7d3b630ff8476e5c84ac0ad37adf9224035200039f95ec1fa95bf83796c0e8986135cee2dcaef19\
+0b249855a7e7397d4a0bf17ea63d978589c6b48118a381fffbd790c44d80233e2e35292a3b5533ca3f2cc173f85cf904adf\
+e2e4e2183dc1eba0ebae07b839a81ff1bc92e292550957c8599af21e9c0497b9234ce345f3f508b1cc872aa55ddb5e773c5\
+c7dd6577b9a8b6daed20ae1ff4b8206fd9f5c8f5a22ba1980bef01ae6fcb2659b97ad5b985fa81c019ffe008ddd9c8130c0\
+6fc6032b2149c2209fc438a7e8c3b20ce03650ad31c4ee48f169777a0ae182b72ca31b81540f61f167d8d7adf4f6bb2330f\
+f5c24037245000d8172c12ab5d5aa5890b8b12db0f0e7296264eb66e7f9714c31004649fb4b864005f9c43c80db3f6de52f\
+d44d6e2036bfe7f5807156ed5ab591d06fd6bb93ba4334ea2739af8b41ed2686454e60b666d10738bb7ba88001\">\
+<seinfo value=\"network_stack\"\/><\/signer>"
+
+DEVICE=$1
+ADB_CMD="adb -s $DEVICE"
+
+if [ -z "$DEVICE" ]; then
+ echo "Usage: aospify_device.sh [device_serial]"
+ exit 1
+fi
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "Run build/envsetup.sh first to set ANDROID_BUILD_TOP"
+ exit 1
+fi
+
+if ! $ADB_CMD wait-for-device shell pm path com.google.android.networkstack; then
+ echo "This device is already not using GMS modules"
+ exit 1
+fi
+
+read -p "This script is only for test purposes and highly likely to make your device unusable. \
+Continue ? <y/N>" prompt
+if [[ $prompt != "y" ]]
+then
+ exit 0
+fi
+
+cd $ANDROID_BUILD_TOP
+source build/envsetup.sh
+lunch aosp_arm64-trunk_staging-userdebug
+m NetworkStack CaptivePortalLogin com.android.tethering com.android.cellbroadcast \
+ com.android.resolv deapexer \
+ out/target/product/generic_arm64/system/etc/selinux/plat_mac_permissions.xml \
+ out/target/product/generic_arm64/system/etc/permissions/com.android.networkstack.xml
+
+$ADB_CMD root
+$ADB_CMD remount
+$ADB_CMD reboot
+
+echo "Waiting for boot..."
+$ADB_CMD wait-for-device;
+until [[ $($ADB_CMD shell getprop sys.boot_completed) == 1 ]]; do
+ sleep 1;
+done
+
+$ADB_CMD root
+$ADB_CMD remount
+
+push_apk priv-app NetworkStackGoogle NetworkStack
+push_apk app CaptivePortalLoginGoogle CaptivePortalLogin
+push_apex com.google.android.tethering com.android.tethering
+push_apex com.google.android.cellbroadcast com.android.cellbroadcast
+push_apex com.google.android.resolv com.android.resolv
+
+# Replace the network_stack key used to set its sepolicy context
+rm -f /tmp/pulled_plat_mac_permissions.xml
+$ADB_CMD pull /system/etc/selinux/plat_mac_permissions.xml /tmp/pulled_plat_mac_permissions.xml
+sed_replace='s/<signer signature="[0-9a-fA-F]+"><seinfo value="network_stack"\/><\/signer>/'$NETWORKSTACK_AOSP_SEPOLICY_KEY'/'
+sed -E "$sed_replace" /tmp/pulled_plat_mac_permissions.xml |
+ $ADB_CMD shell 'cat > /system/etc/selinux/plat_mac_permissions.xml'
+rm /tmp/pulled_plat_mac_permissions.xml
+
+# Update the networkstack privapp-permissions allowlist
+rm -f /tmp/pulled_privapp-permissions.xml
+$ADB_CMD pull /system/etc/permissions/privapp-permissions-google.xml /tmp/pulled_privapp-permissions.xml
+
+# Remove last </permission> line, and the permissions for com.google.android.networkstack
+sed -nE '1,/<\/permissions>/p' /tmp/pulled_privapp-permissions.xml \
+ | sed -E '/com.google.android.networkstack/,/privapp-permissions/d' > /tmp/modified_privapp-permissions.xml
+# Add the AOSP permissions and re-add the </permissions> line
+sed -nE '/com.android.networkstack/,/privapp-permissions/p' $ANDROID_PRODUCT_OUT/system/etc/permissions/com.android.networkstack.xml \
+ >> /tmp/modified_privapp-permissions.xml
+echo '</permissions>' >> /tmp/modified_privapp-permissions.xml
+
+$ADB_CMD push /tmp/modified_privapp-permissions.xml /system/etc/permissions/privapp-permissions-google.xml
+
+rm /tmp/pulled_privapp-permissions.xml /tmp/modified_privapp-permissions.xml
+
+echo "Done modifying, rebooting"
+$ADB_CMD reboot
\ No newline at end of file