Merge "Ban use of Thread.sleep() - HostsideRestrictBackgroundNetworkTests and ..."
diff --git a/Cronet/tests/common/Android.bp b/Cronet/tests/common/Android.bp
new file mode 100644
index 0000000..1ed0881
--- /dev/null
+++ b/Cronet/tests/common/Android.bp
@@ -0,0 +1,39 @@
+// 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 {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+// TODO: Consider merging with ConnectivityCoverageTests which is a collection of all
+// Connectivity tests being used for coverage. This will depend on how far we decide to
+// go with merging NetHttp and Tethering targets.
+android_test {
+    name: "NetHttpCoverageTests",
+    defaults: ["CronetTestJavaDefaults"],
+    sdk_version: "test_current",
+    test_suites: ["general-tests", "mts-tethering"],
+    static_libs: [
+        "modules-utils-native-coverage-listener",
+        "CtsNetHttpTestsLib",
+        "NetHttpTestsLibPreJarJar",
+    ],
+    jarjar_rules: ":framework-tethering-jarjar-rules",
+    compile_multilib: "both",
+}
diff --git a/Cronet/tests/common/AndroidManifest.xml b/Cronet/tests/common/AndroidManifest.xml
new file mode 100644
index 0000000..efe880c
--- /dev/null
+++ b/Cronet/tests/common/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="com.android.net.http.tests.coverage">
+    <!-- NetHttpCoverageTests combines CtsNetHttpTestCases and NetHttpTests targets,
+     so permissions and others are declared in their respective manifests -->
+    <application tools:replace="android:label"
+                 android:label="NetHttp coverage tests">
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.net.http.tests.coverage"
+                     android:label="NetHttp coverage tests">
+    </instrumentation>
+</manifest>
diff --git a/Cronet/tests/common/AndroidTest.xml b/Cronet/tests/common/AndroidTest.xml
new file mode 100644
index 0000000..ca298dd
--- /dev/null
+++ b/Cronet/tests/common/AndroidTest.xml
@@ -0,0 +1,33 @@
+<!--
+  ~ 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" />
+    <!-- Tethering/Connectivity is a SDK 30+ module -->
+    <object type="module_controller"
+            class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+    <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" />
+        <option name="hidden-api-checks" value="false"/>
+        <option
+            name="device-listeners"
+            value="com.android.modules.utils.testing.NativeCoverageHackInstrumentationListener" />
+    </test>
+</configuration>
diff --git a/Cronet/tests/cts/Android.bp b/Cronet/tests/cts/Android.bp
index 2c28b8d..9f92dba 100644
--- a/Cronet/tests/cts/Android.bp
+++ b/Cronet/tests/cts/Android.bp
@@ -41,25 +41,22 @@
     defaults: [cronet_test_java_defaults],
 }
 
-android_test {
-    name: "CtsNetHttpTestCases",
-    compile_multilib: "both", // Include both the 32 and 64 bit versions
-    defaults: [
-        "CronetTestJavaDefaults",
-        "cts_defaults",
-    ],
+android_library {
+    name: "CtsNetHttpTestsLib",
     sdk_version: "test_current",
     srcs: [
         "src/**/*.java",
         "src/**/*.kt",
     ],
     static_libs: [
+        "androidx.test.ext.junit",
         "androidx.test.rules",
         "androidx.core_core",
         "ctstestrunner-axt",
         "ctstestserver",
         "junit",
         "hamcrest-library",
+        "kotlin-test",
     ],
     libs: [
         "android.test.runner",
@@ -69,7 +66,17 @@
         "framework-tethering",
         "org.apache.http.legacy",
     ],
+}
 
+android_test {
+    name: "CtsNetHttpTestCases",
+    defaults: [
+        "cts_defaults",
+        "CronetTestJavaDefaults",
+    ],
+    sdk_version: "test_current",
+    compile_multilib: "both", // Include both the 32 and 64 bit versions
+    static_libs: ["CtsNetHttpTestsLib"],
     // Tag this as a cts test artifact
     test_suites: [
         "cts",
diff --git a/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt
new file mode 100644
index 0000000..e17b63f
--- /dev/null
+++ b/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.http.cts
+
+import android.content.Context
+import android.net.http.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 androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+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(AndroidJUnit4::class)
+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, callback.executor)
+            .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/HttpEngineTest.java b/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
index 6d27b43..8663a67 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
+++ b/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
@@ -47,6 +47,7 @@
 
     private HttpEngine.Builder mEngineBuilder;
     private TestUrlRequestCallback mCallback;
+    private UrlRequest mRequest;
     private HttpEngine mEngine;
 
     @Before
@@ -59,6 +60,10 @@
 
     @After
     public void tearDown() throws Exception {
+        if (mRequest != null) {
+            mRequest.cancel();
+            mCallback.blockForDone();
+        }
         if (mEngine != null) {
             mEngine.shutdown();
         }
@@ -73,9 +78,12 @@
         mEngine = mEngineBuilder.build();
         UrlRequest.Builder builder =
                 mEngine.newUrlRequestBuilder(URL, mCallback, mCallback.getExecutor());
-        builder.build().start();
+        mRequest = builder.build();
+        mRequest.start();
 
-        mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
+        // 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());
@@ -86,9 +94,12 @@
         mEngine = mEngineBuilder.setEnableHttp2(false).build();
         UrlRequest.Builder builder =
                 mEngine.newUrlRequestBuilder(URL, mCallback, mCallback.getExecutor());
-        builder.build().start();
+        mRequest = builder.build();
+        mRequest.start();
 
-        mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
+        // 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());
@@ -104,9 +115,13 @@
             mCallback = new TestUrlRequestCallback();
             UrlRequest.Builder builder =
                     mEngine.newUrlRequestBuilder(URL, mCallback, mCallback.getExecutor());
-            builder.build().start();
+            mRequest = builder.build();
+            mRequest.start();
 
-            mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
+            // This tests uses a non-hermetic server. Instead of asserting, assume the next
+            // callback. This way, if the request were to fail, the test would just be skipped
+            // instead of failing.
+            mCallback.assumeCallback(ResponseStep.ON_SUCCEEDED);
             UrlResponseInfo info = mCallback.mResponseInfo;
             assumeOKStatusCode(info);
             quicWasUsed = isQuic(info.getNegotiatedProtocol());
diff --git a/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt
new file mode 100644
index 0000000..a2611e4
--- /dev/null
+++ b/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt
@@ -0,0 +1,59 @@
+/*
+ * 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 androidx.test.core.app.ApplicationProvider
+import kotlin.test.assertEquals
+import kotlin.test.assertIs
+import kotlin.test.assertSame
+import kotlin.test.assertTrue
+import org.junit.Test
+
+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, callback.executor).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/UrlRequestTest.java b/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java
index f96d651..5256bae 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java
+++ b/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java
@@ -125,4 +125,10 @@
         assertEquals(testData, mCallback.mResponseAsString);
         dataProvider.assertClosed();
     }
+
+    @Test
+    public void testUrlRequestFail_FailedCalled() throws Exception {
+        createUrlRequestBuilder("http://0.0.0.0:0/").build().start();
+        mCallback.expectCallback(ResponseStep.ON_FAILED);
+    }
 }
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
index 0b9e90f..fc4912c 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/util/TestUrlRequestCallback.java
+++ b/Cronet/tests/cts/src/android/net/http/cts/util/TestUrlRequestCallback.java
@@ -16,6 +16,7 @@
 
 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.assertNotNull;
@@ -23,6 +24,8 @@
 import static org.junit.Assert.assertSame;
 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;
@@ -232,6 +235,19 @@
     }
 
     /**
+     * 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.
      */
diff --git a/Cronet/tests/mts/Android.bp b/Cronet/tests/mts/Android.bp
new file mode 100644
index 0000000..cfafc5b
--- /dev/null
+++ b/Cronet/tests/mts/Android.bp
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_library {
+    name: "NetHttpTestsLibPreJarJar",
+    srcs: [":cronet_aml_javatests_sources"],
+    static_libs: [
+        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "junit",
+    ],
+    libs: [
+        "android.test.base",
+        "framework-tethering-pre-jarjar",
+    ]
+}
+
+android_test {
+     name: "NetHttpTests",
+     defaults: [
+        "CronetTestJavaDefaults",
+        "mts-target-sdk-version-current",
+     ],
+     compile_multilib: "both",
+     sdk_version: "test_current",
+     static_libs: ["NetHttpTestsLibPreJarJar"],
+     jarjar_rules: ":framework-tethering-jarjar-rules",
+     test_suites: [
+         "general-tests",
+         "mts-tethering",
+     ],
+}
+
diff --git a/Cronet/tests/mts/AndroidManifest.xml b/Cronet/tests/mts/AndroidManifest.xml
new file mode 100644
index 0000000..62c2060
--- /dev/null
+++ b/Cronet/tests/mts/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.net.http.mts">
+
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.INTERNET"/>
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.net.http.mts"
+                     android:label="MTS tests of android.net.http">
+    </instrumentation>
+
+</manifest>
\ No newline at end of file
diff --git a/Cronet/tests/mts/AndroidTest.xml b/Cronet/tests/mts/AndroidTest.xml
new file mode 100644
index 0000000..8cb549e
--- /dev/null
+++ b/Cronet/tests/mts/AndroidTest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<configuration description="Runs NetHttp Mainline Tests.">
+    <!-- Only run tests if the device under test is SDK version 30 or above. -->
+    <object type="module_controller"
+            class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="test-file-name" value="NetHttpTests.apk" />
+    </target_preparer>
+
+    <option name="test-tag" value="NetHttpTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.net.http.mts" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+
+    <!-- Only run NetHttpTests in MTS if the Tethering Mainline module is installed. -->
+    <object type="module_controller"
+            class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.tethering" />
+    </object>
+</configuration>
\ No newline at end of file
diff --git a/TEST_MAPPING b/TEST_MAPPING
index a1e81c8..4d3ecdf 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -58,6 +58,17 @@
       ]
     },
     {
+      "name": "CtsNetTestCasesMaxTargetSdk33",
+      "options": [
+        {
+          "exclude-annotation": "com.android.testutils.SkipPresubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.RequiresDevice"
+        }
+      ]
+    },
+    {
       "name": "bpf_existence_test"
     },
     {
@@ -102,6 +113,11 @@
     },
     {
       "name": "FrameworksNetDeflakeTest"
+    },
+    // Run in postsubmit to confirm test passes continously since this is a new test setup
+    // TODO: move tests to presubmit
+    {
+      "name": "NetHttpTests"
     }
   ],
   "mainline-presubmit": [
@@ -138,6 +154,17 @@
         }
       ]
     },
+    {
+      "name": "CtsNetTestCasesMaxTargetSdk33[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]",
+      "options": [
+        {
+          "exclude-annotation": "com.android.testutils.SkipPresubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.RequiresDevice"
+        }
+      ]
+    },
     // Test with APK modules only, in cases where APEX is not supported, or the other modules
     // were simply not updated
     {
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index b26911c..67206cd 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -144,7 +144,6 @@
 
     compat_configs: [
         "connectivity-platform-compat-config",
-        "connectivity-t-platform-compat-config",
     ],
 }
 
diff --git a/Tethering/common/TetheringLib/cronet_enabled/api/current.txt b/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
index c0157b7..c8bcb3b 100644
--- a/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
+++ b/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
@@ -30,8 +30,9 @@
   }
 
   public abstract class HttpEngine {
+    method public void bindToNetwork(@Nullable android.net.Network);
     method public abstract java.net.URLStreamHandlerFactory createURLStreamHandlerFactory();
-    method public abstract String getVersionString();
+    method public static String getVersionString();
     method public abstract android.net.http.UrlRequest.Builder newUrlRequestBuilder(String, android.net.http.UrlRequest.Callback, java.util.concurrent.Executor);
     method public abstract java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
     method public abstract void shutdown();
@@ -130,6 +131,7 @@
   public abstract static class UrlRequest.Builder {
     method public abstract android.net.http.UrlRequest.Builder addHeader(String, String);
     method public abstract android.net.http.UrlRequest.Builder allowDirectExecutor();
+    method public abstract android.net.http.UrlRequest.Builder bindToNetwork(@Nullable android.net.Network);
     method public abstract android.net.http.UrlRequest build();
     method public abstract android.net.http.UrlRequest.Builder disableCache();
     method public abstract android.net.http.UrlRequest.Builder setHttpMethod(String);
diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp
index 11e3dc0..5e08aba 100644
--- a/Tethering/tests/integration/Android.bp
+++ b/Tethering/tests/integration/Android.bp
@@ -21,8 +21,7 @@
     name: "TetheringIntegrationTestsDefaults",
     defaults: ["framework-connectivity-test-defaults"],
     srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
+        "base/**/*.java",
     ],
     min_sdk_version: "30",
     static_libs: [
@@ -47,6 +46,16 @@
     ],
 }
 
+android_library {
+    name: "TetheringIntegrationTestsBaseLib",
+    target_sdk_version: "current",
+    platform_apis: true,
+    defaults: ["TetheringIntegrationTestsDefaults"],
+    visibility: [
+        "//packages/modules/Connectivity/Tethering/tests/mts",
+    ]
+}
+
 // Library including tethering integration tests targeting the latest stable SDK.
 // Use with NetworkStackJarJarRules.
 android_library {
@@ -54,6 +63,9 @@
     target_sdk_version: "33",
     platform_apis: true,
     defaults: ["TetheringIntegrationTestsDefaults"],
+    srcs: [
+        "src/**/*.java",
+    ],
     visibility: [
         "//packages/modules/Connectivity/tests/cts/tethering",
         "//packages/modules/Connectivity/tests:__subpackages__",
@@ -68,12 +80,16 @@
     target_sdk_version: "current",
     platform_apis: true,
     defaults: ["TetheringIntegrationTestsDefaults"],
+    srcs: [
+        "src/**/*.java",
+    ],
     visibility: [
         "//packages/modules/Connectivity/tests/cts/tethering",
         "//packages/modules/Connectivity/Tethering/tests/mts",
     ]
 }
 
+// TODO: remove because TetheringIntegrationTests has been covered by ConnectivityCoverageTests.
 android_test {
     name: "TetheringIntegrationTests",
     platform_apis: true,
@@ -81,6 +97,9 @@
     test_suites: [
         "device-tests",
     ],
+    srcs: [
+        "src/**/*.java",
+    ],
     compile_multilib: "both",
     jarjar_rules: ":NetworkStackJarJarRules",
 }
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
similarity index 100%
rename from Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java
rename to Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
diff --git a/Tethering/tests/integration/src/android/net/TetheringTester.java b/Tethering/tests/integration/base/android/net/TetheringTester.java
similarity index 100%
rename from Tethering/tests/integration/src/android/net/TetheringTester.java
rename to Tethering/tests/integration/base/android/net/TetheringTester.java
diff --git a/Tethering/tests/integration/src/android/net/CtsEthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
similarity index 78%
rename from Tethering/tests/integration/src/android/net/CtsEthernetTetheringTest.java
rename to Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index aea6728..fb4b9fa 100644
--- a/Tethering/tests/integration/src/android/net/CtsEthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -16,7 +16,6 @@
 
 package android.net;
 
-import static android.Manifest.permission.DUMP;
 import static android.net.InetAddresses.parseNumericAddress;
 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
 import static android.net.TetheringManager.TETHERING_ETHERNET;
@@ -26,7 +25,6 @@
 import static android.system.OsConstants.ICMP_ECHO;
 import static android.system.OsConstants.ICMP_ECHOREPLY;
 import static android.system.OsConstants.IPPROTO_ICMP;
-import static android.system.OsConstants.IPPROTO_UDP;
 
 import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
 import static com.android.net.module.util.HexDump.dumpHexString;
@@ -39,39 +37,28 @@
 import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET;
 import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
 import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET;
-import static com.android.testutils.DeviceInfoUtils.KVersion;
-import static com.android.testutils.TestPermissionUtil.runAsShell;
 
 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 static org.junit.Assert.fail;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
-import android.content.Context;
 import android.net.TetheringManager.TetheringRequest;
 import android.net.TetheringTester.TetheredDevice;
 import android.os.Build;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.os.VintfRuntimeInfo;
 import android.util.Log;
-import android.util.Pair;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.net.module.util.BpfDump;
 import com.android.net.module.util.Ipv6Utils;
 import com.android.net.module.util.Struct;
-import com.android.net.module.util.bpf.Tether4Key;
-import com.android.net.module.util.bpf.Tether4Value;
-import com.android.net.module.util.bpf.TetherStatsKey;
-import com.android.net.module.util.bpf.TetherStatsValue;
 import com.android.net.module.util.structs.EthernetHeader;
 import com.android.net.module.util.structs.Icmpv4Header;
 import com.android.net.module.util.structs.Ipv4Header;
@@ -79,8 +66,6 @@
 import com.android.net.module.util.structs.UdpHeader;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-import com.android.testutils.DeviceInfoUtils;
-import com.android.testutils.DumpTestUtils;
 import com.android.testutils.TapPacketReader;
 
 import org.junit.Rule;
@@ -96,9 +81,7 @@
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Random;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
@@ -106,34 +89,13 @@
 
 @RunWith(AndroidJUnit4.class)
 @MediumTest
-public class CtsEthernetTetheringTest extends EthernetTetheringTestBase {
+public class EthernetTetheringTest extends EthernetTetheringTestBase {
     @Rule
     public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
 
-    private static final String TAG = CtsEthernetTetheringTest.class.getSimpleName();
-
-    private static final int DUMP_POLLING_MAX_RETRY = 100;
-    private static final int DUMP_POLLING_INTERVAL_MS = 50;
-    // Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
-    // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
-    private static final int UDP_STREAM_TS_MS = 2000;
-    // Give slack time for waiting UDP stream mode because handling conntrack event in user space
-    // may not in precise time. Used to reduce the flaky rate.
-    private static final int UDP_STREAM_SLACK_MS = 500;
-    // Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
-    private static final int RX_UDP_PACKET_SIZE = 30;
-    private static final int RX_UDP_PACKET_COUNT = 456;
-    // Per TX UDP packet size: ethhdr (14) + iphdr (20) + udphdr (8) + payload (2) = 44 bytes.
-    private static final int TX_UDP_PACKET_SIZE = 44;
-    private static final int TX_UDP_PACKET_COUNT = 123;
+    private static final String TAG = EthernetTetheringTest.class.getSimpleName();
 
     private static final short DNS_PORT = 53;
-
-    private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
-    private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
-    private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
-    private static final String LINE_DELIMITER = "\\n";
-
     private static final short ICMPECHO_CODE = 0x0;
     private static final short ICMPECHO_ID = 0x0;
     private static final short ICMPECHO_SEQ = 0x0;
@@ -529,7 +491,7 @@
     // remote ip              public ip                           private ip
     // 8.8.8.8:443            <Upstream ip>:9876                  <TetheredDevice ip>:9876
     //
-    private void runUdp4Test(boolean verifyBpf) throws Exception {
+    private void runUdp4Test() throws Exception {
         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
                 toList(TEST_IP4_DNS));
         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
@@ -549,123 +511,6 @@
         final InetAddress clientIp = tethered.ipv4Addr;
         sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
         sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
-
-        if (verifyBpf) {
-            // Send second UDP packet in original direction.
-            // The BPF coordinator only offloads the ASSURED conntrack entry. The "request + reply"
-            // packets can make status IPS_SEEN_REPLY to be set. Need one more packet to make
-            // conntrack status IPS_ASSURED_BIT to be set. Note the third packet needs to delay
-            // 2 seconds because kernel monitors a UDP connection which still alive after 2 seconds
-            // and apply ASSURED flag.
-            // See kernel upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5 and
-            // nf_conntrack_udp_packet in net/netfilter/nf_conntrack_proto_udp.c
-            Thread.sleep(UDP_STREAM_TS_MS);
-            sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
-
-            // Give a slack time for handling conntrack event in user space.
-            Thread.sleep(UDP_STREAM_SLACK_MS);
-
-            // [1] Verify IPv4 upstream rule map.
-            final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
-                    Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
-            assertNotNull(upstreamMap);
-            assertEquals(1, upstreamMap.size());
-
-            final Map.Entry<Tether4Key, Tether4Value> rule =
-                    upstreamMap.entrySet().iterator().next();
-
-            final Tether4Key upstream4Key = rule.getKey();
-            assertEquals(IPPROTO_UDP, upstream4Key.l4proto);
-            assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), upstream4Key.src4));
-            assertEquals(LOCAL_PORT, upstream4Key.srcPort);
-            assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), upstream4Key.dst4));
-            assertEquals(REMOTE_PORT, upstream4Key.dstPort);
-
-            final Tether4Value upstream4Value = rule.getValue();
-            assertTrue(Arrays.equals(tetheringUpstreamIp.getAddress(),
-                    InetAddress.getByAddress(upstream4Value.src46).getAddress()));
-            assertEquals(LOCAL_PORT, upstream4Value.srcPort);
-            assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
-                    InetAddress.getByAddress(upstream4Value.dst46).getAddress()));
-            assertEquals(REMOTE_PORT, upstream4Value.dstPort);
-
-            // [2] Verify stats map.
-            // Transmit packets on both direction for verifying stats. Because we only care the
-            // packet count in stats test, we just reuse the existing packets to increaes
-            // the packet count on both direction.
-
-            // Send packets on original direction.
-            for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
-                sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester,
-                        false /* is4To6 */);
-            }
-
-            // Send packets on reply direction.
-            for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
-                sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
-            }
-
-            // Dump stats map to verify.
-            final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump(
-                    TetherStatsKey.class, TetherStatsValue.class, DUMPSYS_RAWMAP_ARG_STATS);
-            assertNotNull(statsMap);
-            assertEquals(1, statsMap.size());
-
-            final Map.Entry<TetherStatsKey, TetherStatsValue> stats =
-                    statsMap.entrySet().iterator().next();
-
-            // TODO: verify the upstream index in TetherStatsKey.
-
-            final TetherStatsValue statsValue = stats.getValue();
-            assertEquals(RX_UDP_PACKET_COUNT, statsValue.rxPackets);
-            assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE, statsValue.rxBytes);
-            assertEquals(0, statsValue.rxErrors);
-            assertEquals(TX_UDP_PACKET_COUNT, statsValue.txPackets);
-            assertEquals(TX_UDP_PACKET_COUNT * TX_UDP_PACKET_SIZE, statsValue.txBytes);
-            assertEquals(0, statsValue.txErrors);
-        }
-    }
-
-    private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
-        final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion);
-        return current.isInRange(new KVersion(4, 14, 222), new KVersion(4, 19, 0))
-                || current.isInRange(new KVersion(4, 19, 176), new KVersion(5, 4, 0))
-                || current.isAtLeast(new KVersion(5, 4, 98));
-    }
-
-    @Test
-    public void testIsUdpOffloadSupportedByKernel() throws Exception {
-        assertFalse(isUdpOffloadSupportedByKernel("4.14.221"));
-        assertTrue(isUdpOffloadSupportedByKernel("4.14.222"));
-        assertTrue(isUdpOffloadSupportedByKernel("4.16.0"));
-        assertTrue(isUdpOffloadSupportedByKernel("4.18.0"));
-        assertFalse(isUdpOffloadSupportedByKernel("4.19.0"));
-
-        assertFalse(isUdpOffloadSupportedByKernel("4.19.175"));
-        assertTrue(isUdpOffloadSupportedByKernel("4.19.176"));
-        assertTrue(isUdpOffloadSupportedByKernel("5.2.0"));
-        assertTrue(isUdpOffloadSupportedByKernel("5.3.0"));
-        assertFalse(isUdpOffloadSupportedByKernel("5.4.0"));
-
-        assertFalse(isUdpOffloadSupportedByKernel("5.4.97"));
-        assertTrue(isUdpOffloadSupportedByKernel("5.4.98"));
-        assertTrue(isUdpOffloadSupportedByKernel("5.10.0"));
-    }
-
-    private static void assumeKernelSupportBpfOffloadUdpV4() {
-        final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
-        assumeTrue("Kernel version " + kernelVersion + " doesn't support IPv4 UDP BPF offload",
-                isUdpOffloadSupportedByKernel(kernelVersion));
-    }
-
-    @Test
-    public void testKernelSupportBpfOffloadUdpV4() throws Exception {
-        assumeKernelSupportBpfOffloadUdpV4();
-    }
-
-    @Test
-    public void testTetherConfigBpfOffloadEnabled() throws Exception {
-        assumeTrue(isTetherConfigBpfOffloadEnabled());
     }
 
     /**
@@ -674,73 +519,7 @@
      */
     @Test
     public void testTetherUdpV4() throws Exception {
-        runUdp4Test(false /* verifyBpf */);
-    }
-
-    /**
-     * BPF offload IPv4 UDP tethering test. Verify that UDP tethered packets are offloaded by BPF.
-     * Minimum test requirement:
-     * 1. S+ device.
-     * 2. Tethering config enables tethering BPF offload.
-     * 3. Kernel supports IPv4 UDP BPF offload. See #isUdpOffloadSupportedByKernel.
-     *
-     * TODO: consider enabling the test even tethering config disables BPF offload. See b/238288883
-     */
-    @Test
-    @IgnoreUpTo(Build.VERSION_CODES.R)
-    public void testTetherUdpV4_VerifyBpf() throws Exception {
-        assumeTrue("Tethering config disabled BPF offload", isTetherConfigBpfOffloadEnabled());
-        assumeKernelSupportBpfOffloadUdpV4();
-
-        runUdp4Test(true /* verifyBpf */);
-    }
-
-    @NonNull
-    private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap(
-            Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
-            throws Exception {
-        final String[] args = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG, mapArg};
-        final String rawMapStr = runAsShell(DUMP, () ->
-                DumpTestUtils.dumpService(Context.TETHERING_SERVICE, args));
-        final HashMap<K, V> map = new HashMap<>();
-
-        for (final String line : rawMapStr.split(LINE_DELIMITER)) {
-            final Pair<K, V> rule =
-                    BpfDump.fromBase64EncodedString(keyClass, valueClass, line.trim());
-            map.put(rule.first, rule.second);
-        }
-        return map;
-    }
-
-    @Nullable
-    private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump(
-            Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
-            throws Exception {
-        for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) {
-            final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, mapArg);
-            if (!map.isEmpty()) return map;
-
-            Thread.sleep(DUMP_POLLING_INTERVAL_MS);
-        }
-
-        fail("Cannot get rules after " + DUMP_POLLING_MAX_RETRY * DUMP_POLLING_INTERVAL_MS + "ms");
-        return null;
-    }
-
-    private boolean isTetherConfigBpfOffloadEnabled() throws Exception {
-        final String dumpStr = runAsShell(DUMP, () ->
-                DumpTestUtils.dumpService(Context.TETHERING_SERVICE, "--short"));
-
-        // BPF offload tether config can be overridden by "config_tether_enable_bpf_offload" in
-        // packages/modules/Connectivity/Tethering/res/values/config.xml. OEM may disable config by
-        // RRO to override the enabled default value. Get the tethering config via dumpsys.
-        // $ dumpsys tethering
-        //   mIsBpfEnabled: true
-        boolean enabled = dumpStr.contains("mIsBpfEnabled: true");
-        if (!enabled) {
-            Log.d(TAG, "BPF offload tether config not enabled: " + dumpStr);
-        }
-        return enabled;
+        runUdp4Test();
     }
 
     @NonNull
diff --git a/Tethering/tests/mts/Android.bp b/Tethering/tests/mts/Android.bp
index ae36499..4f4b03c 100644
--- a/Tethering/tests/mts/Android.bp
+++ b/Tethering/tests/mts/Android.bp
@@ -33,6 +33,7 @@
     ],
 
     static_libs: [
+        "TetheringIntegrationTestsBaseLib",
         "androidx.test.rules",
         // mockito-target-extended-minus-junit4 used in this lib have dependency with
         // jni_libs libdexmakerjvmtiagent and libstaticjvmtiagent.
diff --git a/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java b/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java
new file mode 100644
index 0000000..cb57d13
--- /dev/null
+++ b/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java
@@ -0,0 +1,304 @@
+/*
+ * 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;
+
+import static android.Manifest.permission.DUMP;
+import static android.system.OsConstants.IPPROTO_UDP;
+
+import static com.android.testutils.DeviceInfoUtils.KVersion;
+import static com.android.testutils.TestPermissionUtil.runAsShell;
+
+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 static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.TetheringTester.TetheredDevice;
+import android.os.Build;
+import android.os.VintfRuntimeInfo;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.net.module.util.BpfDump;
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.bpf.Tether4Key;
+import com.android.net.module.util.bpf.Tether4Value;
+import com.android.net.module.util.bpf.TetherStatsKey;
+import com.android.net.module.util.bpf.TetherStatsValue;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DeviceInfoUtils;
+import com.android.testutils.DumpTestUtils;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class MtsEthernetTetheringTest extends EthernetTetheringTestBase {
+    @Rule
+    public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+
+    private static final String TAG = MtsEthernetTetheringTest.class.getSimpleName();
+
+    private static final int DUMP_POLLING_MAX_RETRY = 100;
+    private static final int DUMP_POLLING_INTERVAL_MS = 50;
+    // Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
+    // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
+    private static final int UDP_STREAM_TS_MS = 2000;
+    // Give slack time for waiting UDP stream mode because handling conntrack event in user space
+    // may not in precise time. Used to reduce the flaky rate.
+    private static final int UDP_STREAM_SLACK_MS = 500;
+    // Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
+    private static final int RX_UDP_PACKET_SIZE = 30;
+    private static final int RX_UDP_PACKET_COUNT = 456;
+    // Per TX UDP packet size: ethhdr (14) + iphdr (20) + udphdr (8) + payload (2) = 44 bytes.
+    private static final int TX_UDP_PACKET_SIZE = 44;
+    private static final int TX_UDP_PACKET_COUNT = 123;
+
+    private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
+    private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
+    private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
+    private static final String LINE_DELIMITER = "\\n";
+
+    private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
+        final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion);
+        return current.isInRange(new KVersion(4, 14, 222), new KVersion(4, 19, 0))
+                || current.isInRange(new KVersion(4, 19, 176), new KVersion(5, 4, 0))
+                || current.isAtLeast(new KVersion(5, 4, 98));
+    }
+
+    @Test
+    public void testIsUdpOffloadSupportedByKernel() throws Exception {
+        assertFalse(isUdpOffloadSupportedByKernel("4.14.221"));
+        assertTrue(isUdpOffloadSupportedByKernel("4.14.222"));
+        assertTrue(isUdpOffloadSupportedByKernel("4.16.0"));
+        assertTrue(isUdpOffloadSupportedByKernel("4.18.0"));
+        assertFalse(isUdpOffloadSupportedByKernel("4.19.0"));
+
+        assertFalse(isUdpOffloadSupportedByKernel("4.19.175"));
+        assertTrue(isUdpOffloadSupportedByKernel("4.19.176"));
+        assertTrue(isUdpOffloadSupportedByKernel("5.2.0"));
+        assertTrue(isUdpOffloadSupportedByKernel("5.3.0"));
+        assertFalse(isUdpOffloadSupportedByKernel("5.4.0"));
+
+        assertFalse(isUdpOffloadSupportedByKernel("5.4.97"));
+        assertTrue(isUdpOffloadSupportedByKernel("5.4.98"));
+        assertTrue(isUdpOffloadSupportedByKernel("5.10.0"));
+    }
+
+    private static void assumeKernelSupportBpfOffloadUdpV4() {
+        final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
+        assumeTrue("Kernel version " + kernelVersion + " doesn't support IPv4 UDP BPF offload",
+                isUdpOffloadSupportedByKernel(kernelVersion));
+    }
+
+    @Test
+    public void testKernelSupportBpfOffloadUdpV4() throws Exception {
+        assumeKernelSupportBpfOffloadUdpV4();
+    }
+
+    private boolean isTetherConfigBpfOffloadEnabled() throws Exception {
+        final String dumpStr = runAsShell(DUMP, () ->
+                DumpTestUtils.dumpService(Context.TETHERING_SERVICE, "--short"));
+
+        // BPF offload tether config can be overridden by "config_tether_enable_bpf_offload" in
+        // packages/modules/Connectivity/Tethering/res/values/config.xml. OEM may disable config by
+        // RRO to override the enabled default value. Get the tethering config via dumpsys.
+        // $ dumpsys tethering
+        //   mIsBpfEnabled: true
+        boolean enabled = dumpStr.contains("mIsBpfEnabled: true");
+        if (!enabled) {
+            Log.d(TAG, "BPF offload tether config not enabled: " + dumpStr);
+        }
+        return enabled;
+    }
+
+    @Test
+    public void testTetherConfigBpfOffloadEnabled() throws Exception {
+        assumeTrue(isTetherConfigBpfOffloadEnabled());
+    }
+
+    @NonNull
+    private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap(
+            Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
+            throws Exception {
+        final String[] args = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG, mapArg};
+        final String rawMapStr = runAsShell(DUMP, () ->
+                DumpTestUtils.dumpService(Context.TETHERING_SERVICE, args));
+        final HashMap<K, V> map = new HashMap<>();
+
+        for (final String line : rawMapStr.split(LINE_DELIMITER)) {
+            final Pair<K, V> rule =
+                    BpfDump.fromBase64EncodedString(keyClass, valueClass, line.trim());
+            map.put(rule.first, rule.second);
+        }
+        return map;
+    }
+
+    @Nullable
+    private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump(
+            Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
+            throws Exception {
+        for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) {
+            final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, mapArg);
+            if (!map.isEmpty()) return map;
+
+            Thread.sleep(DUMP_POLLING_INTERVAL_MS);
+        }
+
+        fail("Cannot get rules after " + DUMP_POLLING_MAX_RETRY * DUMP_POLLING_INTERVAL_MS + "ms");
+        return null;
+    }
+
+    // Test network topology:
+    //
+    //         public network (rawip)                 private network
+    //                   |                 UE                |
+    // +------------+    V    +------------+------------+    V    +------------+
+    // |   Sever    +---------+  Upstream  | Downstream +---------+   Client   |
+    // +------------+         +------------+------------+         +------------+
+    // remote ip              public ip                           private ip
+    // 8.8.8.8:443            <Upstream ip>:9876                  <TetheredDevice ip>:9876
+    //
+    private void runUdp4Test() throws Exception {
+        final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
+                toList(TEST_IP4_DNS));
+        final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
+
+        // TODO: remove the connectivity verification for upstream connected notification race.
+        // Because async upstream connected notification can't guarantee the tethering routing is
+        // ready to use. Need to test tethering connectivity before testing.
+        // For short term plan, consider using IPv6 RA to get MAC address because the prefix comes
+        // from upstream. That can guarantee that the routing is ready. Long term plan is that
+        // refactors upstream connected notification from async to sync.
+        probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
+
+        final MacAddress srcMac = tethered.macAddr;
+        final MacAddress dstMac = tethered.routerMacAddr;
+        final InetAddress remoteIp = REMOTE_IP4_ADDR;
+        final InetAddress tetheringUpstreamIp = TEST_IP4_ADDR.getAddress();
+        final InetAddress clientIp = tethered.ipv4Addr;
+        sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
+        sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
+
+        // Send second UDP packet in original direction.
+        // The BPF coordinator only offloads the ASSURED conntrack entry. The "request + reply"
+        // packets can make status IPS_SEEN_REPLY to be set. Need one more packet to make
+        // conntrack status IPS_ASSURED_BIT to be set. Note the third packet needs to delay
+        // 2 seconds because kernel monitors a UDP connection which still alive after 2 seconds
+        // and apply ASSURED flag.
+        // See kernel upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5 and
+        // nf_conntrack_udp_packet in net/netfilter/nf_conntrack_proto_udp.c
+        Thread.sleep(UDP_STREAM_TS_MS);
+        sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
+
+        // Give a slack time for handling conntrack event in user space.
+        Thread.sleep(UDP_STREAM_SLACK_MS);
+
+        // [1] Verify IPv4 upstream rule map.
+        final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
+                Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
+        assertNotNull(upstreamMap);
+        assertEquals(1, upstreamMap.size());
+
+        final Map.Entry<Tether4Key, Tether4Value> rule =
+                upstreamMap.entrySet().iterator().next();
+
+        final Tether4Key upstream4Key = rule.getKey();
+        assertEquals(IPPROTO_UDP, upstream4Key.l4proto);
+        assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), upstream4Key.src4));
+        assertEquals(LOCAL_PORT, upstream4Key.srcPort);
+        assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), upstream4Key.dst4));
+        assertEquals(REMOTE_PORT, upstream4Key.dstPort);
+
+        final Tether4Value upstream4Value = rule.getValue();
+        assertTrue(Arrays.equals(tetheringUpstreamIp.getAddress(),
+                InetAddress.getByAddress(upstream4Value.src46).getAddress()));
+        assertEquals(LOCAL_PORT, upstream4Value.srcPort);
+        assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
+                InetAddress.getByAddress(upstream4Value.dst46).getAddress()));
+        assertEquals(REMOTE_PORT, upstream4Value.dstPort);
+
+        // [2] Verify stats map.
+        // Transmit packets on both direction for verifying stats. Because we only care the
+        // packet count in stats test, we just reuse the existing packets to increaes
+        // the packet count on both direction.
+
+        // Send packets on original direction.
+        for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
+            sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester,
+                    false /* is4To6 */);
+        }
+
+        // Send packets on reply direction.
+        for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
+            sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
+        }
+
+        // Dump stats map to verify.
+        final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump(
+                TetherStatsKey.class, TetherStatsValue.class, DUMPSYS_RAWMAP_ARG_STATS);
+        assertNotNull(statsMap);
+        assertEquals(1, statsMap.size());
+
+        final Map.Entry<TetherStatsKey, TetherStatsValue> stats =
+                statsMap.entrySet().iterator().next();
+
+        // TODO: verify the upstream index in TetherStatsKey.
+
+        final TetherStatsValue statsValue = stats.getValue();
+        assertEquals(RX_UDP_PACKET_COUNT, statsValue.rxPackets);
+        assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE, statsValue.rxBytes);
+        assertEquals(0, statsValue.rxErrors);
+        assertEquals(TX_UDP_PACKET_COUNT, statsValue.txPackets);
+        assertEquals(TX_UDP_PACKET_COUNT * TX_UDP_PACKET_SIZE, statsValue.txBytes);
+        assertEquals(0, statsValue.txErrors);
+    }
+
+    /**
+     * BPF offload IPv4 UDP tethering test. Verify that UDP tethered packets are offloaded by BPF.
+     * Minimum test requirement:
+     * 1. S+ device.
+     * 2. Tethering config enables tethering BPF offload.
+     * 3. Kernel supports IPv4 UDP BPF offload. See #isUdpOffloadSupportedByKernel.
+     *
+     * TODO: consider enabling the test even tethering config disables BPF offload. See b/238288883
+     */
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testTetherBpfOffloadUdpV4() throws Exception {
+        assumeTrue("Tethering config disabled BPF offload", isTetherConfigBpfOffloadEnabled());
+        assumeKernelSupportBpfOffloadUdpV4();
+
+        runUdp4Test();
+    }
+}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 98a3b1d..79590b7 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -29,6 +29,7 @@
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
@@ -2678,35 +2679,67 @@
     public void testUpstreamNetworkChanged() {
         final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM)
                 mTetheringDependencies.mUpstreamNetworkMonitorSM;
+        final InOrder inOrder = inOrder(mNotificationUpdater);
+
         // Gain upstream.
         final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
         initTetheringUpstream(upstreamState);
         stateMachine.chooseUpstreamType(true);
         mTetheringEventCallback.expectUpstreamChanged(upstreamState.network);
-        verify(mNotificationUpdater)
+        inOrder.verify(mNotificationUpdater)
                 .onUpstreamCapabilitiesChanged(upstreamState.networkCapabilities);
 
+        // Set the upstream with the same network ID but different object and the same capability.
+        final UpstreamNetworkState upstreamState2 = buildMobileIPv4UpstreamState();
+        initTetheringUpstream(upstreamState2);
+        stateMachine.chooseUpstreamType(true);
+        // Bug: duplicated upstream change event.
+        mTetheringEventCallback.expectUpstreamChanged(upstreamState2.network);
+        inOrder.verify(mNotificationUpdater)
+                .onUpstreamCapabilitiesChanged(upstreamState2.networkCapabilities);
+
+        // Set the upstream with the same network ID but different object and different capability.
+        final UpstreamNetworkState upstreamState3 = buildMobileIPv4UpstreamState();
+        assertFalse(upstreamState3.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED));
+        upstreamState3.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
+        initTetheringUpstream(upstreamState3);
+        stateMachine.chooseUpstreamType(true);
+        // Bug: duplicated upstream change event.
+        mTetheringEventCallback.expectUpstreamChanged(upstreamState3.network);
+        inOrder.verify(mNotificationUpdater)
+                .onUpstreamCapabilitiesChanged(upstreamState3.networkCapabilities);
+
         // Lose upstream.
         initTetheringUpstream(null);
         stateMachine.chooseUpstreamType(true);
         mTetheringEventCallback.expectUpstreamChanged(NULL_NETWORK);
-        verify(mNotificationUpdater).onUpstreamCapabilitiesChanged(null);
+        inOrder.verify(mNotificationUpdater).onUpstreamCapabilitiesChanged(null);
     }
 
     @Test
     public void testUpstreamCapabilitiesChanged() {
         final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM)
                 mTetheringDependencies.mUpstreamNetworkMonitorSM;
+        final InOrder inOrder = inOrder(mNotificationUpdater);
         final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
         initTetheringUpstream(upstreamState);
+
         stateMachine.chooseUpstreamType(true);
+        inOrder.verify(mNotificationUpdater)
+                .onUpstreamCapabilitiesChanged(upstreamState.networkCapabilities);
 
         stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState);
-        // Should have two onUpstreamCapabilitiesChanged().
-        // One is called by reportUpstreamChanged(). One is called by EVENT_ON_CAPABILITIES.
-        verify(mNotificationUpdater, times(2))
+        inOrder.verify(mNotificationUpdater)
                 .onUpstreamCapabilitiesChanged(upstreamState.networkCapabilities);
-        reset(mNotificationUpdater);
+
+        // Verify that onUpstreamCapabilitiesChanged is called if current upstream network
+        // capabilities changed.
+        // Expect that capability is changed with new capability VALIDATED.
+        assertFalse(upstreamState.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED));
+        upstreamState.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
+        stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState);
+        inOrder.verify(mNotificationUpdater)
+                .onUpstreamCapabilitiesChanged(upstreamState.networkCapabilities);
 
         // Verify that onUpstreamCapabilitiesChanged won't be called if not current upstream network
         // capabilities changed.
@@ -2714,7 +2747,7 @@
                 upstreamState.linkProperties, upstreamState.networkCapabilities,
                 new Network(WIFI_NETID));
         stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState2);
-        verify(mNotificationUpdater, never()).onUpstreamCapabilitiesChanged(any());
+        inOrder.verify(mNotificationUpdater, never()).onUpstreamCapabilitiesChanged(any());
     }
 
     @Test
diff --git a/framework-t/Android.bp b/framework-t/Android.bp
index d40fad9..7ef20c5 100644
--- a/framework-t/Android.bp
+++ b/framework-t/Android.bp
@@ -164,6 +164,7 @@
     ],
 }
 
+// This rule is not used anymore(b/268440216).
 platform_compat_config {
     name: "connectivity-t-platform-compat-config",
     src: ":framework-connectivity-t",
diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java
index f633a8f..748b1ba 100644
--- a/framework-t/src/android/net/NetworkTemplate.java
+++ b/framework-t/src/android/net/NetworkTemplate.java
@@ -383,8 +383,9 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mMatchRule, Arrays.hashCode(mMatchWifiNetworkKeys),
-                mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged);
+        return Objects.hash(mMatchRule, Arrays.hashCode(mMatchSubscriberIds),
+                Arrays.hashCode(mMatchWifiNetworkKeys), mMetered, mRoaming, mDefaultNetwork,
+                mRatType, mOemManaged);
     }
 
     @Override
@@ -397,6 +398,7 @@
                     && mDefaultNetwork == other.mDefaultNetwork
                     && mRatType == other.mRatType
                     && mOemManaged == other.mOemManaged
+                    && Arrays.equals(mMatchSubscriberIds, other.mMatchSubscriberIds)
                     && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys);
         }
         return false;
diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java
index e38ae8e..b4f8897 100644
--- a/framework-t/src/android/net/nsd/NsdManager.java
+++ b/framework-t/src/android/net/nsd/NsdManager.java
@@ -16,6 +16,8 @@
 
 package android.net.nsd;
 
+import static android.net.connectivity.ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -24,8 +26,6 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
 import android.app.compat.CompatChanges;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledSince;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
@@ -137,28 +137,6 @@
     private static final boolean DBG = false;
 
     /**
-     * When enabled, apps targeting < Android 12 are considered legacy for
-     * the NSD native daemon.
-     * The platform will only keep the daemon running as long as there are
-     * any legacy apps connected.
-     *
-     * After Android 12, direct communication with the native daemon might not work since the native
-     * daemon won't always stay alive. Using the NSD APIs from NsdManager as the replacement is
-     * recommended.
-     * Another alternative could be bundling your own mdns solutions instead of
-     * depending on the system mdns native daemon.
-     *
-     * This compatibility change applies to Android 13 and later only. To toggle behavior on
-     * Android 12 and Android 12L, use RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS.
-     *
-     * @hide
-     */
-    @ChangeId
-    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
-    // This was a platform change ID with value 191844585L before T
-    public static final long RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER = 235355681L;
-
-    /**
      * Broadcast intent action to indicate whether network service discovery is
      * enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state
      * information as int.
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index f623b05..193bd92 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -15,7 +15,7 @@
     method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.LinkProperties getRedactedLinkPropertiesForPackage(@NonNull android.net.LinkProperties, int, @NonNull String);
     method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.NetworkCapabilities getRedactedNetworkCapabilitiesForPackage(@NonNull android.net.NetworkCapabilities, int, @NonNull String);
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkAllowList(int);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkDenyList(int);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void replaceFirewallChain(int, @NonNull int[]);
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 0b03983..196e023 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -470,7 +470,7 @@
   }
 
   public abstract class SocketKeepalive implements java.lang.AutoCloseable {
-    method public final void start(@IntRange(from=0xa, to=0xe10) int, int);
+    method public final void start(@IntRange(from=0xa, to=0xe10) int, int, @NonNull android.net.Network);
     field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
     field public static final int FLAG_AUTOMATIC_ON_OFF = 1; // 0x1
     field public static final int SUCCESS = 0; // 0x0
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 17389b4..9d3d7c1 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1502,6 +1502,22 @@
     }
 
     /**
+     * Temporarily set automaticOnOff keeplaive TCP polling alarm timer to 1 second.
+     *
+     * TODO: Remove this when the TCP polling design is replaced with callback.
+     * @param timeMs The time of expiry, with System.currentTimeMillis() base. The value should be
+     *               set no more than 5 minutes in the future.
+     * @hide
+     */
+    public void setTestLowTcpPollingTimerForKeepalive(long timeMs) {
+        try {
+            mService.setTestLowTcpPollingTimerForKeepalive(timeMs);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Informs ConnectivityService of whether the legacy lockdown VPN, as implemented by
      * LockdownVpnTracker, is in use. This is deprecated for new devices starting from Android 12
      * but is still supported for backwards compatibility.
@@ -2213,9 +2229,13 @@
         /** The requested keepalive was successfully started. */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public void onStarted() {}
+        /** The keepalive was resumed after being paused by the system. */
+        public void onResumed() {}
         /** The keepalive was successfully stopped. */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public void onStopped() {}
+        /** The keepalive was paused automatically by the system. */
+        public void onPaused() {}
         /** An error occurred. */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public void onError(int error) {}
@@ -2314,6 +2334,18 @@
                 }
 
                 @Override
+                public void onResumed() {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        mExecutor.execute(() -> {
+                            callback.onResumed();
+                        });
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+
+                @Override
                 public void onStopped() {
                     final long token = Binder.clearCallingIdentity();
                     try {
@@ -2327,6 +2359,19 @@
                 }
 
                 @Override
+                public void onPaused() {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        mExecutor.execute(() -> {
+                            callback.onPaused();
+                        });
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                    mExecutor.shutdown();
+                }
+
+                @Override
                 public void onError(int error) {
                     final long token = Binder.clearCallingIdentity();
                     try {
@@ -4856,6 +4901,7 @@
     @RequiresPermission(anyOf = {
             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
             android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD,
             android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS})
     public void registerSystemDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
             @NonNull Handler handler) {
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index acbc31e..db001f9 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -188,7 +188,7 @@
 
     void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId,
             int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
-            String dstAddr, boolean automaticOnOffKeepalives);
+            String dstAddr, boolean automaticOnOffKeepalives, in Network underpinnedNetwork);
 
     void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds,
             in ISocketKeepaliveCallback cb);
@@ -251,4 +251,6 @@
     IBinder getCompanionDeviceManagerProxyService();
 
     void setVpnNetworkPreference(String session, in UidRange[] ranges);
+
+    void setTestLowTcpPollingTimerForKeepalive(long timeMs);
 }
diff --git a/framework/src/android/net/ISocketKeepaliveCallback.aidl b/framework/src/android/net/ISocketKeepaliveCallback.aidl
index 1240e37..0a1de6c 100644
--- a/framework/src/android/net/ISocketKeepaliveCallback.aidl
+++ b/framework/src/android/net/ISocketKeepaliveCallback.aidl
@@ -31,4 +31,8 @@
     void onError(int error);
     /** The keepalive on a TCP socket was stopped because the socket received data. */
     void onDataReceived();
+    /** The keepalive was paused by the system because it's not necessary right now. */
+    void onPaused();
+    /** The keepalive was resumed by the system after being suspended. */
+    void onResumed();
 }
diff --git a/framework/src/android/net/LinkProperties.java b/framework/src/android/net/LinkProperties.java
index b7ee846..e0926e9 100644
--- a/framework/src/android/net/LinkProperties.java
+++ b/framework/src/android/net/LinkProperties.java
@@ -16,19 +16,18 @@
 
 package android.net;
 
+import static android.net.connectivity.ConnectivityCompatChanges.EXCLUDED_ROUTES;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.compat.CompatChanges;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.CollectionUtils;
 import com.android.net.module.util.LinkPropertiesUtils;
@@ -58,17 +57,6 @@
  *
  */
 public final class LinkProperties implements Parcelable {
-    /**
-     * The {@link #getRoutes()} now can contain excluded as well as included routes. Use
-     * {@link RouteInfo#getType()} to determine route type.
-     *
-     * @hide
-     */
-    @ChangeId
-    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
-    @VisibleForTesting
-    public static final long EXCLUDED_ROUTES = 186082280;
-
     // The interface described by the network link.
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private String mIfaceName;
diff --git a/framework/src/android/net/NattSocketKeepalive.java b/framework/src/android/net/NattSocketKeepalive.java
index 77137f4..a83b5b4 100644
--- a/framework/src/android/net/NattSocketKeepalive.java
+++ b/framework/src/android/net/NattSocketKeepalive.java
@@ -66,10 +66,12 @@
      *                    the supplied {@link Callback} will see a call to
      *                    {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
      * @param flags Flags to enable/disable available options on this keepalive.
+     * @param underpinnedNetwork The underpinned network of this keepalive.
+     *
      * @hide
      */
     @Override
-    protected void startImpl(int intervalSec, int flags) {
+    protected void startImpl(int intervalSec, int flags, Network underpinnedNetwork) {
         if (0 != (flags & ~FLAG_AUTOMATIC_ON_OFF)) {
             throw new IllegalArgumentException("Illegal flag value for "
                     + this.getClass().getSimpleName() + " : " + flags);
@@ -79,7 +81,8 @@
             try {
                 mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId,
                         intervalSec, mCallback, mSource.getHostAddress(),
-                        mDestination.getHostAddress(), automaticOnOffKeepalives);
+                        mDestination.getHostAddress(), automaticOnOffKeepalives,
+                        underpinnedNetwork);
             } catch (RemoteException e) {
                 Log.e(TAG, "Error starting socket keepalive: ", e);
                 throw e.rethrowFromSystemServer();
diff --git a/framework/src/android/net/SocketKeepalive.java b/framework/src/android/net/SocketKeepalive.java
index 2911ce7..311126e 100644
--- a/framework/src/android/net/SocketKeepalive.java
+++ b/framework/src/android/net/SocketKeepalive.java
@@ -64,6 +64,12 @@
     public static final int SUCCESS = 0;
 
     /**
+     * Success when trying to suspend.
+     * @hide
+     */
+    public static final int SUCCESS_PAUSED = 1;
+
+    /**
      * No keepalive. This should only be internally as it indicates There is no keepalive.
      * It should not propagate to applications.
      * @hide
@@ -271,6 +277,18 @@
             }
 
             @Override
+            public void onResumed() {
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() -> {
+                        callback.onResumed();
+                    });
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+
+            @Override
             public void onStopped() {
                 final long token = Binder.clearCallingIdentity();
                 try {
@@ -283,6 +301,18 @@
             }
 
             @Override
+            public void onPaused() {
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> {
+                        callback.onPaused();
+                    });
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+
+            @Override
             public void onError(int error) {
                 final long token = Binder.clearCallingIdentity();
                 try {
@@ -325,7 +355,7 @@
      */
     public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
             int intervalSec) {
-        startImpl(intervalSec, 0 /* flags */);
+        startImpl(intervalSec, 0 /* flags */, null /* underpinnedNetwork */);
     }
 
     /**
@@ -344,16 +374,18 @@
      *                    the supplied {@link Callback} will see a call to
      *                    {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
      * @param flags Flags to enable/disable available options on this keepalive.
+     * @param underpinnedNetwork The underpinned network of this keepalive.
      * @hide
      */
     @SystemApi(client = PRIVILEGED_APPS)
     public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
-            int intervalSec, @StartFlags int flags) {
-        startImpl(intervalSec, flags);
+            int intervalSec, @StartFlags int flags, @NonNull Network underpinnedNetwork) {
+        startImpl(intervalSec, flags, underpinnedNetwork);
     }
 
     /** @hide */
-    protected abstract void startImpl(int intervalSec, @StartFlags int flags);
+    protected abstract void startImpl(int intervalSec, @StartFlags int flags,
+            Network underpinnedNetwork);
 
     /**
      * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
@@ -387,8 +419,18 @@
     public static class Callback {
         /** The requested keepalive was successfully started. */
         public void onStarted() {}
+        /**
+         * The keepalive was resumed by the system after being suspended.
+         * @hide
+         **/
+        public void onResumed() {}
         /** The keepalive was successfully stopped. */
         public void onStopped() {}
+        /**
+         * The keepalive was paused by the system because it's not necessary right now.
+         * @hide
+         **/
+        public void onPaused() {}
         /** An error occurred. */
         public void onError(@ErrorCode int error) {}
         /** The keepalive on a TCP socket was stopped because the socket received data. This is
diff --git a/framework/src/android/net/TcpSocketKeepalive.java b/framework/src/android/net/TcpSocketKeepalive.java
index cda5830..b548f6d 100644
--- a/framework/src/android/net/TcpSocketKeepalive.java
+++ b/framework/src/android/net/TcpSocketKeepalive.java
@@ -50,7 +50,7 @@
      *   acknowledgement.
      */
     @Override
-    protected void startImpl(int intervalSec, int flags) {
+    protected void startImpl(int intervalSec, int flags, Network underpinnedNetwork) {
         if (0 != flags) {
             throw new IllegalArgumentException("Illegal flag value for "
                     + this.getClass().getSimpleName() + " : " + flags);
diff --git a/framework/src/android/net/connectivity/ConnectivityCompatChanges.java b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
new file mode 100644
index 0000000..a166675
--- /dev/null
+++ b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
@@ -0,0 +1,67 @@
+/*
+ * 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.connectivity;
+
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
+import android.os.Build;
+
+/**
+ * The class contains all CompatChanges for the Connectivity module.
+ *
+ * <p>This is the centralized place for the CompatChanges used in the Connectivity module.
+ * Putting all the CompatChanges in single place makes it possible to manage them under a single
+ * platform_compat_config.
+ * @hide
+ */
+public final class ConnectivityCompatChanges {
+
+    /**
+     * The {@link android.net.LinkProperties#getRoutes()} now can contain excluded as well as
+     * included routes. Use {@link android.net.RouteInfo#getType()} to determine route type.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
+    public static final long EXCLUDED_ROUTES = 186082280;
+
+    /**
+     * When enabled, apps targeting < Android 12 are considered legacy for
+     * the NSD native daemon.
+     * The platform will only keep the daemon running as long as there are
+     * any legacy apps connected.
+     *
+     * After Android 12, direct communication with the native daemon might not work since the native
+     * daemon won't always stay alive. Using the NSD APIs from NsdManager as the replacement is
+     * recommended.
+     * Another alternative could be bundling your own mdns solutions instead of
+     * depending on the system mdns native daemon.
+     *
+     * This compatibility change applies to Android 13 and later only. To toggle behavior on
+     * Android 12 and Android 12L, use RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+    // This was a platform change ID with value 191844585L before T
+    public static final long RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER = 235355681L;
+
+    private ConnectivityCompatChanges() {
+    }
+}
diff --git a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
index a3299a7..2dbe771 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
@@ -210,7 +210,8 @@
 };
 
 int register_android_server_net_NetworkStatsFactory(JNIEnv* env) {
-    int err = jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsFactory", gMethods,
+    int err = jniRegisterNativeMethods(env,
+            "android/net/connectivity/com/android/server/net/NetworkStatsFactory", gMethods,
             NELEM(gMethods));
     gStringClass = env->FindClass("java/lang/String");
     gStringClass = static_cast<jclass>(env->NewGlobalRef(gStringClass));
diff --git a/service-t/jni/com_android_server_net_NetworkStatsService.cpp b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
index af0b8d8..dab9d07 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
@@ -116,8 +116,9 @@
 };
 
 int register_android_server_net_NetworkStatsService(JNIEnv* env) {
-    return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods,
-                                    NELEM(gMethods));
+    return jniRegisterNativeMethods(env,
+            "android/net/connectivity/com/android/server/net/NetworkStatsService", gMethods,
+            NELEM(gMethods));
 }
 
 }
diff --git a/service-t/src/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java
index 9e71eb3..a884840 100644
--- a/service-t/src/com/android/server/IpSecService.java
+++ b/service-t/src/com/android/server/IpSecService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.net.IpSecManager.FEATURE_IPSEC_TUNNEL_MIGRATION;
 import static android.net.IpSecManager.INVALID_RESOURCE_ID;
 import static android.system.OsConstants.AF_INET;
@@ -65,6 +66,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
+import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.BinderUtils;
 import com.android.net.module.util.NetdUtils;
 import com.android.net.module.util.PermissionUtils;
@@ -102,6 +104,7 @@
 
     private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms
     private static final InetAddress INADDR_ANY;
+    private static final InetAddress IN6ADDR_ANY;
 
     @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10;
 
@@ -110,6 +113,8 @@
     static {
         try {
             INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
+            IN6ADDR_ANY = InetAddress.getByAddress(
+                    new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
         } catch (UnknownHostException e) {
             throw new RuntimeException(e);
         }
@@ -1013,11 +1018,13 @@
     private final class EncapSocketRecord extends OwnedResourceRecord {
         private FileDescriptor mSocket;
         private final int mPort;
+        private final int mFamily;  // TODO: what about IPV6_ADDRFORM?
 
-        EncapSocketRecord(int resourceId, FileDescriptor socket, int port) {
+        EncapSocketRecord(int resourceId, FileDescriptor socket, int port, int family) {
             super(resourceId);
             mSocket = socket;
             mPort = port;
+            mFamily = family;
         }
 
         /** always guarded by IpSecService#this */
@@ -1038,6 +1045,10 @@
             return mSocket;
         }
 
+        public int getFamily() {
+            return mFamily;
+        }
+
         @Override
         protected ResourceTracker getResourceTracker() {
             return getUserRecord().mSocketQuotaTracker;
@@ -1210,15 +1221,16 @@
      * and re-binding, during which the system could *technically* hand that port out to someone
      * else.
      */
-    private int bindToRandomPort(FileDescriptor sockFd) throws IOException {
+    private int bindToRandomPort(FileDescriptor sockFd, int family, InetAddress localAddr)
+            throws IOException {
         for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) {
             try {
-                FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-                Os.bind(probeSocket, INADDR_ANY, 0);
+                FileDescriptor probeSocket = Os.socket(family, SOCK_DGRAM, IPPROTO_UDP);
+                Os.bind(probeSocket, localAddr, 0);
                 int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort();
                 Os.close(probeSocket);
                 Log.v(TAG, "Binding to port " + port);
-                Os.bind(sockFd, INADDR_ANY, port);
+                Os.bind(sockFd, localAddr, port);
                 return port;
             } catch (ErrnoException e) {
                 // Someone miraculously claimed the port just after we closed probeSocket.
@@ -1260,6 +1272,19 @@
     @Override
     public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder)
             throws RemoteException {
+        // Experimental support for IPv6 UDP encap.
+        final int family;
+        final InetAddress localAddr;
+        if (SdkLevel.isAtLeastU() && port >= 65536) {
+            PermissionUtils.enforceNetworkStackPermissionOr(mContext, NETWORK_SETTINGS);
+            port -= 65536;
+            family = AF_INET6;
+            localAddr = IN6ADDR_ANY;
+        } else {
+            family = AF_INET;
+            localAddr = INADDR_ANY;
+        }
+
         if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) {
             throw new IllegalArgumentException(
                     "Specified port number must be a valid non-reserved UDP port");
@@ -1278,7 +1303,7 @@
 
             FileDescriptor sockFd = null;
             try {
-                sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+                sockFd = Os.socket(family, SOCK_DGRAM, IPPROTO_UDP);
                 pFd = ParcelFileDescriptor.dup(sockFd);
             } finally {
                 IoUtils.closeQuietly(sockFd);
@@ -1295,15 +1320,16 @@
             mNetd.ipSecSetEncapSocketOwner(pFd, callingUid);
             if (port != 0) {
                 Log.v(TAG, "Binding to port " + port);
-                Os.bind(pFd.getFileDescriptor(), INADDR_ANY, port);
+                Os.bind(pFd.getFileDescriptor(), localAddr, port);
             } else {
-                port = bindToRandomPort(pFd.getFileDescriptor());
+                port = bindToRandomPort(pFd.getFileDescriptor(), family, localAddr);
             }
 
             userRecord.mEncapSocketRecords.put(
                     resourceId,
                     new RefcountedResource<EncapSocketRecord>(
-                            new EncapSocketRecord(resourceId, pFd.getFileDescriptor(), port),
+                            new EncapSocketRecord(resourceId, pFd.getFileDescriptor(), port,
+                                    family),
                             binder));
             return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port,
                     pFd.getFileDescriptor());
@@ -1580,6 +1606,7 @@
      */
     private void checkIpSecConfig(IpSecConfig config) {
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        EncapSocketRecord encapSocketRecord = null;
 
         switch (config.getEncapType()) {
             case IpSecTransform.ENCAP_NONE:
@@ -1587,7 +1614,7 @@
             case IpSecTransform.ENCAP_ESPINUDP:
             case IpSecTransform.ENCAP_ESPINUDP_NON_IKE:
                 // Retrieve encap socket record; will throw IllegalArgumentException if not found
-                userRecord.mEncapSocketRecords.getResourceOrThrow(
+                encapSocketRecord = userRecord.mEncapSocketRecords.getResourceOrThrow(
                         config.getEncapSocketResourceId());
 
                 int port = config.getEncapRemotePort();
@@ -1641,10 +1668,9 @@
                             + ") have different address families.");
         }
 
-        // Throw an error if UDP Encapsulation is not used in IPv4.
-        if (config.getEncapType() != IpSecTransform.ENCAP_NONE && sourceFamily != AF_INET) {
+        if (encapSocketRecord != null && encapSocketRecord.getFamily() != destinationFamily) {
             throw new IllegalArgumentException(
-                    "UDP Encapsulation is not supported for this address family");
+                    "UDP encapsulation socket and destination address families must match");
         }
 
         switch (config.getMode()) {
diff --git a/service/ServiceConnectivityResources/res/values-mcc310-mnc590/config.xml b/service/ServiceConnectivityResources/res/values-mcc310-mnc590/config.xml
new file mode 120000
index 0000000..2b8e406
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mcc310-mnc590/config.xml
@@ -0,0 +1 @@
+../values-mcc310-mnc004/config.xml
\ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc310-mnc599/config.xml b/service/ServiceConnectivityResources/res/values-mcc310-mnc599/config.xml
new file mode 120000
index 0000000..2b8e406
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mcc310-mnc599/config.xml
@@ -0,0 +1 @@
+../values-mcc310-mnc004/config.xml
\ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc311-mnc270/config.xml b/service/ServiceConnectivityResources/res/values-mcc311-mnc270/config.xml
new file mode 120000
index 0000000..2b8e406
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mcc311-mnc270/config.xml
@@ -0,0 +1 @@
+../values-mcc310-mnc004/config.xml
\ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc311-mnc280/config.xml b/service/ServiceConnectivityResources/res/values-mcc311-mnc280/config.xml
new file mode 120000
index 0000000..2b8e406
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mcc311-mnc280/config.xml
@@ -0,0 +1 @@
+../values-mcc310-mnc004/config.xml
\ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml b/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
deleted file mode 100644
index 7e7025f..0000000
--- a/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 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 values for ConnectivityService
-     DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
-     Overlay package following the overlayable.xml configuration in the same directory:
-     https://source.android.com/devices/architecture/rros -->
-<resources>
-    <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
-         Internet access. Actual device behaviour is controlled by
-         Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
-    <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
-</resources>
\ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml b/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
new file mode 120000
index 0000000..2b8e406
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
@@ -0,0 +1 @@
+../values-mcc310-mnc004/config.xml
\ No newline at end of file
diff --git a/service/jarjar-excludes.txt b/service/jarjar-excludes.txt
index b0d6763..7bd3862 100644
--- a/service/jarjar-excludes.txt
+++ b/service/jarjar-excludes.txt
@@ -1,9 +1,3 @@
 # Classes loaded by SystemServer via their hardcoded name, so they can't be jarjared
 com\.android\.server\.ConnectivityServiceInitializer(\$.+)?
 com\.android\.server\.NetworkStatsServiceInitializer(\$.+)?
-
-# Do not jarjar com.android.server, as several unit tests fail because they lose
-# package-private visibility between jarjared and non-jarjared classes.
-# TODO: fix the tests and also jarjar com.android.server, or at least only exclude a package that
-# is specific to the module like com.android.server.connectivity
-com\.android\.server\..+
diff --git a/service/jni/com_android_server_BpfNetMaps.cpp b/service/jni/com_android_server_BpfNetMaps.cpp
index 05f50b0..77cffda 100644
--- a/service/jni/com_android_server_BpfNetMaps.cpp
+++ b/service/jni/com_android_server_BpfNetMaps.cpp
@@ -236,7 +236,7 @@
 // clang-format on
 
 int register_com_android_server_BpfNetMaps(JNIEnv* env) {
-    return jniRegisterNativeMethods(env, "com/android/server/BpfNetMaps",
+    return jniRegisterNativeMethods(env, "android/net/connectivity/com/android/server/BpfNetMaps",
                                     gMethods, NELEM(gMethods));
 }
 
diff --git a/service/jni/com_android_server_TestNetworkService.cpp b/service/jni/com_android_server_TestNetworkService.cpp
index bd74d54..7aeecfa 100644
--- a/service/jni/com_android_server_TestNetworkService.cpp
+++ b/service/jni/com_android_server_TestNetworkService.cpp
@@ -151,8 +151,9 @@
 };
 
 int register_com_android_server_TestNetworkService(JNIEnv* env) {
-    return jniRegisterNativeMethods(env, "com/android/server/TestNetworkService", gMethods,
-                                    NELEM(gMethods));
+    return jniRegisterNativeMethods(env,
+            "android/net/connectivity/com/android/server/TestNetworkService", gMethods,
+            NELEM(gMethods));
 }
 
 }; // namespace android
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index 7060958..5b42659 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -477,8 +477,9 @@
 };
 
 int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env) {
-    return jniRegisterNativeMethods(env, "com/android/server/connectivity/ClatCoordinator",
-                                    gMethods, NELEM(gMethods));
+    return jniRegisterNativeMethods(env,
+            "android/net/connectivity/com/android/server/connectivity/ClatCoordinator",
+            gMethods, NELEM(gMethods));
 }
 
 };  // namespace android
diff --git a/service/proguard.flags b/service/proguard.flags
index 864a28b..cf25f05 100644
--- a/service/proguard.flags
+++ b/service/proguard.flags
@@ -7,7 +7,7 @@
     *;
 }
 
--keepclassmembers class com.android.server.**,android.net.**,com.android.networkstack.** {
+-keepclassmembers class android.net.**,com.android.networkstack.** {
     static final % POLICY_*;
     static final % NOTIFY_TYPE_*;
     static final % TRANSPORT_*;
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index a570ab1..26335c9 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -766,6 +766,11 @@
     private static final int EVENT_SET_VPN_NETWORK_PREFERENCE = 59;
 
     /**
+     * Event to use low TCP polling timer used in automatic on/off keepalive temporarily.
+     */
+    private static final int EVENT_SET_LOW_TCP_POLLING_UNTIL = 60;
+
+    /**
      * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
      * should be shown.
      */
@@ -783,6 +788,12 @@
     private static final long MAX_TEST_ALLOW_BAD_WIFI_UNTIL_MS = 5 * 60 * 1000L;
 
     /**
+     * The maximum alive time to decrease TCP polling timer in automatic on/off keepalive for
+     * testing.
+     */
+    private static final long MAX_TEST_LOW_TCP_POLLING_UNTIL_MS = 5 * 60 * 1000L;
+
+    /**
      * The priority of the tc police rate limiter -- smaller value is higher priority.
      * This value needs to be coordinated with PRIO_CLAT, PRIO_TETHER4, and PRIO_TETHER6.
      */
@@ -1305,6 +1316,14 @@
         }
 
         /**
+         * @see AutomaticOnOffKeepaliveTracker
+         */
+        public AutomaticOnOffKeepaliveTracker makeAutomaticOnOffKeepaliveTracker(
+                @NonNull Context c, @NonNull Handler h) {
+            return new AutomaticOnOffKeepaliveTracker(c, h);
+        }
+
+        /**
          * @see BatteryStatsManager
          */
         public void reportNetworkInterfaceForTransports(Context context, String iface,
@@ -1567,7 +1586,7 @@
         mSettingsObserver = new SettingsObserver(mContext, mHandler);
         registerSettingsCallbacks();
 
-        mKeepaliveTracker = new AutomaticOnOffKeepaliveTracker(mContext, mHandler);
+        mKeepaliveTracker = mDeps.makeAutomaticOnOffKeepaliveTracker(mContext, mHandler);
         mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
         mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
 
@@ -2863,9 +2882,10 @@
                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
-    private void enforceSettingsOrUseRestrictedNetworksPermission() {
+    private void enforceSettingsOrSetupWizardOrUseRestrictedNetworksPermission() {
         enforceAnyPermissionOf(mContext,
                 android.Manifest.permission.NETWORK_SETTINGS,
+                android.Manifest.permission.NETWORK_SETUP_WIZARD,
                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
                 Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS);
     }
@@ -5001,6 +5021,22 @@
                 mHandler.obtainMessage(EVENT_SET_TEST_ALLOW_BAD_WIFI_UNTIL, timeMs));
     }
 
+    @Override
+    public void setTestLowTcpPollingTimerForKeepalive(long timeMs) {
+        enforceSettingsPermission();
+        if (!Build.isDebuggable()) {
+            throw new IllegalStateException("Is not supported in non-debuggable build");
+        }
+
+        if (timeMs > System.currentTimeMillis() + MAX_TEST_LOW_TCP_POLLING_UNTIL_MS) {
+            throw new IllegalArgumentException("Argument should not exceed "
+                    + MAX_TEST_LOW_TCP_POLLING_UNTIL_MS + "ms from now");
+        }
+
+        mHandler.sendMessage(
+                mHandler.obtainMessage(EVENT_SET_LOW_TCP_POLLING_UNTIL, timeMs));
+    }
+
     private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) {
         if (DBG) log("handleSetAcceptUnvalidated network=" + network +
                 " accept=" + accept + " always=" + always);
@@ -5554,13 +5590,14 @@
                             mKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj);
                     if (null == ki) return; // The callback was unregistered before the alarm fired
 
+                    final Network underpinnedNetwork = ki.getUnderpinnedNetwork();
                     final Network network = ki.getNetwork();
                     boolean networkFound = false;
-                    final ArrayList<NetworkAgentInfo> vpnsRunningOnThisNetwork = new ArrayList<>();
+                    boolean underpinnedNetworkFound = false;
                     for (NetworkAgentInfo n : mNetworkAgentInfos) {
                         if (n.network.equals(network)) networkFound = true;
-                        if (n.isVPN() && n.everConnected() && hasUnderlyingNetwork(n, network)) {
-                            vpnsRunningOnThisNetwork.add(n);
+                        if (n.everConnected() && n.network.equals(underpinnedNetwork)) {
+                            underpinnedNetworkFound = true;
                         }
                     }
 
@@ -5568,12 +5605,11 @@
                     // cleaned up already. There is no point trying to resume keepalives.
                     if (!networkFound) return;
 
-                    if (!vpnsRunningOnThisNetwork.isEmpty()) {
+                    if (underpinnedNetworkFound) {
                         mKeepaliveTracker.handleMonitorAutomaticKeepalive(ki,
-                                // TODO: check all the VPNs running on top of this network
-                                vpnsRunningOnThisNetwork.get(0).network.netId);
+                                underpinnedNetwork.netId);
                     } else {
-                        // If no VPN, then make sure the keepalive is running.
+                        // If no underpinned network, then make sure the keepalive is running.
                         mKeepaliveTracker.handleMaybeResumeKeepalive(ki);
                     }
                     break;
@@ -5642,6 +5678,11 @@
                 case EVENT_SET_VPN_NETWORK_PREFERENCE:
                     handleSetVpnNetworkPreference((VpnNetworkPreferenceInfo) msg.obj);
                     break;
+                case EVENT_SET_LOW_TCP_POLLING_UNTIL: {
+                    final long time = ((Long) msg.obj).longValue();
+                    mKeepaliveTracker.handleSetTestLowTcpPollingTimer(time);
+                    break;
+                }
             }
         }
     }
@@ -6808,7 +6849,7 @@
                 enforceAccessPermission();
                 break;
             case TRACK_SYSTEM_DEFAULT:
-                enforceSettingsOrUseRestrictedNetworksPermission();
+                enforceSettingsOrSetupWizardOrUseRestrictedNetworksPermission();
                 networkCapabilities = new NetworkCapabilities(defaultNc);
                 break;
             case BACKGROUND_REQUEST:
@@ -9828,21 +9869,22 @@
                 getNetworkAgentInfoForNetwork(network), null /* fd */,
                 intervalSeconds, cb, srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT,
                 // Keep behavior of the deprecated method as it is. Set automaticOnOffKeepalives to
-                // false because there is no way and no plan to configure automaticOnOffKeepalives
-                // in this deprecated method.
-                false /* automaticOnOffKeepalives */);
+                // false and set the underpinned network to null because there is no way and no
+                // plan to configure automaticOnOffKeepalives or underpinnedNetwork in this
+                // deprecated method.
+                false /* automaticOnOffKeepalives */, null /* underpinnedNetwork */);
     }
 
     @Override
     public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId,
             int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr,
-            String dstAddr, boolean automaticOnOffKeepalives) {
+            String dstAddr, boolean automaticOnOffKeepalives, Network underpinnedNetwork) {
         try {
             final FileDescriptor fd = pfd.getFileDescriptor();
             mKeepaliveTracker.startNattKeepalive(
                     getNetworkAgentInfoForNetwork(network), fd, resourceId,
-                    intervalSeconds, cb,
-                    srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT, automaticOnOffKeepalives);
+                    intervalSeconds, cb, srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT,
+                    automaticOnOffKeepalives, underpinnedNetwork);
         } finally {
             // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
             // startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately.
diff --git a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
index 8bfbcf7..760a5f3 100644
--- a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
@@ -18,7 +18,7 @@
 
 import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
 import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
-import static android.net.SocketKeepalive.SUCCESS;
+import static android.net.SocketKeepalive.SUCCESS_PAUSED;
 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
@@ -98,6 +98,7 @@
             "com.android.server.connectivity.KeepaliveTracker.TCP_POLLING_ALARM";
     private static final String EXTRA_BINDER_TOKEN = "token";
     private static final long DEFAULT_TCP_POLLING_INTERVAL_MS = 120_000L;
+    private static final long LOW_TCP_POLLING_INTERVAL_MS = 1_000L;
     private static final String AUTOMATIC_ON_OFF_KEEPALIVE_VERSION =
             "automatic_on_off_keepalive_version";
     /**
@@ -156,6 +157,8 @@
      * This should be only updated in ConnectivityService handler thread.
      */
     private final ArrayList<AutomaticOnOffKeepalive> mAutomaticOnOffKeepalives = new ArrayList<>();
+    // TODO: Remove this when TCP polling design is replaced with callback.
+    private long mTestLowTcpPollingTimerUntilMs = 0;
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
@@ -182,7 +185,7 @@
      *                     resumed if a TCP socket is open on the VPN.
      * See the documentation for the states for more detail.
      */
-    public class AutomaticOnOffKeepalive {
+    public class AutomaticOnOffKeepalive implements IBinder.DeathRecipient {
         @NonNull
         private final KeepaliveTracker.KeepaliveInfo mKi;
         @NonNull
@@ -193,11 +196,16 @@
         private final PendingIntent mTcpPollingAlarm;
         @AutomaticOnOffState
         private int mAutomaticOnOffState;
+        @Nullable
+        private final Network mUnderpinnedNetwork;
 
         AutomaticOnOffKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki,
-                final boolean autoOnOff, @NonNull Context context) throws InvalidSocketException {
+                final boolean autoOnOff, @NonNull Context context,
+                @Nullable Network underpinnedNetwork)
+                throws InvalidSocketException {
             this.mKi = Objects.requireNonNull(ki);
             mCallback = ki.mCallback;
+            mUnderpinnedNetwork = underpinnedNetwork;
             if (autoOnOff && mDependencies.isFeatureEnabled(AUTOMATIC_ON_OFF_KEEPALIVE_VERSION)) {
                 mAutomaticOnOffState = STATE_ENABLED;
                 if (null == ki.mFd) {
@@ -225,6 +233,11 @@
             return mKi.getNai().network;
         }
 
+        @Nullable
+        public Network getUnderpinnedNetwork() {
+            return mUnderpinnedNetwork;
+        }
+
         public boolean match(Network network, int slot) {
             return mKi.getNai().network().equals(network) && mKi.getSlot() == slot;
         }
@@ -239,6 +252,40 @@
             return BinderUtils.withCleanCallingIdentity(() -> PendingIntent.getBroadcast(
                     context, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE));
         }
+
+        @Override
+        public void binderDied() {
+            mConnectivityServiceHandler.post(() -> cleanupAutoOnOffKeepalive(this));
+        }
+
+        /** Close this automatic on/off keepalive */
+        public void close() {
+            // Close the duplicated fd that maintains the lifecycle of socket. If this fd was
+            // not duplicated this is a no-op.
+            FileUtils.closeQuietly(mFd);
+        }
+
+        private String getAutomaticOnOffStateName(int state) {
+            switch (state) {
+                case STATE_ENABLED:
+                    return "STATE_ENABLED";
+                case STATE_SUSPENDED:
+                    return "STATE_SUSPENDED";
+                case STATE_ALWAYS_ON:
+                    return "STATE_ALWAYS_ON";
+                default:
+                    Log.e(TAG, "Get unexpected state:" + state);
+                    return Integer.toString(state);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "AutomaticOnOffKeepalive [ "
+                    + mKi
+                    + ", state=" + getAutomaticOnOffStateName(mAutomaticOnOffState)
+                    + " ]";
+        }
     }
 
     public AutomaticOnOffKeepaliveTracker(@NonNull Context context, @NonNull Handler handler) {
@@ -264,7 +311,7 @@
 
     private void startTcpPollingAlarm(@NonNull PendingIntent alarm) {
         final long triggerAtMillis =
-                SystemClock.elapsedRealtime() + DEFAULT_TCP_POLLING_INTERVAL_MS;
+                SystemClock.elapsedRealtime() + getTcpPollingInterval();
         // Setup a non-wake up alarm.
         mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, triggerAtMillis, alarm);
     }
@@ -297,7 +344,7 @@
             // SUSPENDED.
             if (ki.mAutomaticOnOffState == STATE_ENABLED) {
                 ki.mAutomaticOnOffState = STATE_SUSPENDED;
-                handleSuspendKeepalive(ki.mKi);
+                handlePauseKeepalive(ki.mKi);
             }
         } else {
             handleMaybeResumeKeepalive(ki);
@@ -374,6 +421,13 @@
         mKeepaliveTracker.handleStartKeepalive(autoKi.mKi);
 
         // Add automatic on/off request into list to track its life cycle.
+        try {
+            autoKi.mKi.mCallback.asBinder().linkToDeath(autoKi, 0);
+        } catch (RemoteException e) {
+            // The underlying keepalive performs its own cleanup
+            autoKi.binderDied();
+            return;
+        }
         mAutomaticOnOffKeepalives.add(autoKi);
         if (STATE_ALWAYS_ON != autoKi.mAutomaticOnOffState) {
             startTcpPollingAlarm(autoKi.mTcpPollingAlarm);
@@ -384,10 +438,9 @@
         mKeepaliveTracker.handleStartKeepalive(ki);
     }
 
-    private void handleSuspendKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) {
+    private void handlePauseKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) {
         // TODO : mKT.handleStopKeepalive should take a KeepaliveInfo instead
-        // TODO : create a separate success code for suspend
-        mKeepaliveTracker.handleStopKeepalive(ki.getNai(), ki.getSlot(), SUCCESS);
+        mKeepaliveTracker.handleStopKeepalive(ki.getNai(), ki.getSlot(), SUCCESS_PAUSED);
     }
 
     /**
@@ -399,6 +452,8 @@
         if (autoKi.mAutomaticOnOffState != STATE_SUSPENDED) {
             final KeepaliveTracker.KeepaliveInfo ki = autoKi.mKi;
             mKeepaliveTracker.handleStopKeepalive(ki.getNai(), ki.getSlot(), reason);
+        } else {
+            mKeepaliveTracker.finalizePausedKeepalive(autoKi.mKi);
         }
 
         cleanupAutoOnOffKeepalive(autoKi);
@@ -406,10 +461,15 @@
 
     private void cleanupAutoOnOffKeepalive(@NonNull final AutomaticOnOffKeepalive autoKi) {
         ensureRunningOnHandlerThread();
+        autoKi.close();
         if (null != autoKi.mTcpPollingAlarm) mAlarmManager.cancel(autoKi.mTcpPollingAlarm);
-        // Close the duplicated fd that maintains the lifecycle of socket.
-        FileUtils.closeQuietly(autoKi.mFd);
-        mAutomaticOnOffKeepalives.remove(autoKi);
+
+        // If the KI is not in the array, it's because it was already removed, or it was never
+        // added ; the only ways this can happen is if the keepalive is stopped by the app and the
+        // app dies immediately, or if the app died before the link to death could be registered.
+        if (!mAutomaticOnOffKeepalives.remove(autoKi)) return;
+
+        autoKi.mKi.mCallback.asBinder().unlinkToDeath(autoKi, 0);
     }
 
     /**
@@ -425,13 +485,13 @@
             @NonNull String srcAddrString,
             int srcPort,
             @NonNull String dstAddrString,
-            int dstPort, boolean automaticOnOffKeepalives) {
+            int dstPort, boolean automaticOnOffKeepalives, @Nullable Network underpinnedNetwork) {
         final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd,
                 intervalSeconds, cb, srcAddrString, srcPort, dstAddrString, dstPort);
         if (null == ki) return;
         try {
             final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
-                    automaticOnOffKeepalives, mContext);
+                    automaticOnOffKeepalives, mContext, underpinnedNetwork);
             mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
                     // TODO : move ConnectivityService#encodeBool to a static lib.
                     automaticOnOffKeepalives ? 1 : 0, 0, autoKi).sendToTarget();
@@ -454,13 +514,14 @@
             @NonNull String srcAddrString,
             @NonNull String dstAddrString,
             int dstPort,
-            boolean automaticOnOffKeepalives) {
+            boolean automaticOnOffKeepalives,
+            @Nullable Network underpinnedNetwork) {
         final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd,
                 resourceId, intervalSeconds, cb, srcAddrString, dstAddrString, dstPort);
         if (null == ki) return;
         try {
             final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
-                    automaticOnOffKeepalives, mContext);
+                    automaticOnOffKeepalives, mContext, underpinnedNetwork);
             mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
                     // TODO : move ConnectivityService#encodeBool to a static lib.
                     automaticOnOffKeepalives ? 1 : 0, 0, autoKi).sendToTarget();
@@ -489,7 +550,8 @@
         if (null == ki) return;
         try {
             final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
-                    false /* autoOnOff, tcp keepalives are never auto on/off */, mContext);
+                    false /* autoOnOff, tcp keepalives are never auto on/off */,
+                    mContext, null /* underpinnedNetwork, tcp keepalives do not refer to this */);
             mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, autoKi)
                     .sendToTarget();
         } catch (InvalidSocketException e) {
@@ -501,8 +563,18 @@
      * Dump AutomaticOnOffKeepaliveTracker state.
      */
     public void dump(IndentingPrintWriter pw) {
-        // TODO: Dump the necessary information for automatic on/off keepalive.
         mKeepaliveTracker.dump(pw);
+        // Reading DeviceConfig will check if the calling uid and calling package name are the same.
+        // Clear calling identity to align the calling uid and package so that it won't fail if cts
+        // would like to do the dump()
+        final boolean featureEnabled = BinderUtils.withCleanCallingIdentity(
+                () -> mDependencies.isFeatureEnabled(AUTOMATIC_ON_OFF_KEEPALIVE_VERSION));
+        pw.println("AutomaticOnOff enabled: " + featureEnabled);
+        pw.increaseIndent();
+        for (AutomaticOnOffKeepalive autoKi : mAutomaticOnOffKeepalives) {
+            pw.println(autoKi.toString());
+        }
+        pw.decreaseIndent();
     }
 
     /**
@@ -632,6 +704,20 @@
         }
     }
 
+    private long getTcpPollingInterval() {
+        final boolean useLowTimer = mTestLowTcpPollingTimerUntilMs > System.currentTimeMillis();
+        return useLowTimer ? LOW_TCP_POLLING_INTERVAL_MS : DEFAULT_TCP_POLLING_INTERVAL_MS;
+    }
+
+    /**
+     * Temporarily use low TCP polling timer for testing.
+     * The value works when the time set is more than {@link System.currentTimeMillis()}.
+     */
+    public void handleSetTestLowTcpPollingTimer(long timeMs) {
+        Log.d(TAG, "handleSetTestLowTcpPollingTimer: " + timeMs);
+        mTestLowTcpPollingTimerUntilMs = timeMs;
+    }
+
     /**
      * Dependencies class for testing.
      */
diff --git a/service/src/com/android/server/connectivity/KeepaliveTracker.java b/service/src/com/android/server/connectivity/KeepaliveTracker.java
index a512b7c..5572361 100644
--- a/service/src/com/android/server/connectivity/KeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/KeepaliveTracker.java
@@ -32,6 +32,7 @@
 import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
 import static android.net.SocketKeepalive.NO_KEEPALIVE;
 import static android.net.SocketKeepalive.SUCCESS;
+import static android.net.SocketKeepalive.SUCCESS_PAUSED;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -134,6 +135,9 @@
         public final NetworkAgentInfo mNai;
         private final int mType;
         public final FileDescriptor mFd;
+        // True if this was resumed from a previously turned off keepalive, otherwise false.
+        // This is necessary to send the correct callbacks.
+        public final boolean mResumed;
 
         public static final int TYPE_NATT = 1;
         public static final int TYPE_TCP = 2;
@@ -160,6 +164,16 @@
                 int interval,
                 int type,
                 @Nullable FileDescriptor fd) throws InvalidSocketException {
+            this(callback, nai, packet, interval, type, fd, false /* resumed */);
+        }
+
+        KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback,
+                @NonNull NetworkAgentInfo nai,
+                @NonNull KeepalivePacketData packet,
+                int interval,
+                int type,
+                @Nullable FileDescriptor fd,
+                boolean resumed) throws InvalidSocketException {
             mCallback = callback;
             mPid = Binder.getCallingPid();
             mUid = Binder.getCallingUid();
@@ -169,6 +183,7 @@
             mPacket = packet;
             mInterval = interval;
             mType = type;
+            mResumed = resumed;
 
             // For SocketKeepalive, a dup of fd is kept in mFd so the source port from which the
             // keepalives are sent cannot be reused by another app even if the fd gets closed by
@@ -232,6 +247,8 @@
 
         /** Called when the application process is killed. */
         public void binderDied() {
+            // TODO b/267106526 : this is not called on the handler thread but stop() happily
+            // assumes it is, which means this is a pretty dangerous race condition.
             stop(BINDER_DIED);
         }
 
@@ -327,6 +344,10 @@
         }
 
         void start(int slot) {
+            // BINDER_DIED can happen if the binder died before the KeepaliveInfo was created and
+            // the constructor set the state to BINDER_DIED. If that's the case, the KI is already
+            // cleaned up.
+            if (BINDER_DIED == mStartedState) return;
             mSlot = slot;
             int error = isValid();
             if (error == SUCCESS) {
@@ -371,7 +392,10 @@
             // To prevent races from re-entrance of stop(), return if the state is already stopping.
             // This might happen if multiple event sources stop keepalive in a short time. Such as
             // network disconnect after user calls stop(), or tear down socket after binder died.
-            if (mStartedState == STOPPING) return;
+            // Note that it's always possible this method is called by the auto keepalive timer
+            // or any other way after the binder died, hence the check for BINDER_DIED. If the
+            // binder has died, then the KI has already been cleaned up.
+            if (mStartedState == STOPPING || mStartedState == BINDER_DIED) return;
 
             // Store the reason of stopping, and report it after the keepalive is fully stopped.
             if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) {
@@ -382,9 +406,10 @@
                     + ": " + reason);
             switch (mStartedState) {
                 case NOT_STARTED:
-                    // Remove the reference of the keepalive that meet error before starting,
+                    // Remove the reference to this keepalive that had an error before starting,
                     // e.g. invalid parameter.
                     cleanupStoppedKeepalive(mNai, mSlot);
+                    if (BINDER_DIED == reason) mStartedState = BINDER_DIED;
                     break;
                 default:
                     mStartedState = STOPPING;
@@ -422,7 +447,8 @@
          * Construct a new KeepaliveInfo from existing KeepaliveInfo with a new fd.
          */
         public KeepaliveInfo withFd(@NonNull FileDescriptor fd) throws InvalidSocketException {
-            return new KeepaliveInfo(mCallback, mNai, mPacket, mInterval, mType, fd);
+            return new KeepaliveInfo(mCallback, mNai, mPacket, mInterval, mType, fd,
+                    true /* resumed */);
         }
     }
 
@@ -523,6 +549,12 @@
             } catch (RemoteException e) {
                 Log.w(TAG, "Discarded onStop callback: " + reason);
             }
+        } else if (reason == SUCCESS_PAUSED) {
+            try {
+                ki.mCallback.onPaused();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Discarded onPaused callback: " + reason);
+            }
         } else if (reason == DATA_RECEIVED) {
             try {
                 ki.mCallback.onDataReceived();
@@ -540,6 +572,25 @@
         ki.unlinkDeathRecipient();
     }
 
+    /**
+     * Finalize a paused keepalive.
+     *
+     * This will simply send the onStopped() callback after checking that this keepalive is
+     * indeed paused.
+     *
+     * @param ki the keepalive to finalize
+     */
+    public void finalizePausedKeepalive(@NonNull final KeepaliveInfo ki) {
+        if (SUCCESS_PAUSED != ki.mStopReason) {
+            throw new IllegalStateException("Keepalive is not paused");
+        }
+        try {
+            ki.mCallback.onStopped();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Discarded onStopped callback while finalizing paused keepalive");
+        }
+    }
+
     public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) {
         HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
         if (networkKeepalives != null) {
@@ -589,9 +640,14 @@
                 Log.d(TAG, "Started keepalive " + slot + " on " + nai.toShortString());
                 ki.mStartedState = KeepaliveInfo.STARTED;
                 try {
-                    ki.mCallback.onStarted();
+                    if (ki.mResumed) {
+                        ki.mCallback.onResumed();
+                    } else {
+                        ki.mCallback.onStarted();
+                    }
                 } catch (RemoteException e) {
-                    Log.w(TAG, "Discarded onStarted callback");
+                    Log.w(TAG, "Discarded " + (ki.mResumed ? "onResumed" : "onStarted")
+                            + " callback for slot " + slot);
                 }
             } else {
                 Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.toShortString()
diff --git a/tests/common/Android.bp b/tests/common/Android.bp
index 5c9cc63..8e47235 100644
--- a/tests/common/Android.bp
+++ b/tests/common/Android.bp
@@ -65,7 +65,7 @@
     defaults: ["jarjar-rules-combine-defaults"],
     srcs: [
         "tethering-jni-jarjar-rules.txt",
-        ":connectivity-jarjar-rules",
+        ":frameworks-net-tests-jarjar-rules",
         ":TetheringTestsJarJarRules",
         ":NetworkStackJarJarRules",
     ],
diff --git a/tests/common/java/android/net/LinkPropertiesTest.java b/tests/common/java/android/net/LinkPropertiesTest.java
index 5ee375f..09f5d6e 100644
--- a/tests/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/common/java/android/net/LinkPropertiesTest.java
@@ -32,6 +32,7 @@
 
 import android.compat.testing.PlatformCompatChangeRule;
 import android.net.LinkProperties.ProvisioningChange;
+import android.net.connectivity.ConnectivityCompatChanges;
 import android.os.Build;
 import android.system.OsConstants;
 import android.util.ArraySet;
@@ -1261,7 +1262,7 @@
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.R)
     @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
-    @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
+    @EnableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES})
     public void testHasExcludeRoute() {
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName("tun0");
@@ -1274,7 +1275,7 @@
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.R)
     @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
-    @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
+    @EnableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES})
     public void testRouteAddWithSameKey() throws Exception {
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName("wlan0");
@@ -1348,14 +1349,14 @@
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.R)
     @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
-    @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
+    @EnableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES})
     public void testExcludedRoutesEnabledByCompatChange() {
         assertExcludeRoutesVisible();
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.R)
     @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
-    @DisableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
+    @DisableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES})
     public void testExcludedRoutesDisabledByCompatChange() {
         checkExcludeRoutesNotVisibleAfterS();
     }
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
index a62ef8a..f1ab62d 100755
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -41,6 +41,7 @@
 import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_EXPORTED;
 import static com.android.testutils.Cleanup.testAndCleanup;
 import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
+import static com.android.testutils.RecorderCallback.CallbackEntry.BLOCKED_STATUS_INT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -1643,7 +1644,8 @@
             // setRequireVpnForUids setup a lockdown rule asynchronously. So it needs to wait for
             // BlockedStatusCallback to be fired before checking the blocking status of incoming
             // packets.
-            remoteUidCallback.expectBlockedStatusCallback(network, BLOCKED_REASON_LOCKDOWN_VPN);
+            remoteUidCallback.expect(BLOCKED_STATUS_INT, network,
+                    cb -> cb.getReason() == BLOCKED_REASON_LOCKDOWN_VPN);
 
             if (SdkLevel.isAtLeastT()) {
                 // On T and above, lockdown rule drop packets not coming from lo regardless of the
@@ -1818,9 +1820,6 @@
             super.expectAvailableCallbacks(network, false /* suspended */, true /* validated */,
                     BLOCKED_REASON_NONE, NETWORK_CALLBACK_TIMEOUT_MS);
         }
-        public void expectBlockedStatusCallback(Network network, int blockedStatus) {
-            super.expectBlockedStatusCallback(blockedStatus, network, NETWORK_CALLBACK_TIMEOUT_MS);
-        }
         public void onBlockedStatusChanged(Network network, int blockedReasons) {
             getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
         }
diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp
index 23cb15c..f9fe5b0 100644
--- a/tests/cts/net/Android.bp
+++ b/tests/cts/net/Android.bp
@@ -114,34 +114,39 @@
     ],
 }
 
-android_test {
-    name: "CtsNetTestCasesMaxTargetSdk31",  // Must match CtsNetTestCasesMaxTargetSdk31 annotation.
+java_defaults {
+    name: "CtsNetTestCasesMaxTargetSdkDefaults",
     defaults: [
         "CtsNetTestCasesDefaults",
         "CtsNetTestCasesApiStableDefaults",
     ],
-    target_sdk_version: "31",
-    package_name: "android.net.cts.maxtargetsdk31",  // CTS package names must be unique.
-    instrumentation_target_package: "android.net.cts.maxtargetsdk31",
     test_suites: [
         "cts",
         "general-tests",
-        "mts-networking",
+        "mts-tethering",
     ],
 }
 
 android_test {
+    name: "CtsNetTestCasesMaxTargetSdk33",  // Must match CtsNetTestCasesMaxTargetSdk33 annotation.
+    defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"],
+    target_sdk_version: "33",
+    package_name: "android.net.cts.maxtargetsdk33",
+    instrumentation_target_package: "android.net.cts.maxtargetsdk33",
+}
+
+android_test {
+    name: "CtsNetTestCasesMaxTargetSdk31",  // Must match CtsNetTestCasesMaxTargetSdk31 annotation.
+    defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"],
+    target_sdk_version: "31",
+    package_name: "android.net.cts.maxtargetsdk31",  // CTS package names must be unique.
+    instrumentation_target_package: "android.net.cts.maxtargetsdk31",
+}
+
+android_test {
     name: "CtsNetTestCasesMaxTargetSdk30",  // Must match CtsNetTestCasesMaxTargetSdk30 annotation.
-    defaults: [
-        "CtsNetTestCasesDefaults",
-        "CtsNetTestCasesApiStableDefaults",
-    ],
+    defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"],
     target_sdk_version: "30",
     package_name: "android.net.cts.maxtargetsdk30",  // CTS package names must be unique.
     instrumentation_target_package: "android.net.cts.maxtargetsdk30",
-    test_suites: [
-        "cts",
-        "general-tests",
-        "mts-networking",
-    ],
 }
diff --git a/tests/cts/net/native/dns/Android.bp b/tests/cts/net/native/dns/Android.bp
index 434e529..49b9337 100644
--- a/tests/cts/net/native/dns/Android.bp
+++ b/tests/cts/net/native/dns/Android.bp
@@ -24,6 +24,10 @@
         "liblog",
         "libutils",
     ],
+    static_libs: [
+        "libbase",
+        "libnetdutils",
+    ],
     // To be compatible with Q devices, the min_sdk_version must be 29.
     min_sdk_version: "29",
 }
diff --git a/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp b/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp
index e501475..68bd227 100644
--- a/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp
+++ b/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp
@@ -28,6 +28,7 @@
 
 #include <android/multinetwork.h>
 #include <gtest/gtest.h>
+#include <netdutils/NetNativeTestBase.h>
 
 namespace {
 constexpr int MAXPACKET = 8 * 1024;
@@ -101,7 +102,9 @@
 
 } // namespace
 
-TEST (NativeDnsAsyncTest, Async_Query) {
+class NativeDnsAsyncTest : public NetNativeTestBase {};
+
+TEST_F(NativeDnsAsyncTest, Async_Query) {
     // V4
     int fd1 = android_res_nquery(
             NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_a, 0);
@@ -123,7 +126,7 @@
     expectAnswersValid(fd1, AF_INET6, ns_r_noerror);
 }
 
-TEST (NativeDnsAsyncTest, Async_Send) {
+TEST_F(NativeDnsAsyncTest, Async_Send) {
     // V4
     uint8_t buf1[MAXPACKET] = {};
     int len1 = res_mkquery(ns_o_query, "www.googleapis.com",
@@ -162,7 +165,7 @@
     expectAnswersValid(fd1, AF_INET6, ns_r_noerror);
 }
 
-TEST (NativeDnsAsyncTest, Async_NXDOMAIN) {
+TEST_F(NativeDnsAsyncTest, Async_NXDOMAIN) {
     uint8_t buf[MAXPACKET] = {};
     int len = res_mkquery(ns_o_query, "test1-nx.metric.gstatic.com",
             ns_c_in, ns_t_a, nullptr, 0, nullptr, buf, sizeof(buf));
@@ -191,7 +194,7 @@
     expectAnswersValid(fd1, AF_INET6, ns_r_nxdomain);
 }
 
-TEST (NativeDnsAsyncTest, Async_Cancel) {
+TEST_F(NativeDnsAsyncTest, Async_Cancel) {
     int fd = android_res_nquery(
             NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_a, 0);
     errno = 0;
@@ -202,7 +205,7 @@
     // otherwise it will hit fdsan double-close fd.
 }
 
-TEST (NativeDnsAsyncTest, Async_Query_MALFORMED) {
+TEST_F(NativeDnsAsyncTest, Async_Query_MALFORMED) {
     // Empty string to create BLOB and query, we will get empty result and rcode = 0
     // on DNSTLS.
     int fd = android_res_nquery(
@@ -221,7 +224,7 @@
     EXPECT_EQ(-EMSGSIZE, fd);
 }
 
-TEST (NativeDnsAsyncTest, Async_Send_MALFORMED) {
+TEST_F(NativeDnsAsyncTest, Async_Send_MALFORMED) {
     uint8_t buf[10] = {};
     // empty BLOB
     int fd = android_res_nsend(NETWORK_UNSPECIFIED, buf, 10, 0);
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index ccba983..68b20e2 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -2385,7 +2385,7 @@
         }
         public void eventuallyExpectBlockedStatusCallback(Network network, int blockedStatus) {
             super.eventuallyExpect(CallbackEntry.BLOCKED_STATUS_INT, NETWORK_CALLBACK_TIMEOUT_MS,
-                    (it) -> it.getNetwork().equals(network) && it.getBlocked() == blockedStatus);
+                    (it) -> it.getNetwork().equals(network) && it.getReason() == blockedStatus);
         }
         public void onBlockedStatusChanged(Network network, int blockedReasons) {
             getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
index 8234ec1..4fa0080 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -16,6 +16,7 @@
 
 package android.net.cts;
 
+import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.net.IpSecAlgorithm.AUTH_AES_CMAC;
 import static android.net.IpSecAlgorithm.AUTH_AES_XCBC;
 import static android.net.IpSecAlgorithm.AUTH_CRYPT_AES_GCM;
@@ -52,7 +53,9 @@
 
 import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
 import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+import static com.android.testutils.DeviceInfoUtils.isKernelVersionAtLeast;
 import static com.android.testutils.MiscAsserts.assertThrows;
+import static com.android.testutils.TestPermissionUtil.runAsShell;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -62,6 +65,8 @@
 
 import android.net.IpSecAlgorithm;
 import android.net.IpSecManager;
+import android.net.IpSecManager.SecurityParameterIndex;
+import android.net.IpSecManager.UdpEncapsulationSocket;
 import android.net.IpSecTransform;
 import android.net.TrafficStats;
 import android.os.Build;
@@ -73,6 +78,7 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.modules.utils.build.SdkLevel;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
 
@@ -120,7 +126,7 @@
     @Test
     public void testAllocSpi() throws Exception {
         for (InetAddress addr : GOOGLE_DNS_LIST) {
-            IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null;
+            SecurityParameterIndex randomSpi, droidSpi;
             randomSpi = mISM.allocateSecurityParameterIndex(addr);
             assertTrue(
                     "Failed to receive a valid SPI",
@@ -258,6 +264,24 @@
         accepted.close();
     }
 
+    private IpSecTransform buildTransportModeTransform(
+            SecurityParameterIndex spi, InetAddress localAddr,
+            UdpEncapsulationSocket encapSocket)
+            throws Exception {
+        final IpSecTransform.Builder builder =
+                new IpSecTransform.Builder(InstrumentationRegistry.getContext())
+                        .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
+                        .setAuthentication(
+                                new IpSecAlgorithm(
+                                        IpSecAlgorithm.AUTH_HMAC_SHA256,
+                                        AUTH_KEY,
+                                        AUTH_KEY.length * 8));
+        if (encapSocket != null) {
+            builder.setIpv4Encapsulation(encapSocket, encapSocket.getPort());
+        }
+        return builder.buildTransportModeTransform(localAddr, spi);
+    }
+
     /*
      * Alloc outbound SPI
      * Alloc inbound SPI
@@ -268,21 +292,8 @@
      * release transform
      * send data (expect exception)
      */
-    @Test
-    public void testCreateTransform() throws Exception {
-        InetAddress localAddr = InetAddress.getByName(IPV4_LOOPBACK);
-        IpSecManager.SecurityParameterIndex spi =
-                mISM.allocateSecurityParameterIndex(localAddr);
-
-        IpSecTransform transform =
-                new IpSecTransform.Builder(InstrumentationRegistry.getContext())
-                        .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
-                        .setAuthentication(
-                                new IpSecAlgorithm(
-                                        IpSecAlgorithm.AUTH_HMAC_SHA256,
-                                        AUTH_KEY,
-                                        AUTH_KEY.length * 8))
-                        .buildTransportModeTransform(localAddr, spi);
+    private void doTestCreateTransform(String loopbackAddrString, boolean encap) throws Exception {
+        InetAddress localAddr = InetAddress.getByName(loopbackAddrString);
 
         final boolean [][] applyInApplyOut = {
                 {false, false}, {false, true}, {true, false}, {true,true}};
@@ -291,50 +302,93 @@
 
         byte[] in = new byte[data.length];
         DatagramPacket inPacket = new DatagramPacket(in, in.length);
-        DatagramSocket localSocket;
         int localPort;
 
         for(boolean[] io : applyInApplyOut) {
             boolean applyIn = io[0];
             boolean applyOut = io[1];
-            // Bind localSocket to a random available port.
-            localSocket = new DatagramSocket(0);
-            localPort = localSocket.getLocalPort();
-            localSocket.setSoTimeout(200);
-            outPacket.setPort(localPort);
-            if (applyIn) {
-                mISM.applyTransportModeTransform(
-                        localSocket, IpSecManager.DIRECTION_IN, transform);
-            }
-            if (applyOut) {
-                mISM.applyTransportModeTransform(
-                        localSocket, IpSecManager.DIRECTION_OUT, transform);
-            }
-            if (applyIn == applyOut) {
-                localSocket.send(outPacket);
-                localSocket.receive(inPacket);
-                assertTrue("Encapsulated data did not match.",
-                        Arrays.equals(outPacket.getData(), inPacket.getData()));
-                mISM.removeTransportModeTransforms(localSocket);
-                localSocket.close();
-            } else {
-                try {
+            try (
+                SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(localAddr);
+                UdpEncapsulationSocket encapSocket = encap
+                        ? getPrivilegedUdpEncapSocket(/*ipv6=*/ localAddr instanceof Inet6Address)
+                        : null;
+                IpSecTransform transform = buildTransportModeTransform(spi, localAddr,
+                        encapSocket);
+                // Bind localSocket to a random available port.
+                DatagramSocket localSocket = new DatagramSocket(0);
+            ) {
+                localPort = localSocket.getLocalPort();
+                localSocket.setSoTimeout(200);
+                outPacket.setPort(localPort);
+                if (applyIn) {
+                    mISM.applyTransportModeTransform(
+                            localSocket, IpSecManager.DIRECTION_IN, transform);
+                }
+                if (applyOut) {
+                    mISM.applyTransportModeTransform(
+                            localSocket, IpSecManager.DIRECTION_OUT, transform);
+                }
+                if (applyIn == applyOut) {
                     localSocket.send(outPacket);
                     localSocket.receive(inPacket);
-                } catch (IOException e) {
-                    continue;
-                } finally {
+                    assertTrue("Encrypted data did not match.",
+                            Arrays.equals(outPacket.getData(), inPacket.getData()));
                     mISM.removeTransportModeTransforms(localSocket);
-                    localSocket.close();
+                } else {
+                    try {
+                        localSocket.send(outPacket);
+                        localSocket.receive(inPacket);
+                    } catch (IOException e) {
+                        continue;
+                    } finally {
+                        mISM.removeTransportModeTransforms(localSocket);
+                    }
+                    // FIXME: This check is disabled because sockets currently receive data
+                    // if there is a valid SA for decryption, even when the input policy is
+                    // not applied to a socket.
+                    //  fail("Data IO should fail on asymmetrical transforms! + Input="
+                    //          + applyIn + " Output=" + applyOut);
                 }
-                // FIXME: This check is disabled because sockets currently receive data
-                // if there is a valid SA for decryption, even when the input policy is
-                // not applied to a socket.
-                //  fail("Data IO should fail on asymmetrical transforms! + Input="
-                //          + applyIn + " Output=" + applyOut);
             }
         }
-        transform.close();
+    }
+
+    private UdpEncapsulationSocket getPrivilegedUdpEncapSocket(boolean ipv6) throws Exception {
+        return runAsShell(NETWORK_SETTINGS, () -> {
+            if (ipv6) {
+                return mISM.openUdpEncapsulationSocket(65536);
+            } else {
+                // Can't pass 0 to IpSecManager#openUdpEncapsulationSocket(int).
+                return mISM.openUdpEncapsulationSocket();
+            }
+        });
+    }
+
+    private void assumeExperimentalIpv6UdpEncapSupported() throws Exception {
+        assumeTrue("Not supported before U", SdkLevel.isAtLeastU());
+        assumeTrue("Not supported by kernel", isKernelVersionAtLeast("5.15.31")
+                || (isKernelVersionAtLeast("5.10.108") && !isKernelVersionAtLeast("5.15.0")));
+    }
+
+    @Test
+    public void testCreateTransformIpv4() throws Exception {
+        doTestCreateTransform(IPV4_LOOPBACK, false);
+    }
+
+    @Test
+    public void testCreateTransformIpv6() throws Exception {
+        doTestCreateTransform(IPV6_LOOPBACK, false);
+    }
+
+    @Test
+    public void testCreateTransformIpv4Encap() throws Exception {
+        doTestCreateTransform(IPV4_LOOPBACK, true);
+    }
+
+    @Test
+    public void testCreateTransformIpv6Encap() throws Exception {
+        assumeExperimentalIpv6UdpEncapSupported();
+        doTestCreateTransform(IPV6_LOOPBACK, true);
     }
 
     /** Snapshot of TrafficStats as of initStatsChecker call for later comparisons */
@@ -503,8 +557,8 @@
         StatsChecker.initStatsChecker();
         InetAddress local = InetAddress.getByName(localAddress);
 
-        try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket();
-                IpSecManager.SecurityParameterIndex spi =
+        try (UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket();
+                SecurityParameterIndex spi =
                         mISM.allocateSecurityParameterIndex(local)) {
 
             IpSecTransform.Builder transformBuilder =
@@ -656,7 +710,7 @@
     public void testIkeOverUdpEncapSocket() throws Exception {
         // IPv6 not supported for UDP-encap-ESP
         InetAddress local = InetAddress.getByName(IPV4_LOOPBACK);
-        try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
+        try (UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
             NativeUdpSocket wrappedEncapSocket =
                     new NativeUdpSocket(encapSocket.getFileDescriptor());
             checkIkePacket(wrappedEncapSocket, local);
@@ -665,7 +719,7 @@
             IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
             IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
 
-            try (IpSecManager.SecurityParameterIndex spi =
+            try (SecurityParameterIndex spi =
                             mISM.allocateSecurityParameterIndex(local);
                     IpSecTransform transform =
                             new IpSecTransform.Builder(InstrumentationRegistry.getContext())
@@ -1498,7 +1552,7 @@
 
     @Test
     public void testOpenUdpEncapSocketSpecificPort() throws Exception {
-        IpSecManager.UdpEncapsulationSocket encapSocket = null;
+        UdpEncapsulationSocket encapSocket = null;
         int port = -1;
         for (int i = 0; i < MAX_PORT_BIND_ATTEMPTS; i++) {
             try {
@@ -1527,7 +1581,7 @@
 
     @Test
     public void testOpenUdpEncapSocketRandomPort() throws Exception {
-        try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
+        try (UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
             assertTrue("Returned invalid port", encapSocket.getPort() != 0);
         }
     }
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 7ae4688..f578ff3 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -506,9 +506,7 @@
         val lp = LinkProperties(agent.lp)
         lp.setInterfaceName(ifaceName)
         agent.sendLinkProperties(lp)
-        callback.expectLinkPropertiesThat(agent.network!!) {
-            it.getInterfaceName() == ifaceName
-        }
+        callback.expect<LinkPropertiesChanged>(agent.network!!) { it.lp.interfaceName == ifaceName }
         val nc = NetworkCapabilities(agent.nc)
         nc.addCapability(NET_CAPABILITY_NOT_METERED)
         agent.sendNetworkCapabilities(nc)
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index 9b27df5..562e2c6 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -20,6 +20,8 @@
 import android.net.ConnectivityManager
 import android.net.ConnectivityManager.NetworkCallback
 import android.net.LinkProperties
+import android.net.LocalSocket
+import android.net.LocalSocketAddress
 import android.net.Network
 import android.net.NetworkAgentConfig
 import android.net.NetworkCapabilities
@@ -30,6 +32,7 @@
 import android.net.TestNetworkInterface
 import android.net.TestNetworkManager
 import android.net.TestNetworkSpecifier
+import android.net.connectivity.ConnectivityCompatChanges
 import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStarted
 import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStopped
 import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.ServiceFound
@@ -40,8 +43,8 @@
 import android.net.cts.NsdManagerTest.NsdRegistrationRecord.RegistrationEvent.ServiceRegistered
 import android.net.cts.NsdManagerTest.NsdRegistrationRecord.RegistrationEvent.ServiceUnregistered
 import android.net.cts.NsdManagerTest.NsdRegistrationRecord.RegistrationEvent.UnregistrationFailed
-import android.net.cts.NsdManagerTest.NsdResolveRecord.ResolveEvent.ResolveFailed
 import android.net.cts.NsdManagerTest.NsdResolveRecord.ResolveEvent.ResolutionStopped
+import android.net.cts.NsdManagerTest.NsdResolveRecord.ResolveEvent.ResolveFailed
 import android.net.cts.NsdManagerTest.NsdResolveRecord.ResolveEvent.ServiceResolved
 import android.net.cts.NsdManagerTest.NsdResolveRecord.ResolveEvent.StopResolutionFailed
 import android.net.cts.NsdManagerTest.NsdServiceInfoCallbackRecord.ServiceInfoCallbackEvent.RegisterCallbackFailed
@@ -62,6 +65,7 @@
 import android.util.Log
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.runner.AndroidJUnit4
+import com.android.compatibility.common.util.PollingCheck
 import com.android.net.module.util.ArrayTrackRecord
 import com.android.net.module.util.TrackRecord
 import com.android.networkstack.apishim.NsdShimImpl
@@ -71,10 +75,12 @@
 import com.android.testutils.TestableNetworkAgent
 import com.android.testutils.TestableNetworkCallback
 import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk30
+import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk33
 import com.android.testutils.runAsShell
 import com.android.testutils.tryTest
 import com.android.testutils.waitForIdle
 import java.io.File
+import java.io.IOException
 import java.net.ServerSocket
 import java.nio.charset.StandardCharsets
 import java.util.Random
@@ -762,6 +768,65 @@
         }
     }
 
+    private fun checkConnectSocketToMdnsd(shouldFail: Boolean) {
+        val discoveryRecord = NsdDiscoveryRecord()
+        val localSocket = LocalSocket()
+        tryTest {
+            // Discover any service from NsdManager to enforce NsdService to start the mdnsd.
+            nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord)
+            discoveryRecord.expectCallback<DiscoveryStarted>()
+
+            // Checks the /dev/socket/mdnsd is created.
+            val socket = File("/dev/socket/mdnsd")
+            val doesSocketExist = PollingCheck.waitFor(
+                TIMEOUT_MS,
+                {
+                    socket.exists()
+                },
+                { isSocketExist ->
+                    isSocketExist
+                },
+            )
+
+            // If the socket is not created, then no need to check the access.
+            if (doesSocketExist) {
+                // Create a LocalSocket and try to connect to mdnsd.
+                assertFalse("LocalSocket is connected.", localSocket.isConnected)
+                val address = LocalSocketAddress("mdnsd", LocalSocketAddress.Namespace.RESERVED)
+                if (shouldFail) {
+                    assertFailsWith<IOException>("Expect fail but socket connected") {
+                        localSocket.connect(address)
+                    }
+                } else {
+                    localSocket.connect(address)
+                    assertTrue("LocalSocket is not connected.", localSocket.isConnected)
+                }
+            }
+        } cleanup {
+            localSocket.close()
+            nsdManager.stopServiceDiscovery(discoveryRecord)
+            discoveryRecord.expectCallback<DiscoveryStopped>()
+        }
+    }
+
+    /**
+     * Starting from Android U, the access to the /dev/socket/mdnsd is blocked by the
+     * sepolicy(b/265364111).
+     */
+    @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
+    @Test
+    fun testCannotConnectSocketToMdnsd() {
+        val targetSdkVersion = context.packageManager
+                .getTargetSdkVersion(context.applicationInfo.packageName)
+        assumeTrue(targetSdkVersion > Build.VERSION_CODES.TIRAMISU)
+        checkConnectSocketToMdnsd(shouldFail = true)
+    }
+
+    @Test @CtsNetTestCasesMaxTargetSdk33("mdnsd socket is accessible up to target SDK 33")
+    fun testCanConnectSocketToMdnsd() {
+        checkConnectSocketToMdnsd(shouldFail = false)
+    }
+
     @Test @CtsNetTestCasesMaxTargetSdk30("Socket is started with the service up to target SDK 30")
     fun testManagerCreatesLegacySocket() {
         nsdManager // Ensure the lazy-init member is initialized, so NsdManager is created
@@ -783,7 +848,7 @@
         // when the compat change is disabled.
         // Note that before T the compat constant had a different int value.
         assertFalse(CompatChanges.isChangeEnabled(
-                NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER))
+                ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER))
     }
 
     @Test
diff --git a/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 26b058d..3c1340d 100644
--- a/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -37,7 +37,6 @@
 import android.net.TestNetworkStackClient
 import android.net.Uri
 import android.net.metrics.IpConnectivityLog
-import com.android.server.connectivity.MultinetworkPolicyTracker
 import android.os.ConditionVariable
 import android.os.IBinder
 import android.os.SystemConfigManager
@@ -52,7 +51,9 @@
 import com.android.server.NetworkAgentWrapper
 import com.android.server.TestNetIdManager
 import com.android.server.connectivity.MockableSystemProperties
+import com.android.server.connectivity.MultinetworkPolicyTracker
 import com.android.server.connectivity.ProxyTracker
+import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
 import com.android.testutils.TestableNetworkCallback
 import org.junit.After
 import org.junit.Before
@@ -73,8 +74,6 @@
 import org.mockito.MockitoAnnotations
 import org.mockito.Spy
 import kotlin.test.assertEquals
-import kotlin.test.assertFalse
-import kotlin.test.assertNotNull
 import kotlin.test.assertTrue
 import kotlin.test.fail
 
@@ -289,15 +288,16 @@
 
         testCb.expectAvailableCallbacks(na.network, validated = false, tmt = TEST_TIMEOUT_MS)
 
-        val capportData = testCb.expectLinkPropertiesThat(na, TEST_TIMEOUT_MS) {
-            it.captivePortalData != null
+        val capportData = testCb.expect<LinkPropertiesChanged>(na, TEST_TIMEOUT_MS) {
+            it.lp.captivePortalData != null
         }.lp.captivePortalData
-        assertNotNull(capportData)
         assertTrue(capportData.isCaptive)
         assertEquals(Uri.parse("https://login.capport.android.com"), capportData.userPortalUrl)
         assertEquals(Uri.parse("https://venueinfo.capport.android.com"), capportData.venueInfoUrl)
 
-        val nc = testCb.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, na, TEST_TIMEOUT_MS)
-        assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED))
+        testCb.expectCaps(na, TEST_TIMEOUT_MS) {
+            it.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) &&
+                    !it.hasCapability(NET_CAPABILITY_VALIDATED)
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 8db307d..36b3356 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -69,6 +69,7 @@
         "java/com/android/server/VpnManagerServiceTest.java",
         "java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java",
         "java/com/android/server/connectivity/IpConnectivityMetricsTest.java",
+        "java/com/android/server/connectivity/MetricsTestUtil.java",
         "java/com/android/server/connectivity/MultipathPolicyTrackerTest.java",
         "java/com/android/server/connectivity/NetdEventListenerServiceTest.java",
         "java/com/android/server/connectivity/VpnTest.java",
@@ -136,6 +137,37 @@
     visibility: ["//packages/modules/Connectivity/tests:__subpackages__"],
 }
 
+genrule {
+    name: "frameworks-net-tests-jarjar-rules",
+    defaults: ["jarjar-rules-combine-defaults"],
+    srcs: [
+        ":frameworks-net-tests-lib-jarjar-gen",
+        // This is necessary because the tests use framework-connectivity-internal-test-defaults,
+        // which require the user to use connectivity jarjar rules.
+        ":connectivity-jarjar-rules",
+    ],
+    out: ["frameworks-net-tests-jarjar-rules.txt"],
+    visibility: ["//packages/modules/Connectivity/tests:__subpackages__"],
+}
+
+java_genrule {
+    name: "frameworks-net-tests-lib-jarjar-gen",
+    tool_files: [
+        ":FrameworksNetTestsLib{.jar}",
+        "jarjar-excludes.txt",
+    ],
+    tools: [
+        "jarjar-rules-generator",
+    ],
+    out: ["frameworks-net-tests-lib-jarjar-rules.txt"],
+    cmd: "$(location jarjar-rules-generator) " +
+        "$(location :FrameworksNetTestsLib{.jar}) " +
+        "--prefix android.net.connectivity " +
+        "--excludes $(location jarjar-excludes.txt) " +
+        "--output $(out)",
+    visibility: ["//visibility:private"],
+}
+
 android_test {
     name: "FrameworksNetTests",
     enabled: enable_frameworks_net_tests,
@@ -143,7 +175,7 @@
         "FrameworksNetTestsDefaults",
         "FrameworksNetTests-jni-defaults",
     ],
-    jarjar_rules: ":connectivity-jarjar-rules",
+    jarjar_rules: ":frameworks-net-tests-jarjar-rules",
     test_suites: ["device-tests"],
     static_libs: [
         "services.core",
diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml
index 5bac2dd..5d4bdf7 100644
--- a/tests/unit/AndroidManifest.xml
+++ b/tests/unit/AndroidManifest.xml
@@ -63,7 +63,7 @@
         <uses-library android:name="android.test.runner" />
         <uses-library android:name="android.net.ipsec.ike" />
         <activity
-            android:name="com.android.server.connectivity.NetworkNotificationManagerTest$TestDialogActivity"/>
+            android:name="android.net.connectivity.com.android.server.connectivity.NetworkNotificationManagerTest$TestDialogActivity"/>
     </application>
 
     <instrumentation
diff --git a/tests/unit/jarjar-excludes.txt b/tests/unit/jarjar-excludes.txt
new file mode 100644
index 0000000..d2022bf
--- /dev/null
+++ b/tests/unit/jarjar-excludes.txt
@@ -0,0 +1,27 @@
+# Exclude some test prefixes, otherwise the classes reference below can't find
+# them after jarjared.
+android\.compat\..+
+androidx\.test\..+
+com\.android\.frameworks\.tests\..+
+com\.android\.testutils\..+
+com\.android\.dx\.mockito\..+
+com\.android\.internal\.compat\..+
+com\.android\.internal\.org\.bouncycastle\..+
+kotlin\.test\..+
+kotlin\.reflect\..+
+org\.junit\..+
+org\.mockito\..+
+
+# Auto-jarjar-gen can't handle kotlin object expression, exclude the tests which use
+# object expressions.
+#
+# For example: Illegal class access:
+# 'android.net.connectivity.com.android.net.module.util.TrackRecordTest' attempting to access
+# 'com.android.networkstack.tethering.util.TRTInterpreter' (declaration of
+# 'android.net.connectivity.com.android.net.module.util.TrackRecordTest' ...
+#
+# In coverage test, TRTInterpreter don't be jarjar'ed to
+# android.net.connectivity* by frameworks-net-tests-jarjar-rules instead it is
+# jarjar'ed by follow up TetheringTestsJarJarRules.
+# TODO(b/269259216): remove this after fixing Auto-jarjar-gen.
+com\.android\.net\.module\.util\.TrackRecord.*
diff --git a/tests/unit/java/android/net/Ikev2VpnProfileTest.java b/tests/unit/java/android/net/Ikev2VpnProfileTest.java
index 3b68120..e12e961 100644
--- a/tests/unit/java/android/net/Ikev2VpnProfileTest.java
+++ b/tests/unit/java/android/net/Ikev2VpnProfileTest.java
@@ -492,6 +492,29 @@
     }
 
     @Test
+    public void testAutomaticNattAndIpVersionConversionIsLossless() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+        builder.setAutomaticNattKeepaliveTimerEnabled(true);
+        builder.setAutomaticIpVersionSelectionEnabled(true);
+
+        builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+        final Ikev2VpnProfile ikeProfile = builder.build();
+
+        assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
+    }
+
+    @Test
+    public void testAutomaticNattAndIpVersionDefaults() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+        final Ikev2VpnProfile ikeProfile = builder.build();
+
+        assertEquals(false, ikeProfile.isAutomaticNattKeepaliveTimerEnabled());
+        assertEquals(false, ikeProfile.isAutomaticIpVersionSelectionEnabled());
+    }
+
+    @Test
     public void testEquals() throws Exception {
         // Verify building without IkeTunnelConnectionParams
         final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
diff --git a/tests/unit/java/android/net/NetworkTemplateTest.kt b/tests/unit/java/android/net/NetworkTemplateTest.kt
index 78854fb..edbcea9 100644
--- a/tests/unit/java/android/net/NetworkTemplateTest.kt
+++ b/tests/unit/java/android/net/NetworkTemplateTest.kt
@@ -443,6 +443,35 @@
     }
 
     @Test
+    fun testEquals() {
+        val templateImsi1 = NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES)
+                .setSubscriberIds(setOf(TEST_IMSI1)).setRatType(TelephonyManager.NETWORK_TYPE_UMTS)
+                .build()
+        val dupTemplateImsi1 = NetworkTemplate(MATCH_MOBILE, arrayOf(TEST_IMSI1),
+                emptyArray<String>(), METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+                TelephonyManager.NETWORK_TYPE_UMTS, OEM_MANAGED_ALL)
+        val templateImsi2 = NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES)
+                .setSubscriberIds(setOf(TEST_IMSI2)).setRatType(TelephonyManager.NETWORK_TYPE_UMTS)
+                .build()
+
+        assertEquals(templateImsi1, dupTemplateImsi1)
+        assertEquals(dupTemplateImsi1, templateImsi1)
+        assertNotEquals(templateImsi1, templateImsi2)
+
+        val templateWifiKey1 = NetworkTemplate.Builder(MATCH_WIFI)
+                .setWifiNetworkKeys(setOf(TEST_WIFI_KEY1)).build()
+        val dupTemplateWifiKey1 = NetworkTemplate(MATCH_WIFI, emptyArray<String>(),
+                arrayOf(TEST_WIFI_KEY1), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+                NETWORK_TYPE_ALL, OEM_MANAGED_ALL)
+        val templateWifiKey2 = NetworkTemplate.Builder(MATCH_WIFI)
+                .setWifiNetworkKeys(setOf(TEST_WIFI_KEY2)).build()
+
+        assertEquals(templateWifiKey1, dupTemplateWifiKey1)
+        assertEquals(dupTemplateWifiKey1, templateWifiKey1)
+        assertNotEquals(templateWifiKey1, templateWifiKey2)
+    }
+
+    @Test
     fun testParcelUnparcel() {
         val templateMobile = NetworkTemplate(MATCH_MOBILE, arrayOf(TEST_IMSI1),
                 emptyArray<String>(), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
diff --git a/tests/unit/java/android/net/nsd/NsdManagerTest.java b/tests/unit/java/android/net/nsd/NsdManagerTest.java
index 8a4932b..da65b62 100644
--- a/tests/unit/java/android/net/nsd/NsdManagerTest.java
+++ b/tests/unit/java/android/net/nsd/NsdManagerTest.java
@@ -32,6 +32,7 @@
 
 import android.compat.testing.PlatformCompatChangeRule;
 import android.content.Context;
+import android.net.connectivity.ConnectivityCompatChanges;
 import android.os.Build;
 
 import androidx.test.filters.SmallTest;
@@ -81,70 +82,70 @@
     }
 
     @Test
-    @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testResolveServiceS() throws Exception {
         verify(mServiceConn, never()).startDaemon();
         doTestResolveService();
     }
 
     @Test
-    @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testResolveServicePreS() throws Exception {
         verify(mServiceConn).startDaemon();
         doTestResolveService();
     }
 
     @Test
-    @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testDiscoverServiceS() throws Exception {
         verify(mServiceConn, never()).startDaemon();
         doTestDiscoverService();
     }
 
     @Test
-    @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testDiscoverServicePreS() throws Exception {
         verify(mServiceConn).startDaemon();
         doTestDiscoverService();
     }
 
     @Test
-    @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testParallelResolveServiceS() throws Exception {
         verify(mServiceConn, never()).startDaemon();
         doTestParallelResolveService();
     }
 
     @Test
-    @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testParallelResolveServicePreS() throws Exception {
         verify(mServiceConn).startDaemon();
         doTestParallelResolveService();
     }
 
     @Test
-    @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testInvalidCallsS() throws Exception {
         verify(mServiceConn, never()).startDaemon();
         doTestInvalidCalls();
     }
 
     @Test
-    @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testInvalidCallsPreS() throws Exception {
         verify(mServiceConn).startDaemon();
         doTestInvalidCalls();
     }
 
     @Test
-    @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testRegisterServiceS() throws Exception {
         verify(mServiceConn, never()).startDaemon();
         doTestRegisterService();
     }
 
     @Test
-    @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testRegisterServicePreS() throws Exception {
         verify(mServiceConn).startDaemon();
         doTestRegisterService();
diff --git a/tests/unit/java/com/android/internal/net/VpnProfileTest.java b/tests/unit/java/com/android/internal/net/VpnProfileTest.java
index 0a6d2f2..b2dff2e 100644
--- a/tests/unit/java/com/android/internal/net/VpnProfileTest.java
+++ b/tests/unit/java/com/android/internal/net/VpnProfileTest.java
@@ -20,6 +20,7 @@
 import static android.net.cts.util.IkeSessionTestUtils.IKE_PARAMS_V4;
 
 import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
 import static com.android.testutils.ParcelUtils.assertParcelSane;
 
 import static org.junit.Assert.assertEquals;
@@ -55,6 +56,9 @@
     private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
     private static final int ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE = 25;
     private static final int ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION = 26;
+    private static final int ENCODED_INDEX_IKE_TUN_CONN_PARAMS = 27;
+    private static final int ENCODED_INDEX_AUTOMATIC_NATT_KEEPALIVE_TIMER_ENABLED = 28;
+    private static final int ENCODED_INDEX_AUTOMATIC_IP_VERSION_SELECTION_ENABLED = 29;
 
     @Test
     public void testDefaults() throws Exception {
@@ -85,12 +89,15 @@
         assertFalse(p.isRestrictedToTestNetworks);
         assertFalse(p.excludeLocalRoutes);
         assertFalse(p.requiresInternetValidation);
+        assertFalse(p.automaticNattKeepaliveTimerEnabled);
+        assertFalse(p.automaticIpVersionSelectionEnabled);
     }
 
     private VpnProfile getSampleIkev2Profile(String key) {
         final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */,
                 false /* excludesLocalRoutes */, true /* requiresPlatformValidation */,
-                null /* ikeTunConnParams */);
+                null /* ikeTunConnParams */, true /* mAutomaticNattKeepaliveTimerEnabled */,
+                true /* automaticIpVersionSelectionEnabled */);
 
         p.name = "foo";
         p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
@@ -128,7 +135,9 @@
     private VpnProfile getSampleIkev2ProfileWithIkeTunConnParams(String key) {
         final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */,
                 false /* excludesLocalRoutes */, true /* requiresPlatformValidation */,
-                new IkeTunnelConnectionParams(IKE_PARAMS_V4, CHILD_PARAMS));
+                new IkeTunnelConnectionParams(IKE_PARAMS_V4, CHILD_PARAMS),
+                true /* mAutomaticNattKeepaliveTimerEnabled */,
+                true /* automaticIpVersionSelectionEnabled */);
 
         p.name = "foo";
         p.server = "bar";
@@ -166,7 +175,11 @@
 
     @Test
     public void testParcelUnparcel() {
-        if (isAtLeastT()) {
+        if (isAtLeastU()) {
+            // automaticNattKeepaliveTimerEnabled, automaticIpVersionSelectionEnabled added in U.
+            assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 28);
+            assertParcelSane(getSampleIkev2ProfileWithIkeTunConnParams(DUMMY_PROFILE_KEY), 28);
+        } else if (isAtLeastT()) {
             // excludeLocalRoutes, requiresPlatformValidation were added in T.
             assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 26);
             assertParcelSane(getSampleIkev2ProfileWithIkeTunConnParams(DUMMY_PROFILE_KEY), 26);
@@ -221,16 +234,28 @@
                         ENCODED_INDEX_AUTH_PARAMS_INLINE,
                         ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS,
                         ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE,
-                        ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */);
+                        ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION,
+                        ENCODED_INDEX_IKE_TUN_CONN_PARAMS,
+                        ENCODED_INDEX_AUTOMATIC_NATT_KEEPALIVE_TIMER_ENABLED,
+                        ENCODED_INDEX_AUTOMATIC_IP_VERSION_SELECTION_ENABLED
+                        /* missingIndices */);
 
         assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
     }
 
+    private String getEncodedDecodedIkev2ProfileWithtooFewValues() {
+        return getEncodedDecodedIkev2ProfileMissingValues(
+                ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS,
+                ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE,
+                ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION,
+                ENCODED_INDEX_IKE_TUN_CONN_PARAMS,
+                ENCODED_INDEX_AUTOMATIC_NATT_KEEPALIVE_TIMER_ENABLED,
+                ENCODED_INDEX_AUTOMATIC_IP_VERSION_SELECTION_ENABLED /* missingIndices */);
+    }
+
     @Test
     public void testEncodeDecodeMissingIsRestrictedToTestNetworks() {
-        final String tooFewValues =
-                getEncodedDecodedIkev2ProfileMissingValues(
-                        ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
+        final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues();
 
         // Verify decoding without isRestrictedToTestNetworks defaults to false
         final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
@@ -239,10 +264,7 @@
 
     @Test
     public void testEncodeDecodeMissingExcludeLocalRoutes() {
-        final String tooFewValues =
-                getEncodedDecodedIkev2ProfileMissingValues(
-                        ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE,
-                        ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */);
+        final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues();
 
         // Verify decoding without excludeLocalRoutes defaults to false
         final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
@@ -251,9 +273,7 @@
 
     @Test
     public void testEncodeDecodeMissingRequiresValidation() {
-        final String tooFewValues =
-                getEncodedDecodedIkev2ProfileMissingValues(
-                        ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */);
+        final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues();
 
         // Verify decoding without requiresValidation defaults to false
         final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
@@ -261,6 +281,24 @@
     }
 
     @Test
+    public void testEncodeDecodeMissingAutomaticNattKeepaliveTimerEnabled() {
+        final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues();
+
+        // Verify decoding without automaticNattKeepaliveTimerEnabled defaults to false
+        final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
+        assertFalse(decoded.automaticNattKeepaliveTimerEnabled);
+    }
+
+    @Test
+    public void testEncodeDecodeMissingAutomaticIpVersionSelectionEnabled() {
+        final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues();
+
+        // Verify decoding without automaticIpVersionSelectionEnabled defaults to false
+        final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
+        assertFalse(decoded.automaticIpVersionSelectionEnabled);
+    }
+
+    @Test
     public void testEncodeDecodeLoginsNotSaved() {
         final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
         profile.saveLogin = false;
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index bd6920a..ea50999 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -27,6 +27,7 @@
 import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
 import static android.Manifest.permission.NETWORK_FACTORY;
 import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.Manifest.permission.NETWORK_SETUP_WIZARD;
 import static android.Manifest.permission.NETWORK_STACK;
 import static android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
@@ -172,6 +173,7 @@
 import static com.android.testutils.MiscAsserts.assertThrows;
 import static com.android.testutils.RecorderCallback.CallbackEntry.AVAILABLE;
 import static com.android.testutils.RecorderCallback.CallbackEntry.BLOCKED_STATUS;
+import static com.android.testutils.RecorderCallback.CallbackEntry.BLOCKED_STATUS_INT;
 import static com.android.testutils.RecorderCallback.CallbackEntry.LINK_PROPERTIES_CHANGED;
 import static com.android.testutils.RecorderCallback.CallbackEntry.LOSING;
 import static com.android.testutils.RecorderCallback.CallbackEntry.LOST;
@@ -377,6 +379,7 @@
 import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
 import com.android.server.ConnectivityService.NetworkRequestInfo;
 import com.android.server.ConnectivityServiceTest.ConnectivityServiceDependencies.ReportedInterfaces;
+import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker;
 import com.android.server.connectivity.CarrierPrivilegeAuthenticator;
 import com.android.server.connectivity.ClatCoordinator;
 import com.android.server.connectivity.ConnectivityFlags;
@@ -538,6 +541,7 @@
     private MockContext mServiceContext;
     private HandlerThread mCsHandlerThread;
     private ConnectivityServiceDependencies mDeps;
+    private AutomaticOnOffKeepaliveTrackerDependencies mAutoOnOffKeepaliveDependencies;
     private ConnectivityService mService;
     private WrappedConnectivityManager mCm;
     private TestNetworkAgentWrapper mWiFiAgent;
@@ -1838,7 +1842,8 @@
         doReturn(mResources).when(mockResContext).getResources();
         ConnectivityResources.setResourcesContextForTest(mockResContext);
         mDeps = new ConnectivityServiceDependencies(mockResContext);
-
+        mAutoOnOffKeepaliveDependencies =
+                new AutomaticOnOffKeepaliveTrackerDependencies(mServiceContext);
         mService = new ConnectivityService(mServiceContext,
                 mMockDnsResolver,
                 mock(IpConnectivityLog.class),
@@ -1939,6 +1944,12 @@
         }
 
         @Override
+        public AutomaticOnOffKeepaliveTracker makeAutomaticOnOffKeepaliveTracker(final Context c,
+                final Handler h) {
+            return new AutomaticOnOffKeepaliveTracker(c, h, mAutoOnOffKeepaliveDependencies);
+        }
+
+        @Override
         public ConnectivityResources getResources(final Context ctx) {
             return mConnRes;
         }
@@ -2096,6 +2107,20 @@
         }
     }
 
+    private class AutomaticOnOffKeepaliveTrackerDependencies
+            extends AutomaticOnOffKeepaliveTracker.Dependencies {
+        AutomaticOnOffKeepaliveTrackerDependencies(Context context) {
+            super(context);
+        }
+
+        @Override
+        public boolean isFeatureEnabled(@NonNull final String name) {
+            // Tests for enabling the feature are verified in AutomaticOnOffKeepaliveTrackerTest.
+            // Assuming enabled here to focus on ConnectivityService tests.
+            return true;
+        }
+    }
+
     private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) {
         doAnswer(inv -> {
             final long when = inv.getArgument(1);
@@ -2765,7 +2790,7 @@
         if (expectLingering) {
             generalCb.expectLosing(net1);
         }
-        generalCb.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, net2);
+        generalCb.expectCaps(net2, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         defaultCb.expectAvailableDoubleValidatedCallbacks(net2);
 
         // Make sure cell 1 is unwanted immediately if the radio can't time share, but only
@@ -3181,7 +3206,8 @@
         mWiFiAgent.connect(true);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         genericNetworkCallback.expectLosing(mCellAgent);
-        genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        genericNetworkCallback.expectCaps(mWiFiAgent,
+                c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent);
         cellNetworkCallback.expectLosing(mCellAgent);
         assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork());
@@ -3222,17 +3248,17 @@
         final Uri expectedCapportUrl = sanitized ? null : capportUrl;
         newLp.setCaptivePortalApiUrl(capportUrl);
         mWiFiAgent.sendLinkProperties(newLp);
-        callback.expectLinkPropertiesThat(mWiFiAgent, lp ->
-                Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
-        defaultCallback.expectLinkPropertiesThat(mWiFiAgent, lp ->
-                Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
+        callback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, cb ->
+                Objects.equals(expectedCapportUrl, cb.getLp().getCaptivePortalApiUrl()));
+        defaultCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, cb ->
+                Objects.equals(expectedCapportUrl, cb.getLp().getCaptivePortalApiUrl()));
 
         final CaptivePortalData expectedCapportData = sanitized ? null : capportData;
         mWiFiAgent.notifyCapportApiDataChanged(capportData);
-        callback.expectLinkPropertiesThat(mWiFiAgent, lp ->
-                Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
-        defaultCallback.expectLinkPropertiesThat(mWiFiAgent, lp ->
-                Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
+        callback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, cb ->
+                Objects.equals(expectedCapportData, cb.getLp().getCaptivePortalData()));
+        defaultCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, cb ->
+                Objects.equals(expectedCapportData, cb.getLp().getCaptivePortalData()));
 
         final LinkProperties lp = mCm.getLinkProperties(mWiFiAgent.getNetwork());
         assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl());
@@ -3330,7 +3356,7 @@
         callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         // TODO: Investigate sending validated before losing.
         callback.expectLosing(mCellAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent);
         assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork());
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -3339,7 +3365,7 @@
         callback.expectAvailableCallbacksUnvalidated(mEthernetAgent);
         // TODO: Investigate sending validated before losing.
         callback.expectLosing(mWiFiAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetAgent);
+        callback.expectCaps(mEthernetAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetAgent);
         assertEquals(mEthernetAgent.getNetwork(), mCm.getActiveNetwork());
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -3374,7 +3400,7 @@
         // if the network is still up.
         mWiFiAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
         // We expect a notification about the capabilities change, and nothing else.
-        defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiAgent);
+        defaultCallback.expectCaps(mWiFiAgent, c -> !c.hasCapability(NET_CAPABILITY_NOT_METERED));
         defaultCallback.assertNoCallback();
         callback.expect(LOST, mWiFiAgent);
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -3433,7 +3459,7 @@
         callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         // TODO: Investigate sending validated before losing.
         callback.expectLosing(mCellAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent);
         assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork());
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -3460,7 +3486,7 @@
         callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         // TODO: Investigate sending validated before losing.
         callback.expectLosing(mCellAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         NetworkRequest cellRequest = new NetworkRequest.Builder()
@@ -3510,7 +3536,7 @@
         mEthernetAgent.connect(true);
         callback.expectAvailableCallbacksUnvalidated(mEthernetAgent);
         callback.expectLosing(mWiFiAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetAgent);
+        callback.expectCaps(mEthernetAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetAgent);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetAgent);
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -3570,7 +3596,7 @@
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent);
         callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         callback.expectLosing(mCellAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
 
         // File a request for cellular, then release it.
         NetworkRequest cellRequest = new NetworkRequest.Builder()
@@ -3583,7 +3609,8 @@
         // Let linger run its course.
         callback.assertNoCallback();
         final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
-        callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellAgent, lingerTimeoutMs);
+        callback.expectCaps(mCellAgent, lingerTimeoutMs,
+                c -> !c.hasCapability(NET_CAPABILITY_FOREGROUND));
 
         // Clean up.
         mCm.unregisterNetworkCallback(defaultCallback);
@@ -3805,7 +3832,7 @@
         mWiFiAgent.connect(true);
         callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         callback.expectLosing(mCellAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork());
         expectUnvalidationCheckWillNotNotify(mWiFiAgent);
 
@@ -3813,7 +3840,7 @@
         mEthernetAgent.connect(true);
         callback.expectAvailableCallbacksUnvalidated(mEthernetAgent);
         callback.expectLosing(mWiFiAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetAgent);
+        callback.expectCaps(mEthernetAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         assertEquals(mEthernetAgent.getNetwork(), mCm.getActiveNetwork());
         callback.assertNoCallback();
 
@@ -4261,7 +4288,7 @@
         mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiAgent.connectWithPartialConnectivity();
         callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
 
         // Mobile data should be the default network.
         assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork());
@@ -4289,8 +4316,8 @@
         // validated.
         mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true);
         callback.expectLosing(mCellAgent);
-        NetworkCapabilities nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED,
-                mWiFiAgent);
+        NetworkCapabilities nc =
+                callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         assertTrue(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
         assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork());
 
@@ -4304,7 +4331,7 @@
         mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiAgent.connectWithPartialConnectivity();
         callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
 
         // Mobile data should be the default network.
         assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork());
@@ -4336,7 +4363,7 @@
         callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         verify(mWiFiAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
         callback.expectLosing(mCellAgent);
-        nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        nc = callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         assertFalse(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
 
         // Wifi should be the default network.
@@ -4357,7 +4384,7 @@
         verify(mWiFiAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
         callback.expectLosing(mCellAgent);
         assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork());
-        callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
         expectUnvalidationCheckWillNotNotify(mWiFiAgent);
 
         mWiFiAgent.setNetworkValid(false /* privateDnsProbeSent */);
@@ -4365,7 +4392,7 @@
         // Need a trigger point to let NetworkMonitor tell ConnectivityService that the network is
         // validated.
         mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         mWiFiAgent.disconnect();
         callback.expect(LOST, mWiFiAgent);
 
@@ -4381,8 +4408,8 @@
         callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         verify(mWiFiAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
         callback.expectLosing(mCellAgent);
-        callback.expectCapabilitiesWith(
-                NET_CAPABILITY_PARTIAL_CONNECTIVITY | NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)
+                && c.hasCapability(NET_CAPABILITY_VALIDATED));
         expectUnvalidationCheckWillNotNotify(mWiFiAgent);
         mWiFiAgent.disconnect();
         callback.expect(LOST, mWiFiAgent);
@@ -4413,7 +4440,7 @@
         // This is necessary because of b/245893397, the same bug that happens where we use
         // expectAvailableDoubleValidatedCallbacks.
         // TODO : fix b/245893397 and remove this.
-        wifiCallback.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, mWiFiAgent);
+        wifiCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL));
 
         // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
         mCm.startCaptivePortalApp(mWiFiAgent.getNetwork());
@@ -4434,9 +4461,10 @@
                 false /* always */);
         waitForIdle();
         mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true);
-        wifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        wifiCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         validatedCallback.expectAvailableCallbacksValidated(mWiFiAgent);
-        validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiAgent);
+        validatedCallback.expectCaps(mWiFiAgent,
+                c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
 
         mCm.unregisterNetworkCallback(wifiCallback);
         mCm.unregisterNetworkCallback(validatedCallback);
@@ -4638,15 +4666,16 @@
 
         mWiFiAgent.notifyCapportApiDataChanged(testData);
 
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> testData.equals(lp.getCaptivePortalData()));
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> testData.equals(cb.getLp().getCaptivePortalData()));
 
         final LinkProperties newLps = new LinkProperties();
         newLps.setMtu(1234);
         mWiFiAgent.sendLinkProperties(newLps);
         // CaptivePortalData is not lost and unchanged when LPs are received from the NetworkAgent
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> testData.equals(lp.getCaptivePortalData()) && lp.getMtu() == 1234);
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> testData.equals(cb.getLp().getCaptivePortalData())
+                        && cb.getLp().getMtu() == 1234);
     }
 
     private TestNetworkCallback setupNetworkCallbackAndConnectToWifi() throws Exception {
@@ -4740,8 +4769,8 @@
         // Baseline capport data
         mWiFiAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
 
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()));
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> captivePortalTestData.mCapportData.equals(cb.getLp().getCaptivePortalData()));
 
         // Venue URL, T&C URL and friendly name from Network agent with Passpoint source, confirm
         // that API data gets precedence on the bytes remaining.
@@ -4750,9 +4779,9 @@
         mWiFiAgent.sendLinkProperties(linkProperties);
 
         // Make sure that the capport data is merged
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> captivePortalTestData.mExpectedMergedPasspointData
-                        .equals(lp.getCaptivePortalData()));
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> captivePortalTestData.mExpectedMergedPasspointData.equals(
+                        cb.getLp().getCaptivePortalData()));
 
         // Now send this information from non-Passpoint source, confirm that Capport data takes
         // precedence
@@ -4760,9 +4789,9 @@
         mWiFiAgent.sendLinkProperties(linkProperties);
 
         // Make sure that the capport data is merged
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> captivePortalTestData.mExpectedMergedOtherData
-                        .equals(lp.getCaptivePortalData()));
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> captivePortalTestData.mExpectedMergedOtherData.equals(
+                        cb.getLp().getCaptivePortalData()));
 
         // Create a new LP with no Network agent capport data
         final LinkProperties newLps = new LinkProperties();
@@ -4770,21 +4799,22 @@
         mWiFiAgent.sendLinkProperties(newLps);
         // CaptivePortalData is not lost and has the original values when LPs are received from the
         // NetworkAgent
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData())
-                        && lp.getMtu() == 1234);
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> captivePortalTestData.mCapportData.equals(cb.getLp().getCaptivePortalData())
+                        && cb.getLp().getMtu() == 1234);
 
         // Now send capport data only from the Network agent
         mWiFiAgent.notifyCapportApiDataChanged(null);
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> lp.getCaptivePortalData() == null);
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> cb.getLp().getCaptivePortalData() == null);
 
         newLps.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
         mWiFiAgent.sendLinkProperties(newLps);
 
         // Make sure that only the network agent capport data is available
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData()));
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> captivePortalTestData.mNaPasspointData.equals(
+                        cb.getLp().getCaptivePortalData()));
     }
 
     @Test
@@ -4799,25 +4829,26 @@
         mWiFiAgent.sendLinkProperties(linkProperties);
 
         // Make sure that the data is saved correctly
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData()));
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> captivePortalTestData.mNaPasspointData.equals(
+                        cb.getLp().getCaptivePortalData()));
 
         // Expected merged data: Network agent data is preferred, and values that are not used by
         // it are merged from capport data
         mWiFiAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
 
         // Make sure that the Capport data is merged correctly
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> captivePortalTestData.mExpectedMergedPasspointData.equals(
-                        lp.getCaptivePortalData()));
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> captivePortalTestData.mExpectedMergedPasspointData.equals(
+                        cb.getLp().getCaptivePortalData()));
 
         // Now set the naData to null
         linkProperties.setCaptivePortalData(null);
         mWiFiAgent.sendLinkProperties(linkProperties);
 
         // Make sure that the Capport data is retained correctly
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()));
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> captivePortalTestData.mCapportData.equals(cb.getLp().getCaptivePortalData()));
     }
 
     @Test
@@ -4833,17 +4864,17 @@
         mWiFiAgent.sendLinkProperties(linkProperties);
 
         // Make sure that the data is saved correctly
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> captivePortalTestData.mNaOtherData.equals(lp.getCaptivePortalData()));
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> captivePortalTestData.mNaOtherData.equals(cb.getLp().getCaptivePortalData()));
 
         // Expected merged data: Network agent data is preferred, and values that are not used by
         // it are merged from capport data
         mWiFiAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
 
         // Make sure that the Capport data is merged correctly
-        captivePortalCallback.expectLinkPropertiesThat(mWiFiAgent,
-                lp -> captivePortalTestData.mExpectedMergedOtherData.equals(
-                        lp.getCaptivePortalData()));
+        captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent,
+                cb -> captivePortalTestData.mExpectedMergedOtherData.equals(
+                        cb.getLp().getCaptivePortalData()));
     }
 
     private NetworkRequest.Builder newWifiRequestBuilder() {
@@ -5232,7 +5263,8 @@
 
         // Suspend the network.
         mCellAgent.suspend();
-        cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED, mCellAgent);
+        cellNetworkCallback.expectCaps(mCellAgent,
+                c -> !c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
         cellNetworkCallback.expect(SUSPENDED, mCellAgent);
         cellNetworkCallback.assertNoCallback();
         assertEquals(NetworkInfo.State.SUSPENDED, mCm.getActiveNetworkInfo().getState());
@@ -5247,7 +5279,8 @@
         mCm.unregisterNetworkCallback(dfltNetworkCallback);
 
         mCellAgent.resume();
-        cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED, mCellAgent);
+        cellNetworkCallback.expectCaps(mCellAgent,
+                c -> c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
         cellNetworkCallback.expect(RESUMED, mCellAgent);
         cellNetworkCallback.assertNoCallback();
         assertEquals(NetworkInfo.State.CONNECTED, mCm.getActiveNetworkInfo().getState());
@@ -5288,6 +5321,13 @@
         callback.expectAvailableCallbacksUnvalidated(mCellAgent);
         mCm.unregisterNetworkCallback(callback);
 
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
+        mServiceContext.setPermission(NETWORK_SETUP_WIZARD, PERMISSION_GRANTED);
+        mCm.registerSystemDefaultNetworkCallback(callback, handler);
+        callback.expectAvailableCallbacksUnvalidated(mCellAgent);
+        mCm.unregisterNetworkCallback(callback);
+
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
         mCm.registerDefaultNetworkCallbackForUid(APP1_UID, callback, handler);
         callback.expectAvailableCallbacksUnvalidated(mCellAgent);
         mCm.unregisterNetworkCallback(callback);
@@ -5474,10 +5514,10 @@
         // When wifi connects, cell lingers.
         callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         callback.expectLosing(mCellAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         fgCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         fgCallback.expectLosing(mCellAgent);
-        fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        fgCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         assertTrue(isForegroundNetwork(mCellAgent));
         assertTrue(isForegroundNetwork(mWiFiAgent));
 
@@ -5486,7 +5526,7 @@
         int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
         fgCallback.expect(LOST, mCellAgent, timeoutMs);
         // Expect a network capabilities update sans FOREGROUND.
-        callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellAgent);
+        callback.expectCaps(mCellAgent, c -> !c.hasCapability(NET_CAPABILITY_FOREGROUND));
         assertFalse(isForegroundNetwork(mCellAgent));
         assertTrue(isForegroundNetwork(mWiFiAgent));
 
@@ -5499,8 +5539,8 @@
         fgCallback.expectAvailableCallbacksValidated(mCellAgent);
         // Expect a network capabilities update with FOREGROUND, because the most recent
         // request causes its state to change.
-        cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellAgent);
-        callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellAgent);
+        cellCallback.expectCaps(mCellAgent, c -> c.hasCapability(NET_CAPABILITY_FOREGROUND));
+        callback.expectCaps(mCellAgent, c -> c.hasCapability(NET_CAPABILITY_FOREGROUND));
         assertTrue(isForegroundNetwork(mCellAgent));
         assertTrue(isForegroundNetwork(mWiFiAgent));
 
@@ -5509,7 +5549,7 @@
         mCm.unregisterNetworkCallback(cellCallback);
         fgCallback.expect(LOST, mCellAgent);
         // Expect a network capabilities update sans FOREGROUND.
-        callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellAgent);
+        callback.expectCaps(mCellAgent, c -> !c.hasCapability(NET_CAPABILITY_FOREGROUND));
         assertFalse(isForegroundNetwork(mCellAgent));
         assertTrue(isForegroundNetwork(mWiFiAgent));
 
@@ -5661,7 +5701,8 @@
             // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
             // validated – see testPartialConnectivity.
             mCm.reportNetworkConnectivity(mCellAgent.getNetwork(), true);
-            cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellAgent);
+            cellNetworkCallback.expectCaps(mCellAgent,
+                    c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
             testFactory.expectRequestRemove();
             testFactory.assertRequestCountEquals(0);
             // Accordingly, the factory shouldn't be started.
@@ -5862,14 +5903,15 @@
         mWiFiAgent.setNetworkValid(true /* privateDnsProbeSent */);
         // Have CS reconsider the network (see testPartialConnectivity)
         mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true);
-        wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        wifiNetworkCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         cellCallback.expectOnNetworkUnneeded(defaultCaps);
         wifiCallback.assertNoCallback();
 
         // Wifi is no longer validated. Cell is needed again.
         mWiFiAgent.setNetworkInvalid(true /* invalidBecauseOfPrivateDns */);
         mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), false);
-        wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        wifiNetworkCallback.expectCaps(mWiFiAgent,
+                c -> !c.hasCapability(NET_CAPABILITY_VALIDATED));
         cellCallback.expectOnNetworkNeeded(defaultCaps);
         wifiCallback.assertNoCallback();
 
@@ -5891,7 +5933,8 @@
         wifiCallback.assertNoCallback();
         mWiFiAgent.setNetworkValid(true /* privateDnsProbeSent */);
         mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true);
-        wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        wifiNetworkCallback.expectCaps(mWiFiAgent,
+                c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         cellCallback.expectOnNetworkUnneeded(defaultCaps);
         wifiCallback.assertNoCallback();
 
@@ -5899,7 +5942,8 @@
         // not needed.
         mWiFiAgent.setNetworkInvalid(true /* invalidBecauseOfPrivateDns */);
         mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), false);
-        wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        wifiNetworkCallback.expectCaps(mWiFiAgent,
+                c -> !c.hasCapability(NET_CAPABILITY_VALIDATED));
         cellCallback.assertNoCallback();
         wifiCallback.assertNoCallback();
     }
@@ -5994,7 +6038,7 @@
         // Fail validation on wifi.
         mWiFiAgent.setNetworkInvalid(false /* invalidBecauseOfPrivateDns */);
         mCm.reportNetworkConnectivity(wifiNetwork, false);
-        defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        defaultCallback.expectCaps(mWiFiAgent, c -> !c.hasCapability(NET_CAPABILITY_VALIDATED));
         validatedWifiCallback.expect(LOST, mWiFiAgent);
         expectNotification(mWiFiAgent, NotificationType.LOST_INTERNET);
 
@@ -6045,7 +6089,7 @@
         // Fail validation on wifi and expect the dialog to appear.
         mWiFiAgent.setNetworkInvalid(false /* invalidBecauseOfPrivateDns */);
         mCm.reportNetworkConnectivity(wifiNetwork, false);
-        defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        defaultCallback.expectCaps(mWiFiAgent, c -> !c.hasCapability(NET_CAPABILITY_VALIDATED));
         validatedWifiCallback.expect(LOST, mWiFiAgent);
         expectNotification(mWiFiAgent, NotificationType.LOST_INTERNET);
 
@@ -7262,7 +7306,7 @@
         CallbackEntry.LinkPropertiesChanged cbi =
                 networkCallback.expect(LINK_PROPERTIES_CHANGED, networkAgent);
         networkCallback.expect(BLOCKED_STATUS, networkAgent);
-        networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
+        networkCallback.expectCaps(networkAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         networkCallback.assertNoCallback();
         checkDirectlyConnectedRoutes(cbi.getLp(), asList(myIpv4Address),
                 asList(myIpv4DefaultRoute));
@@ -8548,7 +8592,7 @@
         mMockVpn.getAgent().mNetworkMonitor.forceReevaluation(Process.myUid());
         // Expect to see the validated capability, but no other changes, because the VPN is already
         // the default network for the app.
-        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mMockVpn);
+        callback.expectCaps(mMockVpn, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         callback.assertNoCallback();
 
         mMockVpn.disconnect();
@@ -9156,11 +9200,6 @@
         public void expectAvailableThenValidatedCallbacks(HasNetwork n, int blockedStatus) {
             super.expectAvailableThenValidatedCallbacks(n.getNetwork(), blockedStatus, TIMEOUT_MS);
         }
-        public void expectBlockedStatusCallback(HasNetwork n, int blockedStatus) {
-            // This doesn't work:
-            // super.expectBlockedStatusCallback(blockedStatus, n.getNetwork());
-            super.expectBlockedStatusCallback(blockedStatus, n.getNetwork(), TIMEOUT_MS);
-        }
         public void onBlockedStatusChanged(Network network, int blockedReasons) {
             getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
         }
@@ -9188,8 +9227,9 @@
         assertExtraInfoFromCmPresent(mCellAgent);
 
         setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
-        cellNetworkCallback.expectBlockedStatusCallback(true, mCellAgent);
-        detailedCallback.expectBlockedStatusCallback(mCellAgent, BLOCKED_REASON_BATTERY_SAVER);
+        cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked());
+        detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent,
+                cb -> cb.getReason() == BLOCKED_REASON_BATTERY_SAVER);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -9198,21 +9238,23 @@
         // If blocked state does not change but blocked reason does, the boolean callback is called.
         // TODO: investigate de-duplicating.
         setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED);
-        cellNetworkCallback.expectBlockedStatusCallback(true, mCellAgent);
-        detailedCallback.expectBlockedStatusCallback(mCellAgent,
-                BLOCKED_METERED_REASON_USER_RESTRICTED);
+        cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked());
+        detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent,
+                cb -> cb.getReason() == BLOCKED_METERED_REASON_USER_RESTRICTED);
 
         setBlockedReasonChanged(BLOCKED_REASON_NONE);
-        cellNetworkCallback.expectBlockedStatusCallback(false, mCellAgent);
-        detailedCallback.expectBlockedStatusCallback(mCellAgent, BLOCKED_REASON_NONE);
+        cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> !cb.getBlocked());
+        detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent,
+                cb -> cb.getReason() == BLOCKED_REASON_NONE);
         assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertExtraInfoFromCmPresent(mCellAgent);
 
         setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
-        cellNetworkCallback.expectBlockedStatusCallback(true, mCellAgent);
-        detailedCallback.expectBlockedStatusCallback(mCellAgent, BLOCKED_METERED_REASON_DATA_SAVER);
+        cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked());
+        detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent,
+                cb -> cb.getReason() == BLOCKED_METERED_REASON_DATA_SAVER);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -9220,28 +9262,34 @@
 
         // Restrict the network based on UID rule and NOT_METERED capability change.
         mCellAgent.addCapability(NET_CAPABILITY_NOT_METERED);
-        cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellAgent);
-        cellNetworkCallback.expectBlockedStatusCallback(false, mCellAgent);
-        detailedCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellAgent);
-        detailedCallback.expectBlockedStatusCallback(mCellAgent, BLOCKED_REASON_NONE);
+        cellNetworkCallback.expectCaps(mCellAgent,
+                c -> c.hasCapability(NET_CAPABILITY_NOT_METERED));
+        cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> !cb.getBlocked());
+        detailedCallback.expectCaps(mCellAgent, c -> c.hasCapability(NET_CAPABILITY_NOT_METERED));
+        detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent,
+                cb -> cb.getReason() == BLOCKED_REASON_NONE);
         assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertExtraInfoFromCmPresent(mCellAgent);
 
         mCellAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
-        cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mCellAgent);
-        cellNetworkCallback.expectBlockedStatusCallback(true, mCellAgent);
-        detailedCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mCellAgent);
-        detailedCallback.expectBlockedStatusCallback(mCellAgent, BLOCKED_METERED_REASON_DATA_SAVER);
+        cellNetworkCallback.expectCaps(mCellAgent,
+                c -> !c.hasCapability(NET_CAPABILITY_NOT_METERED));
+        cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked());
+        detailedCallback.expectCaps(mCellAgent,
+                c -> !c.hasCapability(NET_CAPABILITY_NOT_METERED));
+        detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent,
+                cb -> cb.getReason() == BLOCKED_METERED_REASON_DATA_SAVER);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertExtraInfoFromCmBlocked(mCellAgent);
 
         setBlockedReasonChanged(BLOCKED_REASON_NONE);
-        cellNetworkCallback.expectBlockedStatusCallback(false, mCellAgent);
-        detailedCallback.expectBlockedStatusCallback(mCellAgent, BLOCKED_REASON_NONE);
+        cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> !cb.getBlocked());
+        detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent,
+                cb -> cb.getReason() == BLOCKED_REASON_NONE);
         assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -9253,8 +9301,9 @@
 
         // Restrict background data. Networking is not blocked because the network is unmetered.
         setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
-        cellNetworkCallback.expectBlockedStatusCallback(true, mCellAgent);
-        detailedCallback.expectBlockedStatusCallback(mCellAgent, BLOCKED_METERED_REASON_DATA_SAVER);
+        cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked());
+        detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent,
+                cb -> cb.getReason() == BLOCKED_METERED_REASON_DATA_SAVER);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -9263,8 +9312,9 @@
         cellNetworkCallback.assertNoCallback();
 
         setBlockedReasonChanged(BLOCKED_REASON_NONE);
-        cellNetworkCallback.expectBlockedStatusCallback(false, mCellAgent);
-        detailedCallback.expectBlockedStatusCallback(mCellAgent, BLOCKED_REASON_NONE);
+        cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> !cb.getBlocked());
+        detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent,
+                cb -> cb.getReason() == BLOCKED_REASON_NONE);
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertExtraInfoFromCmPresent(mCellAgent);
@@ -9295,7 +9345,7 @@
         mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellAgent.connect(true);
         defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellAgent);
-        defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellAgent);
+        defaultCallback.expectCaps(mCellAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
 
         // Allow to use the network after switching to NOT_METERED network.
         mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -9310,8 +9360,8 @@
 
         // Network becomes NOT_METERED.
         mCellAgent.addCapability(NET_CAPABILITY_NOT_METERED);
-        defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellAgent);
-        defaultCallback.expectBlockedStatusCallback(false, mCellAgent);
+        defaultCallback.expectCaps(mCellAgent, c -> c.hasCapability(NET_CAPABILITY_NOT_METERED));
+        defaultCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> !cb.getBlocked());
 
         // Verify there's no Networkcallbacks invoked after data saver on/off.
         setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
@@ -9452,8 +9502,8 @@
 
         // Disable lockdown, expect to see the network unblocked.
         mMockVpn.setAlwaysOnPackage(null, false /* lockdown */, allowList);
-        callback.expectBlockedStatusCallback(false, mWiFiAgent);
-        defaultCallback.expectBlockedStatusCallback(false, mWiFiAgent);
+        callback.expect(BLOCKED_STATUS, mWiFiAgent, cb -> !cb.getBlocked());
+        defaultCallback.expect(BLOCKED_STATUS, mWiFiAgent, cb -> !cb.getBlocked());
         vpnUidCallback.assertNoCallback();
         vpnUidDefaultCallback.assertNoCallback();
         vpnDefaultCallbackAsUid.assertNoCallback();
@@ -9511,7 +9561,7 @@
         mMockVpn.setAlwaysOnPackage(ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
         waitForIdle();
         expectNetworkRejectNonSecureVpn(inOrder, true, uidRangeParcels);
-        defaultCallback.expectBlockedStatusCallback(true, mWiFiAgent);
+        defaultCallback.expect(BLOCKED_STATUS, mWiFiAgent, cb -> cb.getBlocked());
         assertBlockedCallbackInAnyOrder(callback, true, mWiFiAgent, mCellAgent);
         vpnUidCallback.assertNoCallback();
         vpnUidDefaultCallback.assertNoCallback();
@@ -9524,7 +9574,7 @@
 
         // Disable lockdown. Everything is unblocked.
         mMockVpn.setAlwaysOnPackage(null, false /* lockdown */, allowList);
-        defaultCallback.expectBlockedStatusCallback(false, mWiFiAgent);
+        defaultCallback.expect(BLOCKED_STATUS, mWiFiAgent, cb -> !cb.getBlocked());
         assertBlockedCallbackInAnyOrder(callback, false, mWiFiAgent, mCellAgent);
         vpnUidCallback.assertNoCallback();
         vpnUidDefaultCallback.assertNoCallback();
@@ -9565,7 +9615,7 @@
 
         // Enable lockdown and connect a VPN. The VPN is not blocked.
         mMockVpn.setAlwaysOnPackage(ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
-        defaultCallback.expectBlockedStatusCallback(true, mWiFiAgent);
+        defaultCallback.expect(BLOCKED_STATUS, mWiFiAgent, cb -> cb.getBlocked());
         assertBlockedCallbackInAnyOrder(callback, true, mWiFiAgent, mCellAgent);
         vpnUidCallback.assertNoCallback();
         vpnUidDefaultCallback.assertNoCallback();
@@ -10049,7 +10099,7 @@
             // changes back to cellular.
             mWiFiAgent.removeCapability(testCap);
             callbackWithCap.expectAvailableCallbacksValidated(mCellAgent);
-            callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiAgent);
+            callbackWithoutCap.expectCaps(mWiFiAgent, c -> !c.hasCapability(testCap));
             verify(mMockNetd).networkSetDefault(eq(mCellAgent.getNetwork().netId));
             reset(mMockNetd);
 
@@ -10319,19 +10369,19 @@
         // Expect clatd to be stopped and started with the new prefix.
         mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
                 cellNetId, PREFIX_OPERATION_ADDED, kOtherNat64PrefixString, 96));
-        networkCallback.expectLinkPropertiesThat(mCellAgent,
-                (lp) -> lp.getStackedLinks().size() == 0);
+        networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
+                cb -> cb.getLp().getStackedLinks().size() == 0);
         verifyClatdStop(null /* inOrder */, MOBILE_IFNAME);
         assertRoutesRemoved(cellNetId, stackedDefault);
         verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_MOBILE_IFNAME);
 
         verifyClatdStart(null /* inOrder */, MOBILE_IFNAME, cellNetId,
                 kOtherNat64Prefix.toString());
-        networkCallback.expectLinkPropertiesThat(mCellAgent,
-                (lp) -> lp.getNat64Prefix().equals(kOtherNat64Prefix));
+        networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
+                cb -> cb.getLp().getNat64Prefix().equals(kOtherNat64Prefix));
         clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true);
-        networkCallback.expectLinkPropertiesThat(mCellAgent,
-                (lp) -> lp.getStackedLinks().size() == 1);
+        networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
+                cb -> cb.getLp().getStackedLinks().size() == 1);
         assertRoutesAdded(cellNetId, stackedDefault);
         verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_MOBILE_IFNAME);
         reset(mMockNetd);
@@ -10372,7 +10422,8 @@
         // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
         mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
                 cellNetId, PREFIX_OPERATION_REMOVED, kOtherNat64PrefixString, 96));
-        networkCallback.expectLinkPropertiesThat(mCellAgent, lp -> lp.getNat64Prefix() == null);
+        networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
+                cb -> cb.getLp().getNat64Prefix() == null);
 
         // Remove IPv4 address and expect prefix discovery and clatd to be started again.
         cellLp.removeLinkAddress(myIpv4);
@@ -10389,22 +10440,24 @@
 
         // Clat iface comes up. Expect stacked link to be added.
         clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true);
-        networkCallback.expectLinkPropertiesThat(mCellAgent,
-                lp -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null);
+        networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
+                cb -> cb.getLp().getStackedLinks().size() == 1
+                        && cb.getLp().getNat64Prefix() != null);
         assertRoutesAdded(cellNetId, stackedDefault);
         verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_MOBILE_IFNAME);
 
         // NAT64 prefix is removed. Expect that clat is stopped.
         mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
                 cellNetId, PREFIX_OPERATION_REMOVED, kNat64PrefixString, 96));
-        networkCallback.expectLinkPropertiesThat(mCellAgent,
-                lp -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
+        networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
+                cb -> cb.getLp().getStackedLinks().size() == 0
+                        && cb.getLp().getNat64Prefix() == null);
         assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault);
 
         // Stop has no effect because clat is already stopped.
         verifyClatdStop(null /* inOrder */, MOBILE_IFNAME);
-        networkCallback.expectLinkPropertiesThat(mCellAgent,
-                lp -> lp.getStackedLinks().size() == 0);
+        networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
+                cb -> cb.getLp().getStackedLinks().size() == 0);
         verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_MOBILE_IFNAME);
         verify(mMockNetd, times(1)).interfaceGetCfg(CLAT_MOBILE_IFNAME);
         // Clean up.
@@ -10438,9 +10491,9 @@
         verifyClatdStart(null /* inOrder */, MOBILE_IFNAME, cellNetId, kNat64Prefix.toString());
         clat = getNat464Xlat(mCellAgent);
         clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true /* up */);
-        networkCallback.expectLinkPropertiesThat(mCellAgent,
-                lp -> lp.getStackedLinks().size() == 1
-                        && lp.getNat64Prefix().equals(kNat64Prefix));
+        networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
+                cb -> cb.getLp().getStackedLinks().size() == 1
+                        && cb.getLp().getNat64Prefix().equals(kNat64Prefix));
         verify(mMockNetd).networkAddInterface(cellNetId, CLAT_MOBILE_IFNAME);
         // assertRoutesAdded sees all calls since last mMockNetd reset, so expect IPv6 routes again.
         assertRoutesAdded(cellNetId, ipv6Subnet, ipv6Default, stackedDefault);
@@ -10464,7 +10517,8 @@
 
     private void expectNat64PrefixChange(TestNetworkCallback callback,
             TestNetworkAgentWrapper agent, IpPrefix prefix) {
-        callback.expectLinkPropertiesThat(agent, x -> Objects.equals(x.getNat64Prefix(), prefix));
+        callback.expect(LINK_PROPERTIES_CHANGED, agent,
+                x -> Objects.equals(x.getLp().getNat64Prefix(), prefix));
     }
 
     @Test
@@ -10699,7 +10753,7 @@
         mWiFiAgent.connect(true);
         networkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         networkCallback.expectLosing(mCellAgent);
-        networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        networkCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
                 eq(Integer.toString(TRANSPORT_WIFI)));
         verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
@@ -10723,7 +10777,7 @@
         mWiFiAgent.connect(true);
         networkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         networkCallback.expectLosing(mCellAgent);
-        networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        networkCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
                 eq(Integer.toString(TRANSPORT_WIFI)));
         verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
@@ -12103,7 +12157,8 @@
         lp.addRoute(rio1);
         lp.addRoute(defaultRoute);
         mCellAgent.sendLinkProperties(lp);
-        networkCallback.expectLinkPropertiesThat(mCellAgent, x -> x.getRoutes().size() == 3);
+        networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
+                x -> x.getLp().getRoutes().size() == 3);
 
         assertRoutesAdded(netId, direct, rio1, defaultRoute);
         reset(mMockNetd);
@@ -12118,7 +12173,8 @@
         assertTrue(lp.getRoutes().contains(defaultWithMtu));
 
         mCellAgent.sendLinkProperties(lp);
-        networkCallback.expectLinkPropertiesThat(mCellAgent, x -> x.getRoutes().contains(rio2));
+        networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
+                x -> x.getLp().getRoutes().contains(rio2));
 
         assertRoutesRemoved(netId, rio1);
         assertRoutesAdded(netId, rio2);
@@ -12397,7 +12453,7 @@
         // sees the network come up and validate later
         allNetworksCb.expectAvailableCallbacksUnvalidated(mWiFiAgent);
         allNetworksCb.expectLosing(mCellAgent);
-        allNetworksCb.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiAgent);
+        allNetworksCb.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
         allNetworksCb.expect(LOST, mCellAgent, TEST_LINGER_DELAY_MS * 2);
 
         // The cell network has disconnected (see LOST above) because it was outscored and
@@ -17114,15 +17170,17 @@
             mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), false);
             // Wi-Fi is now detected to have a portal : cell should become the default network.
             mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent);
-            wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiAgent);
-            wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, mWiFiAgent);
+            wifiNetworkCallback.expectCaps(mWiFiAgent,
+                    c -> !c.hasCapability(NET_CAPABILITY_VALIDATED));
+            wifiNetworkCallback.expectCaps(mWiFiAgent,
+                    c -> c.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL));
 
             // Wi-Fi becomes valid again. The default network goes back to Wi-Fi.
             mWiFiAgent.setNetworkValid(false /* privateDnsProbeSent */);
             mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true);
             mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiAgent);
-            wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_CAPTIVE_PORTAL,
-                    mWiFiAgent);
+            wifiNetworkCallback.expectCaps(mWiFiAgent,
+                    c -> !c.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL));
 
             // Wi-Fi roaming from wifiNc2 to wifiNc1, and the network now has partial connectivity.
             mWiFiAgent.setNetworkCapabilities(wifiNc1, true);
@@ -17133,15 +17191,15 @@
             // Wi-Fi now only offers partial connectivity, so in the absence of accepting partial
             // connectivity explicitly for this network, it loses default status to cell.
             mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent);
-            wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
-                    mWiFiAgent);
+            wifiNetworkCallback.expectCaps(mWiFiAgent,
+                    c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
 
             // Wi-Fi becomes valid again. The default network goes back to Wi-Fi.
             mWiFiAgent.setNetworkValid(false /* privateDnsProbeSent */);
             mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true);
             mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiAgent);
-            wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
-                    mWiFiAgent);
+            wifiNetworkCallback.expectCaps(mWiFiAgent,
+                    c -> !c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
         }
         mCm.unregisterNetworkCallback(wifiNetworkCallback);
 
diff --git a/tests/unit/java/com/android/server/IpSecServiceTest.java b/tests/unit/java/com/android/server/IpSecServiceTest.java
index 6955620..4b6857c 100644
--- a/tests/unit/java/com/android/server/IpSecServiceTest.java
+++ b/tests/unit/java/com/android/server/IpSecServiceTest.java
@@ -82,7 +82,7 @@
     private static final int MAX_NUM_ENCAP_SOCKETS = 100;
     private static final int MAX_NUM_SPIS = 100;
     private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
-    private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
+    private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 200000;
 
     private static final InetAddress INADDR_ANY;
 
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index 5a3bc64..0680772 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -53,6 +53,7 @@
 import android.content.Context;
 import android.net.INetd;
 import android.net.Network;
+import android.net.connectivity.ConnectivityCompatChanges;
 import android.net.mdns.aidl.DiscoveryInfo;
 import android.net.mdns.aidl.GetAddressInfo;
 import android.net.mdns.aidl.IMDnsEventListener;
@@ -187,7 +188,7 @@
     }
 
     @Test
-    @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testPreSClients() throws Exception {
         // Pre S client connected, the daemon should be started.
         connectClient(mService);
@@ -214,7 +215,7 @@
     }
 
     @Test
-    @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testNoDaemonStartedWhenClientsConnect() throws Exception {
         // Creating an NsdManager will not cause daemon startup.
         connectClient(mService);
@@ -248,7 +249,7 @@
     }
 
     @Test
-    @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testClientRequestsAreGCedAtDisconnection() throws Exception {
         final NsdManager client = connectClient(mService);
         final INsdManagerCallback cb1 = getCallback();
@@ -291,7 +292,7 @@
     }
 
     @Test
-    @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
+    @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)
     public void testCleanupDelayNoRequestActive() throws Exception {
         final NsdManager client = connectClient(mService);
 
diff --git a/tools/gn2bp/Android.bp.swp b/tools/gn2bp/Android.bp.swp
index 9f34b06..93443f5 100644
--- a/tools/gn2bp/Android.bp.swp
+++ b/tools/gn2bp/Android.bp.swp
@@ -263,6 +263,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DIS_PARTITION_ALLOC_IMPL",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-DPA_PCSCAN_STACK_SUPPORTED",
@@ -272,6 +273,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-O3",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -284,18 +293,29 @@
         "libgtest_prod_headers",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
         android_arm: {
             srcs: [
                 "base/allocator/partition_allocator/starscan/stack/asm/arm/push_registers_asm.cc",
             ],
+            cflags: [
+                "-fstack-protector",
+            ],
         },
         android_arm64: {
             srcs: [
                 "base/allocator/partition_allocator/starscan/stack/asm/arm64/push_registers_asm.cc",
             ],
             cflags: [
+                "-fstack-protector",
                 "-march=armv8-a+memtag",
+                "-mno-outline",
+                "-mno-outline-atomics",
             ],
         },
         android_x86: {
@@ -311,6 +331,7 @@
                 "base/allocator/partition_allocator/starscan/stack/asm/x64/push_registers_asm.cc",
             ],
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -972,6 +993,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-DUSE_CHROMIUM_ICU=1",
@@ -986,6 +1008,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-O2",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -1002,6 +1032,11 @@
         "libgtest_prod_headers",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
         android_arm: {
             srcs: [
@@ -1011,11 +1046,19 @@
                 "base/profiler/chrome_unwinder_android_v2.cc",
                 "base/trace_event/cfi_backtrace_android.cc",
             ],
+            cflags: [
+                "-fstack-protector",
+            ],
         },
         android_arm64: {
             srcs: [
                 "base/android/reached_code_profiler.cc",
             ],
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
         },
         android_x86: {
             srcs: [
@@ -1030,6 +1073,7 @@
                 "base/android/reached_code_profiler_stub.cc",
             ],
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -1366,6 +1410,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -1374,6 +1419,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-O2",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -1382,7 +1435,24 @@
         "buildtools/third_party/libc++abi/trunk/include",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -1390,6 +1460,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -1400,7 +1471,7 @@
 cc_genrule {
     name: "cronet_aml_base_build_date",
     cmd: "$(location build/write_build_date_header.py) $(out) " +
-         "1674804594",
+         "1676008584",
     out: [
         "base/generated_build_date.h",
     ],
@@ -1463,7 +1534,7 @@
     name: "cronet_aml_base_debugging_buildflags",
     cmd: "if [[ ( $$CC_ARCH == 'x86_64' && $$CC_OS == 'android' ) ]]; " +
          "then " +
-         "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" FROM_HERE_USES_LOCATION_BUILTINS=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"false\" UNSAFE_DEVELOPER_BUILD=\"false\" CAN_UNWIND_WITH_CFI_TABLE=\"false\" EXCLUDE_UNWIND_TABLES=\"false\" ENABLE_GDBINIT_WARNING=\"false\" ENABLE_LLDBINIT_WARNING=\"false\" EXPENSIVE_DCHECKS_ARE_ON=\"false\" ENABLE_STACK_TRACE_LINE_NUMBERS=\"false\"' | " +
+         "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" FROM_HERE_USES_LOCATION_BUILTINS=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"false\" UNSAFE_DEVELOPER_BUILD=\"false\" CAN_UNWIND_WITH_CFI_TABLE=\"false\" EXCLUDE_UNWIND_TABLES=\"true\" ENABLE_GDBINIT_WARNING=\"false\" ENABLE_LLDBINIT_WARNING=\"false\" EXPENSIVE_DCHECKS_ARE_ON=\"false\" ENABLE_STACK_TRACE_LINE_NUMBERS=\"false\"' | " +
          "$(location build/write_buildflag_header.py) --output " +
          "$(out) " +
          "--rulename " +
@@ -1475,7 +1546,7 @@
          "fi; " +
          "if [[ ( $$CC_ARCH == 'x86' && $$CC_OS == 'android' ) ]]; " +
          "then " +
-         "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" FROM_HERE_USES_LOCATION_BUILTINS=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"true\" UNSAFE_DEVELOPER_BUILD=\"false\" CAN_UNWIND_WITH_CFI_TABLE=\"false\" EXCLUDE_UNWIND_TABLES=\"false\" ENABLE_GDBINIT_WARNING=\"false\" ENABLE_LLDBINIT_WARNING=\"false\" EXPENSIVE_DCHECKS_ARE_ON=\"false\" ENABLE_STACK_TRACE_LINE_NUMBERS=\"false\"' | " +
+         "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" FROM_HERE_USES_LOCATION_BUILTINS=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"false\" UNSAFE_DEVELOPER_BUILD=\"false\" CAN_UNWIND_WITH_CFI_TABLE=\"false\" EXCLUDE_UNWIND_TABLES=\"true\" ENABLE_GDBINIT_WARNING=\"false\" ENABLE_LLDBINIT_WARNING=\"false\" EXPENSIVE_DCHECKS_ARE_ON=\"false\" ENABLE_STACK_TRACE_LINE_NUMBERS=\"false\"' | " +
          "$(location build/write_buildflag_header.py) --output " +
          "$(out) " +
          "--rulename " +
@@ -1487,7 +1558,7 @@
          "fi; " +
          "if [[ ( $$CC_ARCH == 'arm' && $$CC_OS == 'android' ) ]]; " +
          "then " +
-         "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" FROM_HERE_USES_LOCATION_BUILTINS=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"false\" UNSAFE_DEVELOPER_BUILD=\"false\" CAN_UNWIND_WITH_CFI_TABLE=\"true\" EXCLUDE_UNWIND_TABLES=\"false\" ENABLE_GDBINIT_WARNING=\"false\" ENABLE_LLDBINIT_WARNING=\"false\" EXPENSIVE_DCHECKS_ARE_ON=\"false\" ENABLE_STACK_TRACE_LINE_NUMBERS=\"false\"' | " +
+         "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" FROM_HERE_USES_LOCATION_BUILTINS=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"false\" UNSAFE_DEVELOPER_BUILD=\"false\" CAN_UNWIND_WITH_CFI_TABLE=\"true\" EXCLUDE_UNWIND_TABLES=\"true\" ENABLE_GDBINIT_WARNING=\"false\" ENABLE_LLDBINIT_WARNING=\"false\" EXPENSIVE_DCHECKS_ARE_ON=\"false\" ENABLE_STACK_TRACE_LINE_NUMBERS=\"false\"' | " +
          "$(location build/write_buildflag_header.py) --output " +
          "$(out) " +
          "--rulename " +
@@ -1499,7 +1570,7 @@
          "fi; " +
          "if [[ ( $$CC_ARCH == 'arm64' && $$CC_OS == 'android' ) ]]; " +
          "then " +
-         "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" FROM_HERE_USES_LOCATION_BUILTINS=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"true\" UNSAFE_DEVELOPER_BUILD=\"false\" CAN_UNWIND_WITH_CFI_TABLE=\"false\" EXCLUDE_UNWIND_TABLES=\"false\" ENABLE_GDBINIT_WARNING=\"false\" ENABLE_LLDBINIT_WARNING=\"false\" EXPENSIVE_DCHECKS_ARE_ON=\"false\" ENABLE_STACK_TRACE_LINE_NUMBERS=\"false\"' | " +
+         "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" FROM_HERE_USES_LOCATION_BUILTINS=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"true\" UNSAFE_DEVELOPER_BUILD=\"false\" CAN_UNWIND_WITH_CFI_TABLE=\"false\" EXCLUDE_UNWIND_TABLES=\"true\" ENABLE_GDBINIT_WARNING=\"false\" ENABLE_LLDBINIT_WARNING=\"false\" EXPENSIVE_DCHECKS_ARE_ON=\"false\" ENABLE_STACK_TRACE_LINE_NUMBERS=\"false\"' | " +
          "$(location build/write_buildflag_header.py) --output " +
          "$(out) " +
          "--rulename " +
@@ -1685,6 +1756,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -1693,6 +1765,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -1702,6 +1782,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -1709,6 +1801,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -1916,6 +2009,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -1924,6 +2018,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -1932,7 +2034,24 @@
         "buildtools/third_party/libc++abi/trunk/include",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -1940,6 +2059,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -1963,11 +2083,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-O2",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -1976,7 +2105,24 @@
         "buildtools/third_party/libc++abi/trunk/include",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -1984,6 +2130,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -2222,6 +2369,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DLIBCXX_BUILDING_LIBCXXABI",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
@@ -2230,6 +2378,13 @@
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCPP_OVERRIDABLE_FUNC_VIS=__attribute__((__visibility__(\"default\")))",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -2249,6 +2404,8 @@
                 "-DANDROID",
                 "-DANDROID_NDK_VERSION_ROLL=r23_1",
                 "-DHAVE_SYS_UIO_H",
+                "-Oz",
+                "-fstack-protector",
             ],
         },
         android_arm64: {
@@ -2256,6 +2413,10 @@
                 "-DANDROID",
                 "-DANDROID_NDK_VERSION_ROLL=r23_1",
                 "-DHAVE_SYS_UIO_H",
+                "-Oz",
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
             ],
         },
         android_x86: {
@@ -2263,6 +2424,7 @@
                 "-DANDROID",
                 "-DANDROID_NDK_VERSION_ROLL=r23_1",
                 "-DHAVE_SYS_UIO_H",
+                "-Oz",
                 "-msse3",
             ],
         },
@@ -2271,19 +2433,22 @@
                 "-DANDROID",
                 "-DANDROID_NDK_VERSION_ROLL=r23_1",
                 "-DHAVE_SYS_UIO_H",
+                "-Oz",
+                "-fstack-protector",
                 "-msse3",
             ],
         },
         host: {
             cflags: [
                 "-DCR_SYSROOT_KEY=20220331T153654Z-0",
-                "-DNO_UNWIND_TABLES",
                 "-DUSE_AURA=1",
                 "-DUSE_OZONE=1",
                 "-DUSE_UDEV",
                 "-D_FILE_OFFSET_BITS=64",
                 "-D_LARGEFILE64_SOURCE",
                 "-D_LARGEFILE_SOURCE",
+                "-O2",
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -2321,6 +2486,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DLIBCXXABI_SILENT_TERMINATE",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
@@ -2328,6 +2494,13 @@
         "-D_LIBCPP_CONSTINIT=constinit",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -2350,6 +2523,8 @@
                 "-DANDROID",
                 "-DANDROID_NDK_VERSION_ROLL=r23_1",
                 "-DHAVE_SYS_UIO_H",
+                "-Oz",
+                "-fstack-protector",
             ],
         },
         android_arm64: {
@@ -2360,6 +2535,10 @@
                 "-DANDROID",
                 "-DANDROID_NDK_VERSION_ROLL=r23_1",
                 "-DHAVE_SYS_UIO_H",
+                "-Oz",
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
             ],
         },
         android_x86: {
@@ -2370,6 +2549,7 @@
                 "-DANDROID",
                 "-DANDROID_NDK_VERSION_ROLL=r23_1",
                 "-DHAVE_SYS_UIO_H",
+                "-Oz",
                 "-msse3",
             ],
         },
@@ -2381,6 +2561,8 @@
                 "-DANDROID",
                 "-DANDROID_NDK_VERSION_ROLL=r23_1",
                 "-DHAVE_SYS_UIO_H",
+                "-Oz",
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -2390,13 +2572,14 @@
             ],
             cflags: [
                 "-DCR_SYSROOT_KEY=20220331T153654Z-0",
-                "-DNO_UNWIND_TABLES",
                 "-DUSE_AURA=1",
                 "-DUSE_OZONE=1",
                 "-DUSE_UDEV",
                 "-D_FILE_OFFSET_BITS=64",
                 "-D_LARGEFILE64_SOURCE",
                 "-D_LARGEFILE_SOURCE",
+                "-O2",
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -2504,6 +2687,7 @@
         "-DHAVE_PTHREAD",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -2512,6 +2696,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -2527,10 +2719,25 @@
     ],
     cpp_std: "c++17",
     ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
         "-Wl,--script,external/cronet/base/android/library_loader/anchor_functions.lds",
     ],
     stem: "libcronet.108.0.5359.128",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -2538,6 +2745,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -3170,6 +3378,7 @@
         "-DHAVE_PTHREAD",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -3178,6 +3387,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -3193,6 +3410,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -3200,6 +3429,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -3536,6 +3766,7 @@
         "-DHAVE_PTHREAD",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -3544,6 +3775,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -3559,6 +3798,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -3566,6 +3817,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -3631,6 +3883,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -3639,6 +3892,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -3650,6 +3911,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -3657,6 +3930,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -3707,6 +3981,7 @@
         "-DHAVE_PTHREAD",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -3715,6 +3990,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -3727,6 +4010,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -3734,6 +4029,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -3840,6 +4136,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -3848,6 +4145,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -3858,7 +4163,24 @@
         "third_party/boringssl/src/include/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -3866,6 +4188,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -3953,6 +4276,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -3961,6 +4285,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -3971,7 +4303,24 @@
         "third_party/boringssl/src/include/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -3979,6 +4328,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -3990,7 +4340,6 @@
     name: "cronet_aml_defaults",
     cflags: [
         "-DGOOGLE_PROTOBUF_NO_RTTI",
-        "-O2",
         "-Wno-ambiguous-reversed-operator",
         "-Wno-error=return-type",
         "-Wno-macro-redefined",
@@ -4002,7 +4351,6 @@
         "-Wno-unreachable-code-loop-increment",
         "-Wno-unused-parameter",
         "-fPIC",
-        "-fvisibility=hidden",
     ],
     stl: "none",
     apex_available: [
@@ -4604,6 +4952,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
         "-DNET_IMPLEMENTATION",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -4612,6 +4961,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -4628,6 +4985,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -4635,6 +5004,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -4708,6 +5078,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
         "-DNET_IMPLEMENTATION",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -4716,6 +5087,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -4732,6 +5111,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -4739,6 +5130,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -4825,6 +5217,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
         "-DNET_IMPLEMENTATION",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -4833,6 +5226,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -4849,6 +5250,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -4856,6 +5269,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -5493,6 +5907,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
         "-DNET_IMPLEMENTATION",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -5501,6 +5916,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -5516,16 +5939,29 @@
         "third_party/protobuf/src/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
         android_arm: {
             srcs: [
                 "net/disk_cache/blockfile/mapped_file_bypass_mmap_posix.cc",
             ],
+            cflags: [
+                "-fstack-protector",
+            ],
         },
         android_arm64: {
             srcs: [
                 "net/disk_cache/blockfile/mapped_file_bypass_mmap_posix.cc",
             ],
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
         },
         android_x86: {
             srcs: [
@@ -5540,6 +5976,7 @@
                 "net/disk_cache/blockfile/mapped_file_bypass_mmap_posix.cc",
             ],
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -5600,6 +6037,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
         "-DNET_IMPLEMENTATION",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -5608,6 +6046,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -5621,6 +6067,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -5628,6 +6086,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -5832,6 +6291,7 @@
         "-DHAVE_PTHREAD",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -5840,6 +6300,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -5855,6 +6323,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -5862,6 +6342,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -5901,6 +6382,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -5909,6 +6391,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -5919,7 +6409,24 @@
         "third_party/boringssl/src/include/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -5927,6 +6434,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6401,6 +6909,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DIS_QUICHE_IMPL",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -6409,6 +6918,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6423,7 +6940,24 @@
         "third_party/protobuf/src/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6431,6 +6965,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6473,6 +7008,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -6481,6 +7017,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6492,6 +7036,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6499,6 +7055,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6539,6 +7096,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DIS_URI_TEMPLATE_IMPL",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -6547,6 +7105,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6557,7 +7123,24 @@
         "third_party/boringssl/src/include/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6565,6 +7148,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6593,11 +7177,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6608,6 +7201,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6615,6 +7220,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6639,11 +7245,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6654,6 +7269,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6661,6 +7288,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6685,11 +7313,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6700,6 +7337,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6707,6 +7356,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6731,11 +7381,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6746,6 +7405,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6753,6 +7424,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6777,11 +7449,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6792,6 +7473,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6799,6 +7492,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6823,11 +7517,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6838,6 +7541,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6845,6 +7560,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6869,11 +7585,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6884,6 +7609,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6891,6 +7628,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6916,11 +7654,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6931,6 +7678,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6938,6 +7697,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -6962,11 +7722,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -6977,6 +7746,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -6984,6 +7765,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7010,11 +7792,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7025,6 +7816,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7032,6 +7835,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7056,11 +7860,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7071,6 +7884,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7078,6 +7903,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7102,11 +7928,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7117,6 +7952,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7124,6 +7971,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7148,11 +7996,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7163,6 +8020,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7170,6 +8039,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7194,11 +8064,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7209,6 +8088,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7216,6 +8107,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7240,11 +8132,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7255,6 +8156,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7262,6 +8175,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7286,11 +8200,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7301,6 +8224,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7308,6 +8243,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7332,11 +8268,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7347,6 +8292,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7354,6 +8311,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7378,11 +8336,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7393,6 +8360,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7400,6 +8379,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7424,11 +8404,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7439,6 +8428,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7446,6 +8447,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7470,11 +8472,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7485,6 +8496,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7492,6 +8515,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7517,11 +8541,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7532,6 +8565,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7539,6 +8584,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7566,11 +8612,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7581,6 +8636,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7588,6 +8655,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7615,11 +8683,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7630,6 +8707,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7637,6 +8726,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7664,11 +8754,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7679,6 +8778,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7686,6 +8797,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7713,11 +8825,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7728,6 +8849,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7735,6 +8868,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7762,11 +8896,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7777,6 +8920,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7784,6 +8939,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7811,11 +8967,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7826,6 +8991,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7833,6 +9010,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7857,11 +9035,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7872,6 +9059,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7879,6 +9078,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7903,11 +9103,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7918,6 +9127,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7925,6 +9146,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7952,11 +9174,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -7967,6 +9198,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -7974,6 +9217,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -7999,11 +9243,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8014,6 +9267,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8021,6 +9286,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8045,11 +9311,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8060,6 +9335,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8067,6 +9354,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8093,11 +9381,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8108,6 +9405,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8115,6 +9424,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8145,11 +9455,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8160,6 +9479,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8167,6 +9498,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8191,11 +9523,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8206,6 +9547,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8213,6 +9566,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8237,11 +9591,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8252,6 +9615,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8259,6 +9634,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8283,11 +9659,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8298,6 +9683,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8305,6 +9702,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8331,11 +9729,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8346,6 +9753,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8353,6 +9772,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8382,11 +9802,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8397,6 +9826,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8404,6 +9845,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8440,11 +9882,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8455,6 +9906,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8462,6 +9925,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8486,11 +9950,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8501,6 +9974,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8508,6 +9993,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8538,11 +10024,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8553,6 +10048,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8560,6 +10067,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8584,11 +10092,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8599,6 +10116,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8606,6 +10135,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8638,11 +10168,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8653,6 +10192,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8660,6 +10211,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8688,11 +10240,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8703,6 +10264,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8710,6 +10283,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8734,11 +10308,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8749,6 +10332,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8756,6 +10351,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8780,11 +10376,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8795,6 +10400,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8802,6 +10419,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8825,11 +10443,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8840,6 +10467,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8847,6 +10486,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -8870,6 +10510,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -8878,6 +10519,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -8887,6 +10536,18 @@
     ],
     cpp_std: "c++17",
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -8894,6 +10555,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -9186,12 +10848,21 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-DOPENSSL_SMALL",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -9201,7 +10872,24 @@
         "third_party/boringssl/src/include/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -9209,6 +10897,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -9229,6 +10918,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -9237,6 +10927,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -9263,6 +10961,9 @@
                 "third_party/boringssl/src/crypto/curve25519/asm/x25519-asm-arm.S",
                 "third_party/boringssl/src/crypto/poly1305/poly1305_arm_asm.S",
             ],
+            cflags: [
+                "-fstack-protector",
+            ],
         },
         android_arm64: {
             srcs: [
@@ -9280,6 +10981,11 @@
                 "third_party/boringssl/linux-aarch64/crypto/fipsmodule/vpaes-armv8.S",
                 "third_party/boringssl/linux-aarch64/crypto/test/trampoline-armv8.S",
             ],
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
         },
         android_x86: {
             srcs: [
@@ -9325,6 +11031,7 @@
                 "third_party/boringssl/src/crypto/hrss/asm/poly_rq_mul.S",
             ],
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -9353,6 +11060,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -9361,6 +11069,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -9370,7 +11086,24 @@
         "third_party/brotli/include/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -9378,6 +11111,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -9407,11 +11141,20 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-O2",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -9421,7 +11164,24 @@
         "third_party/brotli/include/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -9429,6 +11189,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -9696,6 +11457,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-DUCONFIG_ONLY_HTML_CONVERSION=1",
@@ -9711,6 +11473,14 @@
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -9721,8 +11491,25 @@
         "third_party/icu/source/i18n/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     rtti: true,
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -9730,6 +11517,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -9953,6 +11741,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-DUCONFIG_ONLY_HTML_CONVERSION=1",
@@ -9969,6 +11758,14 @@
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -9979,8 +11776,25 @@
         "third_party/icu/source/i18n/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     rtti: true,
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -9988,6 +11802,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -10025,11 +11840,20 @@
         "-DHAVE_CONFIG_H",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-O2",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -10039,7 +11863,24 @@
         "third_party/libevent/android/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -10047,6 +11888,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -10215,6 +12057,7 @@
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -10223,6 +12066,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -10231,7 +12082,24 @@
         "buildtools/third_party/libc++abi/trunk/include",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -10239,6 +12107,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -10365,6 +12234,15 @@
         "-D_LARGEFILE_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-O2",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fstack-protector",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
         "-msse3",
     ],
     local_include_dirs: [
@@ -10375,6 +12253,11 @@
         "third_party/protobuf/src/",
     ],
     cpp_std: "c++20",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
 }
 
 // GN: //third_party/protobuf:protobuf_lite
@@ -10432,11 +12315,20 @@
         "-DHAVE_PTHREAD",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_GNU_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-O2",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -10446,7 +12338,24 @@
         "third_party/protobuf/src/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -10454,6 +12363,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -10502,6 +12412,15 @@
         "-D_LARGEFILE_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-O2",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fstack-protector",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
         "-msse3",
     ],
     local_include_dirs: [
@@ -10512,6 +12431,11 @@
         "third_party/protobuf/src/",
     ],
     cpp_std: "c++20",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
 }
 
 // GN: //third_party/protobuf:protoc_lib
@@ -10637,6 +12561,15 @@
         "-D_LARGEFILE_SOURCE",
         "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-O2",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fstack-protector",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
         "-msse3",
     ],
     local_include_dirs: [
@@ -10647,6 +12580,11 @@
         "third_party/protobuf/src/",
     ],
     cpp_std: "c++20",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
 }
 
 // GN: //url:buildflags
@@ -10741,6 +12679,7 @@
         "-DHAVE_SYS_UIO_H",
         "-DIS_URL_IMPL",
         "-DNDEBUG",
+        "-DNO_UNWIND_TABLES",
         "-DNVALGRIND",
         "-DOFFICIAL_BUILD",
         "-D_FORTIFY_SOURCE=2",
@@ -10749,6 +12688,14 @@
         "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
         "-D__STDC_CONSTANT_MACROS",
         "-D__STDC_FORMAT_MACROS",
+        "-Oz",
+        "-fdata-sections",
+        "-ffunction-sections",
+        "-fno-asynchronous-unwind-tables",
+        "-fno-unwind-tables",
+        "-fvisibility-inlines-hidden",
+        "-fvisibility=hidden",
+        "-g1",
     ],
     local_include_dirs: [
         "./",
@@ -10759,7 +12706,24 @@
         "third_party/boringssl/src/include/",
     ],
     cpp_std: "c++17",
+    ldflags: [
+        "-Wl,--as-needed",
+        "-Wl,--gc-sections",
+        "-Wl,--icf=all",
+    ],
     target: {
+        android_arm: {
+            cflags: [
+                "-fstack-protector",
+            ],
+        },
+        android_arm64: {
+            cflags: [
+                "-fstack-protector",
+                "-mno-outline",
+                "-mno-outline-atomics",
+            ],
+        },
         android_x86: {
             cflags: [
                 "-msse3",
@@ -10767,6 +12731,7 @@
         },
         android_x86_64: {
             cflags: [
+                "-fstack-protector",
                 "-msse3",
             ],
         },
@@ -10821,15 +12786,11 @@
         "SPDX-license-identifier-Apache-2.0",
         "SPDX-license-identifier-BSD",
         "SPDX-license-identifier-BSL-1.0",
-        "SPDX-license-identifier-GPL",
-        "SPDX-license-identifier-GPL-2.0",
-        "SPDX-license-identifier-GPL-3.0",
         "SPDX-license-identifier-ICU",
         "SPDX-license-identifier-ISC",
-        "SPDX-license-identifier-LGPL",
-        "SPDX-license-identifier-LGPL-2.1",
         "SPDX-license-identifier-MIT",
         "SPDX-license-identifier-MPL",
+        "SPDX-license-identifier-MPL-1.1",
         "SPDX-license-identifier-MPL-2.0",
         "SPDX-license-identifier-NCSA",
         "SPDX-license-identifier-OpenSSL",
diff --git a/tools/gn2bp/desc_arm.json b/tools/gn2bp/desc_arm.json
index ff1a7e2..6f72c94 100644
--- a/tools/gn2bp/desc_arm.json
+++ b/tools/gn2bp/desc_arm.json
Binary files differ
diff --git a/tools/gn2bp/desc_arm64.json b/tools/gn2bp/desc_arm64.json
index 20c942f..0732834 100644
--- a/tools/gn2bp/desc_arm64.json
+++ b/tools/gn2bp/desc_arm64.json
Binary files differ
diff --git a/tools/gn2bp/desc_x64.json b/tools/gn2bp/desc_x64.json
index b25932b..49e5cae 100644
--- a/tools/gn2bp/desc_x64.json
+++ b/tools/gn2bp/desc_x64.json
Binary files differ
diff --git a/tools/gn2bp/desc_x86.json b/tools/gn2bp/desc_x86.json
index b4bc6e9..51d4153 100644
--- a/tools/gn2bp/desc_x86.json
+++ b/tools/gn2bp/desc_x86.json
Binary files differ
diff --git a/tools/gn2bp/gen_android_bp b/tools/gn2bp/gen_android_bp
index 9d2d858..592c070 100755
--- a/tools/gn2bp/gen_android_bp
+++ b/tools/gn2bp/gen_android_bp
@@ -126,6 +126,30 @@
   "-msse3",
   # needed for zlib:zlib
   "-msse4.2",
+  # flags to reduce binary size
+  "-O1",
+  "-O2",
+  "-O3",
+  "-Oz",
+  "-g1",
+  "-g2",
+  "-fdata-sections",
+  "-ffunction-sections",
+  "-fvisibility=hidden",
+  "-fvisibility-inlines-hidden",
+  "-fstack-protector",
+  "-mno-outline",
+  "-mno-outline-atomics",
+  "-fno-asynchronous-unwind-tables",
+  "-fno-unwind-tables",
+]
+
+# Linker flags which are passed through to the blueprint.
+ldflag_allowlist = [
+  # flags to reduce binary size
+  "-Wl,--as-needed",
+  "-Wl,--gc-sections",
+  "-Wl,--icf=all",
 ]
 
 def get_linker_script_ldflag(script_path):
@@ -296,6 +320,7 @@
     self.export_system_include_dirs = set()
     self.generated_headers = set()
     self.export_generated_headers = set()
+    self.ldflags = set()
 
   def to_string(self, output):
     nested_out = []
@@ -313,6 +338,7 @@
     self._output_field(nested_out, 'export_system_include_dirs')
     self._output_field(nested_out, 'generated_headers')
     self._output_field(nested_out, 'export_generated_headers')
+    self._output_field(nested_out, 'ldflags')
 
     if nested_out:
       output.append('    %s: {' % self.name)
@@ -1242,8 +1268,10 @@
   cflags |= set("-D%s" % define.replace("\"", "\\\"") for define in defines)
   return cflags
 
-def set_module_flags(module, cflags, defines):
+def set_module_flags(module, module_type, cflags, defines, ldflags):
   module.cflags.update(_get_cflags(cflags, defines))
+  if module_type != 'cc_object':
+    module.ldflags.update({flag for flag in ldflags if flag in ldflag_allowlist})
   # TODO: implement proper cflag parsing.
   for flag in cflags:
     if '-std=' in flag:
@@ -1335,11 +1363,12 @@
   module.rtti = target.rtti
 
   if target.type in gn_utils.LINKER_UNIT_TYPES:
-    set_module_flags(module, target.cflags, target.defines)
+    set_module_flags(module, module.type, target.cflags, target.defines, target.ldflags)
     set_module_include_dirs(module, target.cflags, target.include_dirs)
     # TODO: set_module_xxx is confusing, apply similar function to module and target in better way.
     for arch_name, arch in target.arch.items():
-      set_module_flags(module.target[arch_name], arch.cflags, arch.defines)
+      set_module_flags(module.target[arch_name], module.type,
+                       arch.cflags, arch.defines, arch.ldflags)
       # -Xclang -target-feature -Xclang +mte are used to enable MTE (Memory Tagging Extensions).
       # Flags which does not start with '-' could not be in the cflags so enabling MTE by
       # -march and -mcpu Feature Modifiers. MTE is only available on arm64. This is needed for
@@ -1607,10 +1636,8 @@
       '-Wno-sign-promo',
       '-Wno-unused-parameter',
       '-Wno-null-pointer-subtraction', # Needed to libevent
-      '-fvisibility=hidden',
       '-Wno-ambiguous-reversed-operator', # needed for icui18n
       '-Wno-unreachable-code-loop-increment', # needed for icui18n
-      '-O2',
       '-fPIC',
   ]
   # Chromium builds do not add a dependency for headers found inside the
@@ -1667,24 +1694,20 @@
 def create_license_module(blueprint):
   module = Module("license", "external_cronet_license", "LICENSE")
   module.license_kinds.update({
-      'SPDX-license-identifier-LGPL-2.1',
-      'SPDX-license-identifier-GPL-2.0',
       'SPDX-license-identifier-MPL',
+      'SPDX-license-identifier-MPL-1.1',
       'SPDX-license-identifier-ISC',
-      'SPDX-license-identifier-GPL',
       'SPDX-license-identifier-AFL-2.0',
       'SPDX-license-identifier-MPL-2.0',
       'SPDX-license-identifier-BSD',
       'SPDX-license-identifier-Apache-2.0',
       'SPDX-license-identifier-BSL-1.0',
-      'SPDX-license-identifier-LGPL',
-      'SPDX-license-identifier-GPL-3.0',
       'SPDX-license-identifier-Unicode-DFS',
       'SPDX-license-identifier-NCSA',
       'SPDX-license-identifier-OpenSSL',
       'SPDX-license-identifier-MIT',
       "SPDX-license-identifier-ICU",
-      'legacy_unencumbered', # public domain
+      'legacy_unencumbered',
   })
   module.license_text.update({
       "LICENSE",
diff --git a/tools/gn2bp/gen_desc_json.sh b/tools/gn2bp/gen_desc_json.sh
index 1f60eb9..bf9b21d 100755
--- a/tools/gn2bp/gen_desc_json.sh
+++ b/tools/gn2bp/gen_desc_json.sh
@@ -41,27 +41,32 @@
     "target_os = \"android\""
     "enable_websockets = false"
     "disable_file_support = true"
-    "disable_brotli_filter = false"
     "is_component_build = false"
     "use_crash_key_stubs = true"
     "use_partition_alloc = false"
     "include_transport_security_state_preload_list = false"
     "use_platform_icu_alternatives = true"
     "default_min_sdk_version = 19"
-    "use_errorprone_java_compiler = true"
     "enable_reporting = true"
     "use_hashed_jni_names = true"
-    "treat_warnings_as_errors = false"
     "enable_base_tracing = false"
     "is_cronet_build = true"
     "is_debug = false"
     "is_official_build = true"
+    "use_nss_certs = false"
+    "clang_use_default_sample_profile = false"
+    "media_use_ffmpeg=false"
+    "use_thin_lto=false"
+    "enable_resource_allowlist_generation=false"
+    "enable_jdk_library_desugaring=false"
+    "exclude_unwind_tables=true"
+    "symbol_level=1"
   )
   gn_args+=("target_cpu = \"${1}\"")
 
   # Only set arm_use_neon on arm architectures to prevent warning from being
   # written to json output.
-  if [[ "$1" =~ ^arm ]]; then
+  if [[ "$1" = "arm" ]]; then
     gn_args+=("arm_use_neon = false")
   fi
 
diff --git a/tools/gn2bp/gn_utils.py b/tools/gn2bp/gn_utils.py
index 3d709e5..6095455 100644
--- a/tools/gn2bp/gn_utils.py
+++ b/tools/gn2bp/gn_utils.py
@@ -119,6 +119,7 @@
         self.deps = set()
         self.transitive_static_libs_deps = set()
         self.source_set_deps = set()
+        self.ldflags = set()
 
         # These are valid only for type == 'action'
         self.inputs = set()
@@ -207,7 +208,7 @@
                   'libs', 'proto_paths'):
         self.__dict__[key].update(other.__dict__.get(key, []))
 
-      for key_in_arch in ('cflags', 'defines', 'include_dirs', 'source_set_deps'):
+      for key_in_arch in ('cflags', 'defines', 'include_dirs', 'source_set_deps', 'ldflags'):
         self.arch[arch].__dict__[key_in_arch].update(
           other.arch[arch].__dict__.get(key_in_arch, []))
 
@@ -250,7 +251,7 @@
         return
 
       for key in ('sources', 'cflags', 'defines', 'include_dirs', 'deps', 'source_set_deps',
-                  'inputs', 'outputs', 'args', 'script', 'response_file_contents'):
+                  'inputs', 'outputs', 'args', 'script', 'response_file_contents', 'ldflags'):
         self._finalize_attribute(key)
 
 
@@ -392,7 +393,7 @@
 
     target.arch[arch].cflags.update(desc.get('cflags', []) + desc.get('cflags_cc', []))
     target.libs.update(desc.get('libs', []))
-    target.ldflags.update(desc.get('ldflags', []))
+    target.arch[arch].ldflags.update(desc.get('ldflags', []))
     target.arch[arch].defines.update(desc.get('defines', []))
     target.arch[arch].include_dirs.update(desc.get('include_dirs', []))
     target.output_name = desc.get('output_name', None)