Merge "Add networkAllowBypassVpnOnNetwork to INetd.aidl interface" 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 0b6ecef..0000000
--- a/Cronet/tests/common/Android.bp
+++ /dev/null
@@ -1,79 +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.
-// Target used for coverage. Combines CTS tests and our MTS tests.
-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"],
-}
-
-// MTS-only specific targets.
-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)",
-}
-
-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",
-}
diff --git a/Cronet/tests/common/AndroidManifest.xml b/Cronet/tests/common/AndroidManifest.xml
deleted file mode 100644
index 418af86..0000000
--- a/Cronet/tests/common/AndroidManifest.xml
+++ /dev/null
@@ -1,36 +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">
-
-    <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"
-                 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 bb7ed11..0000000
--- a/Cronet/tests/common/AndroidTest.xml
+++ /dev/null
@@ -1,59 +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 however Cronet is installed on 31+ due to b/270049141. -->
-    <object type="module_controller"
-            class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" />
-    <!-- Only run NetHttpCoverageTests 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>
-    <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/common/jarjar_excludes.txt b/Cronet/tests/common/jarjar_excludes.txt
deleted file mode 100644
index b5cdf6e..0000000
--- a/Cronet/tests/common/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/common/res/raw/quicroot.pem b/Cronet/tests/common/res/raw/quicroot.pem
deleted file mode 100644
index af21b3e..0000000
--- a/Cronet/tests/common/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/common/res/values/cronet-test-rule-configuration.xml b/Cronet/tests/common/res/values/cronet-test-rule-configuration.xml
deleted file mode 100644
index 48ce420..0000000
--- a/Cronet/tests/common/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/common/res/xml/network_security_config.xml b/Cronet/tests/common/res/xml/network_security_config.xml
deleted file mode 100644
index 32b7171..0000000
--- a/Cronet/tests/common/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/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/TEST_MAPPING b/TEST_MAPPING
index 2856554..375397b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -252,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": [
@@ -292,9 +279,6 @@
     },
     {
       "name": "FrameworksNetTests"
-    },
-    {
-      "name": "NetHttpCoverageTests"
     }
   ],
   "mainline-presubmit": [
@@ -421,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": [
         {
@@ -480,6 +452,9 @@
       "path": "packages/modules/CaptivePortalLogin"
     },
     {
+      "path": "external/cronet"
+    },
+    {
       "path": "vendor/xts/gts-tests/hostsidetests/networkstack"
     }
   ]
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 56537d9..c726dab 100644
--- a/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
+++ b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
@@ -100,23 +100,26 @@
     public static final long ENABLE_MATCH_LOCAL_NETWORK = 319212206L;
 
     /**
-     * On Android {@link android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM} or higher releases, when
-     * apps targeting Android {@link android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM} or higher
-     * that do not have the {@link android.Manifest.permission#INTERNET} permission call
-     * {@link android.net.ConnectivityManager#getActiveNetworkInfo()}, the state of the returned
-     * {@link android.net.NetworkInfo} object will always be
-     * {@link android.net.NetworkInfo.DetailedState#BLOCKED}. This is because apps without the
-     * permission cannot access any network.
+     * 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,
-     * will instead receive objects with the network's current state,
-     * such as {@link android.net.NetworkInfo.DetailedState#CONNECTED}.
+     * 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.UPSIDE_DOWN_CAKE)
-    public static final long NETWORKINFO_WITHOUT_INTERNET_BLOCKED = 333340911L;
+    @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 ccb6acb..dc67f83 100644
--- a/netbpfload/NetBpfLoad.cpp
+++ b/netbpfload/NetBpfLoad.cpp
@@ -306,6 +306,7 @@
 
         if (bad && !isGSI()) {
             ALOGE("Unsupported kernel version (%07x).", kernelVersion());
+            sleep(60);
         }
     }
 
@@ -432,6 +433,7 @@
             ALOGE("Failed to set bpf.progs_loaded property to 1.");
             return 125;
         }
+        ALOGI("success.");
         return 0;
     }
 
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index b535ebf..91fec90 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "BpfHandler"
+#define LOG_TAG "NetdUpdatable"
 
 #include "BpfHandler.h"
 
diff --git a/remoteauth/service/jni/Android.bp b/remoteauth/service/jni/Android.bp
index c0ac779..fc91e0c 100644
--- a/remoteauth/service/jni/Android.bp
+++ b/remoteauth/service/jni/Android.bp
@@ -12,7 +12,7 @@
     srcs: ["src/lib.rs"],
     rustlibs: [
         "libbinder_rs",
-        "libjni",
+        "libjni_legacy",
         "liblazy_static",
         "liblog_rust",
         "liblogger",
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 23af0f8..1047232 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -55,6 +55,7 @@
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.os.UserHandle;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.ArraySet;
@@ -815,8 +816,11 @@
      */
     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     public int getNetPermForUid(final int uid) {
+        final int appId = UserHandle.getAppId(uid);
         try {
-            final U8 permissions = sUidPermissionMap.getValue(new S32(uid));
+            // Key of uid permission map is appId
+            // TODO: Rename map name
+            final U8 permissions = sUidPermissionMap.getValue(new S32(appId));
             return permissions != null ? permissions.val : PERMISSION_INTERNET;
         } catch (ErrnoException e) {
             Log.wtf(TAG, "Failed to get permission for uid: " + uid);
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 46bd9bc..99ed4ce 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -102,7 +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.NETWORKINFO_WITHOUT_INTERNET_BLOCKED;
+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;
@@ -120,6 +120,7 @@
 import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr;
 import static com.android.net.module.util.PermissionUtils.hasAnyPermissionOf;
 import static com.android.server.ConnectivityStatsLog.CONNECTIVITY_STATE_SAMPLE;
+import static com.android.server.connectivity.ConnectivityFlags.DELAY_DESTROY_SOCKETS;
 import static com.android.server.connectivity.ConnectivityFlags.REQUEST_RESTRICTED_WIFI;
 import static com.android.server.connectivity.ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING;
 
@@ -554,6 +555,8 @@
      * default network for each app.
      * Order ints passed to netd must be in the 0~999 range. Larger values code for
      * a lower priority, see {@link NativeUidRangeConfig}.
+     * Note that only the highest priority preference is applied if the uid is the target of
+     * multiple preferences.
      *
      * Requests that don't code for a per-app preference use PREFERENCE_ORDER_INVALID.
      * The default request uses PREFERENCE_ORDER_DEFAULT.
@@ -996,14 +999,18 @@
     // Flag to enable the feature of closing frozen app sockets.
     private final boolean mDestroyFrozenSockets;
 
-    // Flag to optimize closing frozen app sockets by waiting for the cellular modem to wake up.
-    private final boolean mDelayDestroyFrozenSockets;
+    // Flag to optimize closing app sockets by waiting for the cellular modem to wake up.
+    private final boolean mDelayDestroySockets;
 
     // Flag to allow SysUI to receive connectivity reports for wifi picker UI.
     private final boolean mAllowSysUiConnectivityReports;
 
     // Uids that ConnectivityService is pending to close sockets of.
-    private final Set<Integer> mPendingFrozenUids = new ArraySet<>();
+    // Key is uid and value is reasons of socket destroy
+    private final SparseIntArray mDestroySocketPendingUids = new SparseIntArray();
+
+    private static final int DESTROY_SOCKET_REASON_NONE = 0;
+    private static final int DESTROY_SOCKET_REASON_FROZEN = 1 << 0;
 
     // Flag to drop packets to VPN addresses ingressing via non-VPN interfaces.
     private final boolean mIngressToVpnAddressFiltering;
@@ -1952,8 +1959,7 @@
 
         mDestroyFrozenSockets = mDeps.isAtLeastV() || (mDeps.isAtLeastU()
                 && mDeps.isFeatureEnabled(context, KEY_DESTROY_FROZEN_SOCKETS_VERSION));
-        mDelayDestroyFrozenSockets = mDeps.isAtLeastU()
-                && mDeps.isFeatureEnabled(context, DELAY_DESTROY_FROZEN_SOCKETS_VERSION);
+        mDelayDestroySockets = mDeps.isFeatureNotChickenedOut(context, DELAY_DESTROY_SOCKETS);
         mAllowSysUiConnectivityReports = mDeps.isFeatureNotChickenedOut(
                 mContext, ALLOW_SYSUI_CONNECTIVITY_REPORTS);
         if (mDestroyFrozenSockets) {
@@ -2229,6 +2235,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.
      */
@@ -2243,8 +2254,13 @@
         try {
             final boolean metered = nc == null ? true : nc.isMetered();
             if (mDeps.isAtLeastV()) {
-                return mBpfNetMaps.isUidNetworkingBlocked(uid, metered)
-                        || (mBpfNetMaps.getNetPermForUid(uid) & PERMISSION_INTERNET) == 0;
+                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);
             }
@@ -2325,12 +2341,7 @@
         final int uid = mDeps.getCallingUid();
         final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
         if (nai == null) return null;
-        // Ignore blocked state to keep the backward compatibility if the compat flag is
-        // disabled and app does not have PERMISSION_INTERNET.
-        final boolean ignoreBlocked = mDeps.isAtLeastV()
-                && !mDeps.isChangeEnabled(NETWORKINFO_WITHOUT_INTERNET_BLOCKED, uid)
-                && (mBpfNetMaps.getNetPermForUid(uid) & PERMISSION_INTERNET) == 0;
-        final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, ignoreBlocked);
+        final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false /* ignoreBlocked */);
         maybeLogBlockedNetworkInfo(networkInfo, uid);
         return networkInfo;
     }
@@ -3342,44 +3353,51 @@
         return !mNetworkActivityTracker.isDefaultNetworkActive();
     }
 
-    private void handleFrozenUids(int[] uids, int[] frozenStates) {
-        final ArraySet<Integer> ownerUids = new ArraySet<>();
-
-        for (int i = 0; i < uids.length; i++) {
-            if (frozenStates[i] == UID_FROZEN_STATE_FROZEN) {
-                ownerUids.add(uids[i]);
-            } else {
-                mPendingFrozenUids.remove(uids[i]);
-            }
-        }
-
-        if (ownerUids.isEmpty()) {
-            return;
-        }
-
-        if (mDelayDestroyFrozenSockets && isCellNetworkIdle()) {
-            // Delay closing sockets to avoid waking the cell modem up.
-            // Wi-Fi network state is not considered since waking Wi-Fi modem up is much cheaper
-            // than waking cell modem up.
-            mPendingFrozenUids.addAll(ownerUids);
+    private void updateDestroySocketReasons(final int uid, final int reason,
+            final boolean addReason) {
+        final int destroyReasons = mDestroySocketPendingUids.get(uid, DESTROY_SOCKET_REASON_NONE);
+        if (addReason) {
+            mDestroySocketPendingUids.put(uid, destroyReasons | reason);
         } else {
-            try {
-                mDeps.destroyLiveTcpSocketsByOwnerUids(ownerUids);
-            } catch (SocketException | InterruptedIOException | ErrnoException e) {
-                loge("Exception in socket destroy: " + e);
+            final int newDestroyReasons = destroyReasons & ~reason;
+            if (newDestroyReasons == DESTROY_SOCKET_REASON_NONE) {
+                mDestroySocketPendingUids.delete(uid);
+            } else {
+                mDestroySocketPendingUids.put(uid, newDestroyReasons);
             }
         }
     }
 
-    private void closePendingFrozenSockets() {
+    private void handleFrozenUids(int[] uids, int[] frozenStates) {
         ensureRunningOnConnectivityServiceThread();
+        for (int i = 0; i < uids.length; i++) {
+            final int uid = uids[i];
+            final boolean addReason = frozenStates[i] == UID_FROZEN_STATE_FROZEN;
+            updateDestroySocketReasons(uid, DESTROY_SOCKET_REASON_FROZEN, addReason);
+        }
+
+        if (!mDelayDestroySockets || !isCellNetworkIdle()) {
+            destroyPendingSockets();
+        }
+    }
+
+    private void destroyPendingSockets() {
+        ensureRunningOnConnectivityServiceThread();
+        if (mDestroySocketPendingUids.size() == 0) {
+            return;
+        }
+
+        Set<Integer> uids = new ArraySet<>();
+        for (int i = 0; i < mDestroySocketPendingUids.size(); i++) {
+            uids.add(mDestroySocketPendingUids.keyAt(i));
+        }
 
         try {
-            mDeps.destroyLiveTcpSocketsByOwnerUids(mPendingFrozenUids);
+            mDeps.destroyLiveTcpSocketsByOwnerUids(uids);
         } catch (SocketException | InterruptedIOException | ErrnoException e) {
-            loge("Failed to close pending frozen app sockets: " + e);
+            loge("Failed to destroy sockets: " + e);
         }
-        mPendingFrozenUids.clear();
+        mDestroySocketPendingUids.clear();
     }
 
     private void handleReportNetworkActivity(final NetworkActivityParams params) {
@@ -3396,40 +3414,42 @@
             isCellNetworkActivity = params.label == TRANSPORT_CELLULAR;
         }
 
-        if (mDelayDestroyFrozenSockets
-                && params.isActive
-                && isCellNetworkActivity
-                && !mPendingFrozenUids.isEmpty()) {
-            closePendingFrozenSockets();
+        if (mDelayDestroySockets && params.isActive && isCellNetworkActivity) {
+            destroyPendingSockets();
         }
     }
 
     /**
-     * If the cellular network is no longer the default network, close pending frozen sockets.
+     * If the cellular network is no longer the default network, destroy pending sockets.
      *
      * @param newNetwork new default network
      * @param oldNetwork old default network
      */
-    private void maybeClosePendingFrozenSockets(NetworkAgentInfo newNetwork,
+    private void maybeDestroyPendingSockets(NetworkAgentInfo newNetwork,
             NetworkAgentInfo oldNetwork) {
         final boolean isOldNetworkCellular = oldNetwork != null
                 && oldNetwork.networkCapabilities.hasTransport(TRANSPORT_CELLULAR);
         final boolean isNewNetworkCellular = newNetwork != null
                 && newNetwork.networkCapabilities.hasTransport(TRANSPORT_CELLULAR);
 
-        if (isOldNetworkCellular
-                && !isNewNetworkCellular
-                && !mPendingFrozenUids.isEmpty()) {
-            closePendingFrozenSockets();
+        if (isOldNetworkCellular && !isNewNetworkCellular) {
+            destroyPendingSockets();
         }
     }
 
-    private void dumpCloseFrozenAppSockets(IndentingPrintWriter pw) {
-        pw.println("CloseFrozenAppSockets:");
+    private void dumpDestroySockets(IndentingPrintWriter pw) {
+        pw.println("DestroySockets:");
         pw.increaseIndent();
         pw.print("mDestroyFrozenSockets="); pw.println(mDestroyFrozenSockets);
-        pw.print("mDelayDestroyFrozenSockets="); pw.println(mDelayDestroyFrozenSockets);
-        pw.print("mPendingFrozenUids="); pw.println(mPendingFrozenUids);
+        pw.print("mDelayDestroySockets="); pw.println(mDelayDestroySockets);
+        pw.print("mDestroySocketPendingUids:");
+        pw.increaseIndent();
+        for (int i = 0; i < mDestroySocketPendingUids.size(); i++) {
+            final int uid = mDestroySocketPendingUids.keyAt(i);
+            final int reasons = mDestroySocketPendingUids.valueAt(i);
+            pw.print(uid + ": reasons=" + reasons);
+        }
+        pw.decreaseIndent();
         pw.decreaseIndent();
     }
 
@@ -3455,9 +3475,6 @@
 
     @VisibleForTesting
     static final String KEY_DESTROY_FROZEN_SOCKETS_VERSION = "destroy_frozen_sockets_version";
-    @VisibleForTesting
-    static final String DELAY_DESTROY_FROZEN_SOCKETS_VERSION =
-            "delay_destroy_frozen_sockets_version";
 
     @VisibleForTesting
     public static final String ALLOW_SYSUI_CONNECTIVITY_REPORTS =
@@ -4091,7 +4108,7 @@
         dumpAvoidBadWifiSettings(pw);
 
         pw.println();
-        dumpCloseFrozenAppSockets(pw);
+        dumpDestroySockets(pw);
 
         pw.println();
         dumpBpfProgramStatus(pw);
@@ -5204,7 +5221,7 @@
 
                 if (mDefaultRequest == nri) {
                     mNetworkActivityTracker.updateDefaultNetwork(null /* newNetwork */, nai);
-                    maybeClosePendingFrozenSockets(null /* newNetwork */, nai);
+                    maybeDestroyPendingSockets(null /* newNetwork */, nai);
                     ensureNetworkTransitionWakelock(nai.toShortString());
                 }
             }
@@ -10080,7 +10097,7 @@
             mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
         }
         mNetworkActivityTracker.updateDefaultNetwork(newDefaultNetwork, oldDefaultNetwork);
-        maybeClosePendingFrozenSockets(newDefaultNetwork, oldDefaultNetwork);
+        maybeDestroyPendingSockets(newDefaultNetwork, oldDefaultNetwork);
         mProxyTracker.setDefaultProxy(null != newDefaultNetwork
                 ? newDefaultNetwork.linkProperties.getHttpProxy() : null);
         resetHttpProxyForNonDefaultNetwork(oldDefaultNetwork);
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index aec4f24..634a8fa 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -524,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");
@@ -604,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.
@@ -647,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/ConnectivityFlags.java b/service/src/com/android/server/connectivity/ConnectivityFlags.java
index 176307d..7ea7f95 100644
--- a/service/src/com/android/server/connectivity/ConnectivityFlags.java
+++ b/service/src/com/android/server/connectivity/ConnectivityFlags.java
@@ -44,6 +44,8 @@
 
     public static final String BACKGROUND_FIREWALL_CHAIN = "background_firewall_chain";
 
+    public static final String DELAY_DESTROY_SOCKETS = "delay_destroy_sockets";
+
     private boolean mNoRematchAllRequestsOnRegister;
 
     /**
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/MulticastRoutingCoordinatorService.java b/service/src/com/android/server/connectivity/MulticastRoutingCoordinatorService.java
index ac479b8..af4aee5 100644
--- a/service/src/com/android/server/connectivity/MulticastRoutingCoordinatorService.java
+++ b/service/src/com/android/server/connectivity/MulticastRoutingCoordinatorService.java
@@ -168,14 +168,18 @@
     public void applyMulticastRoutingConfig(
             final String iifName, final String oifName, final MulticastRoutingConfig newConfig) {
         checkOnHandlerThread();
+        Objects.requireNonNull(iifName, "IifName can't be null");
+        Objects.requireNonNull(oifName, "OifName can't be null");
 
         if (newConfig.getForwardingMode() != FORWARD_NONE) {
             // Make sure iif and oif are added as multicast forwarding interfaces
-            try {
-                maybeAddAndTrackInterface(iifName);
-                maybeAddAndTrackInterface(oifName);
-            } catch (IllegalStateException e) {
-                Log.e(TAG, "Failed to apply multicast routing config, ", e);
+            if (!maybeAddAndTrackInterface(iifName) || !maybeAddAndTrackInterface(oifName)) {
+                Log.e(
+                        TAG,
+                        "Failed to apply multicast routing config from "
+                                + iifName
+                                + " to "
+                                + oifName);
                 return;
             }
         }
@@ -258,9 +262,14 @@
         }
     }
 
+    /**
+     * Returns the next available virtual index for multicast routing, or -1 if the number of
+     * virtual interfaces has reached max value.
+     */
     private int getNextAvailableVirtualIndex() {
         if (mVirtualInterfaces.size() >= MAX_NUM_OF_MULTICAST_VIRTUAL_INTERFACES) {
-            throw new IllegalStateException("Can't allocate new multicast virtual interface");
+            Log.e(TAG, "Can't allocate new multicast virtual interface");
+            return -1;
         }
         for (int i = 0; i < mVirtualInterfaces.size(); i++) {
             if (!mVirtualInterfaces.contains(i)) {
@@ -291,12 +300,23 @@
         return mVirtualInterfaces.get(virtualIndex);
     }
 
-    private void maybeAddAndTrackInterface(String ifName) {
+    /**
+     * Returns {@code true} if the interfaces is added and tracked, or {@code false} when failed
+     * to add the interface.
+     */
+    private boolean maybeAddAndTrackInterface(String ifName) {
         checkOnHandlerThread();
-        if (getIndexForValue(mVirtualInterfaces, ifName) >= 0) return;
+        if (getIndexForValue(mVirtualInterfaces, ifName) >= 0) return true;
 
         int nextVirtualIndex = getNextAvailableVirtualIndex();
+        if (nextVirtualIndex < 0) {
+            return false;
+        }
         int ifIndex = mDependencies.getInterfaceIndex(ifName);
+        if (ifIndex == 0) {
+            Log.e(TAG, "Can't get interface index for " + ifName);
+            return false;
+        }
         final StructMif6ctl mif6ctl =
                     new StructMif6ctl(
                             nextVirtualIndex,
@@ -309,10 +329,11 @@
             Log.d(TAG, "Added mifi " + nextVirtualIndex + " to MIF");
         } catch (ErrnoException e) {
             Log.e(TAG, "failed to add multicast virtual interface", e);
-            return;
+            return false;
         }
         mVirtualInterfaces.put(nextVirtualIndex, ifName);
         mInterfaces.put(ifIndex, ifName);
+        return true;
     }
 
     @VisibleForTesting
@@ -798,13 +819,12 @@
             NetworkUtils.setsockoptBytes(fd, IPPROTO_IPV6, MRT6_DEL_MFC, bytes);
         }
 
-        public Integer getInterfaceIndex(String ifName) {
-            try {
-                NetworkInterface ni = NetworkInterface.getByName(ifName);
-                return ni.getIndex();
-            } catch (NullPointerException | SocketException e) {
-                return null;
-            }
+        /**
+         * Returns the interface index for an interface name, or 0 if the interface index could
+         * not be found.
+         */
+        public int getInterfaceIndex(String ifName) {
+            return Os.if_nametoindex(ifName);
         }
 
         public NetworkInterface getNetworkInterface(int physicalIndex) {
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/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/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/tests/common/Android.bp b/tests/common/Android.bp
index 6e9d614..e95a81a 100644
--- a/tests/common/Android.bp
+++ b/tests/common/Android.bp
@@ -201,3 +201,8 @@
     name: "connectivity-mainline-presubmit-java-defaults",
     test_mainline_modules: mainline_presubmit_modules,
 }
+
+filegroup {
+    name: "connectivity_mainline_test_map",
+    srcs: ["connectivity_mainline_test.map"],
+}
diff --git a/tests/common/connectivity_mainline_test.map b/tests/common/connectivity_mainline_test.map
new file mode 100644
index 0000000..043312e
--- /dev/null
+++ b/tests/common/connectivity_mainline_test.map
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+# Some connectivity tests run on older OS versions, and for those tests, many
+# library dependencies (such as libbase and libc++) need to be linked
+# statically. The tests also need to be linked with a version script to ensure
+# that the statically-linked library isn't exported from the executable, where
+# it would override the shared libraries that the OS itself uses. See
+# b/333438055 for an example of what goes wrong when libc++ is partially
+# exported from an executable.
+{
+  local:
+    *;
+};
diff --git a/tests/mts/Android.bp b/tests/mts/Android.bp
index 336be2e..c118d0a 100644
--- a/tests/mts/Android.bp
+++ b/tests/mts/Android.bp
@@ -31,6 +31,8 @@
     header_libs: [
         "bpf_headers",
     ],
+    version_script: ":connectivity_mainline_test_map",
+    stl: "libc++_static",
     static_libs: [
         "libbase",
         "libmodules-utils-build",
diff --git a/tests/native/connectivity_native_test/Android.bp b/tests/native/connectivity_native_test/Android.bp
index 2f66d17..c5088c6 100644
--- a/tests/native/connectivity_native_test/Android.bp
+++ b/tests/native/connectivity_native_test/Android.bp
@@ -17,8 +17,9 @@
         "connectivity_native_test.cpp",
     ],
     header_libs: ["bpf_connectivity_headers"],
+    version_script: ":connectivity_mainline_test_map",
+    stl: "libc++_static",
     shared_libs: [
-        "libbase",
         "libbinder_ndk",
         "liblog",
         "libnetutils",
@@ -26,6 +27,7 @@
     ],
     static_libs: [
         "connectivity_native_aidl_interface-lateststable-ndk",
+        "libbase",
         "libcutils",
         "libmodules-utils-build",
         "libutils",
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 717c5a1..2718961 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -152,7 +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.NETWORKINFO_WITHOUT_INTERNET_BLOCKED;
+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;
@@ -163,7 +163,6 @@
 import static android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
 
 import static com.android.server.ConnectivityService.ALLOW_SATALLITE_NETWORK_FALLBACK;
-import static com.android.server.ConnectivityService.DELAY_DESTROY_FROZEN_SOCKETS_VERSION;
 import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
 import static com.android.server.ConnectivityService.ALLOW_SYSUI_CONNECTIVITY_REPORTS;
 import static com.android.server.ConnectivityService.KEY_DESTROY_FROZEN_SOCKETS_VERSION;
@@ -178,6 +177,7 @@
 import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackRegister;
 import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister;
 import static com.android.server.connectivity.ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN;
+import static com.android.server.connectivity.ConnectivityFlags.DELAY_DESTROY_SOCKETS;
 import static com.android.server.connectivity.ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING;
 import static com.android.testutils.Cleanup.testAndCleanup;
 import static com.android.testutils.ConcurrentUtils.await;
@@ -1948,7 +1948,8 @@
         setAlwaysOnNetworks(false);
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
 
-        mDeps.setChangeIdEnabled(true, NETWORKINFO_WITHOUT_INTERNET_BLOCKED, Process.myUid());
+        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
@@ -2168,8 +2169,6 @@
                     return true;
                 case KEY_DESTROY_FROZEN_SOCKETS_VERSION:
                     return true;
-                case DELAY_DESTROY_FROZEN_SOCKETS_VERSION:
-                    return true;
                 default:
                     return super.isFeatureEnabled(context, name);
             }
@@ -2186,6 +2185,8 @@
                     return true;
                 case BACKGROUND_FIREWALL_CHAIN:
                     return true;
+                case DELAY_DESTROY_SOCKETS:
+                    return true;
                 default:
                     return super.isFeatureNotChickenedOut(context, name);
             }
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/connectivityservice/CSActiveNetworkInfoTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSActiveNetworkInfoTest.kt
index 1891a78..360a298 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSActiveNetworkInfoTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSActiveNetworkInfoTest.kt
@@ -24,7 +24,7 @@
 import android.net.NetworkCapabilities.TRANSPORT_WIFI
 import android.net.NetworkInfo.DetailedState.BLOCKED
 import android.net.NetworkInfo.DetailedState.CONNECTED
-import android.net.connectivity.ConnectivityCompatChanges.NETWORKINFO_WITHOUT_INTERNET_BLOCKED
+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
@@ -53,7 +53,7 @@
             permissions: Int,
             expectBlocked: Boolean
     ) {
-        deps.setChangeIdEnabled(changeEnabled, NETWORKINFO_WITHOUT_INTERNET_BLOCKED)
+        deps.setChangeIdEnabled(changeEnabled, NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION)
         doReturn(permissions).`when`(bpfNetMaps).getNetPermForUid(anyInt())
 
         val agent = Agent(nc = nc())
@@ -66,6 +66,7 @@
         } else {
             assertEquals(CONNECTED, networkInfo.detailedState)
         }
+        assertEquals(expectBlocked, cm.activeNetwork == null)
         agent.disconnect()
     }
 
@@ -82,8 +83,8 @@
                 permissions = PERMISSION_INTERNET,
                 expectBlocked = true
         )
-        // getActiveNetworkInfo does not return NetworkInfo with blocked state if the compat change
-        // is disabled and the app does not have PERMISSION_INTERNET
+        // 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,
diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
index 3b06ad0..63ef86e 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
@@ -157,11 +157,11 @@
         it[ConnectivityFlags.NO_REMATCH_ALL_REQUESTS_ON_REGISTER] = true
         it[ConnectivityFlags.REQUEST_RESTRICTED_WIFI] = true
         it[ConnectivityService.KEY_DESTROY_FROZEN_SOCKETS_VERSION] = true
-        it[ConnectivityService.DELAY_DESTROY_FROZEN_SOCKETS_VERSION] = true
         it[ConnectivityService.ALLOW_SYSUI_CONNECTIVITY_REPORTS] = true
         it[ConnectivityService.ALLOW_SATALLITE_NETWORK_FALLBACK] = true
         it[ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING] = true
         it[ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN] = true
+        it[ConnectivityFlags.DELAY_DESTROY_SOCKETS] = true
     }
     fun setFeatureEnabled(flag: String, enabled: Boolean) = enabledFeatures.set(flag, enabled)
 
@@ -171,7 +171,11 @@
     val contentResolver = makeMockContentResolver(context)
 
     val PRIMARY_USER = 0
-    val PRIMARY_USER_INFO = UserInfo(PRIMARY_USER, "" /* name */, UserInfo.FLAG_PRIMARY)
+    val PRIMARY_USER_INFO = UserInfo(
+            PRIMARY_USER,
+            "", // name
+            UserInfo.FLAG_PRIMARY
+    )
     val PRIMARY_USER_HANDLE = UserHandle(PRIMARY_USER)
     val userManager = makeMockUserManager(PRIMARY_USER_INFO, PRIMARY_USER_HANDLE)
     val activityManager = makeActivityManager()
@@ -186,7 +190,11 @@
     val bpfNetMaps = mock<BpfNetMaps>()
     val clatCoordinator = mock<ClatCoordinator>()
     val networkRequestStateStatsMetrics = mock<NetworkRequestStateStatsMetrics>()
-    val proxyTracker = ProxyTracker(context, mock<Handler>(), 16 /* EVENT_PROXY_HAS_CHANGED */)
+    val proxyTracker = ProxyTracker(
+            context,
+            mock<Handler>(),
+            16 // EVENT_PROXY_HAS_CHANGED
+    )
     val systemConfigManager = makeMockSystemConfigManager()
     val batteryStats = mock<IBatteryStats>()
     val batteryManager = BatteryStatsManager(batteryStats)
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/TunInterfaceController.java b/thread/service/java/com/android/server/thread/TunInterfaceController.java
index c3f6ace..976f93d 100644
--- a/thread/service/java/com/android/server/thread/TunInterfaceController.java
+++ b/thread/service/java/com/android/server/thread/TunInterfaceController.java
@@ -16,30 +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;
@@ -47,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;
 
@@ -62,14 +75,13 @@
 
     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 NetworkInterface mNetworkInterface;
     private final List<InetAddress> mMulticastAddresses = new ArrayList<>();
     private final List<RouteInfo> mNetDataPrefixes = new ArrayList<>();
 
+    private ParcelFileDescriptor mParcelTunFd;
+    private NetworkInterface mNetworkInterface;
+
     /** Creates a new {@link TunInterfaceController} instance for given interface. */
     public TunInterfaceController(String interfaceName) {
         mIfName = interfaceName;
@@ -91,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;
     }
 
@@ -128,6 +135,10 @@
             for (LinkAddress address : mLinkProperties.getAllLinkAddresses()) {
                 removeAddress(address);
             }
+            for (RouteInfo route : mLinkProperties.getAllRoutes()) {
+                mLinkProperties.removeRoute(route);
+            }
+            mNetDataPrefixes.clear();
         }
         nativeSetInterfaceUp(mIfName, isUp);
     }
@@ -138,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);
@@ -153,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);
@@ -184,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());
         }
     }
 
@@ -362,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 4028014..61b6eac 100644
--- a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
+++ b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
@@ -176,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();
@@ -185,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);
     }
@@ -307,6 +310,23 @@
                 .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 3a31ea5..46cf562 100644
--- a/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
+++ b/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
@@ -80,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()));
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 78f5770..ada46c8 100644
--- a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
+++ b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
@@ -301,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);
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..8b2bed3
--- /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="ThreadNetworkMultiDeviceTests" />
+      <!-- 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/tools/aospify_device.sh b/tools/aospify_device.sh
index f25ac9d..0176093 100755
--- a/tools/aospify_device.sh
+++ b/tools/aospify_device.sh
@@ -3,10 +3,14 @@
 # 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.
+# partition using overlayfs. The setup wizard should be cleared before running the script.
 #
 # Usage: aospify_device.sh [device_serial]
-# Reset by wiping data (adb reboot bootloader && fastboot erase userdata && fastboot reboot).
+#
+# Reset with "adb enable-verity", then wiping data (from Settings, or:
+# "adb reboot bootloader && fastboot erase userdata && fastboot reboot").
+# Some devices output errors like "Overlayfs teardown failed" on "enable-verity" but it still works
+# (/mnt/scratch should be deleted).
 #
 # This applies to NetworkStack, CaptivePortalLogin, dnsresolver, tethering, cellbroadcast modules,
 # which generally need to be preloaded together (core networking modules + cellbroadcast which
@@ -37,6 +41,10 @@
     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
+        if ! $ADB_CMD shell ls /system/apex/$original_apex_name.apex 1>/dev/null 2>/dev/null; then
+            # Filename observed on some phones, even though it is not actually compressed
+            original_apex_name=${original_apex_name}_compressed
+        fi
         $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
@@ -47,7 +55,7 @@
     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 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/
 }
 
@@ -97,7 +105,7 @@
     exit 1
 fi
 
-if ! $ADB_CMD wait-for-device shell pm path com.google.android.networkstack; then
+if ! $ADB_CMD wait-for-device shell pm path com.google.android.networkstack 1>/dev/null 2>/dev/null; then
     echo "This device is already not using GMS modules"
     exit 1
 fi
@@ -122,8 +130,7 @@
 $ADB_CMD reboot
 
 echo "Waiting for boot..."
-$ADB_CMD wait-for-device;
-until [[ $($ADB_CMD shell getprop sys.boot_completed) == 1 ]]; do
+until [[ $($ADB_CMD wait-for-device shell getprop sys.boot_completed) == 1 ]]; do
     sleep 1;
 done
 
@@ -146,7 +153,12 @@
 
 # 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
+networkstack_permissions=/system/etc/permissions/GoogleNetworkStack_permissions.xml
+if ! $ADB_CMD shell ls $networkstack_permissions 1>/dev/null 2>/dev/null; then
+    networkstack_permissions=/system/etc/permissions/privapp-permissions-google.xml
+fi
+
+$ADB_CMD pull $networkstack_permissions /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 \
@@ -156,7 +168,7 @@
     >> /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
+$ADB_CMD push /tmp/modified_privapp-permissions.xml $networkstack_permissions
 
 rm /tmp/pulled_privapp-permissions.xml /tmp/modified_privapp-permissions.xml