Merge "Add not exported flag to receiver in EntitlementManager"
diff --git a/Cronet/Android.bp b/Cronet/Android.bp
new file mode 100644
index 0000000..3ce88ef
--- /dev/null
+++ b/Cronet/Android.bp
@@ -0,0 +1,106 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_import {
+    name: "cronet_impl_native_java",
+    jars: ["prebuilt/cronet_impl_native_java.jar"],
+    visibility: ["//visibility:private"],
+    apex_available: ["com.android.tethering"],
+    min_sdk_version: "29",
+}
+
+java_import {
+    name: "cronet_impl_common_java",
+    jars: ["prebuilt/cronet_impl_common_java.jar"],
+    visibility: ["//visibility:private"],
+    apex_available: ["com.android.tethering"],
+    min_sdk_version: "29",
+}
+
+java_import {
+    name: "cronet_impl_platform_java",
+    jars: ["prebuilt/cronet_impl_platform_java.jar"],
+    visibility: ["//visibility:private"],
+    apex_available: ["com.android.tethering"],
+    min_sdk_version: "29",
+}
+
+cc_prebuilt_library_shared {
+    name: "libcronet.107.0.5284.2",
+    shared_libs: [
+        "libandroid",
+        "libc",
+        "libdl",
+        "liblog",
+        "libm",
+    ],
+    stl: "libc++_static",
+    target: {
+        android_arm64: {
+            srcs: ["prebuilt/libs/arm64-v8a/libcronet.107.0.5284.2.so"],
+        },
+        android_arm: {
+            srcs: ["prebuilt/libs/armeabi-v7a/libcronet.107.0.5284.2.so"],
+        },
+        android_x86_64: {
+            srcs: ["prebuilt/libs/x86_64/libcronet.107.0.5284.2.so"],
+        },
+        android_x86: {
+            srcs: ["prebuilt/libs/x86/libcronet.107.0.5284.2.so"],
+        },
+    },
+    // These are already stripped, and restripping them just issues diagnostics.
+    strip: {
+        none: true,
+    },
+    apex_available: ["com.android.tethering"],
+    min_sdk_version: "29",
+}
+
+genrule {
+    name: "cronet_api-src",
+    srcs: ["prebuilt/cronet_api-src.jar"],
+    cmd: "cp $(in) $(out)",
+    out: [
+        "cronet_api-src.srcjar",
+    ],
+}
+
+java_sdk_library {
+    name: "framework-cronet",
+    defaults: ["framework-module-defaults"],
+    srcs: [
+        ":cronet_api-src",
+    ],
+    libs: [
+        "androidx.annotation_annotation",
+    ],
+    static_libs: [
+        "androidx.core_core-nodeps",
+        "cronet_impl_common_java",
+        "cronet_impl_native_java",
+        "cronet_impl_platform_java",
+    ],
+    apex_available: ["com.android.tethering"],
+    jarjar_rules: "jarjar-rules.txt",
+    unsafe_ignore_missing_latest_api: true,
+    dist_group: "android",
+    // cronet is used as a shared library.
+    shared_library: true,
+    exclude_kotlinc_generated_files: true,
+}
diff --git a/Cronet/AndroidManifest.xml b/Cronet/AndroidManifest.xml
new file mode 100644
index 0000000..f3b3c3e
--- /dev/null
+++ b/Cronet/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="com.android.cronet"
+  android:versionCode="11"
+  android:versionName="R-initial">
+</manifest>
diff --git a/Cronet/OWNERS b/Cronet/OWNERS
new file mode 100644
index 0000000..62c5737
--- /dev/null
+++ b/Cronet/OWNERS
@@ -0,0 +1,2 @@
+set noparent
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
diff --git a/Cronet/TEST_MAPPING b/Cronet/TEST_MAPPING
new file mode 100644
index 0000000..815d496
--- /dev/null
+++ b/Cronet/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "postsubmit": [
+    {
+      "name": "CronetApiTest"
+    }
+  ]
+}
diff --git a/Cronet/apex/Android.bp b/Cronet/apex/Android.bp
new file mode 100644
index 0000000..180dafb
--- /dev/null
+++ b/Cronet/apex/Android.bp
@@ -0,0 +1,59 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+// CronetApexDefaults uses apex_defaults cronet_apex_defaults specifies. cronet_apex_defaults
+// could be "CronetApexDefaultsEnabled" or "CronetApexDefaultsDisabled" depending on the branch.
+cronet_apex_defaults = "CronetApexDefaultsEnabled"
+// This is a placeholder comment to avoid merge conflicts
+// as cronet_apex_defaults may have different values
+// depending on the branch
+
+apex_defaults {
+    name: "CronetApexDefaults",
+    defaults: [cronet_apex_defaults],
+}
+
+apex_defaults {
+    name: "CronetApexDefaultsEnabled",
+    jni_libs: ["libcronet.107.0.5284.2"],
+    java_libs: ["framework-cronet"],
+    arch: {
+        riscv64: {
+            // TODO: remove this when there is a riscv64 libcronet
+            exclude_jni_libs: ["libcronet.107.0.5284.2"],
+        },
+    },
+}
+
+apex_defaults {
+    name: "CronetApexDefaultsDisabled",
+}
+
+// TODO: Remove cronet apex after com.android.cronet is removed from PRODUCT_PACKAGES
+apex {
+    name: "com.android.cronet",
+    key: "com.android.cronet.key",
+    updatable: false,
+    manifest: "manifest.json",
+}
+
+apex_key {
+    name: "com.android.cronet.key",
+    public_key: "com.android.cronet.avbpubkey",
+    private_key: "com.android.cronet.pem",
+}
diff --git a/Cronet/apex/AndroidManifest.xml b/Cronet/apex/AndroidManifest.xml
new file mode 100644
index 0000000..650badc
--- /dev/null
+++ b/Cronet/apex/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="com.android.cronet">
+  <!-- APEX does not have classes.dex -->
+  <application android:hasCode="false" />
+  <uses-sdk
+      android:minSdkVersion="29"
+  />
+</manifest>
diff --git a/Cronet/apex/com.android.cronet.avbpubkey b/Cronet/apex/com.android.cronet.avbpubkey
new file mode 100644
index 0000000..38aebe0
--- /dev/null
+++ b/Cronet/apex/com.android.cronet.avbpubkey
Binary files differ
diff --git a/Cronet/apex/com.android.cronet.pem b/Cronet/apex/com.android.cronet.pem
new file mode 100644
index 0000000..438653f
--- /dev/null
+++ b/Cronet/apex/com.android.cronet.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEAqpxkMMK57w+fzxLcwF+mEQEbKrDFWXYHL697tv8DBu/aL2tM
+LRHiKFdov0Fsnup++bd9oojI+6qyAyJh4I8nvzKc4onM0eXL++0FPZuiTv6a6r7K
+wyn+NVT2X/0yr2Hs5NL1rKXFmJPAfMoRCW9vQdi5xMlM9QN8mNaqSWddKtrQM3yC
+HDLy2zZd7MlQ1UTnmDqGCG0AVtuM34X0v1o0wAL7UwNdzOARtmnuWzcL5vBwAJg8
+eXFZH5Pt5rITxbU+eYw/V+/sUYyI0Anrj4GG+oyWQxgdxz+FwdpSAt14xtw5IDl7
+pTYqEIm+TQKnWe6NzVWfI89s2nh85hgOSgugfpS4symbfbZd4qNSOcHGQTB1ssvf
+vdYGF1WRFA20VEEOMzTMYsvcfModKNVCpibzHu/SYDIJGL0JyJWu2eIE+mrn3lLD
+nwDZ2P39YyVNpritEkbk5qugaLh9mIFqAD4L4niYLu/AtYq+CXzd7yroM2ycleRq
+JRNsCIUx3A/Z5vKx7IJaMb7Pwap3DAe3u3/2L9NCL6oo074Rf7fh5xkDF4Dua3Gg
+kPw+k183jAQECHORstdVlgVZlMxPif4lxQ8uCHJWxyDsgShPgzMtEjJyrJJQyDon
+X8pN4xqb+WX30XNYBK5sp7x6mc8w4rdAGExhUSdmTS0J/lcfar6A6/j/yg8CAwEA
+AQKCAgAiYafTJ7q+kWB8I2n3Ho9hx95IqRzsHVvvYSbGRve+MyG+App0TrFLvemu
++SlBkTILcs3Prk8KYGjFNu2QimjRIAr7oBd1iSClYSt4Md/wmWBwxAgqclD3QGry
+Bx1quIo7xsOZikKar9PPkg0C4MED/P/ax1JJ4ez/A+uHJVxiIXxpk8LImf/U60zc
+RemTQPKG++w80HKMDmyCMwWSdkRBGZi6Luh9O/51yz0shphQbs2zYPp24r+6HF6J
+6gMQCalQZ1Hwj7oI6RA9FHKzFcA0x5YUaUy+9W8oFK4IQ8duE70zYEIplhO+B3Qh
+ItLEzc0nvwR1+/wMvtE0sU5X36X06AFhkcpjyAdmNVMiG91KGrZqruOufrOQu4VE
+njJ5VEUvWOr+6inZDWIdT3NQvwJCZkT4Vvn9WBAoKM8pkpfhY5HTGq4ttX7McHjF
+p7YBFbHRpzO+OfSwM7f/xq2WLcjOKgsFgv17CUo7KQo1rqWPD/4IKJKW5n6dzDwX
+RRF4dehUMYK2UNAbcN9S8O8nJGcJfb76FExjZtGLrhlDgawLmu71bbq5afot/IQ9
+JuB4KxG59t2JAHGNgM7WfFvcL1Zp1D+kzDEHYKYkyDJh3qB7Tw+StlAQFSQjNBX/
+c1I6DUl68rSHOc2LF4oK8ID1oe/URMg2YoaLlF8un2nGZBfwGQKCAQEA20Ie5hBC
+H8W1vTtyI4jOdn/h11RL8UuLN0xtXYunYCzD4+gAEKsAShbhKnvINThZaoxQ2sxy
+9EB+2Ob8R9muYAxR4Eu4tDBWedYmJEl74MflLMFnIrtFIKy4F54zk7J6uNG3cHRo
+yTpoIcmK101xzz1Ed9Dd0XL6rpegnWIuVlWV4slGAf1l3h6pycfx+HCYcCboz6Nq
+JMA0ioKY0fgz5q+mb7IIObN8JjGdLeBQtNh3fcXby08AT/03psKhjgBsbuyTs7s7
+E3n+jxJ3p4xHP/psU3D/HgKWewp48AJNHY8MLY+Kp0KNoQMSQKHKqsiluGTCKLTJ
+sCWg/2c8xf728wKCAQEAxzNdZ54e6WXexMMIsGoH+wVknTHiizuxN4ZqzY/nCM0M
+9heooChfMAFrq8XMC/6MXgiy5rBhl3H12HlG4S6cq3J07MsMR0N+sUFEobuZURB4
++CbEBebmXx1kymC6FrRG4JuKZWbQ8AKpfd28QO7x915safeq6FA8cILJn4oqBGqQ
+Y8TzMKtuaCzQGoBjSgiMpx1fo9Stl7+dpGiPNsnQEG+SEsXxKoZweJPsuK8G+ZgB
+8YARajLwFfgfsCNp/8fXjA98BYM8eSxURa7USUyCmY4hU3WIGG5qc0/C69Fl35ex
+YZG7XQo1DxW/+gWsdUbAFbI4y+iJ8SRpsFxtFYifdQKCAQA5DiW4PHbYibxXN8bl
+1E3VrEV6oSb57WyWwT6cXyD49+0pu095BuaWYQnK4lcg8j7iaQ0JQraPNNFNZB42
+HEEyIUKVGV9BFGsMXVujibPAtIPAd7t84DqG3Csziillv8YLnhccHk6+PoKmeCm3
+CSIaiZjtjN6MCF2PXUmgatIgCTltwG6FSgleGaCZL3yZ58LjPFzM23tdgN6rRHy7
+9tiaqQ6odi2JxlkCH1sFex/FT6cYhYpCh5ZPOldm/7LGnvmYi9uLo6cl1FMXq/iT
+Ev/feC0EMZ1Rk97QudLqsc6baIQEvxuXlswAICp5wyBX/MqTBzU3HoR1X/VbQOQh
+qc1dAoIBACLjNhqtsNBDzS480krDZz5phWOalwi3naQR4Ka760S5VOnM3vWd3H31
+4bul2sTHAiJ994c7oPv7M4mERAuwNDQ6yYunTDE2+vtkaPbCemmeLvGXKIG4HOTP
+qxVet3i+fiNcWnLD/Rfr/29R5GSi9LHUUbyFaeNiGhPCdDmC4zT+zOcMWWNOwvlv
+z8q0ba9LrAaguF1jJDwNjTh8L4jy84PNZpHvJPvDq/MSRUVbMieInd6EBYjJ/w55
+9GLO8QOhJnkbRSdaAr9eKixCIF/uDHmEUQXi8cEFpZMohwTyGZt9X82szlnPLdfE
+gWjykW/AwmeKXTQpN++J5xDCP0CkOvkCggEBAND4wviHue/+bqY9R5EAIDIZn6kx
+VCK9roebvGjq/Az5AM7IiyUQRANv+6CmeIlXCRBMbaAtgQxhvW5UodA1livgVuzR
+ElF7Br3wfikZ34oWY0Qu8fZI0ru4syAoTiGpaUPJJgStYi76dqne15usTRk/MvwP
+tJzqpkWUYcmNv3g/w92Wr1nIJYXlPKrANSSppRg0P/CAPOHkPxLF0RwC5yIZzC5C
+hiTXSE9AwCFllMRKInnbhUdy/L+xUL6mAbGVvD/DHE7Q2xmPSsdEX5nTZkhEnW/L
+TLLgbsy2+8ouvMJCSNaMq77jq7iCIMTogEfA5GX0UO2Kjf4pnjREOzNQg4I=
+-----END RSA PRIVATE KEY-----
diff --git a/Cronet/apex/com.android.cronet.pk8 b/Cronet/apex/com.android.cronet.pk8
new file mode 100644
index 0000000..a63d761
--- /dev/null
+++ b/Cronet/apex/com.android.cronet.pk8
Binary files differ
diff --git a/Cronet/apex/com.android.cronet.x509.pem b/Cronet/apex/com.android.cronet.x509.pem
new file mode 100644
index 0000000..c9cd874
--- /dev/null
+++ b/Cronet/apex/com.android.cronet.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGIzCCBAugAwIBAgIUKEbkVLro9rIJE3M71D8sgUIngUIwDQYJKoZIhvcNAQEL
+BQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMRswGQYDVQQDDBJjb20uYW5kcm9pZC5jcm9uZXQxIjAgBgkqhkiG9w0BCQEW
+E2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMTkxMjA1MDcwOTIxWhgPNDc1NzEwMzEw
+NzA5MjFaMIGfMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG
+A1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwH
+QW5kcm9pZDEbMBkGA1UEAwwSY29tLmFuZHJvaWQuY3JvbmV0MSIwIAYJKoZIhvcN
+AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAwNXIHR2BeZl/R7tOXgC3KK71rrtK98zucfrNBNp/rUiFqiN527P4
+HLW+CAwnFJGLLzHhSbXiZLXyLS7FfPuMeiULUsv1mIVEVwVhtPvbodxwh5szxlVe
+iVf1WkIV90n2tZojTnhMsiEPt0EBWriPJstdO264snqg+oY9Dktxk4tXtTah/rUI
+KWPHeB0SWQMXZTKb30CVVHZfpG/HCXjUlVLx+14/X56EGi8fxd13q5c56qAybx73
+i6+Sm3+F/jcivDpATuPluvcPaZ4Tel9Nz5NjqjycyXBXh8f8azpN1GkJkltE116W
+ZT1iVIJoDAd540UXhW+TpjTeaEH5OeDOWorQM6nE1N9FMiyReprU7tz+HVmyD44Z
+ah43whi3gmwyjgzscW2Z0xGpgVoHgfz/RyBg5+w6p5AGPR0sewv6zr9HvQhpJsoj
+pl+HD9xcrdGb2yMiwm8RuH9dGW0Nos6p1LiXsxg6VBic3N7S+MGXo/dXdX39tkad
+tD+lNskJUJqyx70ynQtRI66YicyxsFv0BImBC+eGECT3hCgyyxnlvTAeRsVsEWtV
+Z+Xwf5M53/8uXkqGal7cC1bHEkG+0zsR8cc0U+22Nif9HQNIrsjEnybOlP6erV/M
+8yX9umVwDz5QlVKCYJFQOq+awSqR9KD9VX3xIRu8kB6aPtB4A7q3828CAwEAAaNT
+MFEwHQYDVR0OBBYEFBQBcdf/bfLa3knW1ukCOFOt++FtMB8GA1UdIwQYMBaAFBQB
+cdf/bfLa3knW1ukCOFOt++FtMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggIBALG0r81xb6NwaGCF79SeDecbnDE1MbQ2+cRt+eU/Wl2SI2oQqbaa/WP7
+k3vsZvsBFI6r+ZBiKizpbT/N1Fx8pcoH7rsL0MoZRXaCZY6kQJLZN6AAvXEo4NR0
+p01zDvGibVk3z87R98IJHlDPU3NrljxxMCsaUxFEAjae4eS4j8G2TFm6DsTVTeqy
+zveh4NdZFsZSyUN8blChFC/7TytlizeSGNlXLMx8e/VAcxIw+wQPWLk5pNnk3TXu
+HcqwAryW/lt46+iVeTpF4ylFqYyab6Vmf9Vp6+HVatg7YkErJACeoeN4eRv6DfeY
+slMqa2i+W+veVAGP4VApg7iZE5RnNPPHn/80yATKAe0/AztoZpQWZ5g1IAnpCISg
+k65FHVhbkcKdjNQePOGwjictq21KaYFrbXfIwqpejxSqQdLMne02Dj/2kv0dU1jV
+JG9YxVWIpobauYD5mmZvN6PTYJWGQRAsIFFyWfhvnEiohGmVLNEQ3uRaue0yNMXc
+V2t8B81/jNGXwi06qxmjCMnMhucSCSFl2a2V5oiDEcVj4YbaJ+CEJPdopMhQwqab
+EgTkJBeEXoPFenToSIprL/YiuBNvvPETyTYN+hAXh3P7MSeWewkgGhpZhuyzT8F0
+vEo+nt5WhRWl0pEVLFLiOOXR+/LAB3aqrPEdd0NXvxiCb/QaZnCp
+-----END CERTIFICATE-----
diff --git a/Cronet/apex/manifest.json b/Cronet/apex/manifest.json
new file mode 100644
index 0000000..0301e9f
--- /dev/null
+++ b/Cronet/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.cronet",
+  "version": 1
+}
diff --git a/Cronet/api/current.txt b/Cronet/api/current.txt
new file mode 100644
index 0000000..21779bc
--- /dev/null
+++ b/Cronet/api/current.txt
@@ -0,0 +1,175 @@
+// Signature format: 2.0
+package org.chromium.net {
+
+  public abstract class CallbackException extends org.chromium.net.CronetException {
+    ctor protected CallbackException(String, Throwable);
+  }
+
+  public abstract class CronetEngine {
+    ctor public CronetEngine();
+    method public abstract java.net.URLStreamHandlerFactory createURLStreamHandlerFactory();
+    method public abstract byte[] getGlobalMetricsDeltas();
+    method public abstract String getVersionString();
+    method public abstract org.chromium.net.UrlRequest.Builder newUrlRequestBuilder(String, org.chromium.net.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();
+    method public abstract void startNetLogToFile(String, boolean);
+    method public abstract void stopNetLog();
+  }
+
+  public static class CronetEngine.Builder {
+    ctor public CronetEngine.Builder(android.content.Context);
+    method public org.chromium.net.CronetEngine.Builder addPublicKeyPins(String, java.util.Set<byte[]>, boolean, java.util.Date);
+    method public org.chromium.net.CronetEngine.Builder addQuicHint(String, int, int);
+    method public org.chromium.net.CronetEngine build();
+    method public org.chromium.net.CronetEngine.Builder enableBrotli(boolean);
+    method public org.chromium.net.CronetEngine.Builder enableHttp2(boolean);
+    method public org.chromium.net.CronetEngine.Builder enableHttpCache(int, long);
+    method public org.chromium.net.CronetEngine.Builder enablePublicKeyPinningBypassForLocalTrustAnchors(boolean);
+    method public org.chromium.net.CronetEngine.Builder enableQuic(boolean);
+    method public String getDefaultUserAgent();
+    method public org.chromium.net.CronetEngine.Builder setLibraryLoader(org.chromium.net.CronetEngine.Builder.LibraryLoader);
+    method public org.chromium.net.CronetEngine.Builder setStoragePath(String);
+    method public org.chromium.net.CronetEngine.Builder setUserAgent(String);
+    field public static final int HTTP_CACHE_DISABLED = 0; // 0x0
+    field public static final int HTTP_CACHE_DISK = 3; // 0x3
+    field public static final int HTTP_CACHE_DISK_NO_HTTP = 2; // 0x2
+    field public static final int HTTP_CACHE_IN_MEMORY = 1; // 0x1
+  }
+
+  public abstract static class CronetEngine.Builder.LibraryLoader {
+    ctor public CronetEngine.Builder.LibraryLoader();
+    method public abstract void loadLibrary(String);
+  }
+
+  public abstract class CronetException extends java.io.IOException {
+    ctor protected CronetException(String, Throwable);
+  }
+
+  public final class InlineExecutionProhibitedException extends java.util.concurrent.RejectedExecutionException {
+    ctor public InlineExecutionProhibitedException();
+  }
+
+  public abstract class NetworkException extends org.chromium.net.CronetException {
+    ctor protected NetworkException(String, Throwable);
+    method public abstract int getCronetInternalErrorCode();
+    method public abstract int getErrorCode();
+    method public abstract boolean immediatelyRetryable();
+    field public static final int ERROR_ADDRESS_UNREACHABLE = 9; // 0x9
+    field public static final int ERROR_CONNECTION_CLOSED = 5; // 0x5
+    field public static final int ERROR_CONNECTION_REFUSED = 7; // 0x7
+    field public static final int ERROR_CONNECTION_RESET = 8; // 0x8
+    field public static final int ERROR_CONNECTION_TIMED_OUT = 6; // 0x6
+    field public static final int ERROR_HOSTNAME_NOT_RESOLVED = 1; // 0x1
+    field public static final int ERROR_INTERNET_DISCONNECTED = 2; // 0x2
+    field public static final int ERROR_NETWORK_CHANGED = 3; // 0x3
+    field public static final int ERROR_OTHER = 11; // 0xb
+    field public static final int ERROR_QUIC_PROTOCOL_FAILED = 10; // 0xa
+    field public static final int ERROR_TIMED_OUT = 4; // 0x4
+  }
+
+  public abstract class QuicException extends org.chromium.net.NetworkException {
+    ctor protected QuicException(String, Throwable);
+    method public abstract int getQuicDetailedErrorCode();
+  }
+
+  public abstract class UploadDataProvider implements java.io.Closeable {
+    ctor public UploadDataProvider();
+    method public void close() throws java.io.IOException;
+    method public abstract long getLength() throws java.io.IOException;
+    method public abstract void read(org.chromium.net.UploadDataSink, java.nio.ByteBuffer) throws java.io.IOException;
+    method public abstract void rewind(org.chromium.net.UploadDataSink) throws java.io.IOException;
+  }
+
+  public final class UploadDataProviders {
+    method public static org.chromium.net.UploadDataProvider create(java.io.File);
+    method public static org.chromium.net.UploadDataProvider create(android.os.ParcelFileDescriptor);
+    method public static org.chromium.net.UploadDataProvider create(java.nio.ByteBuffer);
+    method public static org.chromium.net.UploadDataProvider create(byte[], int, int);
+    method public static org.chromium.net.UploadDataProvider create(byte[]);
+  }
+
+  public abstract class UploadDataSink {
+    ctor public UploadDataSink();
+    method public abstract void onReadError(Exception);
+    method public abstract void onReadSucceeded(boolean);
+    method public abstract void onRewindError(Exception);
+    method public abstract void onRewindSucceeded();
+  }
+
+  public abstract class UrlRequest {
+    ctor public UrlRequest();
+    method public abstract void cancel();
+    method public abstract void followRedirect();
+    method public abstract void getStatus(org.chromium.net.UrlRequest.StatusListener);
+    method public abstract boolean isDone();
+    method public abstract void read(java.nio.ByteBuffer);
+    method public abstract void start();
+  }
+
+  public abstract static class UrlRequest.Builder {
+    ctor public UrlRequest.Builder();
+    method public abstract org.chromium.net.UrlRequest.Builder addHeader(String, String);
+    method public abstract org.chromium.net.UrlRequest.Builder allowDirectExecutor();
+    method public abstract org.chromium.net.UrlRequest build();
+    method public abstract org.chromium.net.UrlRequest.Builder disableCache();
+    method public abstract org.chromium.net.UrlRequest.Builder setHttpMethod(String);
+    method public abstract org.chromium.net.UrlRequest.Builder setPriority(int);
+    method public abstract org.chromium.net.UrlRequest.Builder setUploadDataProvider(org.chromium.net.UploadDataProvider, java.util.concurrent.Executor);
+    field public static final int REQUEST_PRIORITY_HIGHEST = 4; // 0x4
+    field public static final int REQUEST_PRIORITY_IDLE = 0; // 0x0
+    field public static final int REQUEST_PRIORITY_LOW = 2; // 0x2
+    field public static final int REQUEST_PRIORITY_LOWEST = 1; // 0x1
+    field public static final int REQUEST_PRIORITY_MEDIUM = 3; // 0x3
+  }
+
+  public abstract static class UrlRequest.Callback {
+    ctor public UrlRequest.Callback();
+    method public void onCanceled(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo);
+    method public abstract void onFailed(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, org.chromium.net.CronetException);
+    method public abstract void onReadCompleted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, java.nio.ByteBuffer) throws java.lang.Exception;
+    method public abstract void onRedirectReceived(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, String) throws java.lang.Exception;
+    method public abstract void onResponseStarted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo) throws java.lang.Exception;
+    method public abstract void onSucceeded(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo);
+  }
+
+  public static class UrlRequest.Status {
+    field public static final int CONNECTING = 10; // 0xa
+    field public static final int DOWNLOADING_PAC_FILE = 5; // 0x5
+    field public static final int ESTABLISHING_PROXY_TUNNEL = 8; // 0x8
+    field public static final int IDLE = 0; // 0x0
+    field public static final int INVALID = -1; // 0xffffffff
+    field public static final int READING_RESPONSE = 14; // 0xe
+    field public static final int RESOLVING_HOST = 9; // 0x9
+    field public static final int RESOLVING_HOST_IN_PAC_FILE = 7; // 0x7
+    field public static final int RESOLVING_PROXY_FOR_URL = 6; // 0x6
+    field public static final int SENDING_REQUEST = 12; // 0xc
+    field public static final int SSL_HANDSHAKE = 11; // 0xb
+    field public static final int WAITING_FOR_AVAILABLE_SOCKET = 2; // 0x2
+    field public static final int WAITING_FOR_CACHE = 4; // 0x4
+    field public static final int WAITING_FOR_DELEGATE = 3; // 0x3
+    field public static final int WAITING_FOR_RESPONSE = 13; // 0xd
+    field public static final int WAITING_FOR_STALLED_SOCKET_POOL = 1; // 0x1
+  }
+
+  public abstract static class UrlRequest.StatusListener {
+    ctor public UrlRequest.StatusListener();
+    method public abstract void onStatus(int);
+  }
+
+  public abstract class UrlResponseInfo {
+    ctor public UrlResponseInfo();
+    method public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> getAllHeaders();
+    method public abstract java.util.List<java.util.Map.Entry<java.lang.String,java.lang.String>> getAllHeadersAsList();
+    method public abstract int getHttpStatusCode();
+    method public abstract String getHttpStatusText();
+    method public abstract String getNegotiatedProtocol();
+    method public abstract String getProxyServer();
+    method public abstract long getReceivedByteCount();
+    method public abstract String getUrl();
+    method public abstract java.util.List<java.lang.String> getUrlChain();
+    method public abstract boolean wasCached();
+  }
+
+}
+
diff --git a/Cronet/api/lint-baseline.txt b/Cronet/api/lint-baseline.txt
new file mode 100644
index 0000000..0e2f25b
--- /dev/null
+++ b/Cronet/api/lint-baseline.txt
@@ -0,0 +1,263 @@
+// Baseline format: 1.0
+AcronymName: org.chromium.net.CronetEngine#createURLStreamHandlerFactory():
+    Acronyms should not be capitalized in method names: was `createURLStreamHandlerFactory`, should this be `createUrlStreamHandlerFactory`?
+
+
+AndroidUri: org.chromium.net.CronetEngine#createURLStreamHandlerFactory():
+    Use android.net.Uri instead of java.net.URL (method org.chromium.net.CronetEngine.createURLStreamHandlerFactory())
+AndroidUri: org.chromium.net.CronetEngine#openConnection(java.net.URL):
+    Use android.net.Uri instead of java.net.URL (method org.chromium.net.CronetEngine.openConnection(java.net.URL))
+AndroidUri: org.chromium.net.CronetEngine#openConnection(java.net.URL) parameter #0:
+    Use android.net.Uri instead of java.net.URL (parameter url in org.chromium.net.CronetEngine.openConnection(java.net.URL url))
+
+
+BuilderSetStyle: org.chromium.net.CronetEngine.Builder#enableBrotli(boolean):
+    Builder methods names should use setFoo() / addFoo() / clearFoo() style: method org.chromium.net.CronetEngine.Builder.enableBrotli(boolean)
+BuilderSetStyle: org.chromium.net.CronetEngine.Builder#enableHttp2(boolean):
+    Builder methods names should use setFoo() / addFoo() / clearFoo() style: method org.chromium.net.CronetEngine.Builder.enableHttp2(boolean)
+BuilderSetStyle: org.chromium.net.CronetEngine.Builder#enableHttpCache(int, long):
+    Builder methods names should use setFoo() / addFoo() / clearFoo() style: method org.chromium.net.CronetEngine.Builder.enableHttpCache(int,long)
+BuilderSetStyle: org.chromium.net.CronetEngine.Builder#enablePublicKeyPinningBypassForLocalTrustAnchors(boolean):
+    Builder methods names should use setFoo() / addFoo() / clearFoo() style: method org.chromium.net.CronetEngine.Builder.enablePublicKeyPinningBypassForLocalTrustAnchors(boolean)
+BuilderSetStyle: org.chromium.net.CronetEngine.Builder#enableQuic(boolean):
+    Builder methods names should use setFoo() / addFoo() / clearFoo() style: method org.chromium.net.CronetEngine.Builder.enableQuic(boolean)
+BuilderSetStyle: org.chromium.net.UrlRequest.Builder#allowDirectExecutor():
+    Builder methods names should use setFoo() / addFoo() / clearFoo() style: method org.chromium.net.UrlRequest.Builder.allowDirectExecutor()
+BuilderSetStyle: org.chromium.net.UrlRequest.Builder#disableCache():
+    Builder methods names should use setFoo() / addFoo() / clearFoo() style: method org.chromium.net.UrlRequest.Builder.disableCache()
+
+
+ExecutorRegistration: org.chromium.net.UrlRequest#getStatus(org.chromium.net.UrlRequest.StatusListener):
+    Registration methods should have overload that accepts delivery Executor: `getStatus`
+
+
+GenericException: org.chromium.net.UrlRequest.Callback#onReadCompleted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, java.nio.ByteBuffer):
+    Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: org.chromium.net.UrlRequest.Callback#onRedirectReceived(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, String):
+    Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: org.chromium.net.UrlRequest.Callback#onResponseStarted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo):
+    Methods must not throw generic exceptions (`java.lang.Exception`)
+
+
+GetterOnBuilder: org.chromium.net.CronetEngine.Builder#getDefaultUserAgent():
+    Getter should be on the built object, not the builder: method org.chromium.net.CronetEngine.Builder.getDefaultUserAgent()
+
+
+ListenerInterface: org.chromium.net.UrlRequest.StatusListener:
+    Listeners should be an interface, or otherwise renamed Callback: StatusListener
+
+
+ListenerLast: org.chromium.net.CronetEngine#newUrlRequestBuilder(String, org.chromium.net.UrlRequest.Callback, java.util.concurrent.Executor) parameter #2:
+    Listeners should always be at end of argument list (method `newUrlRequestBuilder`)
+
+
+MissingGetterMatchingBuilder: org.chromium.net.CronetEngine.Builder#addPublicKeyPins(String, java.util.Set<byte[]>, boolean, java.util.Date):
+    org.chromium.net.CronetEngine does not declare a `getPublicKeyPinss()` method matching method org.chromium.net.CronetEngine.Builder.addPublicKeyPins(String,java.util.Set<byte[]>,boolean,java.util.Date)
+MissingGetterMatchingBuilder: org.chromium.net.CronetEngine.Builder#addQuicHint(String, int, int):
+    org.chromium.net.CronetEngine does not declare a `getQuicHints()` method matching method org.chromium.net.CronetEngine.Builder.addQuicHint(String,int,int)
+MissingGetterMatchingBuilder: org.chromium.net.CronetEngine.Builder#setLibraryLoader(org.chromium.net.CronetEngine.Builder.LibraryLoader):
+    org.chromium.net.CronetEngine does not declare a `getLibraryLoader()` method matching method org.chromium.net.CronetEngine.Builder.setLibraryLoader(org.chromium.net.CronetEngine.Builder.LibraryLoader)
+MissingGetterMatchingBuilder: org.chromium.net.CronetEngine.Builder#setStoragePath(String):
+    org.chromium.net.CronetEngine does not declare a `getStoragePath()` method matching method org.chromium.net.CronetEngine.Builder.setStoragePath(String)
+MissingGetterMatchingBuilder: org.chromium.net.CronetEngine.Builder#setUserAgent(String):
+    org.chromium.net.CronetEngine does not declare a `getUserAgent()` method matching method org.chromium.net.CronetEngine.Builder.setUserAgent(String)
+MissingGetterMatchingBuilder: org.chromium.net.UrlRequest.Builder#addHeader(String, String):
+    org.chromium.net.UrlRequest does not declare a `getHeaders()` method matching method org.chromium.net.UrlRequest.Builder.addHeader(String,String)
+MissingGetterMatchingBuilder: org.chromium.net.UrlRequest.Builder#setHttpMethod(String):
+    org.chromium.net.UrlRequest does not declare a `getHttpMethod()` method matching method org.chromium.net.UrlRequest.Builder.setHttpMethod(String)
+MissingGetterMatchingBuilder: org.chromium.net.UrlRequest.Builder#setPriority(int):
+    org.chromium.net.UrlRequest does not declare a `getPriority()` method matching method org.chromium.net.UrlRequest.Builder.setPriority(int)
+MissingGetterMatchingBuilder: org.chromium.net.UrlRequest.Builder#setUploadDataProvider(org.chromium.net.UploadDataProvider, java.util.concurrent.Executor):
+    org.chromium.net.UrlRequest does not declare a `getUploadDataProvider()` method matching method org.chromium.net.UrlRequest.Builder.setUploadDataProvider(org.chromium.net.UploadDataProvider,java.util.concurrent.Executor)
+
+
+MissingNullability: org.chromium.net.CallbackException#CallbackException(String, Throwable) parameter #0:
+    Missing nullability on parameter `message` in method `CallbackException`
+MissingNullability: org.chromium.net.CallbackException#CallbackException(String, Throwable) parameter #1:
+    Missing nullability on parameter `cause` in method `CallbackException`
+MissingNullability: org.chromium.net.CronetEngine#createURLStreamHandlerFactory():
+    Missing nullability on method `createURLStreamHandlerFactory` return
+MissingNullability: org.chromium.net.CronetEngine#getGlobalMetricsDeltas():
+    Missing nullability on method `getGlobalMetricsDeltas` return
+MissingNullability: org.chromium.net.CronetEngine#getVersionString():
+    Missing nullability on method `getVersionString` return
+MissingNullability: org.chromium.net.CronetEngine#newUrlRequestBuilder(String, org.chromium.net.UrlRequest.Callback, java.util.concurrent.Executor):
+    Missing nullability on method `newUrlRequestBuilder` return
+MissingNullability: org.chromium.net.CronetEngine#newUrlRequestBuilder(String, org.chromium.net.UrlRequest.Callback, java.util.concurrent.Executor) parameter #0:
+    Missing nullability on parameter `url` in method `newUrlRequestBuilder`
+MissingNullability: org.chromium.net.CronetEngine#newUrlRequestBuilder(String, org.chromium.net.UrlRequest.Callback, java.util.concurrent.Executor) parameter #1:
+    Missing nullability on parameter `callback` in method `newUrlRequestBuilder`
+MissingNullability: org.chromium.net.CronetEngine#newUrlRequestBuilder(String, org.chromium.net.UrlRequest.Callback, java.util.concurrent.Executor) parameter #2:
+    Missing nullability on parameter `executor` in method `newUrlRequestBuilder`
+MissingNullability: org.chromium.net.CronetEngine#openConnection(java.net.URL):
+    Missing nullability on method `openConnection` return
+MissingNullability: org.chromium.net.CronetEngine#openConnection(java.net.URL) parameter #0:
+    Missing nullability on parameter `url` in method `openConnection`
+MissingNullability: org.chromium.net.CronetEngine#startNetLogToFile(String, boolean) parameter #0:
+    Missing nullability on parameter `fileName` in method `startNetLogToFile`
+MissingNullability: org.chromium.net.CronetEngine.Builder#Builder(android.content.Context) parameter #0:
+    Missing nullability on parameter `context` in method `Builder`
+MissingNullability: org.chromium.net.CronetEngine.Builder#addPublicKeyPins(String, java.util.Set<byte[]>, boolean, java.util.Date):
+    Missing nullability on method `addPublicKeyPins` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#addPublicKeyPins(String, java.util.Set<byte[]>, boolean, java.util.Date) parameter #0:
+    Missing nullability on parameter `hostName` in method `addPublicKeyPins`
+MissingNullability: org.chromium.net.CronetEngine.Builder#addPublicKeyPins(String, java.util.Set<byte[]>, boolean, java.util.Date) parameter #1:
+    Missing nullability on parameter `pinsSha256` in method `addPublicKeyPins`
+MissingNullability: org.chromium.net.CronetEngine.Builder#addPublicKeyPins(String, java.util.Set<byte[]>, boolean, java.util.Date) parameter #3:
+    Missing nullability on parameter `expirationDate` in method `addPublicKeyPins`
+MissingNullability: org.chromium.net.CronetEngine.Builder#addQuicHint(String, int, int):
+    Missing nullability on method `addQuicHint` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#addQuicHint(String, int, int) parameter #0:
+    Missing nullability on parameter `host` in method `addQuicHint`
+MissingNullability: org.chromium.net.CronetEngine.Builder#build():
+    Missing nullability on method `build` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#enableBrotli(boolean):
+    Missing nullability on method `enableBrotli` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#enableHttp2(boolean):
+    Missing nullability on method `enableHttp2` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#enableHttpCache(int, long):
+    Missing nullability on method `enableHttpCache` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#enablePublicKeyPinningBypassForLocalTrustAnchors(boolean):
+    Missing nullability on method `enablePublicKeyPinningBypassForLocalTrustAnchors` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#enableQuic(boolean):
+    Missing nullability on method `enableQuic` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#getDefaultUserAgent():
+    Missing nullability on method `getDefaultUserAgent` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#setLibraryLoader(org.chromium.net.CronetEngine.Builder.LibraryLoader):
+    Missing nullability on method `setLibraryLoader` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#setLibraryLoader(org.chromium.net.CronetEngine.Builder.LibraryLoader) parameter #0:
+    Missing nullability on parameter `loader` in method `setLibraryLoader`
+MissingNullability: org.chromium.net.CronetEngine.Builder#setStoragePath(String):
+    Missing nullability on method `setStoragePath` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#setStoragePath(String) parameter #0:
+    Missing nullability on parameter `value` in method `setStoragePath`
+MissingNullability: org.chromium.net.CronetEngine.Builder#setUserAgent(String):
+    Missing nullability on method `setUserAgent` return
+MissingNullability: org.chromium.net.CronetEngine.Builder#setUserAgent(String) parameter #0:
+    Missing nullability on parameter `userAgent` in method `setUserAgent`
+MissingNullability: org.chromium.net.CronetEngine.Builder.LibraryLoader#loadLibrary(String) parameter #0:
+    Missing nullability on parameter `libName` in method `loadLibrary`
+MissingNullability: org.chromium.net.CronetException#CronetException(String, Throwable) parameter #0:
+    Missing nullability on parameter `message` in method `CronetException`
+MissingNullability: org.chromium.net.CronetException#CronetException(String, Throwable) parameter #1:
+    Missing nullability on parameter `cause` in method `CronetException`
+MissingNullability: org.chromium.net.NetworkException#NetworkException(String, Throwable) parameter #0:
+    Missing nullability on parameter `message` in method `NetworkException`
+MissingNullability: org.chromium.net.NetworkException#NetworkException(String, Throwable) parameter #1:
+    Missing nullability on parameter `cause` in method `NetworkException`
+MissingNullability: org.chromium.net.QuicException#QuicException(String, Throwable) parameter #0:
+    Missing nullability on parameter `message` in method `QuicException`
+MissingNullability: org.chromium.net.QuicException#QuicException(String, Throwable) parameter #1:
+    Missing nullability on parameter `cause` in method `QuicException`
+MissingNullability: org.chromium.net.UploadDataProvider#read(org.chromium.net.UploadDataSink, java.nio.ByteBuffer) parameter #0:
+    Missing nullability on parameter `uploadDataSink` in method `read`
+MissingNullability: org.chromium.net.UploadDataProvider#read(org.chromium.net.UploadDataSink, java.nio.ByteBuffer) parameter #1:
+    Missing nullability on parameter `byteBuffer` in method `read`
+MissingNullability: org.chromium.net.UploadDataProvider#rewind(org.chromium.net.UploadDataSink) parameter #0:
+    Missing nullability on parameter `uploadDataSink` in method `rewind`
+MissingNullability: org.chromium.net.UploadDataProviders#create(android.os.ParcelFileDescriptor):
+    Missing nullability on method `create` return
+MissingNullability: org.chromium.net.UploadDataProviders#create(android.os.ParcelFileDescriptor) parameter #0:
+    Missing nullability on parameter `fd` in method `create`
+MissingNullability: org.chromium.net.UploadDataProviders#create(byte[]):
+    Missing nullability on method `create` return
+MissingNullability: org.chromium.net.UploadDataProviders#create(byte[]) parameter #0:
+    Missing nullability on parameter `data` in method `create`
+MissingNullability: org.chromium.net.UploadDataProviders#create(byte[], int, int):
+    Missing nullability on method `create` return
+MissingNullability: org.chromium.net.UploadDataProviders#create(byte[], int, int) parameter #0:
+    Missing nullability on parameter `data` in method `create`
+MissingNullability: org.chromium.net.UploadDataProviders#create(java.io.File):
+    Missing nullability on method `create` return
+MissingNullability: org.chromium.net.UploadDataProviders#create(java.io.File) parameter #0:
+    Missing nullability on parameter `file` in method `create`
+MissingNullability: org.chromium.net.UploadDataProviders#create(java.nio.ByteBuffer):
+    Missing nullability on method `create` return
+MissingNullability: org.chromium.net.UploadDataProviders#create(java.nio.ByteBuffer) parameter #0:
+    Missing nullability on parameter `buffer` in method `create`
+MissingNullability: org.chromium.net.UploadDataSink#onReadError(Exception) parameter #0:
+    Missing nullability on parameter `exception` in method `onReadError`
+MissingNullability: org.chromium.net.UploadDataSink#onRewindError(Exception) parameter #0:
+    Missing nullability on parameter `exception` in method `onRewindError`
+MissingNullability: org.chromium.net.UrlRequest#getStatus(org.chromium.net.UrlRequest.StatusListener) parameter #0:
+    Missing nullability on parameter `listener` in method `getStatus`
+MissingNullability: org.chromium.net.UrlRequest#read(java.nio.ByteBuffer) parameter #0:
+    Missing nullability on parameter `buffer` in method `read`
+MissingNullability: org.chromium.net.UrlRequest.Builder#addHeader(String, String):
+    Missing nullability on method `addHeader` return
+MissingNullability: org.chromium.net.UrlRequest.Builder#addHeader(String, String) parameter #0:
+    Missing nullability on parameter `header` in method `addHeader`
+MissingNullability: org.chromium.net.UrlRequest.Builder#addHeader(String, String) parameter #1:
+    Missing nullability on parameter `value` in method `addHeader`
+MissingNullability: org.chromium.net.UrlRequest.Builder#allowDirectExecutor():
+    Missing nullability on method `allowDirectExecutor` return
+MissingNullability: org.chromium.net.UrlRequest.Builder#build():
+    Missing nullability on method `build` return
+MissingNullability: org.chromium.net.UrlRequest.Builder#disableCache():
+    Missing nullability on method `disableCache` return
+MissingNullability: org.chromium.net.UrlRequest.Builder#setHttpMethod(String):
+    Missing nullability on method `setHttpMethod` return
+MissingNullability: org.chromium.net.UrlRequest.Builder#setHttpMethod(String) parameter #0:
+    Missing nullability on parameter `method` in method `setHttpMethod`
+MissingNullability: org.chromium.net.UrlRequest.Builder#setPriority(int):
+    Missing nullability on method `setPriority` return
+MissingNullability: org.chromium.net.UrlRequest.Builder#setUploadDataProvider(org.chromium.net.UploadDataProvider, java.util.concurrent.Executor):
+    Missing nullability on method `setUploadDataProvider` return
+MissingNullability: org.chromium.net.UrlRequest.Builder#setUploadDataProvider(org.chromium.net.UploadDataProvider, java.util.concurrent.Executor) parameter #0:
+    Missing nullability on parameter `uploadDataProvider` in method `setUploadDataProvider`
+MissingNullability: org.chromium.net.UrlRequest.Builder#setUploadDataProvider(org.chromium.net.UploadDataProvider, java.util.concurrent.Executor) parameter #1:
+    Missing nullability on parameter `executor` in method `setUploadDataProvider`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onCanceled(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo) parameter #0:
+    Missing nullability on parameter `request` in method `onCanceled`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onCanceled(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo) parameter #1:
+    Missing nullability on parameter `info` in method `onCanceled`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onFailed(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, org.chromium.net.CronetException) parameter #0:
+    Missing nullability on parameter `request` in method `onFailed`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onFailed(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, org.chromium.net.CronetException) parameter #1:
+    Missing nullability on parameter `info` in method `onFailed`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onFailed(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, org.chromium.net.CronetException) parameter #2:
+    Missing nullability on parameter `error` in method `onFailed`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onReadCompleted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, java.nio.ByteBuffer) parameter #0:
+    Missing nullability on parameter `request` in method `onReadCompleted`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onReadCompleted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, java.nio.ByteBuffer) parameter #1:
+    Missing nullability on parameter `info` in method `onReadCompleted`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onReadCompleted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, java.nio.ByteBuffer) parameter #2:
+    Missing nullability on parameter `byteBuffer` in method `onReadCompleted`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onRedirectReceived(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, String) parameter #0:
+    Missing nullability on parameter `request` in method `onRedirectReceived`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onRedirectReceived(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, String) parameter #1:
+    Missing nullability on parameter `info` in method `onRedirectReceived`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onRedirectReceived(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, String) parameter #2:
+    Missing nullability on parameter `newLocationUrl` in method `onRedirectReceived`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onResponseStarted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo) parameter #0:
+    Missing nullability on parameter `request` in method `onResponseStarted`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onResponseStarted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo) parameter #1:
+    Missing nullability on parameter `info` in method `onResponseStarted`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onSucceeded(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo) parameter #0:
+    Missing nullability on parameter `request` in method `onSucceeded`
+MissingNullability: org.chromium.net.UrlRequest.Callback#onSucceeded(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo) parameter #1:
+    Missing nullability on parameter `info` in method `onSucceeded`
+MissingNullability: org.chromium.net.UrlResponseInfo#getAllHeaders():
+    Missing nullability on method `getAllHeaders` return
+MissingNullability: org.chromium.net.UrlResponseInfo#getAllHeadersAsList():
+    Missing nullability on method `getAllHeadersAsList` return
+MissingNullability: org.chromium.net.UrlResponseInfo#getHttpStatusText():
+    Missing nullability on method `getHttpStatusText` return
+MissingNullability: org.chromium.net.UrlResponseInfo#getNegotiatedProtocol():
+    Missing nullability on method `getNegotiatedProtocol` return
+MissingNullability: org.chromium.net.UrlResponseInfo#getProxyServer():
+    Missing nullability on method `getProxyServer` return
+MissingNullability: org.chromium.net.UrlResponseInfo#getUrl():
+    Missing nullability on method `getUrl` return
+MissingNullability: org.chromium.net.UrlResponseInfo#getUrlChain():
+    Missing nullability on method `getUrlChain` return
+
+
+NotCloseable: org.chromium.net.CronetEngine:
+    Classes that release resources (shutdown()) should implement AutoClosable and CloseGuard: class org.chromium.net.CronetEngine
+
+
+StaticFinalBuilder: org.chromium.net.CronetEngine.Builder:
+    Builder must be final: org.chromium.net.CronetEngine.Builder
+StaticFinalBuilder: org.chromium.net.UrlRequest.Builder:
+    Builder must be final: org.chromium.net.UrlRequest.Builder
diff --git a/Cronet/api/module-lib-current.txt b/Cronet/api/module-lib-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/Cronet/api/module-lib-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/Cronet/api/module-lib-removed.txt b/Cronet/api/module-lib-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/Cronet/api/module-lib-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/Cronet/api/removed.txt b/Cronet/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/Cronet/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/Cronet/api/system-current.txt b/Cronet/api/system-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/Cronet/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/Cronet/api/system-removed.txt b/Cronet/api/system-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/Cronet/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/Cronet/api/test-current.txt b/Cronet/api/test-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/Cronet/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/Cronet/api/test-removed.txt b/Cronet/api/test-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/Cronet/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/Cronet/jarjar-rules.txt b/Cronet/jarjar-rules.txt
new file mode 100644
index 0000000..7111ebc
--- /dev/null
+++ b/Cronet/jarjar-rules.txt
@@ -0,0 +1,3 @@
+rule androidx.** com.android.cronet.@0
+rule android.support.** com.android.cronet.@0
+
diff --git a/Cronet/prebuilt/VERSION b/Cronet/prebuilt/VERSION
new file mode 100644
index 0000000..c16ab94
--- /dev/null
+++ b/Cronet/prebuilt/VERSION
@@ -0,0 +1,4 @@
+MAJOR=80
+MINOR=0
+BUILD=3986
+PATCH=0
diff --git a/Cronet/prebuilt/api_version.txt b/Cronet/prebuilt/api_version.txt
new file mode 100644
index 0000000..48082f7
--- /dev/null
+++ b/Cronet/prebuilt/api_version.txt
@@ -0,0 +1 @@
+12
diff --git a/Cronet/prebuilt/cronet_api-src.jar b/Cronet/prebuilt/cronet_api-src.jar
new file mode 100644
index 0000000..924b877
--- /dev/null
+++ b/Cronet/prebuilt/cronet_api-src.jar
Binary files differ
diff --git a/Cronet/prebuilt/cronet_api.jar b/Cronet/prebuilt/cronet_api.jar
new file mode 100644
index 0000000..977b28d
--- /dev/null
+++ b/Cronet/prebuilt/cronet_api.jar
Binary files differ
diff --git a/Cronet/prebuilt/cronet_impl_common_java.jar b/Cronet/prebuilt/cronet_impl_common_java.jar
new file mode 100644
index 0000000..fa71bf3
--- /dev/null
+++ b/Cronet/prebuilt/cronet_impl_common_java.jar
Binary files differ
diff --git a/Cronet/prebuilt/cronet_impl_native_java.jar b/Cronet/prebuilt/cronet_impl_native_java.jar
new file mode 100644
index 0000000..4cdd6f3
--- /dev/null
+++ b/Cronet/prebuilt/cronet_impl_native_java.jar
Binary files differ
diff --git a/Cronet/prebuilt/cronet_impl_platform_java.jar b/Cronet/prebuilt/cronet_impl_platform_java.jar
new file mode 100644
index 0000000..6d6042f
--- /dev/null
+++ b/Cronet/prebuilt/cronet_impl_platform_java.jar
Binary files differ
diff --git a/Cronet/prebuilt/libs/arm64-v8a/libcronet.107.0.5284.2.so b/Cronet/prebuilt/libs/arm64-v8a/libcronet.107.0.5284.2.so
new file mode 100644
index 0000000..7f2540a
--- /dev/null
+++ b/Cronet/prebuilt/libs/arm64-v8a/libcronet.107.0.5284.2.so
Binary files differ
diff --git a/Cronet/prebuilt/libs/armeabi-v7a/libcronet.107.0.5284.2.so b/Cronet/prebuilt/libs/armeabi-v7a/libcronet.107.0.5284.2.so
new file mode 100644
index 0000000..115429a
--- /dev/null
+++ b/Cronet/prebuilt/libs/armeabi-v7a/libcronet.107.0.5284.2.so
Binary files differ
diff --git a/Cronet/prebuilt/libs/x86/libcronet.107.0.5284.2.so b/Cronet/prebuilt/libs/x86/libcronet.107.0.5284.2.so
new file mode 100644
index 0000000..27923f7
--- /dev/null
+++ b/Cronet/prebuilt/libs/x86/libcronet.107.0.5284.2.so
Binary files differ
diff --git a/Cronet/prebuilt/libs/x86_64/libcronet.107.0.5284.2.so b/Cronet/prebuilt/libs/x86_64/libcronet.107.0.5284.2.so
new file mode 100644
index 0000000..803e5cd
--- /dev/null
+++ b/Cronet/prebuilt/libs/x86_64/libcronet.107.0.5284.2.so
Binary files differ
diff --git a/Cronet/tests/apitest/Android.bp b/Cronet/tests/apitest/Android.bp
new file mode 100644
index 0000000..e71c707
--- /dev/null
+++ b/Cronet/tests/apitest/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+    name: "CronetApiCommonTests",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.core_core",
+        "junit",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "android.test.mock",
+        "androidx.annotation_annotation",
+        "framework-cronet",
+    ],
+}
+
+android_test {
+    name: "CronetApiTest",
+    sdk_version: "test_current",
+    test_suites: ["device-tests"],
+    certificate: "platform",
+    static_libs: [
+        "CronetApiCommonTests",
+    ],
+}
diff --git a/Cronet/tests/apitest/AndroidManifest.xml b/Cronet/tests/apitest/AndroidManifest.xml
new file mode 100644
index 0000000..db0f0b3
--- /dev/null
+++ b/Cronet/tests/apitest/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="org.chromium.net.test">
+
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="framework-cronet" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="org.chromium.net.test"
+        android:label="Cronet API Networking Tests" />
+</manifest>
\ No newline at end of file
diff --git a/Cronet/tests/apitest/src/org/chromium/net/test/CronetApiTest.java b/Cronet/tests/apitest/src/org/chromium/net/test/CronetApiTest.java
new file mode 100644
index 0000000..86f2173
--- /dev/null
+++ b/Cronet/tests/apitest/src/org/chromium/net/test/CronetApiTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.chromium.net.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.os.Handler;
+import android.os.Looper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.Random;
+
+import org.chromium.net.CronetEngine;
+import org.chromium.net.CronetException;
+import org.chromium.net.UrlRequest;
+import org.chromium.net.UrlResponseInfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CronetApiTest {
+    private static final String TAG = CronetApiTest.class.getSimpleName();
+    static final String HTTPS_PREFIX = "https://";
+    static final int TIMEOUT_MS = 12_000;
+
+    private final String[] mTestDomains = {"www.google.com", "www.android.com"};
+    @NonNull
+    private CronetEngine mCronetEngine;
+    @NonNull
+    private ConnectivityManager mCm;
+    @NonNull
+    private Executor mExecutor;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        CronetEngine.Builder builder = new CronetEngine.Builder(context);
+        builder.enableHttpCache(CronetEngine.Builder.HTTP_CACHE_IN_MEMORY, 100 * 1024)
+                .enableHttp2(true)
+                //.enableBrotli(true)
+                .enableQuic(true);
+        mCronetEngine = builder.build();
+        mExecutor = new Handler(Looper.getMainLooper())::post;
+    }
+
+    static private void assertGreaterThan(String msg, int first, int second) {
+        assertTrue(msg + " Excepted " + first + " to be greater than " + second, first > second);
+    }
+
+    private void assertHasTestableNetworks() {
+        assertNotNull("This test requires a working Internet connection",
+            mCm.getActiveNetwork());
+    }
+
+    private String getRandomDomain() {
+        int index = (new Random()).nextInt(mTestDomains.length);
+        return mTestDomains[index];
+    }
+
+    class VerifyUrlRequestCallback extends UrlRequest.Callback {
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+        private final String mUrl;
+
+        VerifyUrlRequestCallback(@NonNull String url) {
+            this.mUrl = url;
+        }
+
+        public boolean waitForAnswer() throws InterruptedException {
+            return mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        }
+
+        @Override
+        public void onRedirectReceived(
+                UrlRequest request, UrlResponseInfo info, String newLocationUrl) {
+            request.followRedirect();
+        }
+
+        @Override
+        public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
+            request.read(ByteBuffer.allocateDirect(32 * 1024));
+        }
+
+        @Override
+        public void onReadCompleted(
+            UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) {
+            byteBuffer.clear();
+            request.read(byteBuffer);
+        }
+
+
+        @Override
+        public void onSucceeded(UrlRequest request, UrlResponseInfo info) {
+            assertEquals("Unexpected http status code from " + mUrl + ".",
+                    200, info.getHttpStatusCode());
+            assertGreaterThan("Received byte from " + mUrl + " is 0.",
+                    (int)info.getReceivedByteCount(), 0);
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) {
+            fail(mUrl + error.getMessage());
+        }
+    }
+
+    @Test
+    public void testUrlGet() throws Exception {
+        assertHasTestableNetworks();
+        String url = HTTPS_PREFIX + getRandomDomain();
+        VerifyUrlRequestCallback callback = new VerifyUrlRequestCallback(url);
+        UrlRequest.Builder builder = mCronetEngine.newUrlRequestBuilder(url, callback, mExecutor);
+        builder.build().start();
+        assertTrue(url + " but not complete after " + TIMEOUT_MS + "ms.",
+                callback.waitForAnswer());
+    }
+
+}
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 3ab1ec2..f203191 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -21,11 +21,15 @@
 java_defaults {
     name: "TetheringApiLevel",
     sdk_version: "module_current",
-    target_sdk_version: "33",
     min_sdk_version: "30",
 }
 
 java_defaults {
+    name: "TetheringReleaseTargetSdk",
+    target_sdk_version: "33",
+}
+
+java_defaults {
     name: "TetheringExternalLibs",
     // Libraries not including Tethering's own framework-tethering (different flavors of that one
     // are needed depending on the build rule)
@@ -81,7 +85,8 @@
     defaults: [
         "ConnectivityNextEnableDefaults",
         "TetheringAndroidLibraryDefaults",
-        "TetheringApiLevel"
+        "TetheringApiLevel",
+        "TetheringReleaseTargetSdk"
     ],
     static_libs: [
         "NetworkStackApiCurrentShims",
@@ -94,7 +99,8 @@
     name: "TetheringApiStableLib",
     defaults: [
         "TetheringAndroidLibraryDefaults",
-        "TetheringApiLevel"
+        "TetheringApiLevel",
+        "TetheringReleaseTargetSdk"
     ],
     static_libs: [
         "NetworkStackApiStableShims",
@@ -180,7 +186,12 @@
 // Non-updatable tethering running in the system server process for devices not using the module
 android_app {
     name: "InProcessTethering",
-    defaults: ["TetheringAppDefaults", "TetheringApiLevel", "ConnectivityNextEnableDefaults"],
+    defaults: [
+        "TetheringAppDefaults",
+        "TetheringApiLevel",
+        "ConnectivityNextEnableDefaults",
+        "TetheringReleaseTargetSdk"
+    ],
     static_libs: ["TetheringApiCurrentLib"],
     certificate: "platform",
     manifest: "AndroidManifest_InProcess.xml",
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 8cf46ef..e59c8e4 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -54,6 +54,7 @@
     name: "com.android.tethering",
     defaults: [
         "ConnectivityApexDefaults",
+        "CronetApexDefaults",
         "r-launched-apex-module",
     ],
     compile_multilib: "both",
@@ -69,7 +70,10 @@
                 "libservice-connectivity",
                 "libandroid_net_connectivity_com_android_net_module_util_jni",
             ],
-            native_shared_libs: ["libnetd_updatable"],
+            native_shared_libs: [
+                "libcom.android.tethering.connectivity_native",
+                "libnetd_updatable",
+            ],
         },
         both: {
             jni_libs: [
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index ebc9d26..6a5089d 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -403,6 +403,18 @@
                 return null;
             }
         }
+
+        /** Get error BPF map. */
+        @Nullable public IBpfMap<S32, S32> getBpfErrorMap() {
+            if (!isAtLeastS()) return null;
+            try {
+                return new BpfMap<>(TETHER_ERROR_MAP_PATH,
+                    BpfMap.BPF_F_RDONLY, S32.class, S32.class);
+            } catch (ErrnoException e) {
+                Log.e(TAG, "Cannot create error map: " + e);
+                return null;
+            }
+        }
     }
 
     @VisibleForTesting
@@ -1287,13 +1299,15 @@
     }
 
     private void dumpCounters(@NonNull IndentingPrintWriter pw) {
-        if (!mDeps.isAtLeastS()) {
-            pw.println("No counter support");
-            return;
-        }
-        try (IBpfMap<S32, S32> map = new BpfMap<>(TETHER_ERROR_MAP_PATH, BpfMap.BPF_F_RDONLY,
-                S32.class, S32.class)) {
-
+        try (IBpfMap<S32, S32> map = mDeps.getBpfErrorMap()) {
+            if (map == null) {
+                pw.println("No error counter support");
+                return;
+            }
+            if (map.isEmpty()) {
+                pw.println("<empty>");
+                return;
+            }
             map.forEach((k, v) -> {
                 String counterName;
                 try {
@@ -1307,7 +1321,7 @@
                 if (v.val > 0) pw.println(String.format("%s: %d", counterName, v.val));
             });
         } catch (ErrnoException | IOException e) {
-            pw.println("Error dumping counter map: " + e);
+            pw.println("Error dumping error counter map: " + e);
         }
     }
 
diff --git a/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java b/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java
index 2c6054d..ffcea4e 100644
--- a/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java
+++ b/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java
@@ -76,8 +76,7 @@
                     .setUpstreamType(UpstreamType.UT_UNKNOWN)
                     .setErrorCode(ErrorCode.EC_NO_ERROR)
                     .setUpstreamEvents(UpstreamEvents.newBuilder())
-                    .setDurationMillis(0)
-                    .build();
+                    .setDurationMillis(0);
         mBuilderMap.put(downstreamType, statsBuilder);
     }
 
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index c61b6eb..f0f9a31 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -76,7 +76,7 @@
 import android.net.TetheringManager.TetheringEventCallback;
 import android.net.TetheringManager.TetheringRequest;
 import android.net.TetheringTester.TetheredDevice;
-import android.net.cts.util.CtsNetUtils;;
+import android.net.cts.util.CtsNetUtils;
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 5f4454b..f0d9057 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -53,6 +53,7 @@
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -99,6 +100,7 @@
 import com.android.net.module.util.InterfaceParams;
 import com.android.net.module.util.NetworkStackConstants;
 import com.android.net.module.util.SharedLog;
+import com.android.net.module.util.Struct.S32;
 import com.android.net.module.util.bpf.Tether4Key;
 import com.android.net.module.util.bpf.Tether4Value;
 import com.android.net.module.util.bpf.TetherStatsKey;
@@ -108,6 +110,7 @@
 import com.android.net.module.util.ip.IpNeighborMonitor.NeighborEvent;
 import com.android.net.module.util.ip.IpNeighborMonitor.NeighborEventConsumer;
 import com.android.networkstack.tethering.BpfCoordinator;
+import com.android.networkstack.tethering.BpfCoordinator.ClientInfo;
 import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
 import com.android.networkstack.tethering.PrivateAddressCoordinator;
 import com.android.networkstack.tethering.Tether6Value;
@@ -197,6 +200,7 @@
     @Mock private BpfMap<TetherStatsKey, TetherStatsValue> mBpfStatsMap;
     @Mock private BpfMap<TetherLimitKey, TetherLimitValue> mBpfLimitMap;
     @Mock private BpfMap<TetherDevKey, TetherDevValue> mBpfDevMap;
+    @Mock private BpfMap<S32, S32> mBpfErrorMap;
 
     @Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor;
 
@@ -360,6 +364,11 @@
                     public BpfMap<TetherDevKey, TetherDevValue> getBpfDevMap() {
                         return mBpfDevMap;
                     }
+
+                    @Nullable
+                    public BpfMap<S32, S32> getBpfErrorMap() {
+                        return mBpfErrorMap;
+                    }
                 };
         mBpfCoordinator = spy(new BpfCoordinator(mBpfDeps));
 
@@ -1520,4 +1529,56 @@
         verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(
                 mIpServer, makeForwardingRule(IPSEC_IFINDEX, neigh, mac));
     }
+
+    // TODO: move to BpfCoordinatorTest once IpNeighborMonitor is migrated to BpfCoordinator.
+    @Test
+    public void addRemoveTetherClient() throws Exception {
+        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+                DEFAULT_USING_BPF_OFFLOAD);
+
+        final int myIfindex = TEST_IFACE_PARAMS.index;
+        final int notMyIfindex = myIfindex - 1;
+
+        final InetAddress neighA = InetAddresses.parseNumericAddress("192.168.80.1");
+        final InetAddress neighB = InetAddresses.parseNumericAddress("192.168.80.2");
+        final InetAddress neighLL = InetAddresses.parseNumericAddress("169.254.0.1");
+        final InetAddress neighMC = InetAddresses.parseNumericAddress("224.0.0.1");
+        final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00");
+        final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a");
+        final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b");
+
+        // Events on other interfaces are ignored.
+        recvNewNeigh(notMyIfindex, neighA, NUD_REACHABLE, macA);
+        verifyNoMoreInteractions(mBpfCoordinator);
+
+        // Events on this interface are received and sent to BpfCoordinator.
+        recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
+        verify(mBpfCoordinator).tetherOffloadClientAdd(mIpServer, new ClientInfo(myIfindex,
+                TEST_IFACE_PARAMS.macAddr, (Inet4Address) neighA, macA));
+        clearInvocations(mBpfCoordinator);
+
+        recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+        verify(mBpfCoordinator).tetherOffloadClientAdd(mIpServer, new ClientInfo(myIfindex,
+                TEST_IFACE_PARAMS.macAddr, (Inet4Address) neighB, macB));
+        clearInvocations(mBpfCoordinator);
+
+        // Link-local and multicast neighbors are ignored.
+        recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA);
+        verifyNoMoreInteractions(mBpfCoordinator);
+        recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA);
+        verifyNoMoreInteractions(mBpfCoordinator);
+        clearInvocations(mBpfCoordinator);
+
+        // A neighbor that is no longer valid causes the client to be removed.
+        // NUD_FAILED events do not have a MAC address.
+        recvNewNeigh(myIfindex, neighA, NUD_FAILED, null);
+        verify(mBpfCoordinator).tetherOffloadClientRemove(mIpServer,  new ClientInfo(myIfindex,
+                TEST_IFACE_PARAMS.macAddr, (Inet4Address) neighA, macNull));
+        clearInvocations(mBpfCoordinator);
+
+        // A neighbor that is deleted causes the client to be removed.
+        recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
+        verify(mBpfCoordinator).tetherOffloadClientRemove(mIpServer, new ClientInfo(myIfindex,
+                TEST_IFACE_PARAMS.macAddr, (Inet4Address) neighB, macNull));
+    }
 }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
index bbca565..225fed7 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -94,11 +94,13 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.net.module.util.CollectionUtils;
 import com.android.net.module.util.IBpfMap;
 import com.android.net.module.util.InterfaceParams;
 import com.android.net.module.util.NetworkStackConstants;
 import com.android.net.module.util.SharedLog;
+import com.android.net.module.util.Struct.S32;
 import com.android.net.module.util.bpf.Tether4Key;
 import com.android.net.module.util.bpf.Tether4Value;
 import com.android.net.module.util.bpf.TetherStatsKey;
@@ -128,6 +130,7 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.MockitoSession;
 
+import java.io.StringWriter;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -135,6 +138,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
+import java.util.Map;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -192,13 +196,11 @@
             UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.fromString("44:55:66:00:00:0c"),
             NetworkStackConstants.ETHER_MTU);
 
-    private static final HashMap<Integer, UpstreamInformation> UPSTREAM_INFORMATIONS =
-            new HashMap<Integer, UpstreamInformation>() {{
-                    put(UPSTREAM_IFINDEX, new UpstreamInformation(UPSTREAM_IFACE_PARAMS,
-                            PUBLIC_ADDR, NetworkCapabilities.TRANSPORT_CELLULAR, TEST_NET_ID));
-                    put(UPSTREAM_IFINDEX2, new UpstreamInformation(UPSTREAM_IFACE_PARAMS2,
-                            PUBLIC_ADDR2, NetworkCapabilities.TRANSPORT_WIFI, TEST_NET_ID2));
-            }};
+    private static final Map<Integer, UpstreamInformation> UPSTREAM_INFORMATIONS = Map.of(
+            UPSTREAM_IFINDEX, new UpstreamInformation(UPSTREAM_IFACE_PARAMS,
+                    PUBLIC_ADDR, NetworkCapabilities.TRANSPORT_CELLULAR, TEST_NET_ID),
+            UPSTREAM_IFINDEX2, new UpstreamInformation(UPSTREAM_IFACE_PARAMS2,
+                    PUBLIC_ADDR2, NetworkCapabilities.TRANSPORT_WIFI, TEST_NET_ID2));
 
     private static final ClientInfo CLIENT_INFO_A = new ClientInfo(DOWNSTREAM_IFINDEX,
             DOWNSTREAM_MAC, PRIVATE_ADDR, MAC_A);
@@ -362,9 +364,6 @@
     @Mock private IpServer mIpServer2;
     @Mock private TetheringConfiguration mTetherConfig;
     @Mock private ConntrackMonitor mConntrackMonitor;
-    @Mock private IBpfMap<TetherDownstream6Key, Tether6Value> mBpfDownstream6Map;
-    @Mock private IBpfMap<TetherUpstream6Key, Tether6Value> mBpfUpstream6Map;
-    @Mock private IBpfMap<TetherDevKey, TetherDevValue> mBpfDevMap;
 
     // Late init since methods must be called by the thread that created this object.
     private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb;
@@ -383,10 +382,18 @@
             spy(new TestBpfMap<>(Tether4Key.class, Tether4Value.class));
     private final IBpfMap<Tether4Key, Tether4Value> mBpfUpstream4Map =
             spy(new TestBpfMap<>(Tether4Key.class, Tether4Value.class));
+    private final IBpfMap<TetherDownstream6Key, Tether6Value> mBpfDownstream6Map =
+            spy(new TestBpfMap<>(TetherDownstream6Key.class, Tether6Value.class));
+    private final IBpfMap<TetherUpstream6Key, Tether6Value> mBpfUpstream6Map =
+            spy(new TestBpfMap<>(TetherUpstream6Key.class, Tether6Value.class));
     private final IBpfMap<TetherStatsKey, TetherStatsValue> mBpfStatsMap =
             spy(new TestBpfMap<>(TetherStatsKey.class, TetherStatsValue.class));
     private final IBpfMap<TetherLimitKey, TetherLimitValue> mBpfLimitMap =
             spy(new TestBpfMap<>(TetherLimitKey.class, TetherLimitValue.class));
+    private final IBpfMap<TetherDevKey, TetherDevValue> mBpfDevMap =
+            spy(new TestBpfMap<>(TetherDevKey.class, TetherDevValue.class));
+    private final IBpfMap<S32, S32> mBpfErrorMap =
+            spy(new TestBpfMap<>(S32.class, S32.class));
     private BpfCoordinator.Dependencies mDeps =
             spy(new BpfCoordinator.Dependencies() {
                     @NonNull
@@ -457,6 +464,11 @@
                     public IBpfMap<TetherDevKey, TetherDevValue> getBpfDevMap() {
                         return mBpfDevMap;
                     }
+
+                    @Nullable
+                    public IBpfMap<S32, S32> getBpfErrorMap() {
+                        return mBpfErrorMap;
+                    }
             });
 
     @Before public void setUp() {
@@ -2099,4 +2111,88 @@
         assertEquals("upstreamIfindex: 1001, downstreamIfindex: 1003, address: 2001:db8::1, "
                 + "srcMac: 12:34:56:78:90:ab, dstMac: 00:00:00:00:00:0a", rule.toString());
     }
+
+    private void verifyDump(@NonNull final BpfCoordinator coordinator) {
+        final StringWriter stringWriter = new StringWriter();
+        final IndentingPrintWriter ipw = new IndentingPrintWriter(stringWriter, " ");
+        coordinator.dump(ipw);
+        assertFalse(stringWriter.toString().isEmpty());
+    }
+
+    @Test
+    public void testDumpDoesNotCrash() throws Exception {
+        // This dump test only used to for improving mainline module test coverage and doesn't
+        // really do any meaningful tests.
+        // TODO: consider verifying the dump content and separate tests into testDumpXXX().
+        final BpfCoordinator coordinator = makeBpfCoordinator();
+
+        // [1] Dump mostly empty content.
+        verifyDump(coordinator);
+
+        // [2] Dump mostly non-empty content.
+        // Test the following dump function and fill the corresponding content to execute
+        // code as more as possible for test coverage.
+        // - dumpBpfForwardingRulesIpv4
+        //   * mBpfDownstream4Map
+        //   * mBpfUpstream4Map
+        // - dumpBpfForwardingRulesIpv6
+        //   * mBpfDownstream6Map
+        //   * mBpfUpstream6Map
+        // - dumpStats
+        //   * mBpfStatsMap
+        // - dumpDevmap
+        //   * mBpfDevMap
+        // - dumpCounters
+        //   * mBpfErrorMap
+        // - dumpIpv6ForwardingRulesByDownstream
+        //   * mIpv6ForwardingRules
+
+        // dumpBpfForwardingRulesIpv4
+        mBpfDownstream4Map.insertEntry(
+                new TestDownstream4Key.Builder().build(),
+                new TestDownstream4Value.Builder().build());
+        mBpfUpstream4Map.insertEntry(
+                new TestUpstream4Key.Builder().build(),
+                new TestUpstream4Value.Builder().build());
+
+        // dumpBpfForwardingRulesIpv6
+        final Ipv6ForwardingRule rule = buildTestForwardingRule(UPSTREAM_IFINDEX, NEIGH_A, MAC_A);
+        mBpfDownstream6Map.insertEntry(rule.makeTetherDownstream6Key(), rule.makeTether6Value());
+
+        final TetherUpstream6Key upstream6Key = new TetherUpstream6Key(DOWNSTREAM_IFINDEX,
+                DOWNSTREAM_MAC);
+        final Tether6Value upstream6Value = new Tether6Value(UPSTREAM_IFINDEX,
+                MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS,
+                ETH_P_IPV6, NetworkStackConstants.ETHER_MTU);
+        mBpfUpstream6Map.insertEntry(upstream6Key, upstream6Value);
+
+        // dumpStats
+        mBpfStatsMap.insertEntry(
+                new TetherStatsKey(UPSTREAM_IFINDEX),
+                new TetherStatsValue(
+                        0L /* rxPackets */, 0L /* rxBytes */, 0L /* rxErrors */,
+                        0L /* txPackets */, 0L /* txBytes */, 0L /* txErrors */));
+
+        // dumpDevmap
+        coordinator.addUpstreamNameToLookupTable(UPSTREAM_IFINDEX, UPSTREAM_IFACE);
+        mBpfDevMap.insertEntry(
+                new TetherDevKey(UPSTREAM_IFINDEX),
+                new TetherDevValue(UPSTREAM_IFINDEX));
+
+        // dumpCounters
+        // The error code is defined in packages/modules/Connectivity/bpf_progs/bpf_tethering.h.
+        mBpfErrorMap.insertEntry(
+                new S32(0 /* INVALID_IPV4_VERSION */),
+                new S32(1000 /* count */));
+
+        // dumpIpv6ForwardingRulesByDownstream
+        final HashMap<IpServer, LinkedHashMap<Inet6Address, Ipv6ForwardingRule>>
+                ipv6ForwardingRules = coordinator.getForwardingRulesForTesting();
+        final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> addressRuleMap =
+                new LinkedHashMap<>();
+        addressRuleMap.put(rule.address, rule);
+        ipv6ForwardingRules.put(mIpServer, addressRuleMap);
+
+        verifyDump(coordinator);
+    }
 }
diff --git a/bpf_progs/bpf_net_helpers.h b/bpf_progs/bpf_net_helpers.h
index e382713..c39269e 100644
--- a/bpf_progs/bpf_net_helpers.h
+++ b/bpf_progs/bpf_net_helpers.h
@@ -28,9 +28,12 @@
 
 static int (*bpf_skb_pull_data)(struct __sk_buff* skb, __u32 len) = (void*)BPF_FUNC_skb_pull_data;
 
-static int (*bpf_skb_load_bytes)(struct __sk_buff* skb, int off, void* to,
+static int (*bpf_skb_load_bytes)(const struct __sk_buff* skb, int off, void* to,
                                  int len) = (void*)BPF_FUNC_skb_load_bytes;
 
+static int (*bpf_skb_load_bytes_relative)(const struct __sk_buff* skb, int off, void* to, int len,
+                                          int start_hdr) = (void*)BPF_FUNC_skb_load_bytes_relative;
+
 static int (*bpf_skb_store_bytes)(struct __sk_buff* skb, __u32 offset, const void* from, __u32 len,
                                   __u64 flags) = (void*)BPF_FUNC_skb_store_bytes;
 
diff --git a/bpf_progs/bpf_shared.h b/bpf_progs/bpf_shared.h
index 85b9f86..7b1106a 100644
--- a/bpf_progs/bpf_shared.h
+++ b/bpf_progs/bpf_shared.h
@@ -95,13 +95,13 @@
 
 // 'static' - otherwise these constants end up in .rodata in the resulting .o post compilation
 static const int COOKIE_UID_MAP_SIZE = 10000;
-static const int UID_COUNTERSET_MAP_SIZE = 2000;
+static const int UID_COUNTERSET_MAP_SIZE = 4000;
 static const int APP_STATS_MAP_SIZE = 10000;
 static const int STATS_MAP_SIZE = 5000;
 static const int IFACE_INDEX_NAME_MAP_SIZE = 1000;
 static const int IFACE_STATS_MAP_SIZE = 1000;
 static const int CONFIGURATION_MAP_SIZE = 2;
-static const int UID_OWNER_MAP_SIZE = 2000;
+static const int UID_OWNER_MAP_SIZE = 4000;
 
 #ifdef __cplusplus
 
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index a2214dc..b8c6131 100644
--- a/bpf_progs/clatd.c
+++ b/bpf_progs/clatd.c
@@ -38,8 +38,19 @@
 #include "bpf_shared.h"
 #include "clat_mark.h"
 
-// From kernel:include/net/ip.h
-#define IP_DF 0x4000  // Flag: "Don't Fragment"
+// IP flags. (from kernel's include/net/ip.h)
+#define IP_CE      0x8000  // Flag: "Congestion" (really reserved 'evil bit')
+#define IP_DF      0x4000  // Flag: "Don't Fragment"
+#define IP_MF      0x2000  // Flag: "More Fragments"
+#define IP_OFFSET  0x1FFF  // "Fragment Offset" part
+
+// from kernel's include/net/ipv6.h
+struct frag_hdr {
+    __u8   nexthdr;
+    __u8   reserved;        // always zero
+    __be16 frag_off;        // 13 bit offset, 2 bits zero, 1 bit "More Fragments"
+    __be32 identification;
+};
 
 DEFINE_BPF_MAP_GRW(clat_ingress6_map, HASH, ClatIngress6Key, ClatIngress6Value, 16, AID_SYSTEM)
 
@@ -89,7 +100,32 @@
 
     if (!v) return TC_ACT_PIPE;
 
-    switch (ip6->nexthdr) {
+    __u8 proto = ip6->nexthdr;
+    __be16 ip_id = 0;
+    __be16 frag_off = htons(IP_DF);
+    __u16 tot_len = ntohs(ip6->payload_len) + sizeof(struct iphdr);  // cannot overflow, see above
+
+    if (proto == IPPROTO_FRAGMENT) {
+        // Must have (ethernet and) ipv6 header and ipv6 fragment extension header
+        if (data + l2_header_size + sizeof(*ip6) + sizeof(struct frag_hdr) > data_end)
+            return TC_ACT_PIPE;
+        const struct frag_hdr *frag = (const struct frag_hdr *)(ip6 + 1);
+        proto = frag->nexthdr;
+        // Trivial hash of 32-bit IPv6 ID field into 16-bit IPv4 field.
+        ip_id = (frag->identification) ^ (frag->identification >> 16);
+        // Conversion of 16-bit IPv6 frag offset to 16-bit IPv4 frag offset field.
+        // IPv6 is '13 bits of offset in multiples of 8' + 2 zero bits + more fragment bit
+        // IPv4 is zero bit + don't frag bit + more frag bit + '13 bits of offset in multiples of 8'
+        frag_off = ntohs(frag->frag_off);
+        frag_off = ((frag_off & 1) << 13) | (frag_off >> 3);
+        frag_off = htons(frag_off);
+        // Note that by construction tot_len is guaranteed to not underflow here
+        tot_len -= sizeof(struct frag_hdr);
+        // This is a badly formed IPv6 packet with less payload than the size of an IPv6 Frag EH
+        if (tot_len < sizeof(struct iphdr)) return TC_ACT_PIPE;
+    }
+
+    switch (proto) {
         case IPPROTO_TCP:  // For TCP & UDP the checksum neutrality of the chosen IPv6
         case IPPROTO_UDP:  // address means there is no need to update their checksums.
         case IPPROTO_GRE:  // We do not need to bother looking at GRE/ESP headers,
@@ -114,14 +150,14 @@
             .version = 4,                                                      // u4
             .ihl = sizeof(struct iphdr) / sizeof(__u32),                       // u4
             .tos = (ip6->priority << 4) + (ip6->flow_lbl[0] >> 4),             // u8
-            .tot_len = htons(ntohs(ip6->payload_len) + sizeof(struct iphdr)),  // u16
-            .id = 0,                                                           // u16
-            .frag_off = htons(IP_DF),                                          // u16
+            .tot_len = htons(tot_len),                                         // be16
+            .id = ip_id,                                                       // be16
+            .frag_off = frag_off,                                              // be16
             .ttl = ip6->hop_limit,                                             // u8
-            .protocol = ip6->nexthdr,                                          // u8
+            .protocol = proto,                                                 // u8
             .check = 0,                                                        // u16
-            .saddr = ip6->saddr.in6_u.u6_addr32[3],                            // u32
-            .daddr = v->local4.s_addr,                                         // u32
+            .saddr = ip6->saddr.in6_u.u6_addr32[3],                            // be32
+            .daddr = v->local4.s_addr,                                         // be32
     };
 
     // Calculate the IPv4 one's complement checksum of the IPv4 header.
@@ -171,6 +207,13 @@
     //   return -ENOTSUPP;
     bpf_csum_update(skb, sum6);
 
+    if (frag_off != htons(IP_DF)) {
+        // If we're converting an IPv6 Fragment, we need to trim off 8 more bytes
+        // We're beyond recovery on error here... but hard to imagine how this could fail.
+        if (bpf_skb_adjust_room(skb, -(__s32)sizeof(struct frag_hdr), BPF_ADJ_ROOM_NET, /*flags*/0))
+            return TC_ACT_SHOT;
+    }
+
     // bpf_skb_change_proto() invalidates all pointers - reload them.
     data = (void*)(long)skb->data;
     data_end = (void*)(long)skb->data_end;
@@ -211,11 +254,6 @@
 
 DEFINE_BPF_MAP_GRW(clat_egress4_map, HASH, ClatEgress4Key, ClatEgress4Value, 16, AID_SYSTEM)
 
-DEFINE_BPF_PROG("schedcls/egress4/clat_ether", AID_ROOT, AID_SYSTEM, sched_cls_egress4_clat_ether)
-(struct __sk_buff* skb) {
-    return TC_ACT_PIPE;
-}
-
 DEFINE_BPF_PROG("schedcls/egress4/clat_rawip", AID_ROOT, AID_SYSTEM, sched_cls_egress4_clat_rawip)
 (struct __sk_buff* skb) {
     // Must be meta-ethernet IPv4 frame
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index 10559dd..f9484fc 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -47,9 +47,16 @@
 
 #define IP_PROTO_OFF offsetof(struct iphdr, protocol)
 #define IPV6_PROTO_OFF offsetof(struct ipv6hdr, nexthdr)
+
+// offsetof(struct iphdr, ihl) -- but that's a bitfield
 #define IPPROTO_IHL_OFF 0
-#define TCP_FLAG_OFF 13
-#define RST_OFFSET 2
+
+// This is offsetof(struct tcphdr, "32 bit tcp flag field")
+// The tcp flags are after be16 source, dest & be32 seq, ack_seq, hence 12 bytes in.
+//
+// Note that TCP_FLAG_{ACK,PSH,RST,SYN,FIN} are htonl(0x00{10,08,04,02,01}0000)
+// see include/uapi/linux/tcp.h
+#define TCP_FLAG32_OFF 12
 
 // For maps netd does not need to access
 #define DEFINE_BPF_MAP_NO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
@@ -97,9 +104,15 @@
 // programs that need to be usable by netd, but not by netutils_wrappers
 // (this is because these are currently attached by the mainline provided libnetd_updatable .so
 // which is loaded into netd and thus runs as netd uid/gid/selinux context)
-#define DEFINE_NETD_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
+#define DEFINE_NETD_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, minKV, maxKV) \
     DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \
-                        KVER_NONE, KVER_INF, false, "fs_bpf_netd_readonly", "")
+                        minKV, maxKV, false, "fs_bpf_netd_readonly", "")
+
+#define DEFINE_NETD_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \
+    DEFINE_NETD_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF)
+
+#define DEFINE_NETD_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
+    DEFINE_NETD_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, KVER_NONE)
 
 // programs that only need to be usable by the system server
 #define DEFINE_SYS_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
@@ -176,46 +189,49 @@
 DEFINE_UPDATE_STATS(stats_map_A, StatsKey)
 DEFINE_UPDATE_STATS(stats_map_B, StatsKey)
 
-static inline bool skip_owner_match(struct __sk_buff* skb) {
-    int offset = -1;
-    int ret = 0;
+// both of these return 0 on success or -EFAULT on failure (and zero out the buffer)
+static __always_inline inline int bpf_skb_load_bytes_net(const struct __sk_buff* skb, int off,
+                                                         void* to, int len, bool is_4_19) {
+    return is_4_19
+        ? bpf_skb_load_bytes_relative(skb, off, to, len, BPF_HDR_START_NET)
+        : bpf_skb_load_bytes(skb, off, to, len);
+}
+
+static __always_inline inline bool skip_owner_match(struct __sk_buff* skb, bool is_4_19) {
     if (skb->protocol == htons(ETH_P_IP)) {
-        offset = IP_PROTO_OFF;
-        uint8_t proto, ihl;
-        uint8_t flag;
-        ret = bpf_skb_load_bytes(skb, offset, &proto, 1);
-        if (!ret) {
-            if (proto == IPPROTO_ESP) {
-                return true;
-            } else if (proto == IPPROTO_TCP) {
-                ret = bpf_skb_load_bytes(skb, IPPROTO_IHL_OFF, &ihl, 1);
-                ihl = ihl & 0x0F;
-                ret = bpf_skb_load_bytes(skb, ihl * 4 + TCP_FLAG_OFF, &flag, 1);
-                if (ret == 0 && (flag >> RST_OFFSET & 1)) {
-                    return true;
-                }
-            }
-        }
-    } else if (skb->protocol == htons(ETH_P_IPV6)) {
-        offset = IPV6_PROTO_OFF;
         uint8_t proto;
-        ret = bpf_skb_load_bytes(skb, offset, &proto, 1);
-        if (!ret) {
-            if (proto == IPPROTO_ESP) {
-                return true;
-            } else if (proto == IPPROTO_TCP) {
-                uint8_t flag;
-                ret = bpf_skb_load_bytes(skb, sizeof(struct ipv6hdr) + TCP_FLAG_OFF, &flag, 1);
-                if (ret == 0 && (flag >> RST_OFFSET & 1)) {
-                    return true;
-                }
-            }
-        }
+        // no need to check for success, proto will be zeroed if bpf_skb_load_bytes_net() fails
+        (void)bpf_skb_load_bytes_net(skb, IP_PROTO_OFF, &proto, sizeof(proto), is_4_19);
+        if (proto == IPPROTO_ESP) return true;
+        if (proto != IPPROTO_TCP) return false;  // handles read failure above
+        uint8_t ihl;
+        // we don't check for success, as this cannot fail, as it is earlier in the packet than
+        // proto, the reading of which must have succeeded, additionally the next read
+        // (a little bit deeper in the packet in spite of ihl being zeroed) of the tcp flags
+        // field will also fail, and that failure we already handle correctly
+        // (we also don't check that ihl in [0x45,0x4F] nor that ipv4 header checksum is correct)
+        (void)bpf_skb_load_bytes_net(skb, IPPROTO_IHL_OFF, &ihl, sizeof(ihl), is_4_19);
+        uint32_t flag;
+        // if the read below fails, we'll just assume no TCP flags are set, which is fine.
+        (void)bpf_skb_load_bytes_net(skb, (ihl & 0xF) * 4 + TCP_FLAG32_OFF,
+                                     &flag, sizeof(flag), is_4_19);
+        return flag & TCP_FLAG_RST;  // false on read failure
+    } else if (skb->protocol == htons(ETH_P_IPV6)) {
+        uint8_t proto;
+        // no need to check for success, proto will be zeroed if bpf_skb_load_bytes_net() fails
+        (void)bpf_skb_load_bytes_net(skb, IPV6_PROTO_OFF, &proto, sizeof(proto), is_4_19);
+        if (proto == IPPROTO_ESP) return true;
+        if (proto != IPPROTO_TCP) return false;  // handles read failure above
+        uint32_t flag;
+        // if the read below fails, we'll just assume no TCP flags are set, which is fine.
+        (void)bpf_skb_load_bytes_net(skb, sizeof(struct ipv6hdr) + TCP_FLAG32_OFF,
+                                     &flag, sizeof(flag), is_4_19);
+        return flag & TCP_FLAG_RST;  // false on read failure
     }
     return false;
 }
 
-static __always_inline BpfConfig getConfig(uint32_t configKey) {
+static __always_inline inline BpfConfig getConfig(uint32_t configKey) {
     uint32_t mapSettingKey = configKey;
     BpfConfig* config = bpf_configuration_map_lookup_elem(&mapSettingKey);
     if (!config) {
@@ -230,8 +246,9 @@
 // DROP_IF_UNSET is set of rules that should DROP if globally enabled, and per-uid bit is NOT set
 #define DROP_IF_UNSET (DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH | LOW_POWER_STANDBY_MATCH)
 
-static inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid, int direction) {
-    if (skip_owner_match(skb)) return BPF_PASS;
+static __always_inline inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid,
+                                                  int direction, bool is_4_19) {
+    if (skip_owner_match(skb, is_4_19)) return BPF_PASS;
 
     if (is_system_uid(uid)) return BPF_PASS;
 
@@ -273,7 +290,8 @@
     }
 }
 
-static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, int direction) {
+static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, int direction,
+                                                      bool is_4_19) {
     uint32_t sock_uid = bpf_get_socket_uid(skb);
     uint64_t cookie = bpf_get_socket_cookie(skb);
     UidTagValue* utag = bpf_cookie_tag_map_lookup_elem(&cookie);
@@ -293,7 +311,7 @@
         return BPF_PASS;
     }
 
-    int match = bpf_owner_match(skb, sock_uid, direction);
+    int match = bpf_owner_match(skb, sock_uid, direction, is_4_19);
     if ((direction == BPF_EGRESS) && (match == BPF_DROP)) {
         // If an outbound packet is going to be dropped, we do not count that
         // traffic.
@@ -338,14 +356,28 @@
     return match;
 }
 
-DEFINE_NETD_BPF_PROG("cgroupskb/ingress/stats", AID_ROOT, AID_SYSTEM, bpf_cgroup_ingress)
+DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/ingress/stats$4_19", AID_ROOT, AID_SYSTEM,
+                                bpf_cgroup_ingress_4_19, KVER(4, 19, 0), KVER_INF)
 (struct __sk_buff* skb) {
-    return bpf_traffic_account(skb, BPF_INGRESS);
+    return bpf_traffic_account(skb, BPF_INGRESS, /* is_4_19 */ true);
 }
 
-DEFINE_NETD_BPF_PROG("cgroupskb/egress/stats", AID_ROOT, AID_SYSTEM, bpf_cgroup_egress)
+DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/ingress/stats$4_14", AID_ROOT, AID_SYSTEM,
+                                bpf_cgroup_ingress_4_14, KVER_NONE, KVER(4, 19, 0))
 (struct __sk_buff* skb) {
-    return bpf_traffic_account(skb, BPF_EGRESS);
+    return bpf_traffic_account(skb, BPF_INGRESS, /* is_4_19 */ false);
+}
+
+DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/egress/stats$4_19", AID_ROOT, AID_SYSTEM,
+                                bpf_cgroup_egress_4_19, KVER(4, 19, 0), KVER_INF)
+(struct __sk_buff* skb) {
+    return bpf_traffic_account(skb, BPF_EGRESS, /* is_4_19 */ true);
+}
+
+DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/egress/stats$4_14", AID_ROOT, AID_SYSTEM,
+                                bpf_cgroup_egress_4_14, KVER_NONE, KVER(4, 19, 0))
+(struct __sk_buff* skb) {
+    return bpf_traffic_account(skb, BPF_EGRESS, /* is_4_19 */ false);
 }
 
 // WARNING: Android T's non-updatable netd depends on the name of this program.
@@ -419,7 +451,8 @@
     return BPF_NOMATCH;
 }
 
-DEFINE_NETD_BPF_PROG("cgroupsock/inet/create", AID_ROOT, AID_ROOT, inet_socket_create)
+DEFINE_NETD_BPF_PROG_KVER("cgroupsock/inet/create", AID_ROOT, AID_ROOT, inet_socket_create,
+                          KVER(4, 14, 0))
 (struct bpf_sock* sk) {
     uint64_t gid_uid = bpf_get_current_uid_gid();
     /*
diff --git a/common/src/com/android/net/module/util/bpf/Tether4Key.java b/common/src/com/android/net/module/util/bpf/Tether4Key.java
index 8273e6a..738256a 100644
--- a/common/src/com/android/net/module/util/bpf/Tether4Key.java
+++ b/common/src/com/android/net/module/util/bpf/Tether4Key.java
@@ -75,7 +75,7 @@
                     Inet4Address.getByAddress(src4), Inet4Address.getByAddress(dst4),
                     Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort));
         } catch (UnknownHostException | IllegalArgumentException e) {
-            return String.format("Invalid IP address", e);
+            return "Invalid IP address" + e;
         }
     }
 }
diff --git a/common/src/com/android/net/module/util/bpf/Tether4Value.java b/common/src/com/android/net/module/util/bpf/Tether4Value.java
index 74fdda2..449c1da 100644
--- a/common/src/com/android/net/module/util/bpf/Tether4Value.java
+++ b/common/src/com/android/net/module/util/bpf/Tether4Value.java
@@ -91,7 +91,7 @@
                     Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort),
                     lastUsed);
         } catch (UnknownHostException | IllegalArgumentException e) {
-            return String.format("Invalid IP address", e);
+            return "Invalid IP address" + e;
         }
     }
 }
diff --git a/framework-t/src/android/net/IpSecAlgorithm.java b/framework-t/src/android/net/IpSecAlgorithm.java
index 10a22ac..aac6f79 100644
--- a/framework-t/src/android/net/IpSecAlgorithm.java
+++ b/framework-t/src/android/net/IpSecAlgorithm.java
@@ -21,6 +21,7 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemProperties;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -351,8 +352,11 @@
             }
         }
 
+        // T introduced calculated property 'ro.vendor.api_level',
+        // which is the API level of the VSR that the device must conform to.
+        int vendorApiLevel = SystemProperties.getInt("ro.vendor.api_level", 10000);
         for (Entry<String, Integer> entry : ALGO_TO_REQUIRED_FIRST_SDK.entrySet()) {
-            if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= entry.getValue()) {
+            if (vendorApiLevel >= entry.getValue()) {
                 enabledAlgos.add(entry.getKey());
             }
         }
@@ -488,4 +492,4 @@
                 && Arrays.equals(lhs.mKey, rhs.mKey)
                 && lhs.mTruncLenBits == rhs.mTruncLenBits);
     }
-};
+}
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index a2a1ac0..073cca2 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}) 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.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/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 547b4ba..39c5af2 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -4080,7 +4080,7 @@
         }
     }
 
-    private class CallbackHandler extends Handler {
+    private static class CallbackHandler extends Handler {
         private static final String TAG = "ConnectivityManager.CallbackHandler";
         private static final boolean DBG = false;
 
@@ -4095,7 +4095,10 @@
         @Override
         public void handleMessage(Message message) {
             if (message.what == EXPIRE_LEGACY_REQUEST) {
-                expireRequest((NetworkCapabilities) message.obj, message.arg1);
+                // the sInstance can't be null because to send this message a ConnectivityManager
+                // instance must have been created prior to creating the thread on which this
+                // Handler is running.
+                sInstance.expireRequest((NetworkCapabilities) message.obj, message.arg1);
                 return;
             }
 
@@ -4786,7 +4789,8 @@
     @SuppressLint({"ExecutorRegistration", "PairedRegistration"})
     @RequiresPermission(anyOf = {
             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_SETTINGS})
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS})
     public void registerSystemDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
             @NonNull Handler handler) {
         CallbackHandler cbHandler = new CallbackHandler(handler);
diff --git a/framework/src/android/net/apf/ApfCapabilities.java b/framework/src/android/net/apf/ApfCapabilities.java
index 663c1b3..64f14a1 100644
--- a/framework/src/android/net/apf/ApfCapabilities.java
+++ b/framework/src/android/net/apf/ApfCapabilities.java
@@ -133,9 +133,7 @@
     public static boolean getApfDrop8023Frames() {
         // TODO: deprecate/remove this method (now unused in the platform), as the resource was
         // moved to NetworkStack.
-        final Resources systemRes = Resources.getSystem();
-        final int id = systemRes.getIdentifier("config_apfDrop802_3Frames", "bool", "android");
-        return systemRes.getBoolean(id);
+        return true;
     }
 
     /**
@@ -144,8 +142,6 @@
     public static @NonNull int[] getApfEtherTypeBlackList() {
         // TODO: deprecate/remove this method (now unused in the platform), as the resource was
         // moved to NetworkStack.
-        final Resources systemRes = Resources.getSystem();
-        final int id = systemRes.getIdentifier("config_apfEthTypeBlackList", "array", "android");
-        return systemRes.getIntArray(id);
+        return new int[] { 0x88a2, 0x88a4, 0x88b8, 0x88cd, 0x88e3 };
     }
 }
diff --git a/nearby/halfsheet/Android.bp b/nearby/halfsheet/Android.bp
index 486a3ff..c84caa6 100644
--- a/nearby/halfsheet/Android.bp
+++ b/nearby/halfsheet/Android.bp
@@ -23,7 +23,6 @@
     sdk_version: "module_current",
     // This is included in tethering apex, which uses min SDK 30
     min_sdk_version: "30",
-    target_sdk_version: "current",
     updatable: true,
     certificate: ":com.android.nearby.halfsheetcertificate",
     libs: [
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index 3f7ed2a..7950ff7 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -87,7 +87,16 @@
     RETURN_IF_NOT_OK(checkProgramAccessible(XT_BPF_INGRESS_PROG_PATH));
     RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_EGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_EGRESS));
     RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_INGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_INGRESS));
-    RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
+
+    // For the devices that support cgroup socket filter, the socket filter
+    // should be loaded successfully by bpfloader. So we attach the filter to
+    // cgroup if the program is pinned properly.
+    // TODO: delete the if statement once all devices should support cgroup
+    // socket filter (ie. the minimum kernel version required is 4.14).
+    if (!access(CGROUP_SOCKET_PROG_PATH, F_OK)) {
+        RETURN_IF_NOT_OK(
+                attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
+    }
     return netdutils::status::ok;
 }
 
diff --git a/service-t/src/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java
index 16b9f1e..6cee08a 100644
--- a/service-t/src/com/android/server/IpSecService.java
+++ b/service-t/src/com/android/server/IpSecService.java
@@ -859,6 +859,13 @@
                             mIkey,
                             0xffffffff,
                             mIfId);
+                    mNetd.ipSecDeleteSecurityPolicy(
+                            mUid,
+                            selAddrFamily,
+                            IpSecManager.DIRECTION_FWD,
+                            mIkey,
+                            0xffffffff,
+                            mIfId);
                 }
             } catch (ServiceSpecificException | RemoteException e) {
                 Log.e(
diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
index 00f6c56..0605abe 100644
--- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
+++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
@@ -269,10 +269,10 @@
         private final Set<Integer> mRequestIds = new ArraySet<>();
 
         private volatile @Nullable IpClientManager mIpClient;
-        private @NonNull NetworkCapabilities mCapabilities;
+        private NetworkCapabilities mCapabilities;
         private @Nullable EthernetIpClientCallback mIpClientCallback;
         private @Nullable EthernetNetworkAgent mNetworkAgent;
-        private @Nullable IpConfiguration mIpConfig;
+        private IpConfiguration mIpConfig;
 
         /**
          * A map of TRANSPORT_* types to legacy transport types available for each type an ethernet
diff --git a/service/Android.bp b/service/Android.bp
index d850015..326f91b 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -22,7 +22,6 @@
 aidl_interface {
     name: "connectivity_native_aidl_interface",
     local_include_dir: "binder",
-    vendor_available: true,
     srcs: [
         "binder/android/net/connectivity/aidl/*.aidl",
     ],
@@ -179,6 +178,7 @@
         "networkstack-client",
         "PlatformProperties",
         "service-connectivity-protos",
+        "service-connectivity-stats-protos",
         "NetworkStackApiStableShims",
     ],
     apex_available: [
@@ -290,6 +290,20 @@
     installable: true,
 }
 
+java_library_static {
+    name: "service-connectivity-stats-protos",
+    sdk_version: "system_current",
+    min_sdk_version: "30",
+    proto: {
+        type: "lite",
+    },
+    srcs: [
+        "src/com/android/metrics/stats.proto",
+    ],
+    static_libs: ["ConnectivityServiceprotos"],
+    apex_available: ["com.android.tethering"],
+}
+
 genrule {
     name: "connectivity-jarjar-rules",
     defaults: ["jarjar-rules-combine-defaults"],
diff --git a/service/ServiceConnectivityResources/Android.bp b/service/ServiceConnectivityResources/Android.bp
index 02b2875..2260596 100644
--- a/service/ServiceConnectivityResources/Android.bp
+++ b/service/ServiceConnectivityResources/Android.bp
@@ -21,9 +21,8 @@
 
 android_app {
     name: "ServiceConnectivityResources",
-    sdk_version: "module_30",
+    sdk_version: "module_current",
     min_sdk_version: "30",
-    target_sdk_version: "33",
     resource_dirs: [
         "res",
     ],
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index de0e20a..5cd6e5d 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -87,7 +87,8 @@
 
 // Picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix.
 jstring com_android_server_connectivity_ClatCoordinator_generateIpv6Address(
-        JNIEnv* env, jobject clazz, jstring ifaceStr, jstring v4Str, jstring prefix64Str) {
+        JNIEnv* env, jobject clazz, jstring ifaceStr, jstring v4Str, jstring prefix64Str,
+        jint mark) {
     ScopedUtfChars iface(env, ifaceStr);
     ScopedUtfChars addr4(env, v4Str);
     ScopedUtfChars prefix64(env, prefix64Str);
@@ -111,7 +112,7 @@
     }
 
     in6_addr v6;
-    if (net::clat::generateIpv6Address(iface.c_str(), v4, nat64Prefix, &v6)) {
+    if (net::clat::generateIpv6Address(iface.c_str(), v4, nat64Prefix, &v6, mark)) {
         jniThrowExceptionFmt(env, "java/io/IOException",
                              "Unable to find global source address on %s for %s", iface.c_str(),
                              prefix64.c_str());
@@ -447,7 +448,7 @@
         {"native_selectIpv4Address", "(Ljava/lang/String;I)Ljava/lang/String;",
          (void*)com_android_server_connectivity_ClatCoordinator_selectIpv4Address},
         {"native_generateIpv6Address",
-         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;",
          (void*)com_android_server_connectivity_ClatCoordinator_generateIpv6Address},
         {"native_createTunInterface", "(Ljava/lang/String;)I",
          (void*)com_android_server_connectivity_ClatCoordinator_createTunInterface},
diff --git a/service/libconnectivity/Android.bp b/service/libconnectivity/Android.bp
new file mode 100644
index 0000000..391ceac
--- /dev/null
+++ b/service/libconnectivity/Android.bp
@@ -0,0 +1,57 @@
+//
+// 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 {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_shared {
+    name: "libcom.android.tethering.connectivity_native",
+    srcs: [
+        "src/**/*.cpp",
+    ],
+    min_sdk_version: "30",
+    static_libs: [
+        "connectivity_native_aidl_interface-V1-ndk",
+    ],
+    export_include_dirs: ["include"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+    ],
+
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    llndk: {
+        symbol_file: "libconnectivity_native.map.txt",
+    },
+    stubs: {
+        symbol_file: "libconnectivity_native.map.txt",
+        versions: [
+            "current",
+        ],
+    },
+    header_abi_checker: {
+        enabled: true,
+        symbol_file: "libconnectivity_native.map.txt",
+    },
+    apex_available: [
+        "com.android.tethering",
+    ],
+}
diff --git a/service/libconnectivity/include/connectivity_native.h b/service/libconnectivity/include/connectivity_native.h
new file mode 100644
index 0000000..5a2509a
--- /dev/null
+++ b/service/libconnectivity/include/connectivity_native.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#ifndef LIBCONNECTIVITY_CONNECTIVITY_NATIVE_H_
+#define LIBCONNECTIVITY_CONNECTIVITY_NATIVE_H_
+
+#include <sys/cdefs.h>
+#include <netinet/in.h>
+
+// For branches that do not yet have __ANDROID_API_U__ defined, like module
+// release branches.
+#ifndef __ANDROID_API_U__
+#define __ANDROID_API_U__ 34
+#endif
+
+__BEGIN_DECLS
+
+/**
+ * Blocks a port from being assigned during bind(). The caller is responsible for updating
+ * /proc/sys/net/ipv4/ip_local_port_range with the port being blocked so that calls to connect()
+ * will not automatically assign one of the blocked ports.
+ * Will return success even if port was already blocked.
+ *
+ * Returns 0 on success, or a POSIX error code (see errno.h) on failure:
+ *  - EINVAL for invalid port number
+ *  - EPERM if the UID of the client doesn't have network stack permission
+ *  - Other errors as per https://man7.org/linux/man-pages/man2/bpf.2.html
+ *
+ * @param port Int corresponding to port number.
+ */
+int AConnectivityNative_blockPortForBind(in_port_t port) __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
+ * Unblocks a port that has previously been blocked.
+ * Will return success even if port was already unblocked.
+ *
+ * Returns 0 on success, or a POSIX error code (see errno.h) on failure:
+ *  - EINVAL for invalid port number
+ *  - EPERM if the UID of the client doesn't have network stack permission
+ *  - Other errors as per https://man7.org/linux/man-pages/man2/bpf.2.html
+ *
+ * @param port Int corresponding to port number.
+ */
+int AConnectivityNative_unblockPortForBind(in_port_t port) __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
+ * Unblocks all ports that have previously been blocked.
+ *
+ * Returns 0 on success, or a POSIX error code (see errno.h) on failure:
+ *  - EINVAL for invalid port number
+ *  - EPERM if the UID of the client doesn't have network stack permission
+ *  - Other errors as per https://man7.org/linux/man-pages/man2/bpf.2.html
+ */
+int AConnectivityNative_unblockAllPortsForBind() __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
+ * Gets the list of ports that have been blocked.
+ *
+ * Returns 0 on success, or a POSIX error code (see errno.h) on failure:
+ *  - EINVAL for invalid port number
+ *  - EPERM if the UID of the client doesn't have network stack permission
+ *  - Other errors as per https://man7.org/linux/man-pages/man2/bpf.2.html
+ *
+ * @param ports Array of ports that will be filled with the port numbers.
+ * @param count Pointer to the size of the ports array; the value will be set to the total number of
+ *              blocked ports, which may be larger than the ports array that was filled.
+ */
+int AConnectivityNative_getPortsBlockedForBind(in_port_t *ports, size_t *count)
+    __INTRODUCED_IN(__ANDROID_API_U__);
+
+__END_DECLS
+
+
+#endif
diff --git a/service/libconnectivity/libconnectivity_native.map.txt b/service/libconnectivity/libconnectivity_native.map.txt
new file mode 100644
index 0000000..19b1074
--- /dev/null
+++ b/service/libconnectivity/libconnectivity_native.map.txt
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+LIBCONNECTIVITY_NATIVE {
+  global:
+    AConnectivityNative_blockPortForBind; # apex llndk
+    AConnectivityNative_getPortsBlockedForBind; # apex llndk
+    AConnectivityNative_unblockPortForBind; # apex llndk
+    AConnectivityNative_unblockAllPortsForBind; # apex llndk
+  local:
+    *;
+};
diff --git a/service/libconnectivity/src/connectivity_native.cpp b/service/libconnectivity/src/connectivity_native.cpp
new file mode 100644
index 0000000..9545ed1
--- /dev/null
+++ b/service/libconnectivity/src/connectivity_native.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#include "connectivity_native.h"
+
+#include <android/binder_manager.h>
+#include <aidl/android/net/connectivity/aidl/ConnectivityNative.h>
+
+using aidl::android::net::connectivity::aidl::IConnectivityNative;
+
+
+static std::shared_ptr<IConnectivityNative> getBinder() {
+    static ndk::SpAIBinder sBinder = ndk::SpAIBinder(reinterpret_cast<AIBinder*>(
+        AServiceManager_getService("connectivity_native")));
+    return aidl::android::net::connectivity::aidl::IConnectivityNative::fromBinder(sBinder);
+}
+
+static int getErrno(const ::ndk::ScopedAStatus& status) {
+    switch (status.getExceptionCode()) {
+        case EX_NONE:
+            return 0;
+        case EX_ILLEGAL_ARGUMENT:
+            return EINVAL;
+        case EX_SECURITY:
+            return EPERM;
+        case EX_SERVICE_SPECIFIC:
+            return status.getServiceSpecificError();
+        default:
+            return EPROTO;
+    }
+}
+
+int AConnectivityNative_blockPortForBind(in_port_t port) {
+    std::shared_ptr<IConnectivityNative> c = getBinder();
+    return getErrno(c->blockPortForBind(port));
+}
+
+int AConnectivityNative_unblockPortForBind(in_port_t port) {
+    std::shared_ptr<IConnectivityNative> c = getBinder();
+    return getErrno(c->unblockPortForBind(port));
+}
+
+int AConnectivityNative_unblockAllPortsForBind() {
+    std::shared_ptr<IConnectivityNative> c = getBinder();
+    return getErrno(c->unblockAllPortsForBind());
+}
+
+int AConnectivityNative_getPortsBlockedForBind(in_port_t *ports, size_t *count) {
+    std::shared_ptr<IConnectivityNative> c = getBinder();
+    std::vector<int32_t> actualBlockedPorts;
+    int err = getErrno(c->getPortsBlockedForBind(&actualBlockedPorts));
+    if (err) {
+        return err;
+    }
+
+    for (int i = 0; i < *count && i < actualBlockedPorts.size(); i++) {
+        ports[i] = actualBlockedPorts[i];
+    }
+    *count = actualBlockedPorts.size();
+    return 0;
+}
diff --git a/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java b/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
index f366363..f7871f3 100644
--- a/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
+++ b/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity.mdns;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.text.TextUtils;
 import android.util.Pair;
 
@@ -38,8 +39,6 @@
  * and the list of the subtypes in the query as a {@link Pair}. If a query is failed to build, or if
  * it can not be enqueued, then call to {@link #call()} returns {@code null}.
  */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 public class EnqueueMdnsQueryCallable implements Callable<Pair<Integer, List<String>>> {
 
     private static final String TAG = "MdnsQueryCallable";
@@ -81,7 +80,10 @@
         this.transactionId = transactionId;
     }
 
+    // Incompatible return type for override of Callable#call().
+    @SuppressWarnings("nullness:override.return.invalid")
     @Override
+    @Nullable
     public Pair<Integer, List<String>> call() {
         try {
             MdnsSocketClient requestSender = weakRequestSender.get();
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsConfigs.java b/service/mdns/com/android/server/connectivity/mdns/MdnsConfigs.java
index 35a685d..75c7e6c 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsConfigs.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsConfigs.java
@@ -97,4 +97,12 @@
     public static boolean allowSearchOptionsToRemoveExpiredService() {
         return false;
     }
+
+    public static boolean allowNetworkInterfaceIndexPropagation() {
+        return true;
+    }
+
+    public static boolean allowMultipleSrvRecordsPerHost() {
+        return true;
+    }
 }
\ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java b/service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java
index 0b2066a..396be5f 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java
@@ -16,19 +16,15 @@
 
 package com.android.server.connectivity.mdns;
 
-import android.annotation.TargetApi;
-import android.os.Build;
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
 
 /** mDNS-related constants. */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 @VisibleForTesting
 public final class MdnsConstants {
     public static final int MDNS_PORT = 5353;
@@ -48,7 +44,6 @@
     private static final String MDNS_IPV4_HOST_ADDRESS = "224.0.0.251";
     private static final String MDNS_IPV6_HOST_ADDRESS = "FF02::FB";
     private static InetAddress mdnsAddress;
-    private static Charset utf8Charset;
     private MdnsConstants() {
     }
 
@@ -79,16 +74,6 @@
     }
 
     public static Charset getUtf8Charset() {
-        synchronized (MdnsConstants.class) {
-            if (utf8Charset == null) {
-                utf8Charset = getUtf8CharsetOnKitKat();
-            }
-            return utf8Charset;
-        }
-    }
-
-    @TargetApi(Build.VERSION_CODES.KITKAT)
-    private static Charset getUtf8CharsetOnKitKat() {
-        return StandardCharsets.UTF_8;
+        return UTF_8;
     }
 }
\ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java
index bd47414..47ac20e 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java
@@ -16,6 +16,8 @@
 
 package com.android.server.connectivity.mdns;
 
+import android.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
@@ -27,12 +29,10 @@
 import java.util.Objects;
 
 /** An mDNS "AAAA" or "A" record, which holds an IPv6 or IPv4 address. */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 @VisibleForTesting
 public class MdnsInetAddressRecord extends MdnsRecord {
-    private Inet6Address inet6Address;
-    private Inet4Address inet4Address;
+    @Nullable private Inet6Address inet6Address;
+    @Nullable private Inet4Address inet4Address;
 
     /**
      * Constructs the {@link MdnsRecord}
@@ -47,11 +47,13 @@
     }
 
     /** Returns the IPv6 address. */
+    @Nullable
     public Inet6Address getInet6Address() {
         return inet6Address;
     }
 
     /** Returns the IPv4 address. */
+    @Nullable
     public Inet4Address getInet4Address() {
         return inet4Address;
     }
@@ -113,7 +115,7 @@
     }
 
     @Override
-    public boolean equals(Object other) {
+    public boolean equals(@Nullable Object other) {
         if (this == other) {
             return true;
         }
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsPacketReader.java b/service/mdns/com/android/server/connectivity/mdns/MdnsPacketReader.java
index 61c5f5a..856a2cd 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsPacketReader.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsPacketReader.java
@@ -16,8 +16,11 @@
 
 package com.android.server.connectivity.mdns;
 
+import android.annotation.Nullable;
 import android.util.SparseArray;
 
+import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
+
 import java.io.EOFException;
 import java.io.IOException;
 import java.net.DatagramPacket;
@@ -195,6 +198,16 @@
         return val;
     }
 
+    @Nullable
+    public TextEntry readTextEntry() throws EOFException {
+        int len = readUInt8();
+        checkRemaining(len);
+        byte[] bytes = new byte[len];
+        System.arraycopy(buf, pos, bytes, 0, bytes.length);
+        pos += len;
+        return TextEntry.fromBytes(bytes);
+    }
+
     /**
      * Reads a specific number of bytes.
      *
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsPacketWriter.java b/service/mdns/com/android/server/connectivity/mdns/MdnsPacketWriter.java
index 2fed36d..b78aa5d 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsPacketWriter.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsPacketWriter.java
@@ -16,6 +16,8 @@
 
 package com.android.server.connectivity.mdns;
 
+import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
+
 import java.io.IOException;
 import java.net.DatagramPacket;
 import java.net.SocketAddress;
@@ -147,6 +149,12 @@
         writeBytes(utf8);
     }
 
+    public void writeTextEntry(TextEntry textEntry) throws IOException {
+        byte[] bytes = textEntry.toBytes();
+        writeUInt8(bytes.length);
+        writeBytes(bytes);
+    }
+
     /**
      * Writes a series of labels. Uses name compression.
      *
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java
index 0166815..9641a40 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java
@@ -16,14 +16,14 @@
 
 package com.android.server.connectivity.mdns;
 
+import android.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
 import java.util.Arrays;
 
 /** An mDNS "PTR" record, which holds a name (the "pointer"). */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 @VisibleForTesting
 public class MdnsPointerRecord extends MdnsRecord {
     private String[] pointer;
@@ -66,7 +66,7 @@
     }
 
     @Override
-    public boolean equals(Object other) {
+    public boolean equals(@Nullable Object other) {
         if (this == other) {
             return true;
         }
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java
index 24fb09e..35f6da1 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java
@@ -16,6 +16,10 @@
 
 package com.android.server.connectivity.mdns;
 
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.annotation.Nullable;
 import android.os.SystemClock;
 import android.text.TextUtils;
 
@@ -24,14 +28,11 @@
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Objects;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Abstract base class for mDNS records. Stores the header fields and provides methods for reading
  * the record from and writing it to a packet.
  */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 public abstract class MdnsRecord {
     public static final int TYPE_A = 0x0001;
     public static final int TYPE_AAAA = 0x001C;
@@ -59,11 +60,14 @@
      * @param reader The reader to read the record from.
      * @throws IOException If an error occurs while reading the packet.
      */
+    // call to readData(com.android.server.connectivity.mdns.MdnsPacketReader) not allowed on given
+    // receiver.
+    @SuppressWarnings("nullness:method.invocation.invalid")
     protected MdnsRecord(String[] name, int type, MdnsPacketReader reader) throws IOException {
         this.name = name;
         this.type = type;
         cls = reader.readUInt16();
-        ttlMillis = TimeUnit.SECONDS.toMillis(reader.readUInt32());
+        ttlMillis = SECONDS.toMillis(reader.readUInt32());
         int dataLength = reader.readUInt16();
 
         receiptTimeMillis = SystemClock.elapsedRealtime();
@@ -157,7 +161,7 @@
         writer.writeUInt16(type);
         writer.writeUInt16(cls);
 
-        writer.writeUInt32(TimeUnit.MILLISECONDS.toSeconds(getRemainingTTL(now)));
+        writer.writeUInt32(MILLISECONDS.toSeconds(getRemainingTTL(now)));
 
         int dataLengthPos = writer.getWritePosition();
         writer.writeUInt16(0); // data length
@@ -194,7 +198,7 @@
     }
 
     @Override
-    public boolean equals(Object other) {
+    public boolean equals(@Nullable Object other) {
         if (!(other instanceof MdnsRecord)) {
             return false;
         }
@@ -231,7 +235,7 @@
         }
 
         @Override
-        public boolean equals(Object other) {
+        public boolean equals(@Nullable Object other) {
             if (this == other) {
                 return true;
             }
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java b/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java
index 9f3894f..623168c 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java
@@ -16,6 +16,8 @@
 
 package com.android.server.connectivity.mdns;
 
+import android.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
@@ -25,8 +27,6 @@
 import java.util.List;
 
 /** An mDNS response. */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 public class MdnsResponse {
     private final List<MdnsRecord> records;
     private final List<MdnsPointerRecord> pointerRecords;
@@ -35,6 +35,7 @@
     private MdnsInetAddressRecord inet4AddressRecord;
     private MdnsInetAddressRecord inet6AddressRecord;
     private long lastUpdateTime;
+    private int interfaceIndex = MdnsSocket.INTERFACE_INDEX_UNSPECIFIED;
 
     /** Constructs a new, empty response. */
     public MdnsResponse(long now) {
@@ -77,7 +78,7 @@
     }
 
     @VisibleForTesting
-    /* package */ synchronized void clearPointerRecords() {
+    synchronized void clearPointerRecords() {
         pointerRecords.clear();
     }
 
@@ -90,15 +91,16 @@
         return false;
     }
 
+    @Nullable
     public synchronized List<String> getSubtypes() {
         List<String> subtypes = null;
-
         for (MdnsPointerRecord pointerRecord : pointerRecords) {
-            if (pointerRecord.hasSubtype()) {
+            String pointerRecordSubtype = pointerRecord.getSubtype();
+            if (pointerRecordSubtype != null) {
                 if (subtypes == null) {
                     subtypes = new LinkedList<>();
                 }
-                subtypes.add(pointerRecord.getSubtype());
+                subtypes.add(pointerRecordSubtype);
             }
         }
 
@@ -165,7 +167,8 @@
     }
 
     /** Sets the IPv4 address record. */
-    public synchronized boolean setInet4AddressRecord(MdnsInetAddressRecord newInet4AddressRecord) {
+    public synchronized boolean setInet4AddressRecord(
+            @Nullable MdnsInetAddressRecord newInet4AddressRecord) {
         if (recordsAreSame(this.inet4AddressRecord, newInet4AddressRecord)) {
             return false;
         }
@@ -189,7 +192,8 @@
     }
 
     /** Sets the IPv6 address record. */
-    public synchronized boolean setInet6AddressRecord(MdnsInetAddressRecord newInet6AddressRecord) {
+    public synchronized boolean setInet6AddressRecord(
+            @Nullable MdnsInetAddressRecord newInet6AddressRecord) {
         if (recordsAreSame(this.inet6AddressRecord, newInet6AddressRecord)) {
             return false;
         }
@@ -203,6 +207,21 @@
         return true;
     }
 
+    /**
+     * Updates the index of the network interface at which this response was received. Can be set to
+     * {@link MdnsSocket#INTERFACE_INDEX_UNSPECIFIED} if unset.
+     */
+    public synchronized void setInterfaceIndex(int interfaceIndex) {
+        this.interfaceIndex = interfaceIndex;
+    }
+
+    /**
+     * Returns the index of the network interface at which this response was received. Can be set to
+     * {@link MdnsSocket#INTERFACE_INDEX_UNSPECIFIED} if unset.
+     */
+    public synchronized int getInterfaceIndex() {
+        return interfaceIndex;
+    }
 
     /** Gets the IPv6 address record. */
     public synchronized MdnsInetAddressRecord getInet6AddressRecord() {
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java b/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
index 3e5fc42..861acbb 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
@@ -25,19 +25,20 @@
 import java.io.EOFException;
 import java.io.IOException;
 import java.net.DatagramPacket;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 
 /** A class that decodes mDNS responses from UDP packets. */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 public class MdnsResponseDecoder {
 
     public static final int SUCCESS = 0;
     private static final String TAG = "MdnsResponseDecoder";
     private static final MdnsLogger LOGGER = new MdnsLogger(TAG);
-    private final String[] serviceType;
+    private final boolean allowMultipleSrvRecordsPerHost =
+            MdnsConfigs.allowMultipleSrvRecordsPerHost();
+    @Nullable private final String[] serviceType;
     private final Clock clock;
 
     /** Constructs a new decoder that will extract responses for the given service type. */
@@ -92,9 +93,12 @@
      * the responses for completeness; the caller should do that.
      *
      * @param packet The packet to read from.
+     * @param interfaceIndex the network interface index (or {@link
+     *     MdnsSocket#INTERFACE_INDEX_UNSPECIFIED} if not known) at which the packet was received
      * @return A list of mDNS responses, or null if the packet contained no appropriate responses.
      */
-    public int decode(@NonNull DatagramPacket packet, @NonNull List<MdnsResponse> responses) {
+    public int decode(@NonNull DatagramPacket packet, @NonNull List<MdnsResponse> responses,
+            int interfaceIndex) {
         MdnsPacketReader reader = new MdnsPacketReader(packet);
 
         List<MdnsRecord> records;
@@ -278,11 +282,18 @@
         for (MdnsRecord record : records) {
             if (record instanceof MdnsInetAddressRecord) {
                 MdnsInetAddressRecord inetRecord = (MdnsInetAddressRecord) record;
-                MdnsResponse response = findResponseWithHostName(responses, inetRecord.getName());
-                if (inetRecord.getInet4Address() != null && response != null) {
-                    response.setInet4AddressRecord(inetRecord);
-                } else if (inetRecord.getInet6Address() != null && response != null) {
-                    response.setInet6AddressRecord(inetRecord);
+                if (allowMultipleSrvRecordsPerHost) {
+                    List<MdnsResponse> matchingResponses =
+                            findResponsesWithHostName(responses, inetRecord.getName());
+                    for (MdnsResponse response : matchingResponses) {
+                        assignInetRecord(response, inetRecord, interfaceIndex);
+                    }
+                } else {
+                    MdnsResponse response =
+                            findResponseWithHostName(responses, inetRecord.getName());
+                    if (response != null) {
+                        assignInetRecord(response, inetRecord, interfaceIndex);
+                    }
                 }
             }
         }
@@ -290,6 +301,39 @@
         return SUCCESS;
     }
 
+    private static void assignInetRecord(
+            MdnsResponse response, MdnsInetAddressRecord inetRecord, int interfaceIndex) {
+        if (inetRecord.getInet4Address() != null) {
+            response.setInet4AddressRecord(inetRecord);
+            response.setInterfaceIndex(interfaceIndex);
+        } else if (inetRecord.getInet6Address() != null) {
+            response.setInet6AddressRecord(inetRecord);
+            response.setInterfaceIndex(interfaceIndex);
+        }
+    }
+
+    private static List<MdnsResponse> findResponsesWithHostName(
+            @Nullable List<MdnsResponse> responses, String[] hostName) {
+        if (responses == null || responses.isEmpty()) {
+            return List.of();
+        }
+
+        List<MdnsResponse> result = null;
+        for (MdnsResponse response : responses) {
+            MdnsServiceRecord serviceRecord = response.getServiceRecord();
+            if (serviceRecord == null) {
+                continue;
+            }
+            if (Arrays.equals(serviceRecord.getServiceHost(), hostName)) {
+                if (result == null) {
+                    result = new ArrayList<>(/* initialCapacity= */ responses.size());
+                }
+                result.add(response);
+            }
+        }
+        return result == null ? List.of() : result;
+    }
+
     public static class Clock {
         public long elapsedRealtime() {
             return SystemClock.elapsedRealtime();
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceInfo.java b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceInfo.java
index 2e4a4e5..f1b2def 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceInfo.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceInfo.java
@@ -17,11 +17,16 @@
 package com.android.server.connectivity.mdns;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import com.android.net.module.util.ByteUtils;
+
+import java.nio.charset.Charset;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -34,6 +39,8 @@
  * @hide
  */
 public class MdnsServiceInfo implements Parcelable {
+    private static final Charset US_ASCII = Charset.forName("us-ascii");
+    private static final Charset UTF_8 = Charset.forName("utf-8");
 
     /** @hide */
     public static final Parcelable.Creator<MdnsServiceInfo> CREATOR =
@@ -49,7 +56,9 @@
                             source.readInt(),
                             source.readString(),
                             source.readString(),
-                            source.createStringArrayList());
+                            source.createStringArrayList(),
+                            source.createTypedArrayList(TextEntry.CREATOR),
+                            source.readInt());
                 }
 
                 @Override
@@ -63,10 +72,63 @@
     private final List<String> subtypes;
     private final String[] hostName;
     private final int port;
+    @Nullable
     private final String ipv4Address;
+    @Nullable
     private final String ipv6Address;
-    private final Map<String, String> attributes = new HashMap<>();
-    List<String> textStrings;
+    final List<String> textStrings;
+    @Nullable
+    final List<TextEntry> textEntries;
+    private final int interfaceIndex;
+
+    private final Map<String, byte[]> attributes;
+
+    /** Constructs a {@link MdnsServiceInfo} object with default values. */
+    public MdnsServiceInfo(
+            String serviceInstanceName,
+            String[] serviceType,
+            @Nullable List<String> subtypes,
+            String[] hostName,
+            int port,
+            @Nullable String ipv4Address,
+            @Nullable String ipv6Address,
+            @Nullable List<String> textStrings) {
+        this(
+                serviceInstanceName,
+                serviceType,
+                subtypes,
+                hostName,
+                port,
+                ipv4Address,
+                ipv6Address,
+                textStrings,
+                /* textEntries= */ null,
+                /* interfaceIndex= */ -1);
+    }
+
+    /** Constructs a {@link MdnsServiceInfo} object with default values. */
+    public MdnsServiceInfo(
+            String serviceInstanceName,
+            String[] serviceType,
+            List<String> subtypes,
+            String[] hostName,
+            int port,
+            @Nullable String ipv4Address,
+            @Nullable String ipv6Address,
+            @Nullable List<String> textStrings,
+            @Nullable List<TextEntry> textEntries) {
+        this(
+                serviceInstanceName,
+                serviceType,
+                subtypes,
+                hostName,
+                port,
+                ipv4Address,
+                ipv6Address,
+                textStrings,
+                textEntries,
+                /* interfaceIndex= */ -1);
+    }
 
     /**
      * Constructs a {@link MdnsServiceInfo} object with default values.
@@ -76,12 +138,14 @@
     public MdnsServiceInfo(
             String serviceInstanceName,
             String[] serviceType,
-            List<String> subtypes,
+            @Nullable List<String> subtypes,
             String[] hostName,
             int port,
-            String ipv4Address,
-            String ipv6Address,
-            List<String> textStrings) {
+            @Nullable String ipv4Address,
+            @Nullable String ipv6Address,
+            @Nullable List<String> textStrings,
+            @Nullable List<TextEntry> textEntries,
+            int interfaceIndex) {
         this.serviceInstanceName = serviceInstanceName;
         this.serviceType = serviceType;
         this.subtypes = new ArrayList<>();
@@ -92,72 +156,123 @@
         this.port = port;
         this.ipv4Address = ipv4Address;
         this.ipv6Address = ipv6Address;
+        this.textStrings = new ArrayList<>();
         if (textStrings != null) {
-            for (String text : textStrings) {
-                int pos = text.indexOf('=');
-                if (pos < 1) {
-                    continue;
-                }
-                attributes.put(text.substring(0, pos).toLowerCase(Locale.ENGLISH),
-                        text.substring(++pos));
+            this.textStrings.addAll(textStrings);
+        }
+        this.textEntries = (textEntries == null) ? null : new ArrayList<>(textEntries);
+
+        // The module side sends both {@code textStrings} and {@code textEntries} for backward
+        // compatibility. We should prefer only {@code textEntries} if it's not null.
+        List<TextEntry> entries =
+                (this.textEntries != null) ? this.textEntries : parseTextStrings(this.textStrings);
+        Map<String, byte[]> attributes = new HashMap<>(entries.size());
+        for (TextEntry entry : entries) {
+            String key = entry.getKey().toLowerCase(Locale.ENGLISH);
+
+            // Per https://datatracker.ietf.org/doc/html/rfc6763#section-6.4, only the first entry
+            // of the same key should be accepted:
+            // If a client receives a TXT record containing the same key more than once, then the
+            // client MUST silently ignore all but the first occurrence of that attribute.
+            if (!attributes.containsKey(key)) {
+                attributes.put(key, entry.getValue());
             }
         }
+        this.attributes = Collections.unmodifiableMap(attributes);
+        this.interfaceIndex = interfaceIndex;
     }
 
-    /** @return the name of this service instance. */
+    private static List<TextEntry> parseTextStrings(List<String> textStrings) {
+        List<TextEntry> list = new ArrayList(textStrings.size());
+        for (String textString : textStrings) {
+            TextEntry entry = TextEntry.fromString(textString);
+            if (entry != null) {
+                list.add(entry);
+            }
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    /** Returns the name of this service instance. */
     public String getServiceInstanceName() {
         return serviceInstanceName;
     }
 
-    /** @return the type of this service instance. */
+    /** Returns the type of this service instance. */
     public String[] getServiceType() {
         return serviceType;
     }
 
-    /** @return the list of subtypes supported by this service instance. */
+    /** Returns the list of subtypes supported by this service instance. */
     public List<String> getSubtypes() {
         return new ArrayList<>(subtypes);
     }
 
-    /**
-     * @return {@code true} if this service instance supports any subtypes.
-     * @return {@code false} if this service instance does not support any subtypes.
-     */
+    /** Returns {@code true} if this service instance supports any subtypes. */
     public boolean hasSubtypes() {
         return !subtypes.isEmpty();
     }
 
-    /** @return the host name of this service instance. */
+    /** Returns the host name of this service instance. */
     public String[] getHostName() {
         return hostName;
     }
 
-    /** @return the port number of this service instance. */
+    /** Returns the port number of this service instance. */
     public int getPort() {
         return port;
     }
 
-    /** @return the IPV4 address of this service instance. */
+    /** Returns the IPV4 address of this service instance. */
+    @Nullable
     public String getIpv4Address() {
         return ipv4Address;
     }
 
-    /** @return the IPV6 address of this service instance. */
+    /** Returns the IPV6 address of this service instance. */
+    @Nullable
     public String getIpv6Address() {
         return ipv6Address;
     }
 
     /**
-     * @return the attribute value for {@code key}.
-     * @return {@code null} if no attribute value exists for {@code key}.
+     * Returns the index of the network interface at which this response was received, or -1 if the
+     * index is not known.
      */
+    public int getInterfaceIndex() {
+        return interfaceIndex;
+    }
+
+    /**
+     * Returns attribute value for {@code key} as a UTF-8 string. It's the caller who must make sure
+     * that the value of {@code key} is indeed a UTF-8 string. {@code null} will be returned if no
+     * attribute value exists for {@code key}.
+     */
+    @Nullable
     public String getAttributeByKey(@NonNull String key) {
+        byte[] value = getAttributeAsBytes(key);
+        if (value == null) {
+            return null;
+        }
+        return new String(value, UTF_8);
+    }
+
+    /**
+     * Returns the attribute value for {@code key} as a byte array. {@code null} will be returned if
+     * no attribute value exists for {@code key}.
+     */
+    @Nullable
+    public byte[] getAttributeAsBytes(@NonNull String key) {
         return attributes.get(key.toLowerCase(Locale.ENGLISH));
     }
 
-    /** @return an immutable map of all attributes. */
+    /** Returns an immutable map of all attributes. */
     public Map<String, String> getAttributes() {
-        return Collections.unmodifiableMap(attributes);
+        Map<String, String> map = new HashMap<>(attributes.size());
+        for (Map.Entry<String, byte[]> kv : attributes.entrySet()) {
+            map.put(kv.getKey(), new String(kv.getValue(), UTF_8));
+        }
+        return Collections.unmodifiableMap(map);
     }
 
     @Override
@@ -167,14 +282,6 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        if (textStrings == null) {
-            // Lazily initialize the parcelable field mTextStrings.
-            textStrings = new ArrayList<>(attributes.size());
-            for (Map.Entry<String, String> kv : attributes.entrySet()) {
-                textStrings.add(String.format(Locale.ROOT, "%s=%s", kv.getKey(), kv.getValue()));
-            }
-        }
-
         out.writeString(serviceInstanceName);
         out.writeStringArray(serviceType);
         out.writeStringList(subtypes);
@@ -183,6 +290,8 @@
         out.writeString(ipv4Address);
         out.writeString(ipv6Address);
         out.writeStringList(textStrings);
+        out.writeTypedList(textEntries);
+        out.writeInt(interfaceIndex);
     }
 
     @Override
@@ -195,4 +304,114 @@
                 ipv4Address,
                 port);
     }
+
+
+    /** Represents a DNS TXT key-value pair defined by RFC 6763. */
+    public static final class TextEntry implements Parcelable {
+        public static final Parcelable.Creator<TextEntry> CREATOR =
+                new Parcelable.Creator<TextEntry>() {
+                    @Override
+                    public TextEntry createFromParcel(Parcel source) {
+                        return new TextEntry(source);
+                    }
+
+                    @Override
+                    public TextEntry[] newArray(int size) {
+                        return new TextEntry[size];
+                    }
+                };
+
+        private final String key;
+        private final byte[] value;
+
+        /** Creates a new {@link TextEntry} instance from a '=' separated string. */
+        @Nullable
+        public static TextEntry fromString(String textString) {
+            return fromBytes(textString.getBytes(UTF_8));
+        }
+
+        /** Creates a new {@link TextEntry} instance from a '=' separated byte array. */
+        @Nullable
+        public static TextEntry fromBytes(byte[] textBytes) {
+            int delimitPos = ByteUtils.indexOf(textBytes, (byte) '=');
+
+            // Per https://datatracker.ietf.org/doc/html/rfc6763#section-6.4:
+            // 1. The key MUST be at least one character.  DNS-SD TXT record strings
+            // beginning with an '=' character (i.e., the key is missing) MUST be
+            // silently ignored.
+            // 2. If there is no '=' in a DNS-SD TXT record string, then it is a
+            // boolean attribute, simply identified as being present, with no value.
+            if (delimitPos < 0) {
+                return new TextEntry(new String(textBytes, US_ASCII), "");
+            } else if (delimitPos == 0) {
+                return null;
+            }
+            return new TextEntry(
+                    new String(Arrays.copyOf(textBytes, delimitPos), US_ASCII),
+                    Arrays.copyOfRange(textBytes, delimitPos + 1, textBytes.length));
+        }
+
+        /** Creates a new {@link TextEntry} with given key and value of a UTF-8 string. */
+        public TextEntry(String key, String value) {
+            this(key, value.getBytes(UTF_8));
+        }
+
+        /** Creates a new {@link TextEntry} with given key and value of a byte array. */
+        public TextEntry(String key, byte[] value) {
+            this.key = key;
+            this.value = value.clone();
+        }
+
+        private TextEntry(Parcel in) {
+            key = in.readString();
+            value = in.createByteArray();
+        }
+
+        public String getKey() {
+            return key;
+        }
+
+        public byte[] getValue() {
+            return value.clone();
+        }
+
+        /** Converts this {@link TextEntry} instance to '=' separated byte array. */
+        public byte[] toBytes() {
+            return ByteUtils.concat(key.getBytes(US_ASCII), new byte[]{'='}, value);
+        }
+
+        /** Converts this {@link TextEntry} instance to '=' separated string. */
+        @Override
+        public String toString() {
+            return key + "=" + new String(value, UTF_8);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object other) {
+            if (this == other) {
+                return true;
+            } else if (!(other instanceof TextEntry)) {
+                return false;
+            }
+            TextEntry otherEntry = (TextEntry) other;
+
+            return key.equals(otherEntry.key) && Arrays.equals(value, otherEntry.value);
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 * key.hashCode() + Arrays.hashCode(value);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(key);
+            out.writeByteArray(value);
+        }
+    }
 }
\ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java
index 7f54d96..c52d25e 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java
@@ -16,6 +16,8 @@
 
 package com.android.server.connectivity.mdns;
 
+import android.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
@@ -24,8 +26,6 @@
 import java.util.Objects;
 
 /** An mDNS "SRV" record, which contains service information. */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 @VisibleForTesting
 public class MdnsServiceRecord extends MdnsRecord {
     public static final int PROTO_NONE = 0;
@@ -131,7 +131,7 @@
     }
 
     @Override
-    public boolean equals(Object other) {
+    public boolean equals(@Nullable Object other) {
         if (this == other) {
             return true;
         }
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
index 4fbc809..8ca71b9 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -29,6 +29,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.connectivity.mdns.util.MdnsLogger;
 
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -43,8 +45,6 @@
  * Instance of this class sends and receives mDNS packets of a given service type and invoke
  * registered {@link MdnsServiceBrowserListener} instances.
  */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 public class MdnsServiceTypeClient {
 
     private static final int DEFAULT_MTU = 1500;
@@ -70,6 +70,7 @@
     private long currentSessionId = 0;
 
     @GuardedBy("lock")
+    @Nullable
     private Future<?> requestTaskFuture;
 
     /**
@@ -96,21 +97,34 @@
         String ipv4Address = null;
         String ipv6Address = null;
         if (response.hasInet4AddressRecord()) {
-            ipv4Address = response.getInet4AddressRecord().getInet4Address().getHostAddress();
+            Inet4Address inet4Address = response.getInet4AddressRecord().getInet4Address();
+            ipv4Address = (inet4Address == null) ? null : inet4Address.getHostAddress();
         }
         if (response.hasInet6AddressRecord()) {
-            ipv6Address = response.getInet6AddressRecord().getInet6Address().getHostAddress();
+            Inet6Address inet6Address = response.getInet6AddressRecord().getInet6Address();
+            ipv6Address = (inet6Address == null) ? null : inet6Address.getHostAddress();
+        }
+        if (ipv4Address == null && ipv6Address == null) {
+            throw new IllegalArgumentException(
+                    "Either ipv4Address or ipv6Address must be non-null");
+        }
+        String serviceInstanceName = response.getServiceInstanceName();
+        if (serviceInstanceName == null) {
+            throw new IllegalStateException(
+                    "mDNS response must have non-null service instance name");
         }
         // TODO: Throw an error message if response doesn't have Inet6 or Inet4 address.
         return new MdnsServiceInfo(
-                response.getServiceInstanceName(),
+                serviceInstanceName,
                 serviceTypeLabels,
                 response.getSubtypes(),
                 hostName,
                 port,
                 ipv4Address,
                 ipv6Address,
-                response.getTextRecord().getStrings());
+                response.getTextRecord().getStrings(),
+                response.getTextRecord().getEntries(),
+                response.getInterfaceIndex());
     }
 
     /**
@@ -126,8 +140,7 @@
             @NonNull MdnsSearchOptions searchOptions) {
         synchronized (lock) {
             this.searchOptions = searchOptions;
-            if (!listeners.contains(listener)) {
-                listeners.add(listener);
+            if (listeners.add(listener)) {
                 for (MdnsResponse existingResponse : instanceNameToResponse.values()) {
                     if (existingResponse.isComplete()) {
                         listener.onServiceFound(
@@ -210,7 +223,10 @@
         if (currentResponse == null) {
             newServiceFound = true;
             currentResponse = response;
-            instanceNameToResponse.put(response.getServiceInstanceName(), currentResponse);
+            String serviceInstanceName = response.getServiceInstanceName();
+            if (serviceInstanceName != null) {
+                instanceNameToResponse.put(serviceInstanceName, currentResponse);
+            }
         } else if (currentResponse.mergeRecordsFrom(response)) {
             existingServiceChanged = true;
         }
@@ -229,7 +245,10 @@
         }
     }
 
-    private void onGoodbyeReceived(@NonNull String serviceInstanceName) {
+    private void onGoodbyeReceived(@Nullable String serviceInstanceName) {
+        if (serviceInstanceName == null) {
+            return;
+        }
         instanceNameToResponse.remove(serviceInstanceName);
         for (MdnsServiceBrowserListener listener : listeners) {
             listener.onServiceRemoved(serviceInstanceName);
@@ -365,7 +384,7 @@
                                 config.expectUnicastResponse,
                                 config.transactionId)
                                 .call();
-            } catch (Exception e) {
+            } catch (RuntimeException e) {
                 LOGGER.e(String.format("Failed to run EnqueueMdnsQueryCallable for subtype: %s",
                         TextUtils.join(",", config.subtypes)), e);
                 result = null;
@@ -403,8 +422,11 @@
                                 == 0) {
                             iter.remove();
                             for (MdnsServiceBrowserListener listener : listeners) {
-                                listener.onServiceRemoved(
-                                        existingResponse.getServiceInstanceName());
+                                String serviceInstanceName =
+                                        existingResponse.getServiceInstanceName();
+                                if (serviceInstanceName != null) {
+                                    listener.onServiceRemoved(serviceInstanceName);
+                                }
                             }
                         }
                     }
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java b/service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java
index 34db7f0..0a9b2fc 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java
@@ -19,11 +19,13 @@
 import android.annotation.NonNull;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.connectivity.mdns.util.MdnsLogger;
 
 import java.io.IOException;
 import java.net.DatagramPacket;
 import java.net.InetSocketAddress;
 import java.net.MulticastSocket;
+import java.net.SocketException;
 import java.util.List;
 
 /**
@@ -32,23 +34,30 @@
  *
  * @see MulticastSocket for javadoc of each public method.
  */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 public class MdnsSocket {
+    private static final MdnsLogger LOGGER = new MdnsLogger("MdnsSocket");
+
+    static final int INTERFACE_INDEX_UNSPECIFIED = -1;
     private static final InetSocketAddress MULTICAST_IPV4_ADDRESS =
             new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT);
     private static final InetSocketAddress MULTICAST_IPV6_ADDRESS =
             new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT);
-    private static boolean isOnIPv6OnlyNetwork = false;
     private final MulticastNetworkInterfaceProvider multicastNetworkInterfaceProvider;
     private final MulticastSocket multicastSocket;
+    private boolean isOnIPv6OnlyNetwork;
 
     public MdnsSocket(
             @NonNull MulticastNetworkInterfaceProvider multicastNetworkInterfaceProvider, int port)
             throws IOException {
+        this(multicastNetworkInterfaceProvider, new MulticastSocket(port));
+    }
+
+    @VisibleForTesting
+    MdnsSocket(@NonNull MulticastNetworkInterfaceProvider multicastNetworkInterfaceProvider,
+            MulticastSocket multicastSocket) throws IOException {
         this.multicastNetworkInterfaceProvider = multicastNetworkInterfaceProvider;
         this.multicastNetworkInterfaceProvider.startWatchingConnectivityChanges();
-        multicastSocket = createMulticastSocket(port);
+        this.multicastSocket = multicastSocket;
         // RFC Spec: https://tools.ietf.org/html/rfc6762
         // Time to live is set 255, which is similar to the jMDNS implementation.
         multicastSocket.setTimeToLive(255);
@@ -103,9 +112,17 @@
         multicastNetworkInterfaceProvider.stopWatchingConnectivityChanges();
     }
 
-    @VisibleForTesting
-    MulticastSocket createMulticastSocket(int port) throws IOException {
-        return new MulticastSocket(port);
+    /**
+     * Returns the index of the network interface that this socket is bound to. If the interface
+     * cannot be determined, returns -1.
+     */
+    public int getInterfaceIndex() {
+        try {
+            return multicastSocket.getNetworkInterface().getIndex();
+        } catch (SocketException e) {
+            LOGGER.e("Failed to retrieve interface index for socket.", e);
+            return -1;
+        }
     }
 
     public boolean isOnIPv6OnlyNetwork() {
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java b/service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java
index 010f761..758221a 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java
@@ -46,8 +46,6 @@
  *
  * <p>See https://tools.ietf.org/html/rfc6763 (namely sections 4 and 5).
  */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
 public class MdnsSocketClient {
 
     private static final String TAG = "MdnsClient";
@@ -71,7 +69,7 @@
     final Queue<DatagramPacket> unicastPacketQueue = new ArrayDeque<>();
     private final Context context;
     private final byte[] multicastReceiverBuffer = new byte[RECEIVER_BUFFER_SIZE];
-    private final byte[] unicastReceiverBuffer;
+    @Nullable private final byte[] unicastReceiverBuffer;
     private final MdnsResponseDecoder responseDecoder;
     private final MulticastLock multicastLock;
     private final boolean useSeparateSocketForUnicast =
@@ -79,6 +77,8 @@
     private final boolean checkMulticastResponse = MdnsConfigs.checkMulticastResponse();
     private final long checkMulticastResponseIntervalMs =
             MdnsConfigs.checkMulticastResponseIntervalMs();
+    private final boolean propagateInterfaceIndex =
+            MdnsConfigs.allowNetworkInterfaceIndexPropagation();
     private final Object socketLock = new Object();
     private final Object timerObject = new Object();
     // If multicast response was received in the current session. The value is reset in the
@@ -92,20 +92,17 @@
     // If the phone is the bad state where it can't receive any multicast response.
     @VisibleForTesting
     AtomicBoolean cannotReceiveMulticastResponse = new AtomicBoolean(false);
-    @VisibleForTesting
-    volatile Thread sendThread;
-    @VisibleForTesting
-    Thread multicastReceiveThread;
-    @VisibleForTesting
-    Thread unicastReceiveThread;
+    @VisibleForTesting @Nullable volatile Thread sendThread;
+    @VisibleForTesting @Nullable Thread multicastReceiveThread;
+    @VisibleForTesting @Nullable Thread unicastReceiveThread;
     private volatile boolean shouldStopSocketLoop;
-    private Callback callback;
-    private MdnsSocket multicastSocket;
-    private MdnsSocket unicastSocket;
+    @Nullable private Callback callback;
+    @Nullable private MdnsSocket multicastSocket;
+    @Nullable private MdnsSocket unicastSocket;
     private int receivedPacketNumber = 0;
-    private Timer logMdnsPacketTimer;
+    @Nullable private Timer logMdnsPacketTimer;
     private AtomicInteger packetsCount;
-    private Timer checkMulticastResponseTimer;
+    @Nullable private Timer checkMulticastResponseTimer;
 
     public MdnsSocketClient(@NonNull Context context, @NonNull MulticastLock multicastLock) {
         this.context = context;
@@ -246,7 +243,12 @@
 
         if (useSeparateSocketForUnicast) {
             unicastReceiveThread =
-                    new Thread(() -> receiveThreadMain(unicastReceiverBuffer, unicastSocket));
+                    new Thread(
+                            () -> {
+                                if (unicastReceiverBuffer != null) {
+                                    receiveThreadMain(unicastReceiverBuffer, unicastSocket);
+                                }
+                            });
             unicastReceiveThread.setName("mdns-unicast-receive");
             unicastReceiveThread.start();
         }
@@ -325,11 +327,15 @@
                             unicastPacketsToSend.addAll(unicastPacketQueue);
                             unicastPacketQueue.clear();
                         }
+                        if (unicastSocket != null) {
+                            sendPackets(unicastPacketsToSend, unicastSocket);
+                        }
                     }
 
-                    // Send all the packets.
-                    sendPackets(multicastPacketsToSend, multicastSocket);
-                    sendPackets(unicastPacketsToSend, unicastSocket);
+                    // Send multicast packets.
+                    if (multicastSocket != null) {
+                        sendPackets(multicastPacketsToSend, multicastSocket);
+                    }
 
                     // Sleep ONLY if no more packets have been added to the queue, while packets
                     // were being sent.
@@ -349,7 +355,9 @@
         } finally {
             LOGGER.log("Send thread stopped.");
             try {
-                multicastSocket.leaveGroup();
+                if (multicastSocket != null) {
+                    multicastSocket.leaveGroup();
+                }
             } catch (Exception t) {
                 LOGGER.e("Failed to leave the group.", t);
             }
@@ -357,17 +365,19 @@
             // Close the socket first. This is the only way to interrupt a blocking receive.
             try {
                 // This is a race with the use of the file descriptor (b/27403984).
-                multicastSocket.close();
+                if (multicastSocket != null) {
+                    multicastSocket.close();
+                }
                 if (unicastSocket != null) {
                     unicastSocket.close();
                 }
-            } catch (Exception t) {
+            } catch (RuntimeException t) {
                 LOGGER.e("Failed to close the mdns socket.", t);
             }
         }
     }
 
-    private void receiveThreadMain(byte[] receiverBuffer, MdnsSocket socket) {
+    private void receiveThreadMain(byte[] receiverBuffer, @Nullable MdnsSocket socket) {
         DatagramPacket packet = new DatagramPacket(receiverBuffer, receiverBuffer.length);
 
         while (!shouldStopSocketLoop) {
@@ -382,7 +392,12 @@
 
                 if (!shouldStopSocketLoop) {
                     String responseType = socket == multicastSocket ? MULTICAST_TYPE : UNICAST_TYPE;
-                    processResponsePacket(packet, responseType);
+                    processResponsePacket(
+                            packet,
+                            responseType,
+                            /* interfaceIndex= */ (socket == null || !propagateInterfaceIndex)
+                                    ? MdnsSocket.INTERFACE_INDEX_UNSPECIFIED
+                                    : socket.getInterfaceIndex());
                 }
             } catch (IOException e) {
                 if (!shouldStopSocketLoop) {
@@ -393,12 +408,12 @@
         LOGGER.log("Receive thread stopped.");
     }
 
-    private int processResponsePacket(@NonNull DatagramPacket packet, String responseType)
-            throws IOException {
+    private int processResponsePacket(
+            @NonNull DatagramPacket packet, String responseType, int interfaceIndex) {
         int packetNumber = ++receivedPacketNumber;
 
         List<MdnsResponse> responses = new LinkedList<>();
-        int errorCode = responseDecoder.decode(packet, responses);
+        int errorCode = responseDecoder.decode(packet, responses, interfaceIndex);
         if (errorCode == MdnsResponseDecoder.SUCCESS) {
             if (responseType.equals(MULTICAST_TYPE)) {
                 receivedMulticastResponse = true;
@@ -414,7 +429,8 @@
             }
             for (MdnsResponse response : responses) {
                 String serviceInstanceName = response.getServiceInstanceName();
-                LOGGER.log("mDNS %s response received: %s", responseType, serviceInstanceName);
+                LOGGER.log("mDNS %s response received: %s at ifIndex %d", responseType,
+                        serviceInstanceName, interfaceIndex);
                 if (callback != null) {
                     callback.onResponseReceived(response);
                 }
@@ -492,7 +508,7 @@
     }
 
     public boolean isOnIPv6OnlyNetwork() {
-        return multicastSocket.isOnIPv6OnlyNetwork();
+        return multicastSocket != null && multicastSocket.isOnIPv6OnlyNetwork();
     }
 
     /** Callback for {@link MdnsSocketClient}. */
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsTextRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsTextRecord.java
index a364560..1e66589 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsTextRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsTextRecord.java
@@ -16,7 +16,10 @@
 
 package com.android.server.connectivity.mdns;
 
+import android.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -24,12 +27,10 @@
 import java.util.List;
 import java.util.Objects;
 
-/** An mDNS "TXT" record, which contains a list of text strings. */
-// TODO(b/242631897): Resolve nullness suppression.
-@SuppressWarnings("nullness")
+/** An mDNS "TXT" record, which contains a list of {@link TextEntry}. */
 @VisibleForTesting
 public class MdnsTextRecord extends MdnsRecord {
-    private List<String> strings;
+    private List<TextEntry> entries;
 
     public MdnsTextRecord(String[] name, MdnsPacketReader reader) throws IOException {
         super(name, TYPE_TXT, reader);
@@ -37,22 +38,34 @@
 
     /** Returns the list of strings. */
     public List<String> getStrings() {
-        return Collections.unmodifiableList(strings);
+        final List<String> list = new ArrayList<>(entries.size());
+        for (TextEntry entry : entries) {
+            list.add(entry.toString());
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    /** Returns the list of TXT key-value pairs. */
+    public List<TextEntry> getEntries() {
+        return Collections.unmodifiableList(entries);
     }
 
     @Override
     protected void readData(MdnsPacketReader reader) throws IOException {
-        strings = new ArrayList<>();
+        entries = new ArrayList<>();
         while (reader.getRemaining() > 0) {
-            strings.add(reader.readString());
+            TextEntry entry = reader.readTextEntry();
+            if (entry != null) {
+                entries.add(entry);
+            }
         }
     }
 
     @Override
     protected void writeData(MdnsPacketWriter writer) throws IOException {
-        if (strings != null) {
-            for (String string : strings) {
-                writer.writeString(string);
+        if (entries != null) {
+            for (TextEntry entry : entries) {
+                writer.writeTextEntry(entry);
             }
         }
     }
@@ -61,9 +74,9 @@
     public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append("TXT: {");
-        if (strings != null) {
-            for (String string : strings) {
-                sb.append(' ').append(string);
+        if (entries != null) {
+            for (TextEntry entry : entries) {
+                sb.append(' ').append(entry);
             }
         }
         sb.append("}");
@@ -73,11 +86,11 @@
 
     @Override
     public int hashCode() {
-        return (super.hashCode() * 31) + Objects.hash(strings);
+        return (super.hashCode() * 31) + Objects.hash(entries);
     }
 
     @Override
-    public boolean equals(Object other) {
+    public boolean equals(@Nullable Object other) {
         if (this == other) {
             return true;
         }
@@ -85,6 +98,6 @@
             return false;
         }
 
-        return super.equals(other) && Objects.equals(strings, ((MdnsTextRecord) other).strings);
+        return super.equals(other) && Objects.equals(entries, ((MdnsTextRecord) other).entries);
     }
 }
\ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/util/MdnsLogger.java b/service/mdns/com/android/server/connectivity/mdns/util/MdnsLogger.java
index 431f1fd..63107e5 100644
--- a/service/mdns/com/android/server/connectivity/mdns/util/MdnsLogger.java
+++ b/service/mdns/com/android/server/connectivity/mdns/util/MdnsLogger.java
@@ -16,6 +16,7 @@
 
 package com.android.server.connectivity.mdns.util;
 
+import android.annotation.Nullable;
 import android.text.TextUtils;
 
 import com.android.net.module.util.SharedLog;
@@ -40,7 +41,7 @@
         mLog.log(message);
     }
 
-    public void log(String message, Object... args) {
+    public void log(String message, @Nullable Object... args) {
         mLog.log(message + " ; " + TextUtils.join(" ; ", args));
     }
 
diff --git a/service/native/libs/libclat/clatutils.cpp b/service/native/libs/libclat/clatutils.cpp
index 4a125ba..be86612 100644
--- a/service/native/libs/libclat/clatutils.cpp
+++ b/service/native/libs/libclat/clatutils.cpp
@@ -126,10 +126,19 @@
 
 // Picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix.
 int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix,
-                        in6_addr* v6) {
+                        in6_addr* v6, uint32_t mark) {
     int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
     if (s == -1) return -errno;
 
+    // Socket's mark affects routing decisions (network selection)
+    // An fwmark is necessary for clat to bypass the VPN during initialization.
+    if ((mark != MARK_UNSET) && setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))) {
+        int ret = errno;
+        ALOGE("setsockopt(SOL_SOCKET, SO_MARK) failed: %s", strerror(errno));
+        close(s);
+        return -ret;
+    }
+
     if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface) + 1) == -1) {
         close(s);
         return -errno;
diff --git a/service/native/libs/libclat/clatutils_test.cpp b/service/native/libs/libclat/clatutils_test.cpp
index 8cca1f4..abd4e81 100644
--- a/service/native/libs/libclat/clatutils_test.cpp
+++ b/service/native/libs/libclat/clatutils_test.cpp
@@ -202,7 +202,8 @@
     in6_addr v6;
     EXPECT_EQ(1, inet_pton(AF_INET6, "::", &v6));  // initialize as zero
 
-    EXPECT_EQ(-ENETUNREACH, generateIpv6Address(tun.name().c_str(), v4, nat64Prefix, &v6));
+    // 0u is MARK_UNSET
+    EXPECT_EQ(-ENETUNREACH, generateIpv6Address(tun.name().c_str(), v4, nat64Prefix, &v6, 0u));
     EXPECT_TRUE(IN6_IS_ADDR_ULA(&v6));
 
     tun.destroy();
diff --git a/service/native/libs/libclat/include/libclat/clatutils.h b/service/native/libs/libclat/include/libclat/clatutils.h
index 812c86e..991b193 100644
--- a/service/native/libs/libclat/include/libclat/clatutils.h
+++ b/service/native/libs/libclat/include/libclat/clatutils.h
@@ -24,7 +24,7 @@
 in_addr_t selectIpv4Address(const in_addr ip, int16_t prefixlen);
 void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix);
 int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix,
-                        in6_addr* v6);
+                        in6_addr* v6, uint32_t mark);
 int detect_mtu(const struct in6_addr* plat_subnet, uint32_t plat_suffix, uint32_t mark);
 int configure_packet_socket(int sock, in6_addr* addr, int ifindex);
 
diff --git a/service/src/com/android/metrics/stats.proto b/service/src/com/android/metrics/stats.proto
new file mode 100644
index 0000000..48b8316
--- /dev/null
+++ b/service/src/com/android/metrics/stats.proto
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package com.android.metrics;
+
+import "frameworks/proto_logging/stats/enums/stats/connectivity/connectivity_service.proto";
+
+/**
+ * Logs NSD(Network service discovery) client session
+ *
+ * Log from:
+ *     packages/modules/Connectivity/service-t/src/com/android/server/NsdService
+ */
+message NetworkNsdReported {
+  // Indicate if the device is using the legacy or the new implementation
+  optional bool is_legacy = 1;
+
+  // It is a random number to represent different clients. Each client is an app on the device.
+  optional int32 client_id = 2;
+
+  // It is a increment_number to represent different transactions.
+  // Each transaction is a request from an app client.
+  optional int32 transaction_id = 3;
+
+  // Indicate the service in resolution is a known service in the discovered services cache
+  optional bool is_known_service = 4;
+
+  // Record each NSD session type
+  optional .android.stats.connectivity.NsdEventType type = 5;
+
+  // The process duration of the event in milli-second
+  optional int64 event_duration_millisec = 6;
+
+  // Record each mdns query result
+  optional .android.stats.connectivity.MdnsQueryResult query_result = 7;
+
+  // Count of services in cache at the end of discovery
+  optional int32 found_service_count = 8;
+
+  // Count of found callback when discovery is stopped
+  optional int32 found_callback_count = 9;
+
+  // Count of lost callback when discovery is stopped
+  optional int32 lost_callback_count = 10;
+
+  // Record query service count before unregistered service
+  optional int32 replied_requests_count = 11;
+}
+
+/**
+ * Logs the number of network count on each list of transports
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message NetworkCountPerTransports {
+    // the number of network count on each list of transports
+    repeated NetworkCountForTransports network_count_for_transports = 1;
+}
+
+/**
+ * Logs the number of network count and transport type
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message NetworkCountForTransports {
+    // Transport types of the network
+    optional int32 transport_types = 1;
+
+    // Number of networks for one list of transport types
+    optional int32 network_count = 2;
+}
+
+/**
+ * Logs a list of networks
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message NetworkList {
+    repeated NetworkDescription network_description = 1;
+}
+
+/**
+ * Logs connection duration in seconds and list of transports
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message ConnectionDurationForTransports {
+    // Transport types of the network
+    optional int32 transport_types = 1;
+
+    // Time duration that the device stays connected to the network
+    optional int32 duration_sec = 2;
+}
+
+/**
+ * Logs connection duration on each list of transports, in seconds
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message ConnectionDurationPerTransports {
+    repeated ConnectionDurationForTransports connection_duration_for_transports = 1;
+}
+
+/**
+ * Logs network request count & request type
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message RequestCountForType {
+    // The type of network request
+    optional .android.stats.connectivity.RequestType request_type = 1;
+
+    // Number of network requests
+    optional int32 request_count = 2;
+}
+
+/**
+ * Logs network request count
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message NetworkRequestCount {
+    // Network request count for request type
+    repeated RequestCountForType request_count_for_type = 1;
+}
+
+/**
+ * Logs information about a network
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message NetworkDescription {
+    // The transport types of the network. A network may include multiple transport types.
+    // Each transfer type is represented by a different bit, defined in
+    // packages/modules/Connectivity/framework/src/android/net/NetworkCapabilities.java
+    optional int32 transport_types = 1;
+
+    // Indicates the network is metered, non-metered or temporarily-unmetered
+    optional .android.stats.connectivity.MeteredState metered_state = 2;
+
+    // Indicates the network is validated, non-validated, partial or portal
+    optional .android.stats.connectivity.ValidatedState validated_state = 3;
+
+    // Record the bitmask of all the policies applied to this score of network.
+    // Each policy is represented by a different bit, defined in
+    // packages/modules/Connectivity/service/src/com/android/server/connectivity/FullScore.java
+    optional int64 score_policies = 4;
+
+    // The capabilities of the network. A network may include multiple network capabilities.
+    // Each capability is represented by a different bit, defined in
+    // packages/modules/Connectivity/framework/src/android/net/NetworkCapabilities.java
+    optional int64 capabilities = 5;
+
+    // Bitfield representing the network's enterprise capability identifier, defined in
+    // packages/modules/Connectivity/framework/src/android/net/NetworkCapabilities.java
+    optional int32 enterprise_id = 6;
+}
+
+/**
+ * Pulls a list of NumberOfRematchesPerReason.
+ *
+ * Pulled from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message NumberOfRematchesPerReason {
+    // Number of network rematches for each rematch reason
+    repeated NumberOfRematchesForReason number_of_rematches_per_reason= 1;
+}
+
+/**
+ * Logs number of network rematches for rematch reason
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message NumberOfRematchesForReason {
+    // The reason of network rematch
+    optional .android.stats.connectivity.RematchReason rematch_reason = 1;
+
+    // Number of network rematches
+    optional int32 rematch_count = 2;
+};
+
+/**
+ * Pulls information for connectivity stats.
+ *
+ * Pulled from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message ConnectivityStateSample {
+    // Number of networks per list of transports
+    optional NetworkCountPerTransports network_count_per_transports = 1;
+
+    // This is a list of networks with their transports and the duration
+    optional ConnectionDurationPerTransports connection_duration_per_transports = 2;
+
+    // Number of requests per category
+    optional NetworkRequestCount network_request_count  = 3;
+
+    // Full list of network details (slice by transport / meteredness / internet+validated)
+    optional NetworkList networks = 4;
+}
+
+
+/**
+ * Pulls information for network selection rematch info.
+ *
+ * Pulled from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message NetworkSelectionRematchReasonsInfo {
+    // Number of rematch per rematch reason
+    optional NumberOfRematchesPerReason number_of_rematches_per_reason = 1;
+}
+
+/**
+ * Logs rematch information for the default network
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message DefaultNetworkRematchInfo {
+    // The session id comes from each reboot, this is used to correlate the statistics of the
+    // networkselect on the same boot
+    optional int64 session_id = 1;
+
+    // The information of old device default network
+    optional NetworkDescription old_network = 2;
+
+    // The information of new device default network
+    optional NetworkDescription new_network = 3;
+
+    // The reason of network rematch
+    optional .android.stats.connectivity.RematchReason rematch_reason = 4;
+
+    // The time duration the device kept the old network as the default in seconds
+    optional int32 time_duration_on_old_network_sec = 5;
+}
+
+/**
+ * Logs network selection performance
+ *
+ * Logs from:
+ *   packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
+ */
+message NetworkSelectionPerformance {
+    // Number of network requests
+    optional int32 number_of_network_requests = 1;
+
+    // List of networks right now
+    // (slice by transport / meteredness / internet+validated)
+    optional NetworkList networks = 2;
+
+    // The latency of selection computed in milli-second
+    optional int32 selection_computed_latency_milli = 3;
+
+    // The latency of selection applied in milli-second
+    optional int32 selection_applied_latency_milli = 4;
+
+    // The latency of selection issued in milli-second
+    optional int32 selection_issued_latency_milli = 5;
+}
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index e732001..2535974 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -75,6 +75,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_5;
@@ -368,7 +369,7 @@
     private static final int DEFAULT_NASCENT_DELAY_MS = 5_000;
 
     // The maximum value for the blocking validation result, in milliseconds.
-    public static final int MAX_VALIDATION_FAILURE_BLOCKING_TIME_MS = 10000;
+    public static final int MAX_VALIDATION_IGNORE_AFTER_ROAM_TIME_MS = 10000;
 
     // The maximum number of network request allowed per uid before an exception is thrown.
     @VisibleForTesting
@@ -1982,9 +1983,6 @@
     @Nullable
     public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) {
         enforceAccessPermission();
-        if (uid != mDeps.getCallingUid()) {
-            enforceNetworkStackPermission(mContext);
-        }
         final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
         if (nai == null) return null;
         return getFilteredNetworkInfo(nai, uid, ignoreBlocked);
@@ -2809,6 +2807,13 @@
                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
+    private void enforceSettingsOrUseRestrictedNetworksPermission() {
+        enforceAnyPermissionOf(mContext,
+                android.Manifest.permission.NETWORK_SETTINGS,
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+                Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+    }
+
     private void enforceNetworkFactoryPermission() {
         // TODO: Check for the BLUETOOTH_STACK permission once that is in the API surface.
         if (UserHandle.getAppId(getCallingUid()) == Process.BLUETOOTH_UID) return;
@@ -3092,7 +3097,7 @@
      * Reads the network specific MTU size from resources.
      * and set it on it's iface.
      */
-    private void updateMtu(LinkProperties newLp, LinkProperties oldLp) {
+    private void updateMtu(@NonNull LinkProperties newLp, @Nullable LinkProperties oldLp) {
         final String iface = newLp.getInterfaceName();
         final int mtu = newLp.getMtu();
         if (oldLp == null && mtu == 0) {
@@ -3125,7 +3130,7 @@
     @VisibleForTesting
     protected static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208";
 
-    private void updateTcpBufferSizes(String tcpBufferSizes) {
+    private void updateTcpBufferSizes(@Nullable String tcpBufferSizes) {
         String[] values = null;
         if (tcpBufferSizes != null) {
             values = tcpBufferSizes.split(",");
@@ -4241,12 +4246,18 @@
         return nai.isCreated() && !nai.isDestroyed();
     }
 
-    private boolean shouldIgnoreValidationFailureAfterRoam(NetworkAgentInfo nai) {
+    @VisibleForTesting
+    boolean shouldIgnoreValidationFailureAfterRoam(NetworkAgentInfo nai) {
         // T+ devices should use unregisterAfterReplacement.
         if (SdkLevel.isAtLeastT()) return false;
+
+        // If the network never roamed, return false. The check below is not sufficient if time
+        // since boot is less than blockTimeOut, though that's extremely unlikely to happen.
+        if (nai.lastRoamTime == 0) return false;
+
         final long blockTimeOut = Long.valueOf(mResources.get().getInteger(
                 R.integer.config_validationFailureAfterRoamIgnoreTimeMillis));
-        if (blockTimeOut <= MAX_VALIDATION_FAILURE_BLOCKING_TIME_MS
+        if (blockTimeOut <= MAX_VALIDATION_IGNORE_AFTER_ROAM_TIME_MS
                 && blockTimeOut >= 0) {
             final long currentTimeMs = SystemClock.elapsedRealtime();
             long timeSinceLastRoam = currentTimeMs - nai.lastRoamTime;
@@ -5756,7 +5767,7 @@
         return mProxyTracker.getGlobalProxy();
     }
 
-    private void handleApplyDefaultProxy(ProxyInfo proxy) {
+    private void handleApplyDefaultProxy(@Nullable ProxyInfo proxy) {
         if (proxy != null && TextUtils.isEmpty(proxy.getHost())
                 && Uri.EMPTY.equals(proxy.getPacFileUrl())) {
             proxy = null;
@@ -5768,8 +5779,8 @@
     // when any network changes proxy.
     // TODO: Remove usage of broadcast extras as they are deprecated and not applicable in a
     // multi-network world where an app might be bound to a non-default network.
-    private void updateProxy(LinkProperties newLp, LinkProperties oldLp) {
-        ProxyInfo newProxyInfo = newLp == null ? null : newLp.getHttpProxy();
+    private void updateProxy(@NonNull LinkProperties newLp, @Nullable LinkProperties oldLp) {
+        ProxyInfo newProxyInfo = newLp.getHttpProxy();
         ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy();
 
         if (!ProxyTracker.proxyInfoEqual(newProxyInfo, oldProxyInfo)) {
@@ -6095,14 +6106,12 @@
     }
 
     private void onUserAdded(@NonNull final UserHandle user) {
-        mPermissionMonitor.onUserAdded(user);
         if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
             handleSetOemNetworkPreference(mOemNetworkPreferences, null);
         }
     }
 
     private void onUserRemoved(@NonNull final UserHandle user) {
-        mPermissionMonitor.onUserRemoved(user);
         // If there was a network preference for this user, remove it.
         handleSetProfileNetworkPreference(
                 List.of(new ProfileNetworkPreferenceList.Preference(user, null, true)),
@@ -6651,7 +6660,7 @@
                 enforceAccessPermission();
                 break;
             case TRACK_SYSTEM_DEFAULT:
-                enforceSettingsPermission();
+                enforceSettingsOrUseRestrictedNetworksPermission();
                 networkCapabilities = new NetworkCapabilities(defaultNc);
                 break;
             case BACKGROUND_REQUEST:
@@ -7494,7 +7503,7 @@
     }
 
     private void updateLinkProperties(NetworkAgentInfo networkAgent, @NonNull LinkProperties newLp,
-            @NonNull LinkProperties oldLp) {
+            @Nullable LinkProperties oldLp) {
         int netId = networkAgent.network.getNetId();
 
         // The NetworkAgent does not know whether clatd is running on its network or not, or whether
@@ -7546,7 +7555,13 @@
             }
             // Start or stop DNS64 detection and 464xlat according to network state.
             networkAgent.clatd.update();
-            notifyIfacesChangedForNetworkStats();
+            // Notify NSS when relevant events happened. Currently, NSS only cares about
+            // interface changed to update clat interfaces accounting.
+            final boolean interfacesChanged = oldLp == null
+                    || !Objects.equals(newLp.getAllInterfaceNames(), oldLp.getAllInterfaceNames());
+            if (interfacesChanged) {
+                notifyIfacesChangedForNetworkStats();
+            }
             networkAgent.networkMonitor().notifyLinkPropertiesChanged(
                     new LinkProperties(newLp, true /* parcelSensitiveFields */));
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
@@ -7633,12 +7648,11 @@
 
     }
 
-    private void updateInterfaces(final @Nullable LinkProperties newLp,
+    private void updateInterfaces(final @NonNull LinkProperties newLp,
             final @Nullable LinkProperties oldLp, final int netId,
             final @NonNull NetworkCapabilities caps) {
         final CompareResult<String> interfaceDiff = new CompareResult<>(
-                oldLp != null ? oldLp.getAllInterfaceNames() : null,
-                newLp != null ? newLp.getAllInterfaceNames() : null);
+                oldLp != null ? oldLp.getAllInterfaceNames() : null, newLp.getAllInterfaceNames());
         if (!interfaceDiff.added.isEmpty()) {
             for (final String iface : interfaceDiff.added) {
                 try {
@@ -7699,12 +7713,13 @@
      * Have netd update routes from oldLp to newLp.
      * @return true if routes changed between oldLp and newLp
      */
-    private boolean updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
+    private boolean updateRoutes(@NonNull LinkProperties newLp, @Nullable LinkProperties oldLp,
+            int netId) {
         // compare the route diff to determine which routes have been updated
         final CompareOrUpdateResult<RouteInfo.RouteKey, RouteInfo> routeDiff =
                 new CompareOrUpdateResult<>(
                         oldLp != null ? oldLp.getAllRoutes() : null,
-                        newLp != null ? newLp.getAllRoutes() : null,
+                        newLp.getAllRoutes(),
                         (r) -> r.getRouteKey());
 
         // add routes before removing old in case it helps with continuous connectivity
@@ -7754,7 +7769,8 @@
                 || !routeDiff.updated.isEmpty();
     }
 
-    private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
+    private void updateDnses(@NonNull LinkProperties newLp, @Nullable LinkProperties oldLp,
+            int netId) {
         if (oldLp != null && newLp.isIdenticalDnses(oldLp)) {
             return;  // no updating necessary
         }
@@ -7771,8 +7787,8 @@
         }
     }
 
-    private void updateVpnFiltering(LinkProperties newLp, LinkProperties oldLp,
-            NetworkAgentInfo nai) {
+    private void updateVpnFiltering(@NonNull LinkProperties newLp, @Nullable LinkProperties oldLp,
+            @NonNull NetworkAgentInfo nai) {
         final String oldIface = getVpnIsolationInterface(nai, nai.networkCapabilities, oldLp);
         final String newIface = getVpnIsolationInterface(nai, nai.networkCapabilities, newLp);
         final boolean wasFiltering = requiresVpnAllowRule(nai, oldLp, oldIface);
@@ -8036,6 +8052,10 @@
         final boolean oldMetered = prevNc.isMetered();
         final boolean newMetered = newNc.isMetered();
         final boolean meteredChanged = oldMetered != newMetered;
+        final boolean oldTempMetered = prevNc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+        final boolean newTempMetered = newNc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+        final boolean tempMeteredChanged = oldTempMetered != newTempMetered;
+
 
         if (meteredChanged) {
             maybeNotifyNetworkBlocked(nai, oldMetered, newMetered,
@@ -8046,7 +8066,7 @@
                 != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
 
         // Report changes that are interesting for network statistics tracking.
-        if (meteredChanged || roamingChanged) {
+        if (meteredChanged || roamingChanged || tempMeteredChanged) {
             notifyIfacesChangedForNetworkStats();
         }
 
@@ -8309,7 +8329,8 @@
         }
     }
 
-    public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
+    public void handleUpdateLinkProperties(@NonNull NetworkAgentInfo nai,
+            @NonNull LinkProperties newLp) {
         ensureRunningOnConnectivityServiceThread();
 
         if (!mNetworkAgentInfos.contains(nai)) {
@@ -9774,8 +9795,8 @@
         return ((VpnTransportInfo) ti).getType();
     }
 
-    private void maybeUpdateWifiRoamTimestamp(NetworkAgentInfo nai, NetworkCapabilities nc) {
-        if (nai == null) return;
+    private void maybeUpdateWifiRoamTimestamp(@NonNull NetworkAgentInfo nai,
+            @NonNull NetworkCapabilities nc) {
         final TransportInfo prevInfo = nai.networkCapabilities.getTransportInfo();
         final TransportInfo newInfo = nc.getTransportInfo();
         if (!(prevInfo instanceof WifiInfo) || !(newInfo instanceof WifiInfo)) {
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index d7c3287..5d04632 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -113,12 +113,12 @@
         return "/sys/fs/bpf/net_shared/map_clatd_clat_" + which + "_map";
     }
 
-    private static String makeProgPath(boolean ingress, boolean ether) {
-        String path = "/sys/fs/bpf/net_shared/prog_clatd_schedcls_"
-                + (ingress ? "ingress6" : "egress4")
-                + "_clat_"
+    private static final String CLAT_EGRESS4_RAWIP_PROG_PATH =
+            "/sys/fs/bpf/net_shared/prog_clatd_schedcls_egress4_clat_rawip";
+
+    private static String makeIngressProgPath(boolean ether) {
+        return "/sys/fs/bpf/net_shared/prog_clatd_schedcls_ingress6_clat_"
                 + (ether ? "ether" : "rawip");
-        return path;
     }
 
     @NonNull
@@ -183,8 +183,8 @@
          */
         @NonNull
         public String generateIpv6Address(@NonNull String iface, @NonNull String v4,
-                @NonNull String prefix64) throws IOException {
-            return native_generateIpv6Address(iface, v4, prefix64);
+                @NonNull String prefix64, int mark) throws IOException {
+            return native_generateIpv6Address(iface, v4, prefix64, mark);
         }
 
         /**
@@ -478,7 +478,7 @@
             // tc filter add dev .. egress prio 4 protocol ip bpf object-pinned /sys/fs/bpf/...
             // direct-action
             mDeps.tcFilterAddDevBpf(tracker.v4ifIndex, EGRESS, (short) PRIO_CLAT, (short) ETH_P_IP,
-                    makeProgPath(EGRESS, RAWIP));
+                    CLAT_EGRESS4_RAWIP_PROG_PATH);
         } catch (IOException e) {
             Log.e(TAG, "tc filter add dev (" + tracker.v4ifIndex + "[" + tracker.v4iface
                     + "]) egress prio PRIO_CLAT protocol ip failure: " + e);
@@ -504,7 +504,7 @@
             // tc filter add dev .. ingress prio 4 protocol ipv6 bpf object-pinned /sys/fs/bpf/...
             // direct-action
             mDeps.tcFilterAddDevBpf(tracker.ifIndex, INGRESS, (short) PRIO_CLAT,
-                    (short) ETH_P_IPV6, makeProgPath(INGRESS, isEthernet));
+                    (short) ETH_P_IPV6, makeIngressProgPath(isEthernet));
         } catch (IOException e) {
             Log.e(TAG, "tc filter add dev (" + tracker.ifIndex + "[" + tracker.iface
                     + "]) ingress prio PRIO_CLAT protocol ipv6 failure: " + e);
@@ -629,10 +629,11 @@
         }
 
         // [2] Generate a checksum-neutral IID.
+        final Integer fwmark = getFwmark(netId);
         final String pfx96Str = nat64Prefix.getAddress().getHostAddress();
         final String v6Str;
         try {
-            v6Str = mDeps.generateIpv6Address(iface, v4Str, pfx96Str);
+            v6Str = mDeps.generateIpv6Address(iface, v4Str, pfx96Str, fwmark);
         } catch (IOException e) {
             throw new IOException("no IPv6 addresses were available for clat: " + e);
         }
@@ -676,7 +677,6 @@
         }
 
         // Detect ipv4 mtu.
-        final Integer fwmark = getFwmark(netId);
         final int detectedMtu;
         try {
             detectedMtu = mDeps.detectMtu(pfx96Str,
@@ -899,7 +899,7 @@
     }
 
     /**
-     * Dump the cordinator information.
+     * Dump the coordinator information.
      *
      * @param pw print writer.
      */
@@ -907,7 +907,7 @@
         // TODO: move map dump to a global place to avoid duplicate dump while there are two or
         // more IPv6 only networks.
         if (isStarted()) {
-            pw.println("CLAT tracker: " + mClatdTracker.toString());
+            pw.println("CLAT tracker: " + mClatdTracker);
             pw.println("Forwarding rules:");
             pw.increaseIndent();
             dumpBpfIngress(pw);
@@ -931,7 +931,7 @@
     private static native String native_selectIpv4Address(String v4addr, int prefixlen)
             throws IOException;
     private static native String native_generateIpv6Address(String iface, String v4,
-            String prefix64) throws IOException;
+            String prefix64, int mark) throws IOException;
     private static native int native_createTunInterface(String tuniface) throws IOException;
     private static native int native_detectMtu(String platSubnet, int platSuffix, int mark)
             throws IOException;
diff --git a/service/src/com/android/server/connectivity/Nat464Xlat.java b/service/src/com/android/server/connectivity/Nat464Xlat.java
index 4e19781..2ac2ad3 100644
--- a/service/src/com/android/server/connectivity/Nat464Xlat.java
+++ b/service/src/com/android/server/connectivity/Nat464Xlat.java
@@ -22,6 +22,7 @@
 import static com.android.net.module.util.CollectionUtils.contains;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.net.ConnectivityManager;
 import android.net.IDnsResolver;
 import android.net.INetd;
@@ -420,7 +421,7 @@
      * This is necessary because the LinkProperties in mNetwork come from the transport layer, which
      * has no idea that 464xlat is running on top of it.
      */
-    public void fixupLinkProperties(@NonNull LinkProperties oldLp, @NonNull LinkProperties lp) {
+    public void fixupLinkProperties(@Nullable LinkProperties oldLp, @NonNull LinkProperties lp) {
         // This must be done even if clatd is not running, because otherwise shouldStartClat would
         // never return true.
         lp.setNat64Prefix(selectNat64Prefix());
@@ -433,6 +434,8 @@
         }
 
         Log.d(TAG, "clatd running, updating NAI for " + mIface);
+        // oldLp can't be null here since shouldStartClat checks null LinkProperties to start clat.
+        // Thus, the status won't pass isRunning check if the oldLp is null.
         for (LinkProperties stacked: oldLp.getStackedLinks()) {
             if (Objects.equals(mIface, stacked.getInterfaceName())) {
                 lp.addStackedLink(stacked);
diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java
index fd1ed60..eee7f3a 100755
--- a/service/src/com/android/server/connectivity/PermissionMonitor.java
+++ b/service/src/com/android/server/connectivity/PermissionMonitor.java
@@ -175,6 +175,22 @@
                 final String[] pkgList =
                         intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                 onExternalApplicationsAvailable(pkgList);
+            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+                final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
+                // User should be filled for below intents, check the existence.
+                if (user == null) {
+                    Log.wtf(TAG, action + " broadcast without EXTRA_USER");
+                    return;
+                }
+                onUserAdded(user);
+            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
+                // User should be filled for below intents, check the existence.
+                if (user == null) {
+                    Log.wtf(TAG, action + " broadcast without EXTRA_USER");
+                    return;
+                }
+                onUserRemoved(user);
             } else {
                 Log.wtf(TAG, "received unexpected intent: " + action);
             }
@@ -408,6 +424,14 @@
                 mIntentReceiver, externalIntentFilter, null /* broadcastPermission */,
                 null /* scheduler */);
 
+        // Listen for user add/remove.
+        final IntentFilter userIntentFilter = new IntentFilter();
+        userIntentFilter.addAction(Intent.ACTION_USER_ADDED);
+        userIntentFilter.addAction(Intent.ACTION_USER_REMOVED);
+        userAllContext.registerReceiver(
+                mIntentReceiver, userIntentFilter, null /* broadcastPermission */,
+                null /* scheduler */);
+
         // Register UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting observer
         mDeps.registerContentObserver(
                 userAllContext,
@@ -547,7 +571,8 @@
      *
      * @hide
      */
-    public synchronized void onUserAdded(@NonNull UserHandle user) {
+    @VisibleForTesting
+    synchronized void onUserAdded(@NonNull UserHandle user) {
         mUsers.add(user);
 
         final List<PackageInfo> apps = getInstalledPackagesAsUser(user);
@@ -578,7 +603,8 @@
      *
      * @hide
      */
-    public synchronized void onUserRemoved(@NonNull UserHandle user) {
+    @VisibleForTesting
+    synchronized void onUserRemoved(@NonNull UserHandle user) {
         mUsers.remove(user);
 
         // Remove uids network permissions that belongs to the user.
@@ -758,7 +784,8 @@
      *
      * @hide
      */
-    public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
+    @VisibleForTesting
+    synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
         // Update uid permission.
         updateAppIdTrafficPermission(uid);
         // Get the appId permission from all users then send the latest permission to netd.
@@ -821,7 +848,8 @@
      *
      * @hide
      */
-    public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
+    @VisibleForTesting
+    synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
         // Update uid permission.
         updateAppIdTrafficPermission(uid);
         // Get the appId permission from all users then send the latest permission to netd.
diff --git a/tests/common/java/android/net/apf/ApfCapabilitiesTest.java b/tests/common/java/android/net/apf/ApfCapabilitiesTest.java
index fa4adcb..8c2ec40 100644
--- a/tests/common/java/android/net/apf/ApfCapabilitiesTest.java
+++ b/tests/common/java/android/net/apf/ApfCapabilitiesTest.java
@@ -33,6 +33,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
 
 import org.junit.Before;
@@ -83,7 +84,11 @@
         assertTrue(caps.hasDataAccess());
     }
 
-    @Test
+    // the property is deleted in U, on S & T getApfDrop8023Frames() is mainline and
+    // hardcoded to return true, so this simply verifies the unused property is also true,
+    // as modifying it would not take effect.  For S+ change NetworkStack's
+    // config_apfDrop802_3Frames instead.
+    @Test @IgnoreAfter(Build.VERSION_CODES.TIRAMISU)
     public void testGetApfDrop8023Frames() {
         // Get com.android.internal.R.bool.config_apfDrop802_3Frames. The test cannot directly
         // use R.bool.config_apfDrop802_3Frames because that is not a stable resource ID.
@@ -105,7 +110,11 @@
                 ApfCapabilities.getApfDrop8023Frames());
     }
 
-    @Test
+    // the property is deleted in U, on S & T getApfEtherTypeBlackList() is mainline and
+    // hardcoded to return a specific default set of ethertypes, so this simply verifies
+    // that the unused property hasn't been changed away from the default, as it would
+    // not take effect.  For S+ change NetworkStack's config_apfEthTypeDenyList instead.
+    @Test @IgnoreAfter(Build.VERSION_CODES.TIRAMISU)
     public void testGetApfEtherTypeBlackList() {
         // Get com.android.internal.R.array.config_apfEthTypeBlackList. The test cannot directly
         // use R.array.config_apfEthTypeBlackList because that is not a stable resource ID.
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 5f032be..8c18a89 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
@@ -38,6 +38,7 @@
 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN;
 import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE;
+import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_EXPORTED;
 import static com.android.testutils.Cleanup.testAndCleanup;
 import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
 
@@ -1550,8 +1551,9 @@
         final DownloadManager dm = context.getSystemService(DownloadManager.class);
         final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
         try {
+            final int flags = SdkLevel.isAtLeastT() ? RECEIVER_EXPORTED : 0;
             context.registerReceiver(receiver,
-                    new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+                    new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), flags);
 
             // Enqueue a request and check only one download.
             final long id = dm.enqueue(new Request(
diff --git a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
index 6b2a1ee..e2821cb 100644
--- a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
@@ -21,12 +21,14 @@
 
 import static androidx.test.InstrumentationRegistry.getContext;
 
+import static com.android.compatibility.common.util.BatteryUtils.hasBattery;
 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 import static com.android.testutils.MiscAsserts.assertThrows;
 import static com.android.testutils.TestPermissionUtil.runAsShell;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -97,6 +99,7 @@
     @RequiresDevice // Virtual hardware does not support wifi battery stats
     public void testReportNetworkInterfaceForTransports() throws Exception {
         try {
+            assumeTrue("Battery is not present. Ignore test.", hasBattery());
             // Simulate the device being unplugged from charging.
             executeShellCommand("cmd battery unplug");
             executeShellCommand("cmd battery set status " + BATTERY_STATUS_DISCHARGING);
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 218eb04..c9899a2 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -1047,12 +1047,22 @@
         final TestNetworkCallback bestMatchingCallback = new TestNetworkCallback();
         final Handler h = new Handler(Looper.getMainLooper());
         if (TestUtils.shouldTestSApis()) {
+            assertThrows(SecurityException.class, () ->
+                    registerSystemDefaultNetworkCallback(systemDefaultCallback, h));
             runWithShellPermissionIdentity(() -> {
                 registerSystemDefaultNetworkCallback(systemDefaultCallback, h);
                 registerDefaultNetworkCallbackForUid(Process.myUid(), perUidCallback, h);
             }, NETWORK_SETTINGS);
             registerBestMatchingNetworkCallback(makeDefaultRequest(), bestMatchingCallback, h);
         }
+        if (TestUtils.shouldTestTApis()) {
+            // Verify registerSystemDefaultNetworkCallback can be accessed via
+            // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
+            final TestNetworkCallback systemDefaultCallback2 = new TestNetworkCallback();
+            runWithShellPermissionIdentity(() ->
+                    registerSystemDefaultNetworkCallback(systemDefaultCallback2, h),
+                    CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+        }
 
         Network wifiNetwork = null;
         mCtsNetUtils.ensureWifiConnected();
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 8940075..db13c49 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -105,6 +105,7 @@
 
 private const val TAG = "DscpPolicyTest"
 private const val PACKET_TIMEOUT_MS = 2_000L
+private const val IPV6_ADDRESS_WAIT_TIME_MS = 10_000L
 
 @AppModeFull(reason = "Instant apps cannot create test networks")
 @RunWith(AndroidJUnit4::class)
@@ -222,7 +223,7 @@
         var inet6Addr: Inet6Address? = null
         val onLinkPrefix = raResponder.prefix
         val startTime = SystemClock.elapsedRealtime()
-        while (SystemClock.elapsedRealtime() - startTime < PACKET_TIMEOUT_MS) {
+        while (SystemClock.elapsedRealtime() - startTime < IPV6_ADDRESS_WAIT_TIME_MS) {
             SystemClock.sleep(50 /* ms */)
             val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
             try {
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
index c7e8b97..aa5654a 100644
--- a/tests/mts/bpf_existence_test.cpp
+++ b/tests/mts/bpf_existence_test.cpp
@@ -100,13 +100,11 @@
     NETD "map_netd_uid_counterset_map",
     NETD "map_netd_uid_owner_map",
     NETD "map_netd_uid_permission_map",
-    SHARED "prog_clatd_schedcls_egress4_clat_ether",
     SHARED "prog_clatd_schedcls_egress4_clat_rawip",
     SHARED "prog_clatd_schedcls_ingress6_clat_ether",
     SHARED "prog_clatd_schedcls_ingress6_clat_rawip",
     NETD "prog_netd_cgroupskb_egress_stats",
     NETD "prog_netd_cgroupskb_ingress_stats",
-    NETD "prog_netd_cgroupsock_inet_create",
     NETD "prog_netd_schedact_ingress_account",
     NETD "prog_netd_skfilter_allowlist_xtbpf",
     NETD "prog_netd_skfilter_denylist_xtbpf",
@@ -114,6 +112,11 @@
     NETD "prog_netd_skfilter_ingress_xtbpf",
 };
 
+// Provided by *current* mainline module for T+ devices with 4.14+ kernels
+static const set<string> MAINLINE_FOR_T_4_14_PLUS = {
+    NETD "prog_netd_cgroupsock_inet_create",
+};
+
 // Provided by *current* mainline module for T+ devices with 5.4+ kernels
 static const set<string> MAINLINE_FOR_T_5_4_PLUS = {
     SHARED "prog_block_bind4_block_port",
@@ -152,6 +155,7 @@
     // Nothing added or removed in SCv2.
 
     DO_EXPECT(IsAtLeastT(), MAINLINE_FOR_T_PLUS);
+    DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(4, 14, 0), MAINLINE_FOR_T_4_14_PLUS);
     DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 4, 0), MAINLINE_FOR_T_5_4_PLUS);
     DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 15, 0), MAINLINE_FOR_T_5_15_PLUS);
 }
diff --git a/tests/native/connectivity_native_test/Android.bp b/tests/native/connectivity_native_test/Android.bp
index 7d43aa8..8825aa4 100644
--- a/tests/native/connectivity_native_test/Android.bp
+++ b/tests/native/connectivity_native_test/Android.bp
@@ -10,7 +10,7 @@
         "vts",
     ],
     test_config_template: "AndroidTestTemplate.xml",
-    min_sdk_version: "31",
+    min_sdk_version: "34",
     tidy: false,
     srcs: [
         "connectivity_native_test.cpp",
diff --git a/tests/native/connectivity_native_test/connectivity_native_test.cpp b/tests/native/connectivity_native_test/connectivity_native_test.cpp
index 3db5265..27a9d35 100644
--- a/tests/native/connectivity_native_test/connectivity_native_test.cpp
+++ b/tests/native/connectivity_native_test/connectivity_native_test.cpp
@@ -14,62 +14,81 @@
  * limitations under the License.
  */
 
-#include <aidl/android/net/connectivity/aidl/ConnectivityNative.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <android-modules-utils/sdk_level.h>
 #include <cutils/misc.h>  // FIRST_APPLICATION_UID
+#include <dlfcn.h>
 #include <gtest/gtest.h>
 #include <netinet/in.h>
 
 #include "bpf/BpfUtils.h"
 
-using aidl::android::net::connectivity::aidl::IConnectivityNative;
+typedef int (*GetPortsBlockedForBind)(in_port_t*, size_t*);
+GetPortsBlockedForBind getPortsBlockedForBind;
+typedef int (*BlockPortForBind)(in_port_t);
+BlockPortForBind blockPortForBind;
+typedef int (*UnblockPortForBind)(in_port_t);
+UnblockPortForBind unblockPortForBind;
+typedef int (*UnblockAllPortsForBind)();
+UnblockAllPortsForBind unblockAllPortsForBind;
 
 class ConnectivityNativeBinderTest : public ::testing::Test {
   public:
-    std::vector<int32_t> mActualBlockedPorts;
-
-    ConnectivityNativeBinderTest() {
-        AIBinder* binder = AServiceManager_getService("connectivity_native");
-        ndk::SpAIBinder sBinder = ndk::SpAIBinder(binder);
-        mService = aidl::android::net::connectivity::aidl::IConnectivityNative::fromBinder(sBinder);
-    }
+    in_port_t mActualBlockedPorts[65535];
+    size_t mActualBlockedPortsCount = 65535;
+    bool restoreBlockedPorts;
 
     void SetUp() override {
-        // Skip test case if not on T.
-        if (!android::modules::sdklevel::IsAtLeastT()) GTEST_SKIP() <<
+        restoreBlockedPorts = false;
+        // Skip test case if not on U.
+        if (!android::modules::sdklevel::IsAtLeastU()) GTEST_SKIP() <<
                 "Should be at least T device.";
 
         // Skip test case if not on 5.4 kernel which is required by bpf prog.
         if (!android::bpf::isAtLeastKernelVersion(5, 4, 0)) GTEST_SKIP() <<
                 "Kernel should be at least 5.4.";
 
-        ASSERT_NE(nullptr, mService.get());
+        // Necessary to use dlopen/dlsym since the lib is only available on U and there
+        // is no Sdk34ModuleController in tradefed yet.
+        // TODO: link against the library directly and add Sdk34ModuleController to
+        // AndroidTest.txml when available.
+        void* nativeLib = dlopen("libcom.android.tethering.connectivity_native.so", RTLD_NOW);
+        ASSERT_NE(nullptr, nativeLib);
+        getPortsBlockedForBind = reinterpret_cast<GetPortsBlockedForBind>(
+                dlsym(nativeLib, "AConnectivityNative_getPortsBlockedForBind"));
+        ASSERT_NE(nullptr, getPortsBlockedForBind);
+        blockPortForBind = reinterpret_cast<BlockPortForBind>(
+                dlsym(nativeLib, "AConnectivityNative_blockPortForBind"));
+        ASSERT_NE(nullptr, blockPortForBind);
+        unblockPortForBind = reinterpret_cast<UnblockPortForBind>(
+                dlsym(nativeLib, "AConnectivityNative_unblockPortForBind"));
+        ASSERT_NE(nullptr, unblockPortForBind);
+        unblockAllPortsForBind = reinterpret_cast<UnblockAllPortsForBind>(
+                dlsym(nativeLib, "AConnectivityNative_unblockAllPortsForBind"));
+        ASSERT_NE(nullptr, unblockAllPortsForBind);
 
         // If there are already ports being blocked on device unblockAllPortsForBind() store
         // the currently blocked ports and add them back at the end of the test. Do this for
         // every test case so additional test cases do not forget to add ports back.
-        ndk::ScopedAStatus status = mService->getPortsBlockedForBind(&mActualBlockedPorts);
-        EXPECT_TRUE(status.isOk()) << status.getDescription ();
-
+        int err = getPortsBlockedForBind(mActualBlockedPorts, &mActualBlockedPortsCount);
+        EXPECT_EQ(err, 0);
+        restoreBlockedPorts = true;
     }
 
     void TearDown() override {
-        ndk::ScopedAStatus status;
-        if (mActualBlockedPorts.size() > 0) {
-            for (int i : mActualBlockedPorts) {
-                mService->blockPortForBind(i);
-                EXPECT_TRUE(status.isOk()) << status.getDescription ();
+        int err;
+        if (mActualBlockedPortsCount > 0 && restoreBlockedPorts) {
+            for (int i=0; i < mActualBlockedPortsCount; i++) {
+                err = blockPortForBind(mActualBlockedPorts[i]);
+                EXPECT_EQ(err, 0);
             }
         }
     }
 
   protected:
-    std::shared_ptr<IConnectivityNative> mService;
-
     void runSocketTest (sa_family_t family, const int type, bool blockPort) {
-        ndk::ScopedAStatus status;
+        int err;
         in_port_t port = 0;
         int sock, sock2;
         // Open two sockets with SO_REUSEADDR and expect they can both bind to port.
@@ -79,16 +98,16 @@
         int blockedPort = 0;
         if (blockPort) {
             blockedPort = ntohs(port);
-            status = mService->blockPortForBind(blockedPort);
-            EXPECT_TRUE(status.isOk()) << status.getDescription ();
+            err = blockPortForBind(blockedPort);
+            EXPECT_EQ(err, 0);
         }
 
         int sock3 = openSocket(&port, family, type, blockPort /* expectBindFail */);
 
         if (blockPort) {
             EXPECT_EQ(-1, sock3);
-            status = mService->unblockPortForBind(blockedPort);
-            EXPECT_TRUE(status.isOk()) << status.getDescription ();
+            err = unblockPortForBind(blockedPort);
+            EXPECT_EQ(err, 0);
         } else {
             EXPECT_NE(-1, sock3);
         }
@@ -177,110 +196,74 @@
 }
 
 TEST_F(ConnectivityNativeBinderTest, BlockPortTwice) {
-    ndk::ScopedAStatus status = mService->blockPortForBind(5555);
-    EXPECT_TRUE(status.isOk()) << status.getDescription ();
-    status = mService->blockPortForBind(5555);
-    EXPECT_TRUE(status.isOk()) << status.getDescription ();
-    status = mService->unblockPortForBind(5555);
-    EXPECT_TRUE(status.isOk()) << status.getDescription ();
+    int err = blockPortForBind(5555);
+    EXPECT_EQ(err, 0);
+    err = blockPortForBind(5555);
+    EXPECT_EQ(err, 0);
+    err = unblockPortForBind(5555);
+    EXPECT_EQ(err, 0);
 }
 
 TEST_F(ConnectivityNativeBinderTest, GetBlockedPorts) {
-    ndk::ScopedAStatus status;
-    std::vector<int> blockedPorts{1, 100, 1220, 1333, 2700, 5555, 5600, 65000};
-    for (int i : blockedPorts) {
-        status = mService->blockPortForBind(i);
-        EXPECT_TRUE(status.isOk()) << status.getDescription ();
+    int err;
+    in_port_t blockedPorts[8] = {1, 100, 1220, 1333, 2700, 5555, 5600, 65000};
+
+    if (mActualBlockedPortsCount > 0) {
+        err = unblockAllPortsForBind();
     }
-    std::vector<int32_t> actualBlockedPorts;
-    status = mService->getPortsBlockedForBind(&actualBlockedPorts);
-    EXPECT_TRUE(status.isOk()) << status.getDescription ();
-    EXPECT_FALSE(actualBlockedPorts.empty());
-    EXPECT_EQ(blockedPorts, actualBlockedPorts);
+
+    for (int i : blockedPorts) {
+        err = blockPortForBind(i);
+        EXPECT_EQ(err, 0);
+    }
+    size_t actualBlockedPortsCount = 8;
+    in_port_t actualBlockedPorts[actualBlockedPortsCount];
+    err = getPortsBlockedForBind((in_port_t*) actualBlockedPorts, &actualBlockedPortsCount);
+    EXPECT_EQ(err, 0);
+    EXPECT_NE(actualBlockedPortsCount, 0);
+    for (int i=0; i < actualBlockedPortsCount; i++) {
+        EXPECT_EQ(blockedPorts[i], actualBlockedPorts[i]);
+    }
 
     // Remove the ports we added.
-    status = mService->unblockAllPortsForBind();
-    EXPECT_TRUE(status.isOk()) << status.getDescription ();
-    status = mService->getPortsBlockedForBind(&actualBlockedPorts);
-    EXPECT_TRUE(status.isOk()) << status.getDescription ();
-    EXPECT_TRUE(actualBlockedPorts.empty());
+    err = unblockAllPortsForBind();
+    EXPECT_EQ(err, 0);
+    err = getPortsBlockedForBind(actualBlockedPorts, &actualBlockedPortsCount);
+    EXPECT_EQ(err, 0);
+    EXPECT_EQ(actualBlockedPortsCount, 0);
 }
 
 TEST_F(ConnectivityNativeBinderTest, UnblockAllPorts) {
-    ndk::ScopedAStatus status;
-    std::vector<int> blockedPorts{1, 100, 1220, 1333, 2700, 5555, 5600, 65000};
+    int err;
+    in_port_t blockedPorts[8] = {1, 100, 1220, 1333, 2700, 5555, 5600, 65000};
 
-    if (mActualBlockedPorts.size() > 0) {
-        status = mService->unblockAllPortsForBind();
+    if (mActualBlockedPortsCount > 0) {
+        err = unblockAllPortsForBind();
     }
 
     for (int i : blockedPorts) {
-        status = mService->blockPortForBind(i);
-        EXPECT_TRUE(status.isOk()) << status.getDescription ();
+        err = blockPortForBind(i);
+        EXPECT_EQ(err, 0);
     }
 
-    std::vector<int32_t> actualBlockedPorts;
-    status = mService->getPortsBlockedForBind(&actualBlockedPorts);
-    EXPECT_TRUE(status.isOk()) << status.getDescription ();
-    EXPECT_FALSE(actualBlockedPorts.empty());
+    size_t actualBlockedPortsCount = 8;
+    in_port_t actualBlockedPorts[actualBlockedPortsCount];
+    err = getPortsBlockedForBind((in_port_t*) actualBlockedPorts, &actualBlockedPortsCount);
+    EXPECT_EQ(err, 0);
+    EXPECT_EQ(actualBlockedPortsCount, 8);
 
-    status = mService->unblockAllPortsForBind();
-    EXPECT_TRUE(status.isOk()) << status.getDescription ();
-    status = mService->getPortsBlockedForBind(&actualBlockedPorts);
-    EXPECT_TRUE(status.isOk()) << status.getDescription ();
-    EXPECT_TRUE(actualBlockedPorts.empty());
+    err = unblockAllPortsForBind();
+    EXPECT_EQ(err, 0);
+    err = getPortsBlockedForBind((in_port_t*) actualBlockedPorts, &actualBlockedPortsCount);
+    EXPECT_EQ(err, 0);
+    EXPECT_EQ(actualBlockedPortsCount, 0);
     // If mActualBlockedPorts is not empty, ports will be added back in teardown.
 }
 
-TEST_F(ConnectivityNativeBinderTest, BlockNegativePort) {
-    int retry = 0;
-    ndk::ScopedAStatus status;
-    do {
-        status = mService->blockPortForBind(-1);
-        // TODO: find out why transaction failed is being thrown on the first attempt.
-    } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
-    EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
-}
-
-TEST_F(ConnectivityNativeBinderTest, UnblockNegativePort) {
-    int retry = 0;
-    ndk::ScopedAStatus status;
-    do {
-        status = mService->unblockPortForBind(-1);
-        // TODO: find out why transaction failed is being thrown on the first attempt.
-    } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
-    EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
-}
-
-TEST_F(ConnectivityNativeBinderTest, BlockMaxPort) {
-    int retry = 0;
-    ndk::ScopedAStatus status;
-    do {
-        status = mService->blockPortForBind(65536);
-        // TODO: find out why transaction failed is being thrown on the first attempt.
-    } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
-    EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
-}
-
-TEST_F(ConnectivityNativeBinderTest, UnblockMaxPort) {
-    int retry = 0;
-    ndk::ScopedAStatus status;
-    do {
-        status = mService->unblockPortForBind(65536);
-        // TODO: find out why transaction failed is being thrown on the first attempt.
-    } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
-    EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
-}
-
 TEST_F(ConnectivityNativeBinderTest, CheckPermission) {
-    int retry = 0;
     int curUid = getuid();
     EXPECT_EQ(0, seteuid(FIRST_APPLICATION_UID + 2000)) << "seteuid failed: " << strerror(errno);
-    ndk::ScopedAStatus status;
-    do {
-        status = mService->blockPortForBind(5555);
-        // TODO: find out why transaction failed is being thrown on the first attempt.
-    } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
-    EXPECT_EQ(EX_SECURITY, status.getExceptionCode());
+    int err = blockPortForBind((in_port_t) 5555);
+    EXPECT_EQ(EPERM, err);
     EXPECT_EQ(0, seteuid(curUid)) << "seteuid failed: " << strerror(errno);
 }
diff --git a/tests/unit/java/android/net/IpSecAlgorithmTest.java b/tests/unit/java/android/net/IpSecAlgorithmTest.java
index 1482055..54ad961 100644
--- a/tests/unit/java/android/net/IpSecAlgorithmTest.java
+++ b/tests/unit/java/android/net/IpSecAlgorithmTest.java
@@ -27,6 +27,7 @@
 import android.content.res.Resources;
 import android.os.Build;
 import android.os.Parcel;
+import android.os.SystemProperties;
 
 import androidx.test.filters.SmallTest;
 
@@ -123,9 +124,7 @@
 
     @Test
     public void testValidationForAlgosAddedInS() throws Exception {
-        if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.R) {
-            return;
-        }
+        if (SystemProperties.getInt("ro.vendor.api_level", 10000) <= Build.VERSION_CODES.R) return;
 
         for (int len : new int[] {160, 224, 288}) {
             checkCryptKeyLenValidation(IpSecAlgorithm.CRYPT_AES_CTR, len);
@@ -194,15 +193,17 @@
     }
 
     private static Set<String> getMandatoryAlgos() {
+        int vendorApiLevel = SystemProperties.getInt("ro.vendor.api_level", 10000);
         return CollectionUtils.filter(
                 ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
-                i -> Build.VERSION.DEVICE_INITIAL_SDK_INT >= ALGO_TO_REQUIRED_FIRST_SDK.get(i));
+                i -> vendorApiLevel >= ALGO_TO_REQUIRED_FIRST_SDK.get(i));
     }
 
     private static Set<String> getOptionalAlgos() {
+        int vendorApiLevel = SystemProperties.getInt("ro.vendor.api_level", 10000);
         return CollectionUtils.filter(
                 ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
-                i -> Build.VERSION.DEVICE_INITIAL_SDK_INT < ALGO_TO_REQUIRED_FIRST_SDK.get(i));
+                i -> vendorApiLevel < ALGO_TO_REQUIRED_FIRST_SDK.get(i));
     }
 
     @Test
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 12478cb..8c9917e 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -1606,9 +1606,9 @@
         mMockVpn = new MockVpn(userId);
     }
 
-    private void mockUidNetworkingBlocked(int uid) {
+    private void mockUidNetworkingBlocked() {
         doAnswer(i -> isUidBlocked(mBlockedReasons, i.getArgument(1))
-        ).when(mNetworkPolicyManager).isUidNetworkingBlocked(eq(uid), anyBoolean());
+        ).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
     }
 
     private boolean isUidBlocked(int blockedReasons, boolean meteredNetwork) {
@@ -2689,7 +2689,7 @@
         final TestNetworkCallback generalCb = new TestNetworkCallback();
         final TestNetworkCallback defaultCb = new TestNetworkCallback();
         mCm.registerNetworkCallback(
-                new NetworkRequest.Builder().addTransportType(transport | transport).build(),
+                new NetworkRequest.Builder().addTransportType(transport).build(),
                 generalCb);
         mCm.registerDefaultNetworkCallback(defaultCb);
 
@@ -2944,7 +2944,8 @@
 
     @Test
     public void testRequiresValidation() {
-        assertTrue(NetworkMonitorUtils.isValidationRequired(false /* isVpnValidationRequired */,
+        assertTrue(NetworkMonitorUtils.isValidationRequired(false /* isDunValidationRequired */,
+                false /* isVpnValidationRequired */,
                 mCm.getDefaultRequest().networkCapabilities));
     }
 
@@ -3476,7 +3477,12 @@
             final int uid, final String packageName) throws Exception {
         doReturn(buildPackageInfo(true /* hasSystemPermission */, uid)).when(mPackageManager)
                 .getPackageInfo(eq(packageName), eq(GET_PERMISSIONS));
-        mService.mPermissionMonitor.onPackageAdded(packageName, uid);
+
+        // Send a broadcast indicating a package was installed.
+        final Intent addedIntent = new Intent(ACTION_PACKAGE_ADDED);
+        addedIntent.putExtra(Intent.EXTRA_UID, uid);
+        addedIntent.setData(Uri.parse("package:" + packageName));
+        processBroadcast(addedIntent);
     }
 
     @Test
@@ -4755,6 +4761,81 @@
         return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
     }
 
+    // A NetworkSpecifier subclass that matches all networks but must not be visible to apps.
+    static class ConfidentialMatchAllNetworkSpecifier extends NetworkSpecifier implements
+            Parcelable {
+        public static final Parcelable.Creator<ConfidentialMatchAllNetworkSpecifier> CREATOR =
+                new Parcelable.Creator<ConfidentialMatchAllNetworkSpecifier>() {
+                    public ConfidentialMatchAllNetworkSpecifier createFromParcel(Parcel in) {
+                        return new ConfidentialMatchAllNetworkSpecifier();
+                    }
+
+                    public ConfidentialMatchAllNetworkSpecifier[] newArray(int size) {
+                        return new ConfidentialMatchAllNetworkSpecifier[size];
+                    }
+                };
+        @Override
+        public boolean canBeSatisfiedBy(NetworkSpecifier other) {
+            return true;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {}
+
+        @Override
+        public NetworkSpecifier redact() {
+            return null;
+        }
+    }
+
+    // A network specifier that matches either another LocalNetworkSpecifier with the same
+    // string or a ConfidentialMatchAllNetworkSpecifier, and can be passed to apps as is.
+    static class LocalStringNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+        public static final Parcelable.Creator<LocalStringNetworkSpecifier> CREATOR =
+                new Parcelable.Creator<LocalStringNetworkSpecifier>() {
+                    public LocalStringNetworkSpecifier createFromParcel(Parcel in) {
+                        return new LocalStringNetworkSpecifier(in);
+                    }
+
+                    public LocalStringNetworkSpecifier[] newArray(int size) {
+                        return new LocalStringNetworkSpecifier[size];
+                    }
+                };
+        private String mString;
+
+        LocalStringNetworkSpecifier(String string) {
+            mString = string;
+        }
+
+        LocalStringNetworkSpecifier(Parcel in) {
+            mString = in.readString();
+        }
+
+        @Override
+        public boolean canBeSatisfiedBy(NetworkSpecifier other) {
+            if (other instanceof LocalStringNetworkSpecifier) {
+                return TextUtils.equals(mString,
+                        ((LocalStringNetworkSpecifier) other).mString);
+            }
+            if (other instanceof ConfidentialMatchAllNetworkSpecifier) return true;
+            return false;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(mString);
+        }
+    }
+
     /**
      * Verify request matching behavior with network specifiers.
      *
@@ -4764,56 +4845,6 @@
      */
     @Test
     public void testNetworkSpecifier() throws Exception {
-        // A NetworkSpecifier subclass that matches all networks but must not be visible to apps.
-        class ConfidentialMatchAllNetworkSpecifier extends NetworkSpecifier implements
-                Parcelable {
-            @Override
-            public boolean canBeSatisfiedBy(NetworkSpecifier other) {
-                return true;
-            }
-
-            @Override
-            public int describeContents() {
-                return 0;
-            }
-
-            @Override
-            public void writeToParcel(Parcel dest, int flags) {}
-
-            @Override
-            public NetworkSpecifier redact() {
-                return null;
-            }
-        }
-
-        // A network specifier that matches either another LocalNetworkSpecifier with the same
-        // string or a ConfidentialMatchAllNetworkSpecifier, and can be passed to apps as is.
-        class LocalStringNetworkSpecifier extends NetworkSpecifier implements Parcelable {
-            private String mString;
-
-            LocalStringNetworkSpecifier(String string) {
-                mString = string;
-            }
-
-            @Override
-            public boolean canBeSatisfiedBy(NetworkSpecifier other) {
-                if (other instanceof LocalStringNetworkSpecifier) {
-                    return TextUtils.equals(mString,
-                            ((LocalStringNetworkSpecifier) other).mString);
-                }
-                if (other instanceof ConfidentialMatchAllNetworkSpecifier) return true;
-                return false;
-            }
-
-            @Override
-            public int describeContents() {
-                return 0;
-            }
-            @Override
-            public void writeToParcel(Parcel dest, int flags) {}
-        }
-
-
         NetworkRequest rEmpty1 = newWifiRequestBuilder().build();
         NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build();
         NetworkRequest rEmpty3 = newWifiRequestBuilder().setNetworkSpecifier("").build();
@@ -4897,6 +4928,29 @@
         return mContext.getAttributionTag();
     }
 
+    static class NonParcelableSpecifier extends NetworkSpecifier {
+        @Override
+        public boolean canBeSatisfiedBy(NetworkSpecifier other) {
+            return false;
+        }
+    }
+    static class ParcelableSpecifier extends NonParcelableSpecifier implements Parcelable {
+        public static final Parcelable.Creator<NonParcelableSpecifier> CREATOR =
+                new Parcelable.Creator<NonParcelableSpecifier>() {
+                    public NonParcelableSpecifier createFromParcel(Parcel in) {
+                        return new NonParcelableSpecifier();
+                    }
+
+                    public NonParcelableSpecifier[] newArray(int size) {
+                        return new NonParcelableSpecifier[size];
+                    }
+                };
+        @Override public int describeContents() {
+            return 0;
+        }
+        @Override public void writeToParcel(Parcel p, int flags) {}
+    }
+
     @Test
     public void testInvalidNetworkSpecifier() {
         assertThrows(IllegalArgumentException.class, () -> {
@@ -4914,17 +4968,6 @@
                     mContext.getPackageName(), getAttributionTag());
         });
 
-        class NonParcelableSpecifier extends NetworkSpecifier {
-            @Override
-            public boolean canBeSatisfiedBy(NetworkSpecifier other) {
-                return false;
-            }
-        };
-        class ParcelableSpecifier extends NonParcelableSpecifier implements Parcelable {
-            @Override public int describeContents() { return 0; }
-            @Override public void writeToParcel(Parcel p, int flags) {}
-        }
-
         final NetworkRequest.Builder builder =
                 new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
         assertThrows(ClassCastException.class, () -> {
@@ -5138,9 +5181,10 @@
     }
 
     @Test
-    public void testRegisterPrivilegedDefaultCallbacksRequireNetworkSettings() throws Exception {
+    public void testRegisterPrivilegedDefaultCallbacksRequirePermissions() throws Exception {
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false /* validated */);
+        mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_DENIED);
 
         final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
         final TestNetworkCallback callback = new TestNetworkCallback();
@@ -5151,6 +5195,12 @@
                 () -> mCm.registerDefaultNetworkCallbackForUid(APP1_UID, callback, handler));
         callback.assertNoCallback();
 
+        mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_GRANTED);
+        mCm.registerSystemDefaultNetworkCallback(callback, handler);
+        mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_DENIED);
+        callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+        mCm.unregisterNetworkCallback(callback);
+
         mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
         mCm.registerSystemDefaultNetworkCallback(callback, handler);
         callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
@@ -7156,17 +7206,38 @@
         mCm.unregisterNetworkCallback(networkCallback);
     }
 
-    private void expectNotifyNetworkStatus(List<Network> defaultNetworks, String defaultIface,
-            Integer vpnUid, String vpnIfname, List<String> underlyingIfaces) throws Exception {
+    private void expectNotifyNetworkStatus(List<Network> allNetworks, List<Network> defaultNetworks,
+            String defaultIface, Integer vpnUid, String vpnIfname, List<String> underlyingIfaces)
+            throws Exception {
         ArgumentCaptor<List<Network>> defaultNetworksCaptor = ArgumentCaptor.forClass(List.class);
         ArgumentCaptor<List<UnderlyingNetworkInfo>> vpnInfosCaptor =
                 ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List<NetworkStateSnapshot>> snapshotsCaptor =
+                ArgumentCaptor.forClass(List.class);
 
         verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(defaultNetworksCaptor.capture(),
-                any(List.class), eq(defaultIface), vpnInfosCaptor.capture());
+                snapshotsCaptor.capture(), eq(defaultIface), vpnInfosCaptor.capture());
 
         assertSameElements(defaultNetworks, defaultNetworksCaptor.getValue());
 
+        List<Network> snapshotNetworks = new ArrayList<Network>();
+        for (NetworkStateSnapshot ns : snapshotsCaptor.getValue()) {
+            snapshotNetworks.add(ns.getNetwork());
+        }
+        assertSameElements(allNetworks, snapshotNetworks);
+
+        if (defaultIface != null) {
+            assertNotNull(
+                    "Did not find interface " + defaultIface + " in call to notifyNetworkStatus",
+                    CollectionUtils.findFirst(snapshotsCaptor.getValue(), (ns) -> {
+                        final LinkProperties lp = ns.getLinkProperties();
+                        if (lp != null && TextUtils.equals(defaultIface, lp.getInterfaceName())) {
+                            return true;
+                        }
+                        return false;
+                    }));
+        }
+
         List<UnderlyingNetworkInfo> infos = vpnInfosCaptor.getValue();
         if (vpnUid != null) {
             assertEquals("Should have exactly one VPN:", 1, infos.size());
@@ -7181,28 +7252,47 @@
     }
 
     private void expectNotifyNetworkStatus(
-            List<Network> defaultNetworks, String defaultIface) throws Exception {
-        expectNotifyNetworkStatus(defaultNetworks, defaultIface, null, null, List.of());
+            List<Network> allNetworks, List<Network> defaultNetworks, String defaultIface)
+            throws Exception {
+        expectNotifyNetworkStatus(allNetworks, defaultNetworks, defaultIface, null, null,
+                List.of());
+    }
+
+    private List<Network> onlyCell() {
+        return List.of(mCellNetworkAgent.getNetwork());
+    }
+
+    private List<Network> onlyWifi() {
+        return List.of(mWiFiNetworkAgent.getNetwork());
+    }
+
+    private List<Network> cellAndWifi() {
+        return List.of(mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork());
     }
 
     @Test
     public void testStatsIfacesChanged() throws Exception {
-        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
-        final List<Network> onlyCell = List.of(mCellNetworkAgent.getNetwork());
-        final List<Network> onlyWifi = List.of(mWiFiNetworkAgent.getNetwork());
-
         LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
         LinkProperties wifiLp = new LinkProperties();
         wifiLp.setInterfaceName(WIFI_IFNAME);
 
-        // Simple connection should have updated ifaces
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+
+        // Simple connection with initial LP should have updated ifaces.
         mCellNetworkAgent.connect(false);
-        mCellNetworkAgent.sendLinkProperties(cellLp);
         waitForIdle();
-        expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
+        expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME);
+        reset(mStatsManager);
+
+        // Verify change fields other than interfaces does not trigger a notification to NSS.
+        cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
+        cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
+                MOBILE_IFNAME));
+        cellLp.setDnsServers(List.of(InetAddress.getAllByName("8.8.8.8")));
+        mCellNetworkAgent.sendLinkProperties(cellLp);
+        verifyNoMoreInteractions(mStatsManager);
         reset(mStatsManager);
 
         // Default network switch should update ifaces.
@@ -7210,37 +7300,62 @@
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
         waitForIdle();
         assertEquals(wifiLp, mService.getActiveLinkProperties());
-        expectNotifyNetworkStatus(onlyWifi, WIFI_IFNAME);
+        expectNotifyNetworkStatus(cellAndWifi(), onlyWifi(), WIFI_IFNAME);
+        reset(mStatsManager);
+
+        // Disconnecting a network updates ifaces again. The soon-to-be disconnected interface is
+        // still in the list to ensure that stats are counted on that interface.
+        // TODO: this means that if anything else uses that interface for any other reason before
+        // notifyNetworkStatus is called again, traffic on that interface will be accounted to the
+        // disconnected network. This is likely a bug in ConnectivityService; it should probably
+        // call notifyNetworkStatus again without the disconnected network.
+        mCellNetworkAgent.disconnect();
+        waitForIdle();
+        expectNotifyNetworkStatus(cellAndWifi(), onlyWifi(), WIFI_IFNAME);
+        verifyNoMoreInteractions(mStatsManager);
+        reset(mStatsManager);
+
+        // Connecting a network updates ifaces even if the network doesn't become default.
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(false);
+        waitForIdle();
+        expectNotifyNetworkStatus(cellAndWifi(), onlyWifi(), WIFI_IFNAME);
         reset(mStatsManager);
 
         // Disconnect should update ifaces.
         mWiFiNetworkAgent.disconnect();
         waitForIdle();
-        expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
+        expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME);
         reset(mStatsManager);
 
         // Metered change should update ifaces
         mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         waitForIdle();
-        expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
+        expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME);
         reset(mStatsManager);
 
         mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         waitForIdle();
-        expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
+        expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME);
         reset(mStatsManager);
 
-        // Temp metered change shouldn't update ifaces
+        // Temp metered change should update ifaces
         mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
         waitForIdle();
-        verify(mStatsManager, never()).notifyNetworkStatus(eq(onlyCell),
+        expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME);
+        reset(mStatsManager);
+
+        // Congested change shouldn't update ifaces
+        mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
+        waitForIdle();
+        verify(mStatsManager, never()).notifyNetworkStatus(eq(onlyCell()),
                 any(List.class), eq(MOBILE_IFNAME), any(List.class));
         reset(mStatsManager);
 
         // Roaming change should update ifaces
         mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
         waitForIdle();
-        expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
+        expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME);
         reset(mStatsManager);
 
         // Test VPNs.
@@ -7254,8 +7369,8 @@
                 List.of(mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork());
 
         // A VPN with default (null) underlying networks sets the underlying network's interfaces...
-        expectNotifyNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
-                List.of(MOBILE_IFNAME));
+        expectNotifyNetworkStatus(cellAndVpn, cellAndVpn, MOBILE_IFNAME, Process.myUid(),
+                VPN_IFNAME, List.of(MOBILE_IFNAME));
 
         // ...and updates them as the default network switches.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -7264,15 +7379,16 @@
         final Network[] onlyNull = new Network[]{null};
         final List<Network> wifiAndVpn =
                 List.of(mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork());
-        final List<Network> cellAndWifi =
-                List.of(mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork());
+        final List<Network> cellWifiAndVpn =
+                List.of(mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork(),
+                        mMockVpn.getNetwork());
         final Network[] cellNullAndWifi =
                 new Network[]{mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
 
         waitForIdle();
         assertEquals(wifiLp, mService.getActiveLinkProperties());
-        expectNotifyNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
-                List.of(WIFI_IFNAME));
+        expectNotifyNetworkStatus(cellWifiAndVpn, wifiAndVpn, WIFI_IFNAME, Process.myUid(),
+                VPN_IFNAME, List.of(WIFI_IFNAME));
         reset(mStatsManager);
 
         // A VPN that sets its underlying networks passes the underlying interfaces, and influences
@@ -7281,23 +7397,23 @@
         // MOBILE_IFNAME even though the default network is wifi.
         // TODO: fix this to pass in the actual default network interface. Whether or not the VPN
         // applies to the system server UID should not have any bearing on network stats.
-        mMockVpn.setUnderlyingNetworks(onlyCell.toArray(new Network[0]));
+        mMockVpn.setUnderlyingNetworks(onlyCell().toArray(new Network[0]));
         waitForIdle();
-        expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
-                List.of(MOBILE_IFNAME));
+        expectNotifyNetworkStatus(cellWifiAndVpn, wifiAndVpn, MOBILE_IFNAME, Process.myUid(),
+                VPN_IFNAME, List.of(MOBILE_IFNAME));
         reset(mStatsManager);
 
-        mMockVpn.setUnderlyingNetworks(cellAndWifi.toArray(new Network[0]));
+        mMockVpn.setUnderlyingNetworks(cellAndWifi().toArray(new Network[0]));
         waitForIdle();
-        expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
-                List.of(MOBILE_IFNAME, WIFI_IFNAME));
+        expectNotifyNetworkStatus(cellWifiAndVpn, wifiAndVpn, MOBILE_IFNAME, Process.myUid(),
+                VPN_IFNAME,  List.of(MOBILE_IFNAME, WIFI_IFNAME));
         reset(mStatsManager);
 
         // Null underlying networks are ignored.
         mMockVpn.setUnderlyingNetworks(cellNullAndWifi);
         waitForIdle();
-        expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
-                List.of(MOBILE_IFNAME, WIFI_IFNAME));
+        expectNotifyNetworkStatus(cellWifiAndVpn, wifiAndVpn, MOBILE_IFNAME, Process.myUid(),
+                VPN_IFNAME,  List.of(MOBILE_IFNAME, WIFI_IFNAME));
         reset(mStatsManager);
 
         // If an underlying network disconnects, that interface should no longer be underlying.
@@ -7310,8 +7426,8 @@
         mCellNetworkAgent.disconnect();
         waitForIdle();
         assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork()));
-        expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
-                List.of(MOBILE_IFNAME, WIFI_IFNAME));
+        expectNotifyNetworkStatus(cellWifiAndVpn, wifiAndVpn, MOBILE_IFNAME, Process.myUid(),
+                VPN_IFNAME, List.of(MOBILE_IFNAME, WIFI_IFNAME));
 
         // Confirm that we never tell NetworkStatsService that cell is no longer the underlying
         // network for the VPN...
@@ -7346,25 +7462,25 @@
         // Also, for the same reason as above, the active interface passed in is null.
         mMockVpn.setUnderlyingNetworks(new Network[0]);
         waitForIdle();
-        expectNotifyNetworkStatus(wifiAndVpn, null);
+        expectNotifyNetworkStatus(wifiAndVpn, wifiAndVpn, null);
         reset(mStatsManager);
 
         // Specifying only a null underlying network is the same as no networks.
         mMockVpn.setUnderlyingNetworks(onlyNull);
         waitForIdle();
-        expectNotifyNetworkStatus(wifiAndVpn, null);
+        expectNotifyNetworkStatus(wifiAndVpn, wifiAndVpn, null);
         reset(mStatsManager);
 
         // Specifying networks that are all disconnected is the same as specifying no networks.
-        mMockVpn.setUnderlyingNetworks(onlyCell.toArray(new Network[0]));
+        mMockVpn.setUnderlyingNetworks(onlyCell().toArray(new Network[0]));
         waitForIdle();
-        expectNotifyNetworkStatus(wifiAndVpn, null);
+        expectNotifyNetworkStatus(wifiAndVpn, wifiAndVpn, null);
         reset(mStatsManager);
 
         // Passing in null again means follow the default network again.
         mMockVpn.setUnderlyingNetworks(null);
         waitForIdle();
-        expectNotifyNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+        expectNotifyNetworkStatus(wifiAndVpn, wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
                 List.of(WIFI_IFNAME));
         reset(mStatsManager);
     }
@@ -7419,7 +7535,7 @@
         mWiFiNetworkAgent.connect(true /* validated */);
 
         final List<Network> none = List.of();
-        expectNotifyNetworkStatus(none, null);  // Wifi is not the default network
+        expectNotifyNetworkStatus(onlyWifi(), none, null);  // Wifi is not the default network
 
         // Create a virtual network based on the wifi network.
         final int ownerUid = 10042;
@@ -7444,7 +7560,9 @@
         assertFalse(nc.hasTransport(TRANSPORT_WIFI));
         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
         final List<Network> onlyVcn = List.of(vcn.getNetwork());
-        expectNotifyNetworkStatus(onlyVcn, vcnIface, ownerUid, vcnIface, List.of(WIFI_IFNAME));
+        final List<Network> vcnAndWifi = List.of(vcn.getNetwork(), mWiFiNetworkAgent.getNetwork());
+        expectNotifyNetworkStatus(vcnAndWifi, onlyVcn, vcnIface, ownerUid, vcnIface,
+                List.of(WIFI_IFNAME));
 
         // Add NOT_METERED to the underlying network, check that it is not propagated.
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
@@ -7467,7 +7585,10 @@
         nc = mCm.getNetworkCapabilities(vcn.getNetwork());
         assertFalse(nc.hasTransport(TRANSPORT_WIFI));
         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_ROAMING));
-        expectNotifyNetworkStatus(onlyVcn, vcnIface, ownerUid, vcnIface, List.of(MOBILE_IFNAME));
+        final List<Network> vcnWifiAndCell = List.of(vcn.getNetwork(),
+                mWiFiNetworkAgent.getNetwork(), mCellNetworkAgent.getNetwork());
+        expectNotifyNetworkStatus(vcnWifiAndCell, onlyVcn, vcnIface, ownerUid, vcnIface,
+                List.of(MOBILE_IFNAME));
     }
 
     @Test
@@ -8212,6 +8333,7 @@
         // VPN networks do not satisfy the default request and are automatically validated
         // by NetworkMonitor
         assertFalse(NetworkMonitorUtils.isValidationRequired(
+                false /* isDunValidationRequired */,
                 NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig())
                         .isVpnValidationRequired(),
                 mMockVpn.getAgent().getNetworkCapabilities()));
@@ -8364,6 +8486,7 @@
         assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
 
         assertFalse(NetworkMonitorUtils.isValidationRequired(
+                false /* isDunValidationRequired */,
                 NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig())
                         .isVpnValidationRequired(),
                 mMockVpn.getAgent().getNetworkCapabilities()));
@@ -8999,7 +9122,7 @@
         final DetailedBlockedStatusCallback detailedCallback = new DetailedBlockedStatusCallback();
         mCm.registerNetworkCallback(cellRequest, detailedCallback);
 
-        mockUidNetworkingBlocked(Process.myUid());
+        mockUidNetworkingBlocked();
 
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
@@ -9114,7 +9237,7 @@
     public void testNetworkBlockedStatusBeforeAndAfterConnect() throws Exception {
         final TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
-        mockUidNetworkingBlocked(Process.myUid());
+        mockUidNetworkingBlocked();
 
         // No Networkcallbacks invoked before any network is active.
         setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
@@ -16726,23 +16849,25 @@
         assertThrows(NullPointerException.class, () -> mService.unofferNetwork(null));
     }
 
-    public void doTestIgnoreValidationAfterRoam(final boolean enabled) throws Exception {
-        assumeFalse(SdkLevel.isAtLeastT());
-        doReturn(enabled ? 5000 : -1).when(mResources)
+    public void doTestIgnoreValidationAfterRoam(int resValue, final boolean enabled)
+            throws Exception {
+        doReturn(resValue).when(mResources)
                 .getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
 
+        final String bssid1 = "AA:AA:AA:AA:AA:AA";
+        final String bssid2 = "BB:BB:BB:BB:BB:BB";
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         NetworkCapabilities wifiNc1 = new NetworkCapabilities()
                 .addCapability(NET_CAPABILITY_INTERNET)
+                .addCapability(NET_CAPABILITY_NOT_VPN)
+                .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                .addCapability(NET_CAPABILITY_TRUSTED)
                 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
                 .addTransportType(TRANSPORT_WIFI)
-                .setTransportInfo(new WifiInfo.Builder().setBssid("AA:AA:AA:AA:AA:AA").build());
-        NetworkCapabilities wifiNc2 = new NetworkCapabilities()
-                .addCapability(NET_CAPABILITY_INTERNET)
-                .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
-                .addTransportType(TRANSPORT_WIFI)
-                .setTransportInfo(new WifiInfo.Builder().setBssid("BB:BB:BB:BB:BB:BB").build());
+                .setTransportInfo(new WifiInfo.Builder().setBssid(bssid1).build());
+        NetworkCapabilities wifiNc2 = new NetworkCapabilities(wifiNc1)
+                .setTransportInfo(new WifiInfo.Builder().setBssid(bssid2).build());
         final LinkProperties wifiLp = new LinkProperties();
         wifiLp.setInterfaceName(WIFI_IFNAME);
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc1);
@@ -16806,6 +16931,7 @@
             wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
                     mWiFiNetworkAgent);
         }
+        mCm.unregisterNetworkCallback(wifiNetworkCallback);
 
         // Wi-Fi roams from wifiNc1 to wifiNc2, and now becomes really invalid. If validation
         // failures after roam are not ignored, this will cause cell to become the default network.
@@ -16816,40 +16942,77 @@
         mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
         mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
 
-        if (!enabled) {
+        if (enabled) {
+            // Network validation failed, but the result will be ignored.
+            assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
+                    NET_CAPABILITY_VALIDATED));
+            mWiFiNetworkAgent.setNetworkValid(false);
+
+            // Behavior of after config_validationFailureAfterRoamIgnoreTimeMillis
+            ConditionVariable waitForValidationBlock = new ConditionVariable();
+            doReturn(50).when(mResources)
+                    .getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
+            // Wi-Fi roaming from wifiNc2 to wifiNc1.
+            mWiFiNetworkAgent.setNetworkCapabilities(wifiNc1, true);
+            mWiFiNetworkAgent.setNetworkInvalid(false);
+            waitForValidationBlock.block(150);
+            mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
             mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
-            return;
+        } else {
+            mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         }
 
-        // Network validation failed, but the result will be ignored.
-        assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
-                NET_CAPABILITY_VALIDATED));
-        mWiFiNetworkAgent.setNetworkValid(false);
+        // Wi-Fi is still connected and would become the default network if cell were to
+        // disconnect. This assertion ensures that the switch to cellular was not caused by
+        // Wi-Fi disconnecting (e.g., because the capability change to wifiNc2 caused it
+        // to stop satisfying the default request).
+        mCellNetworkAgent.disconnect();
+        mDefaultNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent);
+        mDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
 
-        // Behavior of after config_validationFailureAfterRoamIgnoreTimeMillis
-        ConditionVariable waitForValidationBlock = new ConditionVariable();
-        doReturn(50).when(mResources)
-                .getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
-        // Wi-Fi roaming from wifiNc2 to wifiNc1.
-        mWiFiNetworkAgent.setNetworkCapabilities(wifiNc1, true);
-        mWiFiNetworkAgent.setNetworkInvalid(false);
-        waitForValidationBlock.block(150);
-        mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
-        mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
-
-        mCm.unregisterNetworkCallback(wifiNetworkCallback);
     }
 
     @Test
     public void testIgnoreValidationAfterRoamDisabled() throws Exception {
-        doTestIgnoreValidationAfterRoam(false /* enabled */);
+        doTestIgnoreValidationAfterRoam(-1, false /* enabled */);
     }
+
     @Test
     public void testIgnoreValidationAfterRoamEnabled() throws Exception {
-        doTestIgnoreValidationAfterRoam(true /* enabled */);
+        final boolean enabled = !SdkLevel.isAtLeastT();
+        doTestIgnoreValidationAfterRoam(5_000, enabled);
     }
 
     @Test
+    public void testShouldIgnoreValidationFailureAfterRoam() {
+        // Always disabled on T+.
+        assumeFalse(SdkLevel.isAtLeastT());
+
+        NetworkAgentInfo nai = fakeWifiNai(new NetworkCapabilities());
+
+        // Enabled, but never roamed.
+        doReturn(5_000).when(mResources)
+                .getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
+        assertEquals(0, nai.lastRoamTime);
+        assertFalse(mService.shouldIgnoreValidationFailureAfterRoam(nai));
+
+        // Roamed recently.
+        nai.lastRoamTime = SystemClock.elapsedRealtime() - 500 /* ms */;
+        assertTrue(mService.shouldIgnoreValidationFailureAfterRoam(nai));
+
+        // Disabled due to invalid setting (maximum is 10 seconds).
+        doReturn(15_000).when(mResources)
+                .getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
+        assertFalse(mService.shouldIgnoreValidationFailureAfterRoam(nai));
+
+        // Disabled.
+        doReturn(-1).when(mResources)
+                .getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
+        assertFalse(mService.shouldIgnoreValidationFailureAfterRoam(nai));
+    }
+
+
+    @Test
     public void testLegacyTetheringApiGuardWithProperPermission() throws Exception {
         final String testIface = "test0";
         mServiceContext.setPermission(ACCESS_NETWORK_STATE, PERMISSION_DENIED);
@@ -16880,43 +17043,4 @@
             verify(mTetheringManager).getTetherableWifiRegexs();
         });
     }
-
-    @Test
-    public void testGetNetworkInfoForUid() throws Exception {
-        // Setup and verify getNetworkInfoForUid cannot be called without Network Stack permission,
-        // when querying NetworkInfo for other uid.
-        verifyNoNetwork();
-        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
-        mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-                PERMISSION_DENIED);
-
-        final int otherUid = Process.myUid() + 1;
-        assertNull(mCm.getActiveNetwork());
-        assertNull(mCm.getNetworkInfoForUid(mCm.getActiveNetwork(),
-                Process.myUid(), false /* ignoreBlocked */));
-        assertThrows(SecurityException.class, () -> mCm.getNetworkInfoForUid(
-                mCm.getActiveNetwork(), otherUid, false /* ignoreBlocked */));
-        withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () ->
-                assertNull(mCm.getNetworkInfoForUid(mCm.getActiveNetwork(),
-                        otherUid, false /* ignoreBlocked */)));
-
-        // Bringing up validated wifi and verify again. Make the other uid be blocked,
-        // verify the method returns result accordingly.
-        mWiFiNetworkAgent.connect(true);
-        setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
-        mockUidNetworkingBlocked(otherUid);
-        withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () ->
-                verifyActiveNetwork(TRANSPORT_WIFI));
-        checkNetworkInfo(mCm.getNetworkInfoForUid(mCm.getActiveNetwork(),
-                Process.myUid(), false /* ignoreBlocked */), TYPE_WIFI, DetailedState.CONNECTED);
-        assertThrows(SecurityException.class, () -> mCm.getNetworkInfoForUid(
-                mCm.getActiveNetwork(), otherUid, false /* ignoreBlocked */));
-        withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () ->
-                checkNetworkInfo(mCm.getNetworkInfoForUid(mCm.getActiveNetwork(),
-                        otherUid, false /* ignoreBlocked */), TYPE_WIFI, DetailedState.BLOCKED));
-        withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () ->
-                checkNetworkInfo(mCm.getNetworkInfoForUid(mCm.getActiveNetwork(),
-                        otherUid, true /* ignoreBlocked */), TYPE_WIFI, DetailedState.CONNECTED));
-    }
 }
diff --git a/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
index 9401d47..624071a 100644
--- a/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -748,6 +748,13 @@
         // Verify quota and RefcountedResource objects cleaned up
         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
         verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
+
+        for (int direction : new int[] {DIRECTION_OUT, DIRECTION_IN, DIRECTION_FWD}) {
+            verify(mMockNetd, times(ADDRESS_FAMILIES.length))
+                    .ipSecDeleteSecurityPolicy(
+                            anyInt(), anyInt(), eq(direction), anyInt(), anyInt(), anyInt());
+        }
+
         try {
             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                     createTunnelResp.resourceId);
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index 85bc4a9..b651c33 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -220,12 +220,12 @@
          */
         @Override
         public String generateIpv6Address(@NonNull String iface, @NonNull String v4,
-                @NonNull String prefix64) throws IOException {
+                @NonNull String prefix64, int mark) throws IOException {
             if (BASE_IFACE.equals(iface) && XLAT_LOCAL_IPV4ADDR_STRING.equals(v4)
-                    && NAT64_PREFIX_STRING.equals(prefix64)) {
+                    && NAT64_PREFIX_STRING.equals(prefix64) && MARK == mark) {
                 return XLAT_LOCAL_IPV6ADDR_STRING;
             }
-            fail("unsupported args: " + iface + ", " + v4 + ", " + prefix64);
+            fail("unsupported args: " + iface + ", " + v4 + ", " + prefix64 + ", " + mark);
             return null;
         }
 
@@ -417,7 +417,7 @@
 
         // Generate a checksum-neutral IID.
         inOrder.verify(mDeps).generateIpv6Address(eq(BASE_IFACE),
-                eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(NAT64_PREFIX_STRING));
+                eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(NAT64_PREFIX_STRING), eq(MARK));
 
         // Open, configure and bring up the tun interface.
         inOrder.verify(mDeps).createTunInterface(eq(STACKED_IFACE));
@@ -617,7 +617,7 @@
         class FailureDependencies extends TestDependencies {
             @Override
             public String generateIpv6Address(@NonNull String iface, @NonNull String v4,
-                    @NonNull String prefix64) throws IOException {
+                    @NonNull String prefix64, int mark) throws IOException {
                 throw new IOException();
             }
         }
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index 39fd780..3c23d7b 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -31,6 +31,7 @@
 import static android.os.Build.VERSION_CODES.S_V2;
 import static android.os.UserHandle.PER_USER_RANGE;
 
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
 import static com.android.testutils.Cleanup.testAndCleanup;
 import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
 import static com.android.testutils.MiscAsserts.assertThrows;
@@ -93,6 +94,7 @@
 import android.net.LinkProperties;
 import android.net.LocalSocket;
 import android.net.Network;
+import android.net.NetworkAgent;
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo.DetailedState;
@@ -204,6 +206,7 @@
     private static final byte[] TEST_VPN_PSK = "psk".getBytes();
 
     private static final int IP4_PREFIX_LEN = 32;
+    private static final int IP6_PREFIX_LEN = 64;
     private static final int MIN_PORT = 0;
     private static final int MAX_PORT = 65535;
 
@@ -217,15 +220,28 @@
             InetAddresses.parseNumericAddress("192.0.2.201");
     private static final InetAddress TEST_VPN_INTERNAL_IP =
             InetAddresses.parseNumericAddress("198.51.100.10");
+    private static final InetAddress TEST_VPN_INTERNAL_IP6 =
+            InetAddresses.parseNumericAddress("2001:db8::1");
     private static final InetAddress TEST_VPN_INTERNAL_DNS =
             InetAddresses.parseNumericAddress("8.8.8.8");
+    private static final InetAddress TEST_VPN_INTERNAL_DNS6 =
+            InetAddresses.parseNumericAddress("2001:4860:4860::8888");
 
     private static final IkeTrafficSelector IN_TS =
             new IkeTrafficSelector(MIN_PORT, MAX_PORT, TEST_VPN_INTERNAL_IP, TEST_VPN_INTERNAL_IP);
+    private static final IkeTrafficSelector IN_TS6 =
+            new IkeTrafficSelector(
+                    MIN_PORT, MAX_PORT, TEST_VPN_INTERNAL_IP6, TEST_VPN_INTERNAL_IP6);
     private static final IkeTrafficSelector OUT_TS =
             new IkeTrafficSelector(MIN_PORT, MAX_PORT,
                     InetAddresses.parseNumericAddress("0.0.0.0"),
                     InetAddresses.parseNumericAddress("255.255.255.255"));
+    private static final IkeTrafficSelector OUT_TS6 =
+            new IkeTrafficSelector(
+                    MIN_PORT,
+                    MAX_PORT,
+                    InetAddresses.parseNumericAddress("::"),
+                    InetAddresses.parseNumericAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
 
     private static final Network TEST_NETWORK = new Network(Integer.MAX_VALUE);
     private static final Network TEST_NETWORK_2 = new Network(Integer.MAX_VALUE - 1);
@@ -277,6 +293,10 @@
 
         mIpSecManager = new IpSecManager(mContext, mIpSecService);
         mTestDeps = spy(new TestDeps());
+        doReturn(IPV6_MIN_MTU)
+                .when(mTestDeps)
+                .calculateVpnMtu(any(), anyInt(), anyInt(), anyBoolean());
+        doReturn(1500).when(mTestDeps).getJavaNetworkInterfaceMtu(any(), anyInt());
 
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         setMockedPackages(sPackages);
@@ -315,6 +335,8 @@
                         IpSecManager.Status.OK, TEST_TUNNEL_RESOURCE_ID, TEST_IFACE_NAME);
         when(mIpSecService.createTunnelInterface(any(), any(), any(), any(), any()))
                 .thenReturn(tunnelResp);
+        doReturn(new LinkProperties()).when(mConnectivityManager).getLinkProperties(any());
+
         // The unit test should know what kind of permission it needs and set the permission by
         // itself, so set the default value of Context#checkCallingOrSelfPermission to
         // PERMISSION_DENIED.
@@ -1693,9 +1715,12 @@
     }
 
     private ChildSessionConfiguration createChildConfig() {
-        return new ChildSessionConfiguration.Builder(Arrays.asList(IN_TS), Arrays.asList(OUT_TS))
+        return new ChildSessionConfiguration.Builder(
+                        Arrays.asList(IN_TS, IN_TS6), Arrays.asList(OUT_TS, OUT_TS6))
                 .addInternalAddress(new LinkAddress(TEST_VPN_INTERNAL_IP, IP4_PREFIX_LEN))
+                .addInternalAddress(new LinkAddress(TEST_VPN_INTERNAL_IP6, IP6_PREFIX_LEN))
                 .addInternalDnsServer(TEST_VPN_INTERNAL_DNS)
+                .addInternalDnsServer(TEST_VPN_INTERNAL_DNS6)
                 .build();
     }
 
@@ -1742,9 +1767,19 @@
 
     private PlatformVpnSnapshot verifySetupPlatformVpn(IkeSessionConfiguration ikeConfig)
             throws Exception {
+        return verifySetupPlatformVpn(ikeConfig, true);
+    }
+
+    private PlatformVpnSnapshot verifySetupPlatformVpn(
+            IkeSessionConfiguration ikeConfig, boolean mtuSupportsIpv6) throws Exception {
+        if (!mtuSupportsIpv6) {
+            doReturn(IPV6_MIN_MTU - 1).when(mTestDeps).calculateVpnMtu(any(), anyInt(), anyInt(),
+                    anyBoolean());
+        }
+
         doReturn(mMockNetworkAgent).when(mTestDeps)
                 .newNetworkAgent(
-                        any(), any(), anyString(), any(), any(), any(), any(), any());
+                        any(), any(), anyString(), any(), any(), any(), any(), any(), any());
 
         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
@@ -1774,24 +1809,44 @@
                 ArgumentCaptor.forClass(NetworkAgentConfig.class);
         verify(mTestDeps).newNetworkAgent(
                 any(), any(), anyString(), ncCaptor.capture(), lpCaptor.capture(),
-                any(), nacCaptor.capture(), any());
+                any(), nacCaptor.capture(), any(), any());
 
         // Check LinkProperties
         final LinkProperties lp = lpCaptor.getValue();
-        final List<RouteInfo> expectedRoutes = Arrays.asList(
-                new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /*gateway*/,
-                        TEST_IFACE_NAME, RouteInfo.RTN_UNICAST),
-                new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
-                        TEST_IFACE_NAME, RTN_UNREACHABLE));
-        assertEquals(expectedRoutes, lp.getRoutes());
-
-        // Check internal addresses
+        final List<RouteInfo> expectedRoutes =
+                new ArrayList<>(
+                        Arrays.asList(
+                                new RouteInfo(
+                                        new IpPrefix(Inet4Address.ANY, 0),
+                                        null /* gateway */,
+                                        TEST_IFACE_NAME,
+                                        RouteInfo.RTN_UNICAST)));
         final List<LinkAddress> expectedAddresses =
-                Arrays.asList(new LinkAddress(TEST_VPN_INTERNAL_IP, IP4_PREFIX_LEN));
-        assertEquals(expectedAddresses, lp.getLinkAddresses());
+                new ArrayList<>(
+                        Arrays.asList(new LinkAddress(TEST_VPN_INTERNAL_IP, IP4_PREFIX_LEN)));
+        final List<InetAddress> expectedDns = new ArrayList<>(Arrays.asList(TEST_VPN_INTERNAL_DNS));
 
-        // Check internal DNS
-        assertEquals(Arrays.asList(TEST_VPN_INTERNAL_DNS), lp.getDnsServers());
+        if (mtuSupportsIpv6) {
+            expectedRoutes.add(
+                    new RouteInfo(
+                            new IpPrefix(Inet6Address.ANY, 0),
+                            null /* gateway */,
+                            TEST_IFACE_NAME,
+                            RouteInfo.RTN_UNICAST));
+            expectedAddresses.add(new LinkAddress(TEST_VPN_INTERNAL_IP6, IP6_PREFIX_LEN));
+            expectedDns.add(TEST_VPN_INTERNAL_DNS6);
+        } else {
+            expectedRoutes.add(
+                    new RouteInfo(
+                            new IpPrefix(Inet6Address.ANY, 0),
+                            null /* gateway */,
+                            TEST_IFACE_NAME,
+                            RTN_UNREACHABLE));
+        }
+
+        assertEquals(expectedRoutes, lp.getRoutes());
+        assertEquals(expectedAddresses, lp.getLinkAddresses());
+        assertEquals(expectedDns, lp.getDnsServers());
 
         // Check NetworkCapabilities
         assertEquals(Arrays.asList(TEST_NETWORK), ncCaptor.getValue().getUnderlyingNetworks());
@@ -1810,10 +1865,23 @@
     }
 
     @Test
+    public void testStartPlatformVpn_mtuDoesNotSupportIpv6() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot =
+                verifySetupPlatformVpn(
+                        createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
+                        false /* mtuSupportsIpv6 */);
+        vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+    }
+
+    @Test
     public void testStartPlatformVpnMobility_mobikeEnabled() throws Exception {
         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
                 createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
 
+        // Set new MTU on a different network
+        final int newMtu = IPV6_MIN_MTU + 1;
+        doReturn(newMtu).when(mTestDeps).calculateVpnMtu(any(), anyInt(), anyInt(), anyBoolean());
+
         // Mock network loss and verify a cleanup task is scheduled
         vpnSnapShot.nwCb.onLost(TEST_NETWORK);
         verify(mExecutor).schedule(any(Runnable.class), anyLong(), any());
@@ -1842,6 +1910,61 @@
                 vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
         verify(mMockNetworkAgent)
                 .doSetUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
+        verify(mMockNetworkAgent).doSendLinkProperties(argThat(lp -> lp.getMtu() == newMtu));
+        verify(mMockNetworkAgent, never()).unregister();
+
+        vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+    }
+
+    @Test
+    public void testStartPlatformVpnMobility_mobikeEnabledMtuDoesNotSupportIpv6() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot =
+                verifySetupPlatformVpn(
+                        createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+
+        // Set MTU below 1280
+        final int newMtu = IPV6_MIN_MTU - 1;
+        doReturn(newMtu).when(mTestDeps).calculateVpnMtu(any(), anyInt(), anyInt(), anyBoolean());
+
+        // Mock new network available & MOBIKE procedures
+        vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+        vpnSnapShot.ikeCb.onIkeSessionConnectionInfoChanged(createIkeConnectInfo_2());
+        vpnSnapShot.childCb.onIpSecTransformsMigrated(
+                createIpSecTransform(), createIpSecTransform());
+
+        // Verify removal of IPv6 addresses and routes triggers a network agent restart
+        final ArgumentCaptor<LinkProperties> lpCaptor =
+                ArgumentCaptor.forClass(LinkProperties.class);
+        verify(mTestDeps, times(2))
+                .newNetworkAgent(any(), any(), anyString(), any(), lpCaptor.capture(), any(), any(),
+                        any(), any());
+        verify(mMockNetworkAgent).unregister();
+        // mMockNetworkAgent is an old NetworkAgent, so it won't update LinkProperties after
+        // unregistering.
+        verify(mMockNetworkAgent, never()).doSendLinkProperties(any());
+
+        final LinkProperties lp = lpCaptor.getValue();
+
+        for (LinkAddress addr : lp.getLinkAddresses()) {
+            if (addr.isIpv6()) {
+                fail("IPv6 address found on VPN with MTU < IPv6 minimum MTU");
+            }
+        }
+
+        for (InetAddress dnsAddr : lp.getDnsServers()) {
+            if (dnsAddr instanceof Inet6Address) {
+                fail("IPv6 DNS server found on VPN with MTU < IPv6 minimum MTU");
+            }
+        }
+
+        for (RouteInfo routeInfo : lp.getRoutes()) {
+            if (routeInfo.getDestinationLinkAddress().isIpv6()
+                    && !routeInfo.isIPv6UnreachableDefault()) {
+                fail("IPv6 route found on VPN with MTU < IPv6 minimum MTU");
+            }
+        }
+
+        assertEquals(newMtu, lp.getMtu());
 
         vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
     }
@@ -1968,7 +2091,7 @@
     }
 
     @Test
-    public void testDataStallInIkev2VpnMobikeEnabled() throws Exception {
+    public void testDataStallInIkev2VpnRecoveredByMobike() throws Exception {
         final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
                 createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
 
@@ -1980,6 +2103,64 @@
 
         // Verify MOBIKE is triggered
         verifyMobikeTriggered(vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
+
+        // Expect to skip other data stall event if MOBIKE was started.
+        reset(mIkeSessionWrapper);
+        connectivityDiagCallback.onDataStallSuspected(report);
+        verify(mIkeSessionWrapper, never()).setNetwork(any());
+
+        reset(mIkev2SessionCreator);
+
+        // Send validation status update.
+        // Recovered and get network validated. It should not trigger the ike session reset.
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_VALID);
+        verify(mIkev2SessionCreator, never()).createIkeSession(
+                any(), any(), any(), any(), any(), any());
+
+        // Send invalid result to verify no ike session reset since the data stall suspected
+        // variables(timer counter and boolean) was reset.
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mExecutor).schedule(runnableCaptor.capture(), anyLong(), any());
+        runnableCaptor.getValue().run();
+        verify(mIkev2SessionCreator, never()).createIkeSession(
+                any(), any(), any(), any(), any(), any());
+    }
+
+    @Test
+    public void testDataStallInIkev2VpnNotRecoveredByMobike() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+
+        final ConnectivityDiagnosticsCallback connectivityDiagCallback =
+                getConnectivityDiagCallback();
+
+        doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
+        final DataStallReport report = createDataStallReport();
+        connectivityDiagCallback.onDataStallSuspected(report);
+
+        verifyMobikeTriggered(vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
+
+        reset(mIkev2SessionCreator);
+
+        // Send validation status update should result in ike session reset.
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+
+        // Verify reset is scheduled and run.
+        final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mExecutor).schedule(runnableCaptor.capture(), anyLong(), any());
+
+        // Another invalid status reported should not trigger other scheduled recovery.
+        reset(mExecutor);
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        verify(mExecutor, never()).schedule(runnableCaptor.capture(), anyLong(), any());
+
+        runnableCaptor.getValue().run();
+        verify(mIkev2SessionCreator).createIkeSession(any(), any(), any(), any(), any(), any());
     }
 
     @Test
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTests.java
index fdb4d4a..9fc4674 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTests.java
@@ -22,16 +22,19 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 
 import android.util.Log;
 
 import com.android.net.module.util.HexDump;
+import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.EOFException;
 import java.io.IOException;
 import java.net.DatagramPacket;
 import java.net.Inet4Address;
@@ -309,6 +312,14 @@
         assertEquals("b=1234567890", strings.get(1));
         assertEquals("xyz=!@#$", strings.get(2));
 
+        List<TextEntry> entries = record.getEntries();
+        assertNotNull(entries);
+        assertEquals(3, entries.size());
+
+        assertEquals(new TextEntry("a", "hello there"), entries.get(0));
+        assertEquals(new TextEntry("b", "1234567890"), entries.get(1));
+        assertEquals(new TextEntry("xyz", "!@#$"), entries.get(2));
+
         // Encode
         MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
         record.write(writer, record.getReceiptTime());
@@ -321,4 +332,48 @@
 
         assertEquals(dataInText, dataOutText);
     }
+
+    @Test
+    public void textRecord_recordDoesNotHaveDataOfGivenLength_throwsEOFException()
+            throws Exception {
+        final byte[] dataIn = HexDump.hexStringToByteArray(
+                "0474657374000010"
+                        + "000100001194000D"
+                        + "0D613D68656C6C6F" //The TXT entry starts with length of 13, but only 12
+                        + "2074686572"); // characters are following it.
+        DatagramPacket packet = new DatagramPacket(dataIn, dataIn.length);
+        MdnsPacketReader reader = new MdnsPacketReader(packet);
+        String[] name = reader.readLabels();
+        MdnsRecord.labelsToString(name);
+        reader.readUInt16();
+
+        assertThrows(EOFException.class, () -> new MdnsTextRecord(name, reader));
+    }
+
+    @Test
+    public void textRecord_entriesIncludeNonUtf8Bytes_returnsTheSameUtf8Bytes() throws Exception {
+        final byte[] dataIn = HexDump.hexStringToByteArray(
+                "0474657374000010"
+                        + "0001000011940024"
+                        + "0D613D68656C6C6F"
+                        + "2074686572650C62"
+                        + "3D31323334353637"
+                        + "3839300878797A3D"
+                        + "FFEFDFCF");
+        DatagramPacket packet = new DatagramPacket(dataIn, dataIn.length);
+        MdnsPacketReader reader = new MdnsPacketReader(packet);
+        String[] name = reader.readLabels();
+        MdnsRecord.labelsToString(name);
+        reader.readUInt16();
+
+        MdnsTextRecord record = new MdnsTextRecord(name, reader);
+
+        List<TextEntry> entries = record.getEntries();
+        assertNotNull(entries);
+        assertEquals(3, entries.size());
+        assertEquals(new TextEntry("a", "hello there"), entries.get(0));
+        assertEquals(new TextEntry("b", "1234567890"), entries.get(1));
+        assertEquals(new TextEntry("xyz", HexDump.hexStringToByteArray("FFEFDFCF")),
+                entries.get(2));
+    }
 }
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java
index ea9156c..02e00c2 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java
@@ -26,11 +26,14 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
+import android.net.InetAddresses;
+
 import com.android.net.module.util.HexDump;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -106,9 +109,49 @@
             + "63616C0000018001000000780004C0A8010A000001800100000078"
             + "0004C0A8010A00000000000000");
 
-    private static final String DUMMY_CAST_SERVICE_NAME = "_googlecast";
-    private static final String[] DUMMY_CAST_SERVICE_TYPE =
-            new String[] {DUMMY_CAST_SERVICE_NAME, "_tcp", "local"};
+    // Expected to contain two SRV records which point to the same hostname.
+    private static final byte[] matterDuplicateHostname = HexDump.hexStringToByteArray(
+            "00008000000000080000000A095F7365727669636573075F646E732D73"
+            + "64045F756470056C6F63616C00000C000100000078000F075F6D61"
+            + "74746572045F746370C023C00C000C000100000078001A125F4943"
+            + "324639453337374632454139463430045F737562C034C034000C00"
+            + "0100000078002421433246394533373746324541394634302D3030"
+            + "3030303030304534443041334641C034C04F000C00010000007800"
+            + "02C075C00C000C0001000000780002C034C00C000C000100000078"
+            + "0015125F4941413035363731333439334135343144C062C034000C"
+            + "000100000078002421414130353637313334393341353431442D30"
+            + "303030303030304331324446303344C034C0C1000C000100000078"
+            + "0002C0E2C075002100010000007800150000000015A40C33433631"
+            + "3035304338394638C023C07500100001000011940015084352493D"
+            + "35303030074352413D33303003543D31C126001C00010000007800"
+            + "10FE800000000000003E6105FFFE0C89F8C126001C000100000078"
+            + "00102605A601A84657003E6105FFFE0C89F8C12600010001000000"
+            + "780004C0A8018AC0E2002100010000007800080000000015A4C126"
+            + "C0E200100001000011940015084352493D35303030074352413D33"
+            + "303003543D31C126001C0001000000780010FE800000000000003E"
+            + "6105FFFE0C89F8C126001C00010000007800102605A601A8465700"
+            + "3E6105FFFE0C89F8C12600010001000000780004C0A8018A313035"
+            + "304338394638C02300010001000000780004C0A8018AC0A0001000"
+            + "0100001194003A0E56503D36353532312B3332373639084352493D"
+            + "35303030074352413D33303003543D3106443D3236353704434D3D"
+            + "320550483D33360350493D21433246394533373746324541394634"
+            + "302D30303030303030304534443041334641C0F700210001000000"
+            + "7800150000000015A40C334336313035304338394638C023214332"
+            + "46394533373746324541394634302D303030303030303045344430"
+            + "41334641C0F700100001000011940015084352493D353030300743"
+            + "52413D33303003543D310C334336313035304338394638C023001C"
+            + "0001000000780010FE800000000000003E6105FFFE0C89F80C3343"
+            + "36313035304338394638C023001C00010000007800102605A601A8"
+            + "4657003E6105FFFE0C89F80C334336313035304338394638C02300"
+            + "010001000000780004C0A8018A0000000000000000000000000000"
+            + "000000");
+
+    private static final String CAST_SERVICE_NAME = "_googlecast";
+    private static final String[] CAST_SERVICE_TYPE =
+            new String[] {CAST_SERVICE_NAME, "_tcp", "local"};
+    private static final String MATTER_SERVICE_NAME = "_matter";
+    private static final String[] MATTER_SERVICE_TYPE =
+            new String[] {MATTER_SERVICE_NAME, "_tcp", "local"};
 
     private final List<MdnsResponse> responses = new LinkedList<>();
 
@@ -116,13 +159,13 @@
 
     @Before
     public void setUp() {
-        MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, DUMMY_CAST_SERVICE_TYPE);
+        MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE);
         assertNotNull(data);
         DatagramPacket packet = new DatagramPacket(data, data.length);
         packet.setSocketAddress(
                 new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT));
         responses.clear();
-        int errorCode = decoder.decode(packet, responses);
+        int errorCode = decoder.decode(packet, responses, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED);
         assertEquals(MdnsResponseDecoder.SUCCESS, errorCode);
         assertEquals(1, responses.size());
     }
@@ -135,7 +178,7 @@
         packet.setSocketAddress(
                 new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT));
         responses.clear();
-        int errorCode = decoder.decode(packet, responses);
+        int errorCode = decoder.decode(packet, responses, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED);
         assertEquals(MdnsResponseDecoder.SUCCESS, errorCode);
         assertEquals(2, responses.size());
     }
@@ -153,7 +196,7 @@
 
         MdnsServiceRecord serviceRecord = response.getServiceRecord();
         String serviceName = serviceRecord.getServiceName();
-        assertEquals(DUMMY_CAST_SERVICE_NAME, serviceName);
+        assertEquals(CAST_SERVICE_NAME, serviceName);
 
         String serviceInstanceName = serviceRecord.getServiceInstanceName();
         assertEquals("Johnny's Chromecast", serviceInstanceName);
@@ -187,14 +230,14 @@
 
     @Test
     public void testDecodeIPv6AnswerPacket() throws IOException {
-        MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, DUMMY_CAST_SERVICE_TYPE);
+        MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE);
         assertNotNull(data6);
         DatagramPacket packet = new DatagramPacket(data6, data6.length);
         packet.setSocketAddress(
                 new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT));
 
         responses.clear();
-        int errorCode = decoder.decode(packet, responses);
+        int errorCode = decoder.decode(packet, responses, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED);
         assertEquals(MdnsResponseDecoder.SUCCESS, errorCode);
 
         MdnsResponse response = responses.get(0);
@@ -234,4 +277,77 @@
         response.setTextRecord(null);
         assertFalse(response.isComplete());
     }
+
+    @Test
+    public void decode_withInterfaceIndex_populatesInterfaceIndex() {
+        MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE);
+        assertNotNull(data6);
+        DatagramPacket packet = new DatagramPacket(data6, data6.length);
+        packet.setSocketAddress(
+                new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT));
+
+        responses.clear();
+        int errorCode = decoder.decode(packet, responses, /* interfaceIndex= */ 10);
+        assertEquals(errorCode, MdnsResponseDecoder.SUCCESS);
+        assertEquals(responses.size(), 1);
+        assertEquals(responses.get(0).getInterfaceIndex(), 10);
+    }
+
+    @Test
+    public void decode_singleHostname_multipleSrvRecords_flagEnabled_multipleCompleteResponses() {
+        //MdnsScannerConfigsFlagsImpl.allowMultipleSrvRecordsPerHost.override(true);
+        MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, MATTER_SERVICE_TYPE);
+        assertNotNull(matterDuplicateHostname);
+
+        DatagramPacket packet =
+                new DatagramPacket(matterDuplicateHostname, matterDuplicateHostname.length);
+
+        packet.setSocketAddress(
+                new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT));
+
+        responses.clear();
+        int errorCode = decoder.decode(packet, responses, /* interfaceIndex= */ 0);
+        assertEquals(MdnsResponseDecoder.SUCCESS, errorCode);
+
+        // This should emit two records:
+        assertEquals(2, responses.size());
+
+        MdnsResponse response1 = responses.get(0);
+        MdnsResponse response2 = responses.get(0);
+
+        // Both of which are complete:
+        assertTrue(response1.isComplete());
+        assertTrue(response2.isComplete());
+
+        // And should both have the same IPv6 address:
+        assertEquals(InetAddresses.parseNumericAddress("2605:a601:a846:5700:3e61:5ff:fe0c:89f8"),
+                response1.getInet6AddressRecord().getInet6Address());
+        assertEquals(InetAddresses.parseNumericAddress("2605:a601:a846:5700:3e61:5ff:fe0c:89f8"),
+                response2.getInet6AddressRecord().getInet6Address());
+    }
+
+    @Test
+    @Ignore("MdnsConfigs is not configurable currently.")
+    public void decode_singleHostname_multipleSrvRecords_flagDisabled_singleCompleteResponse() {
+        //MdnsScannerConfigsFlagsImpl.allowMultipleSrvRecordsPerHost.override(false);
+        MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, MATTER_SERVICE_TYPE);
+        assertNotNull(matterDuplicateHostname);
+
+        DatagramPacket packet =
+                new DatagramPacket(matterDuplicateHostname, matterDuplicateHostname.length);
+
+        packet.setSocketAddress(
+                new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT));
+
+        responses.clear();
+        int errorCode = decoder.decode(packet, responses, /* interfaceIndex= */ 0);
+        assertEquals(MdnsResponseDecoder.SUCCESS, errorCode);
+
+        // This should emit only two records:
+        assertEquals(2, responses.size());
+
+        // But only the first is complete:
+        assertTrue(responses.get(0).isComplete());
+        assertFalse(responses.get(1).isComplete());
+    }
 }
\ No newline at end of file
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java
index ae16f2b..771e42c 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java
@@ -222,6 +222,19 @@
     }
 
     @Test
+    public void getInterfaceIndex_returnsDefaultValue() {
+        MdnsResponse response = new MdnsResponse(/* now= */ 0);
+        assertEquals(response.getInterfaceIndex(), -1);
+    }
+
+    @Test
+    public void getInterfaceIndex_afterSet_returnsValue() {
+        MdnsResponse response = new MdnsResponse(/* now= */ 0);
+        response.setInterfaceIndex(5);
+        assertEquals(response.getInterfaceIndex(), 5);
+    }
+
+    @Test
     public void mergeRecordsFrom_indicates_change_on_ipv4_address() throws IOException {
         MdnsResponse response = makeMdnsResponse(
                 0,
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java
new file mode 100644
index 0000000..d3934c2
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java
@@ -0,0 +1,273 @@
+/*
+ * 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 com.android.server.connectivity.mdns;
+
+import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.Map;
+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
+public class MdnsServiceInfoTest {
+    @Test
+    public void constructor_createWithOnlyTextStrings_correctAttributes() {
+        MdnsServiceInfo info =
+                new MdnsServiceInfo(
+                        "my-mdns-service",
+                        new String[] {"_googlecast", "_tcp"},
+                        List.of(),
+                        new String[] {"my-host", "local"},
+                        12345,
+                        "192.168.1.1",
+                        "2001::1",
+                        List.of("vn=Google Inc.", "mn=Google Nest Hub Max"),
+                        /* textEntries= */ null);
+
+        assertTrue(info.getAttributeByKey("vn").equals("Google Inc."));
+        assertTrue(info.getAttributeByKey("mn").equals("Google Nest Hub Max"));
+    }
+
+    @Test
+    public void constructor_createWithOnlyTextEntries_correctAttributes() {
+        MdnsServiceInfo info =
+                new MdnsServiceInfo(
+                        "my-mdns-service",
+                        new String[] {"_googlecast", "_tcp"},
+                        List.of(),
+                        new String[] {"my-host", "local"},
+                        12345,
+                        "192.168.1.1",
+                        "2001::1",
+                        /* textStrings= */ null,
+                        List.of(MdnsServiceInfo.TextEntry.fromString("vn=Google Inc."),
+                                MdnsServiceInfo.TextEntry.fromString("mn=Google Nest Hub Max")));
+
+        assertTrue(info.getAttributeByKey("vn").equals("Google Inc."));
+        assertTrue(info.getAttributeByKey("mn").equals("Google Nest Hub Max"));
+    }
+
+    @Test
+    public void constructor_createWithBothTextStringsAndTextEntries_acceptsOnlyTextEntries() {
+        MdnsServiceInfo info =
+                new MdnsServiceInfo(
+                        "my-mdns-service",
+                        new String[] {"_googlecast", "_tcp"},
+                        List.of(),
+                        new String[] {"my-host", "local"},
+                        12345,
+                        "192.168.1.1",
+                        "2001::1",
+                        List.of("vn=Alphabet Inc.", "mn=Google Nest Hub Max", "id=12345"),
+                        List.of(
+                                MdnsServiceInfo.TextEntry.fromString("vn=Google Inc."),
+                                MdnsServiceInfo.TextEntry.fromString("mn=Google Nest Hub Max")));
+
+        assertEquals(Map.of("vn", "Google Inc.", "mn", "Google Nest Hub Max"),
+                info.getAttributes());
+    }
+
+    @Test
+    public void constructor_createWithDuplicateKeys_acceptsTheFirstOne() {
+        MdnsServiceInfo info =
+                new MdnsServiceInfo(
+                        "my-mdns-service",
+                        new String[] {"_googlecast", "_tcp"},
+                        List.of(),
+                        new String[] {"my-host", "local"},
+                        12345,
+                        "192.168.1.1",
+                        "2001::1",
+                        List.of("vn=Alphabet Inc.", "mn=Google Nest Hub Max", "id=12345"),
+                        List.of(MdnsServiceInfo.TextEntry.fromString("vn=Google Inc."),
+                                MdnsServiceInfo.TextEntry.fromString("mn=Google Nest Hub Max"),
+                                MdnsServiceInfo.TextEntry.fromString("mn=Google WiFi Router")));
+
+        assertEquals(Map.of("vn", "Google Inc.", "mn", "Google Nest Hub Max"),
+                info.getAttributes());
+    }
+
+    @Test
+    public void getInterfaceIndex_constructorWithDefaultValues_returnsMinusOne() {
+        MdnsServiceInfo info =
+                new MdnsServiceInfo(
+                        "my-mdns-service",
+                        new String[] {"_googlecast", "_tcp"},
+                        List.of(),
+                        new String[] {"my-host", "local"},
+                        12345,
+                        "192.168.1.1",
+                        "2001::1",
+                        List.of());
+
+        assertEquals(info.getInterfaceIndex(), -1);
+    }
+
+    @Test
+    public void getInterfaceIndex_constructorWithInterfaceIndex_returnsProvidedIndex() {
+        MdnsServiceInfo info =
+                new MdnsServiceInfo(
+                        "my-mdns-service",
+                        new String[] {"_googlecast", "_tcp"},
+                        List.of(),
+                        new String[] {"my-host", "local"},
+                        12345,
+                        "192.168.1.1",
+                        "2001::1",
+                        List.of(),
+                        /* textEntries= */ null,
+                        /* interfaceIndex= */ 20);
+
+        assertEquals(info.getInterfaceIndex(), 20);
+    }
+
+    @Test
+    public void parcelable_canBeParceledAndUnparceled() {
+        Parcel parcel = Parcel.obtain();
+        MdnsServiceInfo beforeParcel =
+                new MdnsServiceInfo(
+                        "my-mdns-service",
+                        new String[] {"_googlecast", "_tcp"},
+                        List.of(),
+                        new String[] {"my-host", "local"},
+                        12345,
+                        "192.168.1.1",
+                        "2001::1",
+                        List.of("vn=Alphabet Inc.", "mn=Google Nest Hub Max", "id=12345"),
+                        List.of(
+                                MdnsServiceInfo.TextEntry.fromString("vn=Google Inc."),
+                                MdnsServiceInfo.TextEntry.fromString("mn=Google Nest Hub Max")));
+
+        beforeParcel.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        MdnsServiceInfo afterParcel = MdnsServiceInfo.CREATOR.createFromParcel(parcel);
+
+        assertEquals(beforeParcel.getServiceInstanceName(), afterParcel.getServiceInstanceName());
+        assertArrayEquals(beforeParcel.getServiceType(), afterParcel.getServiceType());
+        assertEquals(beforeParcel.getSubtypes(), afterParcel.getSubtypes());
+        assertArrayEquals(beforeParcel.getHostName(), afterParcel.getHostName());
+        assertEquals(beforeParcel.getPort(), afterParcel.getPort());
+        assertEquals(beforeParcel.getIpv4Address(), afterParcel.getIpv4Address());
+        assertEquals(beforeParcel.getIpv6Address(), afterParcel.getIpv6Address());
+        assertEquals(beforeParcel.getAttributes(), afterParcel.getAttributes());
+    }
+
+    @Test
+    public void textEntry_parcelable_canBeParceledAndUnparceled() {
+        Parcel parcel = Parcel.obtain();
+        TextEntry beforeParcel = new TextEntry("AA", new byte[] {(byte) 0xFF, (byte) 0xFC});
+
+        beforeParcel.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        TextEntry afterParcel = TextEntry.CREATOR.createFromParcel(parcel);
+
+        assertEquals(beforeParcel, afterParcel);
+    }
+
+    @Test
+    public void textEntry_fromString_keyValueAreExpected() {
+        TextEntry entry = TextEntry.fromString("AA=xxyyzz");
+
+        assertEquals("AA", entry.getKey());
+        assertArrayEquals(new byte[] {'x', 'x', 'y', 'y', 'z', 'z'}, entry.getValue());
+    }
+
+    @Test
+    public void textEntry_fromStringToString_textUnchanged() {
+        TextEntry entry = TextEntry.fromString("AA=xxyyzz");
+
+        assertEquals("AA=xxyyzz", entry.toString());
+    }
+
+    @Test
+    public void textEntry_fromStringWithoutAssignPunc_valueisEmpty() {
+        TextEntry entry = TextEntry.fromString("AA");
+
+        assertEquals("AA", entry.getKey());
+        assertArrayEquals(new byte[] {}, entry.getValue());
+    }
+
+    @Test
+    public void textEntry_fromStringAssignPuncAtBeginning_returnsNull() {
+        TextEntry entry = TextEntry.fromString("=AA");
+
+        assertNull(entry);
+    }
+
+    @Test
+    public void textEntry_fromBytes_keyAndValueAreExpected() {
+        TextEntry entry = TextEntry.fromBytes(
+                new byte[] {'A', 'A', '=', 'x', 'x', 'y', 'y', 'z', 'z'});
+
+        assertEquals("AA", entry.getKey());
+        assertArrayEquals(new byte[] {'x', 'x', 'y', 'y', 'z', 'z'}, entry.getValue());
+    }
+
+    @Test
+    public void textEntry_fromBytesToBytes_textUnchanged() {
+        TextEntry entry = TextEntry.fromBytes(
+                new byte[] {'A', 'A', '=', 'x', 'x', 'y', 'y', 'z', 'z'});
+
+        assertArrayEquals(new byte[] {'A', 'A', '=', 'x', 'x', 'y', 'y', 'z', 'z'},
+                entry.toBytes());
+    }
+
+    @Test
+    public void textEntry_fromBytesWithoutAssignPunc_valueisEmpty() {
+        TextEntry entry = TextEntry.fromBytes(new byte[] {'A', 'A'});
+
+        assertEquals("AA", entry.getKey());
+        assertArrayEquals(new byte[] {}, entry.getValue());
+    }
+
+    @Test
+    public void textEntry_fromBytesAssignPuncAtBeginning_returnsNull() {
+        TextEntry entry = TextEntry.fromBytes(new byte[] {'=', 'A', 'A'});
+
+        assertNull(entry);
+    }
+
+    @Test
+    public void textEntry_fromNonUtf8Bytes_keyValueAreExpected() {
+        TextEntry entry = TextEntry.fromBytes(
+                new byte[] {'A', 'A', '=', (byte) 0xFF, (byte) 0xFE, (byte) 0xFD});
+
+        assertEquals("AA", entry.getKey());
+        assertArrayEquals(new byte[] {(byte) 0xFF, (byte) 0xFE, (byte) 0xFD}, entry.getValue());
+    }
+
+    @Test
+    public void textEntry_equals() {
+        assertEquals(new TextEntry("AA", "xxyyzz"), new TextEntry("AA", "xxyyzz"));
+        assertEquals(new TextEntry("BB", "xxyyzz"), new TextEntry("BB", "xxyyzz"));
+        assertEquals(new TextEntry("AA", "XXYYZZ"), new TextEntry("AA", "XXYYZZ"));
+    }
+}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
index 5843fd0..6b10c71 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
@@ -32,8 +32,11 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 import android.annotation.NonNull;
 
+import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
 import com.android.server.connectivity.mdns.MdnsServiceTypeClient.QueryTaskConfig;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
@@ -53,7 +56,6 @@
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.SocketAddress;
-import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -399,7 +401,8 @@
                         ipV4Address,
                         5353,
                         Collections.singletonList("ABCDE"),
-                        Collections.emptyMap());
+                        Collections.emptyMap(),
+                        /* interfaceIndex= */ 20);
         client.processResponse(initialResponse);
 
         // Process a second response with a different port and updated text attributes.
@@ -409,7 +412,8 @@
                         ipV4Address,
                         5354,
                         Collections.singletonList("ABCDE"),
-                        Collections.singletonMap("key", "value"));
+                        Collections.singletonMap("key", "value"),
+                        /* interfaceIndex= */ 20);
         client.processResponse(secondResponse);
 
         // Verify onServiceFound was called once for the initial response.
@@ -420,6 +424,7 @@
         assertEquals(initialServiceInfo.getPort(), 5353);
         assertEquals(initialServiceInfo.getSubtypes(), Collections.singletonList("ABCDE"));
         assertNull(initialServiceInfo.getAttributeByKey("key"));
+        assertEquals(initialServiceInfo.getInterfaceIndex(), 20);
 
         // Verify onServiceUpdated was called once for the second response.
         verify(mockListenerOne).onServiceUpdated(serviceInfoCaptor.capture());
@@ -430,6 +435,7 @@
         assertTrue(updatedServiceInfo.hasSubtypes());
         assertEquals(updatedServiceInfo.getSubtypes(), Collections.singletonList("ABCDE"));
         assertEquals(updatedServiceInfo.getAttributeByKey("key"), "value");
+        assertEquals(updatedServiceInfo.getInterfaceIndex(), 20);
     }
 
     @Test
@@ -444,7 +450,8 @@
                         ipV6Address,
                         5353,
                         Collections.singletonList("ABCDE"),
-                        Collections.emptyMap());
+                        Collections.emptyMap(),
+                        /* interfaceIndex= */ 20);
         client.processResponse(initialResponse);
 
         // Process a second response with a different port and updated text attributes.
@@ -454,7 +461,8 @@
                         ipV6Address,
                         5354,
                         Collections.singletonList("ABCDE"),
-                        Collections.singletonMap("key", "value"));
+                        Collections.singletonMap("key", "value"),
+                        /* interfaceIndex= */ 20);
         client.processResponse(secondResponse);
 
         System.out.println("secondResponses ip"
@@ -468,6 +476,7 @@
         assertEquals(initialServiceInfo.getPort(), 5353);
         assertEquals(initialServiceInfo.getSubtypes(), Collections.singletonList("ABCDE"));
         assertNull(initialServiceInfo.getAttributeByKey("key"));
+        assertEquals(initialServiceInfo.getInterfaceIndex(), 20);
 
         // Verify onServiceUpdated was called once for the second response.
         verify(mockListenerOne).onServiceUpdated(serviceInfoCaptor.capture());
@@ -478,6 +487,7 @@
         assertTrue(updatedServiceInfo.hasSubtypes());
         assertEquals(updatedServiceInfo.getSubtypes(), Collections.singletonList("ABCDE"));
         assertEquals(updatedServiceInfo.getAttributeByKey("key"), "value");
+        assertEquals(updatedServiceInfo.getInterfaceIndex(), 20);
     }
 
     @Test
@@ -495,7 +505,7 @@
     }
 
     @Test
-    public void reportExistingServiceToNewlyRegisteredListeners() throws UnknownHostException {
+    public void reportExistingServiceToNewlyRegisteredListeners() throws Exception {
         // Process the initial response.
         MdnsResponse initialResponse =
                 createResponse(
@@ -725,14 +735,26 @@
         }
     }
 
-    // Creates a complete mDNS response.
     private MdnsResponse createResponse(
             @NonNull String serviceInstanceName,
             @NonNull String host,
             int port,
             @NonNull List<String> subtypes,
             @NonNull Map<String, String> textAttributes)
-            throws UnknownHostException {
+            throws Exception {
+        return createResponse(serviceInstanceName, host, port, subtypes, textAttributes,
+                /* interfaceIndex= */ -1);
+    }
+
+    // Creates a complete mDNS response.
+    private MdnsResponse createResponse(
+            @NonNull String serviceInstanceName,
+            @NonNull String host,
+            int port,
+            @NonNull List<String> subtypes,
+            @NonNull Map<String, String> textAttributes,
+            int interfaceIndex)
+            throws Exception {
         String[] hostName = new String[]{"hostname"};
         MdnsServiceRecord serviceRecord = mock(MdnsServiceRecord.class);
         when(serviceRecord.getServiceHost()).thenReturn(hostName);
@@ -745,18 +767,23 @@
             when(inetAddressRecord.getInet6Address())
                     .thenReturn((Inet6Address) Inet6Address.getByName(host));
             response.setInet6AddressRecord(inetAddressRecord);
+            response.setInterfaceIndex(interfaceIndex);
         } else {
             when(inetAddressRecord.getInet4Address())
                     .thenReturn((Inet4Address) Inet4Address.getByName(host));
             response.setInet4AddressRecord(inetAddressRecord);
+            response.setInterfaceIndex(interfaceIndex);
         }
 
         MdnsTextRecord textRecord = mock(MdnsTextRecord.class);
         List<String> textStrings = new ArrayList<>();
+        List<TextEntry> textEntries = new ArrayList<>();
         for (Map.Entry<String, String> kv : textAttributes.entrySet()) {
             textStrings.add(kv.getKey() + "=" + kv.getValue());
+            textEntries.add(new TextEntry(kv.getKey(), kv.getValue().getBytes(UTF_8)));
         }
         when(textRecord.getStrings()).thenReturn(textStrings);
+        when(textRecord.getEntries()).thenReturn(textEntries);
 
         response.setServiceRecord(serviceRecord);
         response.setTextRecord(textRecord);
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
index 21ed7eb..b4442a5 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
@@ -18,13 +18,16 @@
 
 import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -45,6 +48,7 @@
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -490,4 +494,55 @@
         assertFalse(mdnsClient.receivedUnicastResponse);
         assertFalse(mdnsClient.cannotReceiveMulticastResponse.get());
     }
+
+    @Test
+    public void startDiscovery_andPropagateInterfaceIndex_includesInterfaceIndex()
+            throws Exception {
+        //MdnsConfigsFlagsImpl.allowNetworkInterfaceIndexPropagation.override(true);
+
+        when(mockMulticastSocket.getInterfaceIndex()).thenReturn(21);
+        mdnsClient =
+                new MdnsSocketClient(mContext, mockMulticastLock) {
+                    @Override
+                    MdnsSocket createMdnsSocket(int port) {
+                        if (port == MdnsConstants.MDNS_PORT) {
+                            return mockMulticastSocket;
+                        }
+                        return mockUnicastSocket;
+                    }
+                };
+        mdnsClient.setCallback(mockCallback);
+        mdnsClient.startDiscovery();
+
+        verify(mockCallback, timeout(TIMEOUT).atLeastOnce())
+                .onResponseReceived(argThat(response -> response.getInterfaceIndex() == 21));
+    }
+
+    @Test
+    @Ignore("MdnsConfigs is not configurable currently.")
+    public void startDiscovery_andDoNotPropagateInterfaceIndex_doesNotIncludeInterfaceIndex()
+            throws Exception {
+        //MdnsConfigsFlagsImpl.allowNetworkInterfaceIndexPropagation.override(false);
+
+        when(mockMulticastSocket.getInterfaceIndex()).thenReturn(21);
+        mdnsClient =
+                new MdnsSocketClient(mContext, mockMulticastLock) {
+                    @Override
+                    MdnsSocket createMdnsSocket(int port) {
+                        if (port == MdnsConstants.MDNS_PORT) {
+                            return mockMulticastSocket;
+                        }
+                        return mockUnicastSocket;
+                    }
+                };
+        mdnsClient.setCallback(mockCallback);
+        mdnsClient.startDiscovery();
+
+        ArgumentCaptor<MdnsResponse> mdnsResponseCaptor =
+                ArgumentCaptor.forClass(MdnsResponse.class);
+        verify(mockMulticastSocket, never()).getInterfaceIndex();
+        verify(mockCallback, timeout(TIMEOUT).atLeast(1))
+                .onResponseReceived(mdnsResponseCaptor.capture());
+        assertEquals(-1, mdnsResponseCaptor.getValue().getInterfaceIndex());
+    }
 }
\ No newline at end of file
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketTests.java
index 9f11a4b..73dbd38 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketTests.java
@@ -53,7 +53,7 @@
     private SocketAddress socketIPv4Address;
     private SocketAddress socketIPv6Address;
 
-    private byte[] data = new byte[25];
+    private final byte[] data = new byte[25];
     private final DatagramPacket datagramPacket = new DatagramPacket(data, data.length);
     private NetworkInterface networkInterface;
 
@@ -74,14 +74,8 @@
     }
 
     @Test
-    public void testMdnsSocket() throws IOException {
-        mdnsSocket =
-                new MdnsSocket(mockMulticastNetworkInterfaceProvider, MdnsConstants.MDNS_PORT) {
-                    @Override
-                    MulticastSocket createMulticastSocket(int port) throws IOException {
-                        return mockMulticastSocket;
-                    }
-                };
+    public void mdnsSocket_basicFunctionality() throws IOException {
+        mdnsSocket = new MdnsSocket(mockMulticastNetworkInterfaceProvider, mockMulticastSocket);
         mdnsSocket.send(datagramPacket);
         verify(mockMulticastSocket).setNetworkInterface(networkInterface);
         verify(mockMulticastSocket).send(datagramPacket);
@@ -100,20 +94,14 @@
     }
 
     @Test
-    public void testIPv6OnlyNetwork_IPv6Enabled() throws IOException {
+    public void ipv6OnlyNetwork_ipv6Enabled() throws IOException {
         // Have mockMulticastNetworkInterfaceProvider send back an IPv6Only networkInterfaceWrapper
         networkInterface = createEmptyNetworkInterface();
         when(mockNetworkInterfaceWrapper.getNetworkInterface()).thenReturn(networkInterface);
         when(mockMulticastNetworkInterfaceProvider.getMulticastNetworkInterfaces())
                 .thenReturn(Collections.singletonList(mockNetworkInterfaceWrapper));
 
-        mdnsSocket =
-                new MdnsSocket(mockMulticastNetworkInterfaceProvider, MdnsConstants.MDNS_PORT) {
-                    @Override
-                    MulticastSocket createMulticastSocket(int port) throws IOException {
-                        return mockMulticastSocket;
-                    }
-                };
+        mdnsSocket = new MdnsSocket(mockMulticastNetworkInterfaceProvider, mockMulticastSocket);
 
         when(mockMulticastNetworkInterfaceProvider.isOnIpV6OnlyNetwork(
                 Collections.singletonList(mockNetworkInterfaceWrapper)))
@@ -130,20 +118,14 @@
     }
 
     @Test
-    public void testIPv6OnlyNetwork_IPv6Toggle() throws IOException {
+    public void ipv6OnlyNetwork_ipv6Toggle() throws IOException {
         // Have mockMulticastNetworkInterfaceProvider send back a networkInterfaceWrapper
         networkInterface = createEmptyNetworkInterface();
         when(mockNetworkInterfaceWrapper.getNetworkInterface()).thenReturn(networkInterface);
         when(mockMulticastNetworkInterfaceProvider.getMulticastNetworkInterfaces())
                 .thenReturn(Collections.singletonList(mockNetworkInterfaceWrapper));
 
-        mdnsSocket =
-                new MdnsSocket(mockMulticastNetworkInterfaceProvider, MdnsConstants.MDNS_PORT) {
-                    @Override
-                    MulticastSocket createMulticastSocket(int port) throws IOException {
-                        return mockMulticastSocket;
-                    }
-                };
+        mdnsSocket = new MdnsSocket(mockMulticastNetworkInterfaceProvider, mockMulticastSocket);
 
         when(mockMulticastNetworkInterfaceProvider.isOnIpV6OnlyNetwork(
                 Collections.singletonList(mockNetworkInterfaceWrapper)))
diff --git a/tools/gn2bp/Android.bp.swp b/tools/gn2bp/Android.bp.swp
new file mode 100644
index 0000000..926061d
--- /dev/null
+++ b/tools/gn2bp/Android.bp.swp
@@ -0,0 +1,6057 @@
+// 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.
+//
+// This file is automatically generated by gen_android_bp. Do not edit.
+
+// GN: //base/allocator:buildflags
+genrule {
+    name: "cronet_aml_base_allocator_buildflags",
+    cmd: "echo '--flags USE_PARTITION_ALLOC=\"false\" USE_ALLOCATOR_SHIM=\"true\" USE_PARTITION_ALLOC_AS_MALLOC=\"false\" USE_BACKUP_REF_PTR=\"false\" USE_ASAN_BACKUP_REF_PTR=\"false\" USE_PARTITION_ALLOC_AS_GWP_ASAN_STORE=\"false\" USE_MTE_CHECKED_PTR=\"false\" FORCE_ENABLE_RAW_PTR_EXCLUSION=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base/allocator:buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/allocator/buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base/allocator/partition_allocator:chromecast_buildflags
+genrule {
+    name: "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags",
+    cmd: "echo '--flags PA_IS_CAST_ANDROID=\"false\" PA_IS_CASTOS=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base/allocator/partition_allocator:chromecast_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/allocator/partition_allocator/chromecast_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base/allocator/partition_allocator:chromeos_buildflags
+genrule {
+    name: "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags",
+    cmd: "echo '--flags PA_IS_CHROMEOS_ASH=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base/allocator/partition_allocator:chromeos_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/allocator/partition_allocator/chromeos_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base/allocator/partition_allocator:debugging_buildflags
+genrule {
+    name: "cronet_aml_base_allocator_partition_allocator_debugging_buildflags",
+    cmd: "echo '--flags PA_DCHECK_IS_ON=\"true\" PA_EXPENSIVE_DCHECKS_ARE_ON=\"true\" PA_DCHECK_IS_CONFIGURABLE=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base/allocator/partition_allocator:debugging_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base/allocator/partition_allocator:logging_buildflags
+genrule {
+    name: "cronet_aml_base_allocator_partition_allocator_logging_buildflags",
+    cmd: "echo '--flags PA_ENABLE_LOG_ERROR_NOT_REACHED=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base/allocator/partition_allocator:logging_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/allocator/partition_allocator/logging_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base/allocator/partition_allocator:partition_alloc
+cc_library_static {
+    name: "cronet_aml_base_allocator_partition_allocator_partition_alloc",
+    srcs: [
+        ":cronet_aml_third_party_android_ndk_cpu_features",
+        "base/allocator/partition_allocator/address_pool_manager.cc",
+        "base/allocator/partition_allocator/address_pool_manager_bitmap.cc",
+        "base/allocator/partition_allocator/address_space_randomization.cc",
+        "base/allocator/partition_allocator/allocation_guard.cc",
+        "base/allocator/partition_allocator/dangling_raw_ptr_checks.cc",
+        "base/allocator/partition_allocator/gwp_asan_support.cc",
+        "base/allocator/partition_allocator/memory_reclaimer.cc",
+        "base/allocator/partition_allocator/oom.cc",
+        "base/allocator/partition_allocator/oom_callback.cc",
+        "base/allocator/partition_allocator/page_allocator.cc",
+        "base/allocator/partition_allocator/page_allocator_internals_posix.cc",
+        "base/allocator/partition_allocator/partition_address_space.cc",
+        "base/allocator/partition_allocator/partition_alloc.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/check.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/cpu.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/debug/alias.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/files/file_path.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/files/file_util_posix.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/logging.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/native_library.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/native_library_posix.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/pkey.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/posix/safe_strerror.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/rand_util.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/rand_util_posix.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/strings/stringprintf.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/time/time.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/time/time_android.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/time/time_conversion_posix.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/time/time_now_posix.cc",
+        "base/allocator/partition_allocator/partition_alloc_base/time/time_override.cc",
+        "base/allocator/partition_allocator/partition_alloc_hooks.cc",
+        "base/allocator/partition_allocator/partition_bucket.cc",
+        "base/allocator/partition_allocator/partition_oom.cc",
+        "base/allocator/partition_allocator/partition_page.cc",
+        "base/allocator/partition_allocator/partition_root.cc",
+        "base/allocator/partition_allocator/partition_stats.cc",
+        "base/allocator/partition_allocator/random.cc",
+        "base/allocator/partition_allocator/reservation_offset_table.cc",
+        "base/allocator/partition_allocator/spinning_mutex.cc",
+        "base/allocator/partition_allocator/starscan/metadata_allocator.cc",
+        "base/allocator/partition_allocator/starscan/pcscan.cc",
+        "base/allocator/partition_allocator/starscan/pcscan_internal.cc",
+        "base/allocator/partition_allocator/starscan/pcscan_scheduling.cc",
+        "base/allocator/partition_allocator/starscan/snapshot.cc",
+        "base/allocator/partition_allocator/starscan/stack/asm/x64/push_registers_asm.cc",
+        "base/allocator/partition_allocator/starscan/stack/stack.cc",
+        "base/allocator/partition_allocator/starscan/stats_collector.cc",
+        "base/allocator/partition_allocator/starscan/write_protector.cc",
+        "base/allocator/partition_allocator/tagging.cc",
+        "base/allocator/partition_allocator/thread_cache.cc",
+    ],
+    generated_headers: [
+        "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_debugging_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_logging_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags",
+    ],
+    export_generated_headers: [
+        "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_debugging_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_logging_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-DIS_PARTITION_ALLOC_IMPL",
+        "-DPA_PCSCAN_STACK_SUPPORTED",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/android_ndk/sources/android/cpufeatures/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //base/allocator/partition_allocator:partition_alloc_buildflags
+genrule {
+    name: "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags",
+    cmd: "echo '--flags ENABLE_PARTITION_ALLOC_AS_MALLOC_SUPPORT=\"true\" ENABLE_BACKUP_REF_PTR_SUPPORT=\"true\" ENABLE_BACKUP_REF_PTR_SLOW_CHECKS=\"false\" ENABLE_DANGLING_RAW_PTR_CHECKS=\"false\" PUT_REF_COUNT_IN_PREVIOUS_SLOT=\"true\" ENABLE_GWP_ASAN_SUPPORT=\"true\" ENABLE_MTE_CHECKED_PTR_SUPPORT=\"false\" RECORD_ALLOC_INFO=\"false\" USE_FREESLOT_BITMAP=\"false\" GLUE_CORE_POOLS=\"false\" ENABLE_SHADOW_METADATA_FOR_64_BITS_POINTERS=\"false\" STARSCAN=\"true\" PA_USE_BASE_TRACING=\"true\" ENABLE_PKEYS=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base/allocator/partition_allocator:partition_alloc_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/allocator/partition_allocator/partition_alloc_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:anchor_functions_buildflags
+genrule {
+    name: "cronet_aml_base_anchor_functions_buildflags",
+    cmd: "echo '--flags USE_LLD=\"true\" SUPPORTS_CODE_ORDERING=\"true\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:anchor_functions_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/android/library_loader/anchor_functions_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:android_runtime_jni_headers
+genrule {
+    name: "cronet_aml_base_android_runtime_jni_headers",
+    cmd: "$(location base/android/jni_generator/jni_generator.py) --ptr_type " +
+         "long " +
+         " " +
+         " " +
+         "--output_dir " +
+         "$(genDir)/base/android_runtime_jni_headers " +
+         "--includes " +
+         "base/android/jni_generator/jni_generator_helper.h " +
+         "--jar_file " +
+         "$(location third_party/android_sdk/public/platforms/android-33/android.jar) " +
+         "--output_name " +
+         "Runnable_jni.h " +
+         "--output_name " +
+         "Runtime_jni.h " +
+         "--input_file " +
+         "java/lang/Runnable.class " +
+         "--input_file " +
+         "java/lang/Runtime.class " +
+         "--javap " +
+         "$$(find out/.path -name javap)",
+    out: [
+        "base/android_runtime_jni_headers/Runnable_jni.h",
+        "base/android_runtime_jni_headers/Runtime_jni.h",
+    ],
+    tool_files: [
+        "base/android/jni_generator/android_jar.classes",
+        "base/android/jni_generator/jni_generator.py",
+        "build/android/gyp/util/__init__.py",
+        "build/android/gyp/util/build_utils.py",
+        "build/gn_helpers.py",
+        "third_party/android_sdk/public/platforms/android-33/android.jar",
+    ],
+}
+
+// GN: //base:base
+cc_library_static {
+    name: "cronet_aml_base_base",
+    srcs: [
+        ":cronet_aml_base_numerics_base_numerics",
+        ":cronet_aml_third_party_abseil_cpp_absl",
+        ":cronet_aml_third_party_abseil_cpp_absl_algorithm_algorithm",
+        ":cronet_aml_third_party_abseil_cpp_absl_algorithm_container",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_atomic_hook",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_base",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_base_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_config",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_core_headers",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_cycleclock_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_dynamic_annotations",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_endian",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_errno_saver",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_fast_type_id",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_log_severity",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_malloc_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_prefetch",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_raw_logging_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_spinlock_wait",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_strerror",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_throw_delegate",
+        ":cronet_aml_third_party_abseil_cpp_absl_cleanup_cleanup",
+        ":cronet_aml_third_party_abseil_cpp_absl_cleanup_cleanup_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_btree",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_common",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_common_policy_traits",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_compressed_tuple",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_container_memory",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_fixed_array",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_flat_hash_map",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_flat_hash_set",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_hash_function_defaults",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_hash_policy_traits",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_hashtable_debug_hooks",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_hashtablez_sampler",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_inlined_vector",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_inlined_vector_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_layout",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_node_hash_map",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_node_hash_set",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_node_slot_policy",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_raw_hash_map",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_raw_hash_set",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_debugging_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_demangle_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_examine_stack",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_failure_signal_handler",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_stacktrace",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_symbolize",
+        ":cronet_aml_third_party_abseil_cpp_absl_functional_any_invocable",
+        ":cronet_aml_third_party_abseil_cpp_absl_functional_bind_front",
+        ":cronet_aml_third_party_abseil_cpp_absl_functional_function_ref",
+        ":cronet_aml_third_party_abseil_cpp_absl_hash_city",
+        ":cronet_aml_third_party_abseil_cpp_absl_hash_hash",
+        ":cronet_aml_third_party_abseil_cpp_absl_hash_low_level_hash",
+        ":cronet_aml_third_party_abseil_cpp_absl_memory_memory",
+        ":cronet_aml_third_party_abseil_cpp_absl_meta_type_traits",
+        ":cronet_aml_third_party_abseil_cpp_absl_numeric_bits",
+        ":cronet_aml_third_party_abseil_cpp_absl_numeric_int128",
+        ":cronet_aml_third_party_abseil_cpp_absl_numeric_representation",
+        ":cronet_aml_third_party_abseil_cpp_absl_profiling_exponential_biased",
+        ":cronet_aml_third_party_abseil_cpp_absl_profiling_sample_recorder",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_distributions",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_distribution_caller",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_fast_uniform_bits",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_fastmath",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_generate_real",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_iostream_state_saver",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_nonsecure_base",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_pcg_engine",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_platform",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_pool_urbg",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_randen",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_engine",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_hwaes",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_hwaes_impl",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_slow",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_salted_seed_seq",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_seed_material",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_traits",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_uniform_helper",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_wide_multiply",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_random",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_seed_gen_exception",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_seed_sequences",
+        ":cronet_aml_third_party_abseil_cpp_absl_status_status",
+        ":cronet_aml_third_party_abseil_cpp_absl_status_statusor",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cord",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cord_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_functions",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_handle",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_info",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_statistics",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_update_scope",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_update_tracker",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_str_format",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_str_format_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_strings",
+        ":cronet_aml_third_party_abseil_cpp_absl_synchronization_graphcycles_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_synchronization_kernel_timeout_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_synchronization_synchronization",
+        ":cronet_aml_third_party_abseil_cpp_absl_time_internal_cctz_civil_time",
+        ":cronet_aml_third_party_abseil_cpp_absl_time_internal_cctz_time_zone",
+        ":cronet_aml_third_party_abseil_cpp_absl_time_time",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_bad_optional_access",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_compare",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_optional",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_span",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_variant",
+        ":cronet_aml_third_party_abseil_cpp_absl_utility_utility",
+        ":cronet_aml_third_party_android_ndk_cpu_features",
+        ":cronet_aml_third_party_ashmem_ashmem",
+        "base/allocator/allocator_check.cc",
+        "base/allocator/allocator_extension.cc",
+        "base/allocator/dispatcher/dispatcher.cc",
+        "base/allocator/dispatcher/internal/dispatch_data.cc",
+        "base/allocator/dispatcher/reentry_guard.cc",
+        "base/allocator/partition_allocator/shim/allocator_shim.cc",
+        "base/allocator/partition_allocator/shim/allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc",
+        "base/android/android_hardware_buffer_compat.cc",
+        "base/android/android_image_reader_compat.cc",
+        "base/android/apk_assets.cc",
+        "base/android/application_status_listener.cc",
+        "base/android/base_feature_list.cc",
+        "base/android/base_features.cc",
+        "base/android/base_jni_onload.cc",
+        "base/android/build_info.cc",
+        "base/android/bundle_utils.cc",
+        "base/android/callback_android.cc",
+        "base/android/child_process_service.cc",
+        "base/android/command_line_android.cc",
+        "base/android/content_uri_utils.cc",
+        "base/android/cpu_features.cc",
+        "base/android/early_trace_event_binding.cc",
+        "base/android/event_log.cc",
+        "base/android/feature_list_jni.cc",
+        "base/android/features_jni.cc",
+        "base/android/field_trial_list.cc",
+        "base/android/important_file_writer_android.cc",
+        "base/android/int_string_callback.cc",
+        "base/android/jank_metric_uma_recorder.cc",
+        "base/android/java_exception_reporter.cc",
+        "base/android/java_handler_thread.cc",
+        "base/android/java_heap_dump_generator.cc",
+        "base/android/java_runtime.cc",
+        "base/android/jni_android.cc",
+        "base/android/jni_array.cc",
+        "base/android/jni_registrar.cc",
+        "base/android/jni_string.cc",
+        "base/android/jni_utils.cc",
+        "base/android/jni_weak_ref.cc",
+        "base/android/library_loader/anchor_functions.cc",
+        "base/android/library_loader/library_loader_hooks.cc",
+        "base/android/library_loader/library_prefetcher.cc",
+        "base/android/library_loader/library_prefetcher_hooks.cc",
+        "base/android/locale_utils.cc",
+        "base/android/memory_pressure_listener_android.cc",
+        "base/android/native_uma_recorder.cc",
+        "base/android/path_service_android.cc",
+        "base/android/path_utils.cc",
+        "base/android/radio_utils.cc",
+        "base/android/reached_addresses_bitset.cc",
+        "base/android/reached_code_profiler_stub.cc",
+        "base/android/remove_stale_data.cc",
+        "base/android/scoped_hardware_buffer_fence_sync.cc",
+        "base/android/scoped_hardware_buffer_handle.cc",
+        "base/android/scoped_java_ref.cc",
+        "base/android/statistics_recorder_android.cc",
+        "base/android/sys_utils.cc",
+        "base/android/task_scheduler/post_task_android.cc",
+        "base/android/task_scheduler/task_runner_android.cc",
+        "base/android/thread_instruction_count.cc",
+        "base/android/timezone_utils.cc",
+        "base/android/trace_event_binding.cc",
+        "base/android/unguessable_token_android.cc",
+        "base/at_exit.cc",
+        "base/barrier_closure.cc",
+        "base/base64.cc",
+        "base/base64url.cc",
+        "base/base_paths.cc",
+        "base/base_paths_android.cc",
+        "base/big_endian.cc",
+        "base/build_time.cc",
+        "base/callback_list.cc",
+        "base/check.cc",
+        "base/check_is_test.cc",
+        "base/check_op.cc",
+        "base/command_line.cc",
+        "base/containers/flat_tree.cc",
+        "base/containers/intrusive_heap.cc",
+        "base/containers/linked_list.cc",
+        "base/cpu.cc",
+        "base/cpu_reduction_experiment.cc",
+        "base/debug/activity_analyzer.cc",
+        "base/debug/activity_tracker.cc",
+        "base/debug/alias.cc",
+        "base/debug/asan_invalid_access.cc",
+        "base/debug/buffered_dwarf_reader.cc",
+        "base/debug/crash_logging.cc",
+        "base/debug/debugger.cc",
+        "base/debug/debugger_posix.cc",
+        "base/debug/dump_without_crashing.cc",
+        "base/debug/dwarf_line_no.cc",
+        "base/debug/elf_reader.cc",
+        "base/debug/proc_maps_linux.cc",
+        "base/debug/profiler.cc",
+        "base/debug/stack_trace.cc",
+        "base/debug/stack_trace_android.cc",
+        "base/debug/task_trace.cc",
+        "base/environment.cc",
+        "base/feature_list.cc",
+        "base/features.cc",
+        "base/file_descriptor_posix.cc",
+        "base/file_descriptor_store.cc",
+        "base/files/file.cc",
+        "base/files/file_descriptor_watcher_posix.cc",
+        "base/files/file_enumerator.cc",
+        "base/files/file_enumerator_posix.cc",
+        "base/files/file_path.cc",
+        "base/files/file_path_watcher.cc",
+        "base/files/file_path_watcher_inotify.cc",
+        "base/files/file_posix.cc",
+        "base/files/file_proxy.cc",
+        "base/files/file_tracing.cc",
+        "base/files/file_util.cc",
+        "base/files/file_util_android.cc",
+        "base/files/file_util_posix.cc",
+        "base/files/important_file_writer.cc",
+        "base/files/important_file_writer_cleaner.cc",
+        "base/files/memory_mapped_file.cc",
+        "base/files/memory_mapped_file_posix.cc",
+        "base/files/safe_base_name.cc",
+        "base/files/scoped_file.cc",
+        "base/files/scoped_file_android.cc",
+        "base/files/scoped_temp_dir.cc",
+        "base/functional/callback_helpers.cc",
+        "base/functional/callback_internal.cc",
+        "base/guid.cc",
+        "base/hash/hash.cc",
+        "base/hash/legacy_hash.cc",
+        "base/hash/md5_boringssl.cc",
+        "base/hash/sha1_boringssl.cc",
+        "base/json/json_file_value_serializer.cc",
+        "base/json/json_parser.cc",
+        "base/json/json_reader.cc",
+        "base/json/json_string_value_serializer.cc",
+        "base/json/json_value_converter.cc",
+        "base/json/json_writer.cc",
+        "base/json/string_escape.cc",
+        "base/json/values_util.cc",
+        "base/lazy_instance_helpers.cc",
+        "base/linux_util.cc",
+        "base/location.cc",
+        "base/logging.cc",
+        "base/memory/aligned_memory.cc",
+        "base/memory/discardable_memory.cc",
+        "base/memory/discardable_memory_allocator.cc",
+        "base/memory/discardable_shared_memory.cc",
+        "base/memory/madv_free_discardable_memory_allocator_posix.cc",
+        "base/memory/madv_free_discardable_memory_posix.cc",
+        "base/memory/memory_pressure_listener.cc",
+        "base/memory/memory_pressure_monitor.cc",
+        "base/memory/nonscannable_memory.cc",
+        "base/memory/page_size_posix.cc",
+        "base/memory/platform_shared_memory_handle.cc",
+        "base/memory/platform_shared_memory_mapper_android.cc",
+        "base/memory/platform_shared_memory_region.cc",
+        "base/memory/platform_shared_memory_region_android.cc",
+        "base/memory/raw_ptr.cc",
+        "base/memory/raw_ptr_asan_bound_arg_tracker.cc",
+        "base/memory/raw_ptr_asan_service.cc",
+        "base/memory/read_only_shared_memory_region.cc",
+        "base/memory/ref_counted.cc",
+        "base/memory/ref_counted_memory.cc",
+        "base/memory/shared_memory_mapper.cc",
+        "base/memory/shared_memory_mapping.cc",
+        "base/memory/shared_memory_security_policy.cc",
+        "base/memory/shared_memory_tracker.cc",
+        "base/memory/unsafe_shared_memory_pool.cc",
+        "base/memory/unsafe_shared_memory_region.cc",
+        "base/memory/weak_ptr.cc",
+        "base/memory/writable_shared_memory_region.cc",
+        "base/message_loop/message_pump.cc",
+        "base/message_loop/message_pump_android.cc",
+        "base/message_loop/message_pump_default.cc",
+        "base/message_loop/message_pump_epoll.cc",
+        "base/message_loop/message_pump_libevent.cc",
+        "base/message_loop/watchable_io_message_pump_posix.cc",
+        "base/message_loop/work_id_provider.cc",
+        "base/metrics/bucket_ranges.cc",
+        "base/metrics/crc32.cc",
+        "base/metrics/dummy_histogram.cc",
+        "base/metrics/field_trial.cc",
+        "base/metrics/field_trial_param_associator.cc",
+        "base/metrics/field_trial_params.cc",
+        "base/metrics/histogram.cc",
+        "base/metrics/histogram_base.cc",
+        "base/metrics/histogram_delta_serialization.cc",
+        "base/metrics/histogram_functions.cc",
+        "base/metrics/histogram_samples.cc",
+        "base/metrics/histogram_snapshot_manager.cc",
+        "base/metrics/metrics_hashes.cc",
+        "base/metrics/persistent_histogram_allocator.cc",
+        "base/metrics/persistent_histogram_storage.cc",
+        "base/metrics/persistent_memory_allocator.cc",
+        "base/metrics/persistent_sample_map.cc",
+        "base/metrics/ranges_manager.cc",
+        "base/metrics/sample_map.cc",
+        "base/metrics/sample_vector.cc",
+        "base/metrics/single_sample_metrics.cc",
+        "base/metrics/sparse_histogram.cc",
+        "base/metrics/statistics_recorder.cc",
+        "base/metrics/user_metrics.cc",
+        "base/native_library.cc",
+        "base/native_library_posix.cc",
+        "base/observer_list_internal.cc",
+        "base/observer_list_threadsafe.cc",
+        "base/observer_list_types.cc",
+        "base/one_shot_event.cc",
+        "base/os_compat_android.cc",
+        "base/path_service.cc",
+        "base/pending_task.cc",
+        "base/pickle.cc",
+        "base/posix/can_lower_nice_to.cc",
+        "base/posix/file_descriptor_shuffle.cc",
+        "base/posix/global_descriptors.cc",
+        "base/posix/safe_strerror.cc",
+        "base/posix/unix_domain_socket.cc",
+        "base/power_monitor/battery_level_provider.cc",
+        "base/power_monitor/battery_state_sampler.cc",
+        "base/power_monitor/moving_average.cc",
+        "base/power_monitor/power_monitor.cc",
+        "base/power_monitor/power_monitor_device_source.cc",
+        "base/power_monitor/power_monitor_device_source_android.cc",
+        "base/power_monitor/power_monitor_features.cc",
+        "base/power_monitor/power_monitor_source.cc",
+        "base/power_monitor/sampling_event_source.cc",
+        "base/power_monitor/timer_sampling_event_source.cc",
+        "base/process/environment_internal.cc",
+        "base/process/internal_linux.cc",
+        "base/process/kill.cc",
+        "base/process/kill_posix.cc",
+        "base/process/launch.cc",
+        "base/process/launch_posix.cc",
+        "base/process/memory.cc",
+        "base/process/memory_linux.cc",
+        "base/process/process_android.cc",
+        "base/process/process_handle.cc",
+        "base/process/process_handle_linux.cc",
+        "base/process/process_handle_posix.cc",
+        "base/process/process_iterator.cc",
+        "base/process/process_iterator_linux.cc",
+        "base/process/process_metrics.cc",
+        "base/process/process_metrics_linux.cc",
+        "base/process/process_metrics_posix.cc",
+        "base/process/process_posix.cc",
+        "base/profiler/arm_cfi_table.cc",
+        "base/profiler/frame.cc",
+        "base/profiler/metadata_recorder.cc",
+        "base/profiler/module_cache.cc",
+        "base/profiler/module_cache_posix.cc",
+        "base/profiler/sample_metadata.cc",
+        "base/profiler/sampling_profiler_thread_token.cc",
+        "base/profiler/stack_base_address_posix.cc",
+        "base/profiler/stack_buffer.cc",
+        "base/profiler/stack_copier.cc",
+        "base/profiler/stack_copier_signal.cc",
+        "base/profiler/stack_copier_suspend.cc",
+        "base/profiler/stack_sampler.cc",
+        "base/profiler/stack_sampler_android.cc",
+        "base/profiler/stack_sampler_impl.cc",
+        "base/profiler/stack_sampling_profiler.cc",
+        "base/profiler/thread_delegate_posix.cc",
+        "base/profiler/unwinder.cc",
+        "base/rand_util.cc",
+        "base/rand_util_posix.cc",
+        "base/run_loop.cc",
+        "base/sampling_heap_profiler/lock_free_address_hash_set.cc",
+        "base/sampling_heap_profiler/poisson_allocation_sampler.cc",
+        "base/sampling_heap_profiler/sampling_heap_profiler.cc",
+        "base/scoped_add_feature_flags.cc",
+        "base/scoped_environment_variable_override.cc",
+        "base/scoped_native_library.cc",
+        "base/sequence_checker.cc",
+        "base/sequence_checker_impl.cc",
+        "base/sequence_token.cc",
+        "base/strings/abseil_string_conversions.cc",
+        "base/strings/abseil_string_number_conversions.cc",
+        "base/strings/escape.cc",
+        "base/strings/latin1_string_conversions.cc",
+        "base/strings/pattern.cc",
+        "base/strings/safe_sprintf.cc",
+        "base/strings/strcat.cc",
+        "base/strings/string_number_conversions.cc",
+        "base/strings/string_piece.cc",
+        "base/strings/string_split.cc",
+        "base/strings/string_util.cc",
+        "base/strings/string_util_constants.cc",
+        "base/strings/stringprintf.cc",
+        "base/strings/sys_string_conversions_posix.cc",
+        "base/strings/utf_offset_string_conversions.cc",
+        "base/strings/utf_string_conversion_utils.cc",
+        "base/strings/utf_string_conversions.cc",
+        "base/substring_set_matcher/matcher_string_pattern.cc",
+        "base/substring_set_matcher/substring_set_matcher.cc",
+        "base/supports_user_data.cc",
+        "base/sync_socket.cc",
+        "base/sync_socket_posix.cc",
+        "base/synchronization/atomic_flag.cc",
+        "base/synchronization/condition_variable_posix.cc",
+        "base/synchronization/lock.cc",
+        "base/synchronization/lock_impl_posix.cc",
+        "base/synchronization/waitable_event_posix.cc",
+        "base/synchronization/waitable_event_watcher_posix.cc",
+        "base/syslog_logging.cc",
+        "base/system/sys_info.cc",
+        "base/system/sys_info_android.cc",
+        "base/system/sys_info_linux.cc",
+        "base/system/sys_info_posix.cc",
+        "base/system/system_monitor.cc",
+        "base/task/cancelable_task_tracker.cc",
+        "base/task/common/checked_lock_impl.cc",
+        "base/task/common/lazy_now.cc",
+        "base/task/common/operations_controller.cc",
+        "base/task/common/scoped_defer_task_posting.cc",
+        "base/task/common/task_annotator.cc",
+        "base/task/current_thread.cc",
+        "base/task/default_delayed_task_handle_delegate.cc",
+        "base/task/deferred_sequenced_task_runner.cc",
+        "base/task/delayed_task_handle.cc",
+        "base/task/lazy_thread_pool_task_runner.cc",
+        "base/task/post_job.cc",
+        "base/task/scoped_set_task_priority_for_current_thread.cc",
+        "base/task/sequence_manager/associated_thread_id.cc",
+        "base/task/sequence_manager/atomic_flag_set.cc",
+        "base/task/sequence_manager/delayed_task_handle_delegate.cc",
+        "base/task/sequence_manager/enqueue_order_generator.cc",
+        "base/task/sequence_manager/fence.cc",
+        "base/task/sequence_manager/hierarchical_timing_wheel.cc",
+        "base/task/sequence_manager/sequence_manager.cc",
+        "base/task/sequence_manager/sequence_manager_impl.cc",
+        "base/task/sequence_manager/sequenced_task_source.cc",
+        "base/task/sequence_manager/task_order.cc",
+        "base/task/sequence_manager/task_queue.cc",
+        "base/task/sequence_manager/task_queue_impl.cc",
+        "base/task/sequence_manager/task_queue_selector.cc",
+        "base/task/sequence_manager/tasks.cc",
+        "base/task/sequence_manager/thread_controller.cc",
+        "base/task/sequence_manager/thread_controller_impl.cc",
+        "base/task/sequence_manager/thread_controller_power_monitor.cc",
+        "base/task/sequence_manager/thread_controller_with_message_pump_impl.cc",
+        "base/task/sequence_manager/time_domain.cc",
+        "base/task/sequence_manager/timing_wheel.cc",
+        "base/task/sequence_manager/wake_up_queue.cc",
+        "base/task/sequence_manager/work_deduplicator.cc",
+        "base/task/sequence_manager/work_queue.cc",
+        "base/task/sequence_manager/work_queue_sets.cc",
+        "base/task/sequenced_task_runner.cc",
+        "base/task/simple_task_executor.cc",
+        "base/task/single_thread_task_executor.cc",
+        "base/task/single_thread_task_runner.cc",
+        "base/task/task_executor.cc",
+        "base/task/task_features.cc",
+        "base/task/task_runner.cc",
+        "base/task/task_traits.cc",
+        "base/task/thread_pool.cc",
+        "base/task/thread_pool/delayed_priority_queue.cc",
+        "base/task/thread_pool/delayed_task_manager.cc",
+        "base/task/thread_pool/environment_config.cc",
+        "base/task/thread_pool/initialization_util.cc",
+        "base/task/thread_pool/job_task_source.cc",
+        "base/task/thread_pool/pooled_parallel_task_runner.cc",
+        "base/task/thread_pool/pooled_sequenced_task_runner.cc",
+        "base/task/thread_pool/pooled_single_thread_task_runner_manager.cc",
+        "base/task/thread_pool/pooled_task_runner_delegate.cc",
+        "base/task/thread_pool/priority_queue.cc",
+        "base/task/thread_pool/sequence.cc",
+        "base/task/thread_pool/service_thread.cc",
+        "base/task/thread_pool/task.cc",
+        "base/task/thread_pool/task_source.cc",
+        "base/task/thread_pool/task_source_sort_key.cc",
+        "base/task/thread_pool/task_tracker.cc",
+        "base/task/thread_pool/thread_group.cc",
+        "base/task/thread_pool/thread_group_impl.cc",
+        "base/task/thread_pool/thread_group_native.cc",
+        "base/task/thread_pool/thread_pool_impl.cc",
+        "base/task/thread_pool/thread_pool_instance.cc",
+        "base/task/thread_pool/worker_thread.cc",
+        "base/task/thread_pool/worker_thread_stack.cc",
+        "base/third_party/cityhash/city.cc",
+        "base/third_party/cityhash_v103/src/city_v103.cc",
+        "base/third_party/nspr/prtime.cc",
+        "base/third_party/superfasthash/superfasthash.c",
+        "base/threading/hang_watcher.cc",
+        "base/threading/platform_thread.cc",
+        "base/threading/platform_thread_android.cc",
+        "base/threading/platform_thread_internal_posix.cc",
+        "base/threading/platform_thread_posix.cc",
+        "base/threading/platform_thread_ref.cc",
+        "base/threading/post_task_and_reply_impl.cc",
+        "base/threading/scoped_blocking_call.cc",
+        "base/threading/scoped_blocking_call_internal.cc",
+        "base/threading/scoped_thread_priority.cc",
+        "base/threading/sequence_local_storage_map.cc",
+        "base/threading/sequence_local_storage_slot.cc",
+        "base/threading/sequenced_task_runner_handle.cc",
+        "base/threading/simple_thread.cc",
+        "base/threading/thread.cc",
+        "base/threading/thread_checker.cc",
+        "base/threading/thread_checker_impl.cc",
+        "base/threading/thread_collision_warner.cc",
+        "base/threading/thread_id_name_manager.cc",
+        "base/threading/thread_local_storage.cc",
+        "base/threading/thread_local_storage_posix.cc",
+        "base/threading/thread_restrictions.cc",
+        "base/threading/thread_task_runner_handle.cc",
+        "base/threading/watchdog.cc",
+        "base/time/clock.cc",
+        "base/time/default_clock.cc",
+        "base/time/default_tick_clock.cc",
+        "base/time/tick_clock.cc",
+        "base/time/time.cc",
+        "base/time/time_android.cc",
+        "base/time/time_conversion_posix.cc",
+        "base/time/time_delta_from_string.cc",
+        "base/time/time_exploded_icu.cc",
+        "base/time/time_exploded_posix.cc",
+        "base/time/time_now_posix.cc",
+        "base/time/time_override.cc",
+        "base/time/time_to_iso8601.cc",
+        "base/timer/elapsed_timer.cc",
+        "base/timer/hi_res_timer_manager_posix.cc",
+        "base/timer/lap_timer.cc",
+        "base/timer/timer.cc",
+        "base/timer/wall_clock_timer.cc",
+        "base/token.cc",
+        "base/trace_event/heap_profiler_allocation_context.cc",
+        "base/trace_event/heap_profiler_allocation_context_tracker.cc",
+        "base/trace_event/memory_allocator_dump_guid.cc",
+        "base/trace_event/trace_event_stub.cc",
+        "base/trace_event/trace_id_helper.cc",
+        "base/unguessable_token.cc",
+        "base/value_iterators.cc",
+        "base/values.cc",
+        "base/version.cc",
+        "base/vlog.cc",
+    ],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+    ],
+    static_libs: [
+        "cronet_aml_base_allocator_partition_allocator_partition_alloc",
+        "cronet_aml_base_base_static",
+        "cronet_aml_base_third_party_double_conversion_double_conversion",
+        "cronet_aml_base_third_party_dynamic_annotations_dynamic_annotations",
+        "cronet_aml_third_party_icu_icui18n",
+        "cronet_aml_third_party_icu_icuuc_private",
+        "cronet_aml_third_party_libevent_libevent",
+        "cronet_aml_third_party_modp_b64_modp_b64",
+        "libssl",
+    ],
+    generated_headers: [
+        "cronet_aml_base_allocator_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_debugging_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_logging_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags",
+        "cronet_aml_base_anchor_functions_buildflags",
+        "cronet_aml_base_android_runtime_jni_headers",
+        "cronet_aml_base_base_jni_headers",
+        "cronet_aml_base_build_date",
+        "cronet_aml_base_cfi_buildflags",
+        "cronet_aml_base_clang_profiling_buildflags",
+        "cronet_aml_base_debugging_buildflags",
+        "cronet_aml_base_feature_list_buildflags",
+        "cronet_aml_base_ios_cronet_buildflags",
+        "cronet_aml_base_logging_buildflags",
+        "cronet_aml_base_message_pump_buildflags",
+        "cronet_aml_base_orderfile_buildflags",
+        "cronet_aml_base_parsing_buildflags",
+        "cronet_aml_base_power_monitor_buildflags",
+        "cronet_aml_base_profiler_buildflags",
+        "cronet_aml_base_sanitizer_buildflags",
+        "cronet_aml_base_synchronization_buildflags",
+        "cronet_aml_base_tracing_buildflags",
+        "cronet_aml_build_branding_buildflags",
+        "cronet_aml_build_chromecast_buildflags",
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_build_config_compiler_compiler_buildflags",
+    ],
+    export_generated_headers: [
+        "cronet_aml_base_allocator_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_debugging_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_logging_buildflags",
+        "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags",
+        "cronet_aml_base_anchor_functions_buildflags",
+        "cronet_aml_base_android_runtime_jni_headers",
+        "cronet_aml_base_base_jni_headers",
+        "cronet_aml_base_build_date",
+        "cronet_aml_base_cfi_buildflags",
+        "cronet_aml_base_clang_profiling_buildflags",
+        "cronet_aml_base_debugging_buildflags",
+        "cronet_aml_base_feature_list_buildflags",
+        "cronet_aml_base_ios_cronet_buildflags",
+        "cronet_aml_base_logging_buildflags",
+        "cronet_aml_base_message_pump_buildflags",
+        "cronet_aml_base_orderfile_buildflags",
+        "cronet_aml_base_parsing_buildflags",
+        "cronet_aml_base_power_monitor_buildflags",
+        "cronet_aml_base_profiler_buildflags",
+        "cronet_aml_base_sanitizer_buildflags",
+        "cronet_aml_base_synchronization_buildflags",
+        "cronet_aml_base_tracing_buildflags",
+        "cronet_aml_build_branding_buildflags",
+        "cronet_aml_build_chromecast_buildflags",
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_build_config_compiler_compiler_buildflags",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DABSL_ALLOCATOR_NOTHROW=1",
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DBASE_IMPLEMENTATION",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-DICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE",
+        "-DUSE_CHROMIUM_ICU=1",
+        "-DU_ENABLE_DYLOAD=0",
+        "-DU_ENABLE_RESOURCE_TRACING=0",
+        "-DU_ENABLE_TRACING=1",
+        "-DU_STATIC_IMPLEMENTATION",
+        "-DU_USING_ICU_NAMESPACE=0",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/abseil-cpp/",
+        "third_party/android_ndk/sources/android/cpufeatures/",
+        "third_party/boringssl/src/include/",
+        "third_party/icu/source/common/",
+        "third_party/icu/source/i18n/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    header_libs: [
+        "jni_headers",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //base:base_jni_headers
+genrule {
+    name: "cronet_aml_base_base_jni_headers",
+    srcs: [
+        "base/android/java/src/org/chromium/base/ApkAssets.java",
+        "base/android/java/src/org/chromium/base/ApplicationStatus.java",
+        "base/android/java/src/org/chromium/base/BaseFeatureList.java",
+        "base/android/java/src/org/chromium/base/BuildInfo.java",
+        "base/android/java/src/org/chromium/base/BundleUtils.java",
+        "base/android/java/src/org/chromium/base/Callback.java",
+        "base/android/java/src/org/chromium/base/CommandLine.java",
+        "base/android/java/src/org/chromium/base/ContentUriUtils.java",
+        "base/android/java/src/org/chromium/base/CpuFeatures.java",
+        "base/android/java/src/org/chromium/base/EarlyTraceEvent.java",
+        "base/android/java/src/org/chromium/base/EventLog.java",
+        "base/android/java/src/org/chromium/base/FeatureList.java",
+        "base/android/java/src/org/chromium/base/Features.java",
+        "base/android/java/src/org/chromium/base/FieldTrialList.java",
+        "base/android/java/src/org/chromium/base/FileUtils.java",
+        "base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java",
+        "base/android/java/src/org/chromium/base/IntStringCallback.java",
+        "base/android/java/src/org/chromium/base/JNIUtils.java",
+        "base/android/java/src/org/chromium/base/JavaExceptionReporter.java",
+        "base/android/java/src/org/chromium/base/JavaHandlerThread.java",
+        "base/android/java/src/org/chromium/base/LocaleUtils.java",
+        "base/android/java/src/org/chromium/base/MemoryPressureListener.java",
+        "base/android/java/src/org/chromium/base/PathService.java",
+        "base/android/java/src/org/chromium/base/PathUtils.java",
+        "base/android/java/src/org/chromium/base/PowerMonitor.java",
+        "base/android/java/src/org/chromium/base/RadioUtils.java",
+        "base/android/java/src/org/chromium/base/SysUtils.java",
+        "base/android/java/src/org/chromium/base/ThreadUtils.java",
+        "base/android/java/src/org/chromium/base/TimezoneUtils.java",
+        "base/android/java/src/org/chromium/base/TraceEvent.java",
+        "base/android/java/src/org/chromium/base/UnguessableToken.java",
+        "base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java",
+        "base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java",
+        "base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java",
+        "base/android/java/src/org/chromium/base/memory/JavaHeapDumpGenerator.java",
+        "base/android/java/src/org/chromium/base/metrics/NativeUmaRecorder.java",
+        "base/android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java",
+        "base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java",
+        "base/android/java/src/org/chromium/base/task/PostTask.java",
+        "base/android/java/src/org/chromium/base/task/TaskRunnerImpl.java",
+    ],
+    cmd: "$(location base/android/jni_generator/jni_generator.py) --ptr_type " +
+         "long " +
+         " " +
+         " " +
+         "--output_dir " +
+         "$(genDir)/base/base_jni_headers " +
+         "--includes " +
+         "base/android/jni_generator/jni_generator_helper.h " +
+         "--use_proxy_hash " +
+         "--output_name " +
+         "ApkAssets_jni.h " +
+         "--output_name " +
+         "ApplicationStatus_jni.h " +
+         "--output_name " +
+         "BaseFeatureList_jni.h " +
+         "--output_name " +
+         "BuildInfo_jni.h " +
+         "--output_name " +
+         "BundleUtils_jni.h " +
+         "--output_name " +
+         "Callback_jni.h " +
+         "--output_name " +
+         "CommandLine_jni.h " +
+         "--output_name " +
+         "ContentUriUtils_jni.h " +
+         "--output_name " +
+         "CpuFeatures_jni.h " +
+         "--output_name " +
+         "EarlyTraceEvent_jni.h " +
+         "--output_name " +
+         "EventLog_jni.h " +
+         "--output_name " +
+         "FeatureList_jni.h " +
+         "--output_name " +
+         "Features_jni.h " +
+         "--output_name " +
+         "FieldTrialList_jni.h " +
+         "--output_name " +
+         "FileUtils_jni.h " +
+         "--output_name " +
+         "ImportantFileWriterAndroid_jni.h " +
+         "--output_name " +
+         "IntStringCallback_jni.h " +
+         "--output_name " +
+         "JNIUtils_jni.h " +
+         "--output_name " +
+         "JavaExceptionReporter_jni.h " +
+         "--output_name " +
+         "JavaHandlerThread_jni.h " +
+         "--output_name " +
+         "LocaleUtils_jni.h " +
+         "--output_name " +
+         "MemoryPressureListener_jni.h " +
+         "--output_name " +
+         "PathService_jni.h " +
+         "--output_name " +
+         "PathUtils_jni.h " +
+         "--output_name " +
+         "PowerMonitor_jni.h " +
+         "--output_name " +
+         "RadioUtils_jni.h " +
+         "--output_name " +
+         "SysUtils_jni.h " +
+         "--output_name " +
+         "ThreadUtils_jni.h " +
+         "--output_name " +
+         "TimezoneUtils_jni.h " +
+         "--output_name " +
+         "TraceEvent_jni.h " +
+         "--output_name " +
+         "UnguessableToken_jni.h " +
+         "--output_name " +
+         "JankMetricUMARecorder_jni.h " +
+         "--output_name " +
+         "LibraryLoader_jni.h " +
+         "--output_name " +
+         "LibraryPrefetcher_jni.h " +
+         "--output_name " +
+         "JavaHeapDumpGenerator_jni.h " +
+         "--output_name " +
+         "NativeUmaRecorder_jni.h " +
+         "--output_name " +
+         "StatisticsRecorderAndroid_jni.h " +
+         "--output_name " +
+         "ChildProcessService_jni.h " +
+         "--output_name " +
+         "PostTask_jni.h " +
+         "--output_name " +
+         "TaskRunnerImpl_jni.h " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/ApkAssets.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/ApplicationStatus.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/BaseFeatureList.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/BuildInfo.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/BundleUtils.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/Callback.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/CommandLine.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/ContentUriUtils.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/CpuFeatures.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/EarlyTraceEvent.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/EventLog.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/FeatureList.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/Features.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/FieldTrialList.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/FileUtils.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/IntStringCallback.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/JNIUtils.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/JavaExceptionReporter.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/JavaHandlerThread.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/LocaleUtils.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/MemoryPressureListener.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/PathService.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/PathUtils.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/PowerMonitor.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/RadioUtils.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/SysUtils.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/ThreadUtils.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/TimezoneUtils.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/TraceEvent.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/UnguessableToken.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/memory/JavaHeapDumpGenerator.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/metrics/NativeUmaRecorder.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/task/PostTask.java) " +
+         "--input_file " +
+         "$(location base/android/java/src/org/chromium/base/task/TaskRunnerImpl.java)",
+    out: [
+        "base/base_jni_headers/ApkAssets_jni.h",
+        "base/base_jni_headers/ApplicationStatus_jni.h",
+        "base/base_jni_headers/BaseFeatureList_jni.h",
+        "base/base_jni_headers/BuildInfo_jni.h",
+        "base/base_jni_headers/BundleUtils_jni.h",
+        "base/base_jni_headers/Callback_jni.h",
+        "base/base_jni_headers/ChildProcessService_jni.h",
+        "base/base_jni_headers/CommandLine_jni.h",
+        "base/base_jni_headers/ContentUriUtils_jni.h",
+        "base/base_jni_headers/CpuFeatures_jni.h",
+        "base/base_jni_headers/EarlyTraceEvent_jni.h",
+        "base/base_jni_headers/EventLog_jni.h",
+        "base/base_jni_headers/FeatureList_jni.h",
+        "base/base_jni_headers/Features_jni.h",
+        "base/base_jni_headers/FieldTrialList_jni.h",
+        "base/base_jni_headers/FileUtils_jni.h",
+        "base/base_jni_headers/ImportantFileWriterAndroid_jni.h",
+        "base/base_jni_headers/IntStringCallback_jni.h",
+        "base/base_jni_headers/JNIUtils_jni.h",
+        "base/base_jni_headers/JankMetricUMARecorder_jni.h",
+        "base/base_jni_headers/JavaExceptionReporter_jni.h",
+        "base/base_jni_headers/JavaHandlerThread_jni.h",
+        "base/base_jni_headers/JavaHeapDumpGenerator_jni.h",
+        "base/base_jni_headers/LibraryLoader_jni.h",
+        "base/base_jni_headers/LibraryPrefetcher_jni.h",
+        "base/base_jni_headers/LocaleUtils_jni.h",
+        "base/base_jni_headers/MemoryPressureListener_jni.h",
+        "base/base_jni_headers/NativeUmaRecorder_jni.h",
+        "base/base_jni_headers/PathService_jni.h",
+        "base/base_jni_headers/PathUtils_jni.h",
+        "base/base_jni_headers/PostTask_jni.h",
+        "base/base_jni_headers/PowerMonitor_jni.h",
+        "base/base_jni_headers/RadioUtils_jni.h",
+        "base/base_jni_headers/StatisticsRecorderAndroid_jni.h",
+        "base/base_jni_headers/SysUtils_jni.h",
+        "base/base_jni_headers/TaskRunnerImpl_jni.h",
+        "base/base_jni_headers/ThreadUtils_jni.h",
+        "base/base_jni_headers/TimezoneUtils_jni.h",
+        "base/base_jni_headers/TraceEvent_jni.h",
+        "base/base_jni_headers/UnguessableToken_jni.h",
+    ],
+    tool_files: [
+        "base/android/jni_generator/android_jar.classes",
+        "base/android/jni_generator/jni_generator.py",
+        "build/android/gyp/util/__init__.py",
+        "build/android/gyp/util/build_utils.py",
+        "build/gn_helpers.py",
+    ],
+}
+
+// GN: //base:base_static
+cc_library_static {
+    name: "cronet_aml_base_base_static",
+    srcs: [
+        "base/base_switches.cc",
+    ],
+    generated_headers: [
+        "cronet_aml_build_chromeos_buildflags",
+    ],
+    export_generated_headers: [
+        "cronet_aml_build_chromeos_buildflags",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //base:build_date
+genrule {
+    name: "cronet_aml_base_build_date",
+    cmd: "$(location build/write_build_date_header.py) $(out) " +
+         "1664686800",
+    out: [
+        "base/generated_build_date.h",
+    ],
+    tool_files: [
+        "build/write_build_date_header.py",
+    ],
+}
+
+// GN: //base:cfi_buildflags
+genrule {
+    name: "cronet_aml_base_cfi_buildflags",
+    cmd: "echo '--flags CFI_CAST_CHECK=\"false && false\" CFI_DIAG=\"false && false\" CFI_ICALL_CHECK=\"false && false\" CFI_ENFORCEMENT_TRAP=\"false && !false\" CFI_ENFORCEMENT_DIAGNOSTIC=\"false && false && !false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:cfi_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/cfi_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:clang_profiling_buildflags
+genrule {
+    name: "cronet_aml_base_clang_profiling_buildflags",
+    cmd: "echo '--flags CLANG_PROFILING=\"false\" CLANG_PROFILING_INSIDE_SANDBOX=\"false\" USE_CLANG_COVERAGE=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:clang_profiling_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/clang_profiling_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:debugging_buildflags
+genrule {
+    name: "cronet_aml_base_debugging_buildflags",
+    cmd: "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"false\" UNSAFE_DEVELOPER_BUILD=\"true\" CAN_UNWIND_WITH_CFI_TABLE=\"false\" EXCLUDE_UNWIND_TABLES=\"false\" ENABLE_GDBINIT_WARNING=\"true\" ENABLE_LLDBINIT_WARNING=\"false\" EXPENSIVE_DCHECKS_ARE_ON=\"true\" ENABLE_STACK_TRACE_LINE_NUMBERS=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:debugging_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/debug/debugging_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:feature_list_buildflags
+genrule {
+    name: "cronet_aml_base_feature_list_buildflags",
+    cmd: "echo '--flags ENABLE_BANNED_BASE_FEATURE_PREFIX=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:feature_list_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/feature_list_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:ios_cronet_buildflags
+genrule {
+    name: "cronet_aml_base_ios_cronet_buildflags",
+    cmd: "echo '--flags CRONET_BUILD=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:ios_cronet_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/message_loop/ios_cronet_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:logging_buildflags
+genrule {
+    name: "cronet_aml_base_logging_buildflags",
+    cmd: "echo '--flags ENABLE_LOG_ERROR_NOT_REACHED=\"false\" USE_RUNTIME_VLOG=\"true\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:logging_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/logging_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:message_pump_buildflags
+genrule {
+    name: "cronet_aml_base_message_pump_buildflags",
+    cmd: "echo '--flags ENABLE_MESSAGE_PUMP_EPOLL=\"true\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:message_pump_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/message_loop/message_pump_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base/numerics:base_numerics
+filegroup {
+    name: "cronet_aml_base_numerics_base_numerics",
+}
+
+// GN: //base:orderfile_buildflags
+genrule {
+    name: "cronet_aml_base_orderfile_buildflags",
+    cmd: "echo '--flags DEVTOOLS_INSTRUMENTATION_DUMPING=\"false\" ORDERFILE_INSTRUMENTATION=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:orderfile_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/android/orderfile/orderfile_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:parsing_buildflags
+genrule {
+    name: "cronet_aml_base_parsing_buildflags",
+    cmd: "echo '--flags BUILD_RUST_JSON_PARSER=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:parsing_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/parsing_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:power_monitor_buildflags
+genrule {
+    name: "cronet_aml_base_power_monitor_buildflags",
+    cmd: "echo '--flags HAS_BATTERY_LEVEL_PROVIDER_IMPL=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:power_monitor_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/power_monitor/power_monitor_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:profiler_buildflags
+genrule {
+    name: "cronet_aml_base_profiler_buildflags",
+    cmd: "echo '--flags ENABLE_ARM_CFI_TABLE=\"false\" IOS_STACK_PROFILER_ENABLED=\"true\" USE_ANDROID_UNWINDER_V2=\"true\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:profiler_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/profiler/profiler_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:sanitizer_buildflags
+genrule {
+    name: "cronet_aml_base_sanitizer_buildflags",
+    cmd: "echo '--flags IS_HWASAN=\"false\" USING_SANITIZER=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:sanitizer_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/sanitizer_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base:synchronization_buildflags
+genrule {
+    name: "cronet_aml_base_synchronization_buildflags",
+    cmd: "echo '--flags ENABLE_MUTEX_PRIORITY_INHERITANCE=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:synchronization_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/synchronization/synchronization_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //base/third_party/double_conversion:double_conversion
+cc_library_static {
+    name: "cronet_aml_base_third_party_double_conversion_double_conversion",
+    srcs: [
+        "base/third_party/double_conversion/double-conversion/bignum-dtoa.cc",
+        "base/third_party/double_conversion/double-conversion/bignum.cc",
+        "base/third_party/double_conversion/double-conversion/cached-powers.cc",
+        "base/third_party/double_conversion/double-conversion/double-to-string.cc",
+        "base/third_party/double_conversion/double-conversion/fast-dtoa.cc",
+        "base/third_party/double_conversion/double-conversion/fixed-dtoa.cc",
+        "base/third_party/double_conversion/double-conversion/string-to-double.cc",
+        "base/third_party/double_conversion/double-conversion/strtod.cc",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //base/third_party/dynamic_annotations:dynamic_annotations
+cc_library_static {
+    name: "cronet_aml_base_third_party_dynamic_annotations_dynamic_annotations",
+    srcs: [
+        "base/third_party/dynamic_annotations/dynamic_annotations.c",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //base:tracing_buildflags
+genrule {
+    name: "cronet_aml_base_tracing_buildflags",
+    cmd: "echo '--flags ENABLE_BASE_TRACING=\"false\" USE_PERFETTO_CLIENT_LIBRARY=\"false\" OPTIONAL_TRACE_EVENTS_ENABLED=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//base:tracing_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "base/tracing_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //build:branding_buildflags
+genrule {
+    name: "cronet_aml_build_branding_buildflags",
+    cmd: "echo '--flags CHROMIUM_BRANDING=\"1\" GOOGLE_CHROME_BRANDING=\"0\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//build:branding_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "build/branding_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //build:buildflag_header_h
+filegroup {
+    name: "cronet_aml_build_buildflag_header_h",
+}
+
+// GN: //build:chromecast_buildflags
+genrule {
+    name: "cronet_aml_build_chromecast_buildflags",
+    cmd: "echo '--flags IS_CASTOS=\"false\" IS_CAST_ANDROID=\"false\" ENABLE_CAST_RECEIVER=\"false\" IS_CHROMECAST=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//build:chromecast_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "build/chromecast_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //build:chromeos_buildflags
+genrule {
+    name: "cronet_aml_build_chromeos_buildflags",
+    cmd: "echo '--flags IS_CHROMEOS_DEVICE=\"false\" IS_CHROMEOS_LACROS=\"false\" IS_CHROMEOS_ASH=\"false\" IS_CHROMEOS_WITH_HW_DETAILS=\"false\" IS_REVEN=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//build:chromeos_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "build/chromeos_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //build/config/compiler:compiler_buildflags
+genrule {
+    name: "cronet_aml_build_config_compiler_compiler_buildflags",
+    cmd: "echo '--flags CLANG_PGO=\"0\" SYMBOL_LEVEL=\"1\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//build/config/compiler:compiler_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "build/config/compiler/compiler_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //buildtools/third_party/libc++:libc++
+filegroup {
+    name: "cronet_aml_buildtools_third_party_libc___libc__",
+    srcs: [
+        "buildtools/third_party/libc++/trunk/src/algorithm.cpp",
+        "buildtools/third_party/libc++/trunk/src/any.cpp",
+        "buildtools/third_party/libc++/trunk/src/atomic.cpp",
+        "buildtools/third_party/libc++/trunk/src/barrier.cpp",
+        "buildtools/third_party/libc++/trunk/src/bind.cpp",
+        "buildtools/third_party/libc++/trunk/src/charconv.cpp",
+        "buildtools/third_party/libc++/trunk/src/chrono.cpp",
+        "buildtools/third_party/libc++/trunk/src/condition_variable.cpp",
+        "buildtools/third_party/libc++/trunk/src/condition_variable_destructor.cpp",
+        "buildtools/third_party/libc++/trunk/src/exception.cpp",
+        "buildtools/third_party/libc++/trunk/src/format.cpp",
+        "buildtools/third_party/libc++/trunk/src/functional.cpp",
+        "buildtools/third_party/libc++/trunk/src/future.cpp",
+        "buildtools/third_party/libc++/trunk/src/hash.cpp",
+        "buildtools/third_party/libc++/trunk/src/ios.cpp",
+        "buildtools/third_party/libc++/trunk/src/ios.instantiations.cpp",
+        "buildtools/third_party/libc++/trunk/src/iostream.cpp",
+        "buildtools/third_party/libc++/trunk/src/legacy_pointer_safety.cpp",
+        "buildtools/third_party/libc++/trunk/src/locale.cpp",
+        "buildtools/third_party/libc++/trunk/src/memory.cpp",
+        "buildtools/third_party/libc++/trunk/src/mutex.cpp",
+        "buildtools/third_party/libc++/trunk/src/mutex_destructor.cpp",
+        "buildtools/third_party/libc++/trunk/src/new.cpp",
+        "buildtools/third_party/libc++/trunk/src/optional.cpp",
+        "buildtools/third_party/libc++/trunk/src/random.cpp",
+        "buildtools/third_party/libc++/trunk/src/random_shuffle.cpp",
+        "buildtools/third_party/libc++/trunk/src/regex.cpp",
+        "buildtools/third_party/libc++/trunk/src/ryu/d2fixed.cpp",
+        "buildtools/third_party/libc++/trunk/src/ryu/d2s.cpp",
+        "buildtools/third_party/libc++/trunk/src/ryu/f2s.cpp",
+        "buildtools/third_party/libc++/trunk/src/shared_mutex.cpp",
+        "buildtools/third_party/libc++/trunk/src/stdexcept.cpp",
+        "buildtools/third_party/libc++/trunk/src/string.cpp",
+        "buildtools/third_party/libc++/trunk/src/strstream.cpp",
+        "buildtools/third_party/libc++/trunk/src/system_error.cpp",
+        "buildtools/third_party/libc++/trunk/src/thread.cpp",
+        "buildtools/third_party/libc++/trunk/src/typeinfo.cpp",
+        "buildtools/third_party/libc++/trunk/src/utility.cpp",
+        "buildtools/third_party/libc++/trunk/src/valarray.cpp",
+        "buildtools/third_party/libc++/trunk/src/variant.cpp",
+        "buildtools/third_party/libc++/trunk/src/vector.cpp",
+        "buildtools/third_party/libc++/trunk/src/verbose_abort.cpp",
+    ],
+}
+
+// GN: //buildtools/third_party/libc++abi:libc++abi
+filegroup {
+    name: "cronet_aml_buildtools_third_party_libc__abi_libc__abi",
+    srcs: [
+        "buildtools/third_party/libc++abi/cxa_demangle_stub.cc",
+        "buildtools/third_party/libc++abi/trunk/src/abort_message.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/cxa_aux_runtime.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/cxa_default_handlers.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/cxa_exception.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/cxa_exception_storage.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/cxa_guard.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/cxa_handlers.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/cxa_personality.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/cxa_thread_atexit.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/cxa_vector.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/cxa_virtual.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/fallback_malloc.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/private_typeinfo.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/stdlib_exception.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/stdlib_stdexcept.cpp",
+        "buildtools/third_party/libc++abi/trunk/src/stdlib_typeinfo.cpp",
+    ],
+}
+
+// GN: //buildtools/third_party/libunwind:libunwind
+filegroup {
+    name: "cronet_aml_buildtools_third_party_libunwind_libunwind",
+    srcs: [
+        "buildtools/third_party/libunwind/trunk/src/Unwind-EHABI.cpp",
+        "buildtools/third_party/libunwind/trunk/src/Unwind-sjlj.c",
+        "buildtools/third_party/libunwind/trunk/src/UnwindLevel1-gcc-ext.c",
+        "buildtools/third_party/libunwind/trunk/src/UnwindLevel1.c",
+        "buildtools/third_party/libunwind/trunk/src/UnwindRegistersRestore.S",
+        "buildtools/third_party/libunwind/trunk/src/UnwindRegistersSave.S",
+        "buildtools/third_party/libunwind/trunk/src/libunwind.cpp",
+    ],
+}
+
+// GN: //components/cronet/android:buildflags
+genrule {
+    name: "cronet_aml_components_cronet_android_buildflags",
+    cmd: "echo '--flags INTEGRATED_MODE=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//components/cronet/android:buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "components/cronet/android/buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //components/cronet/android:cronet
+cc_library_shared {
+    name: "cronet_aml_components_cronet_android_cronet",
+    srcs: [
+        ":cronet_aml_buildtools_third_party_libc___libc__",
+        ":cronet_aml_buildtools_third_party_libc__abi_libc__abi",
+        ":cronet_aml_buildtools_third_party_libunwind_libunwind",
+        ":cronet_aml_components_cronet_android_cronet_static",
+        ":cronet_aml_components_cronet_cronet_common",
+        ":cronet_aml_components_cronet_cronet_version_header",
+        ":cronet_aml_components_cronet_metrics_util",
+        ":cronet_aml_components_cronet_native_cronet_native_headers",
+        ":cronet_aml_components_cronet_native_cronet_native_impl",
+        ":cronet_aml_components_grpc_support_grpc_support",
+        ":cronet_aml_components_grpc_support_headers",
+        ":cronet_aml_components_metrics_library_support",
+        ":cronet_aml_third_party_metrics_proto_metrics_proto_gen",
+        "components/cronet/android/cronet_jni.cc",
+    ],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+        "libprotobuf-cpp-lite",
+    ],
+    static_libs: [
+        "cronet_aml_base_base",
+        "cronet_aml_base_third_party_dynamic_annotations_dynamic_annotations",
+        "cronet_aml_components_prefs_prefs",
+        "cronet_aml_net_net",
+        "cronet_aml_third_party_zlib_zlib",
+        "cronet_aml_url_url",
+    ],
+    generated_headers: [
+        "cronet_aml_base_debugging_buildflags",
+        "cronet_aml_base_logging_buildflags",
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_components_cronet_android_buildflags",
+        "cronet_aml_components_cronet_android_cronet_jni_headers",
+        "cronet_aml_components_cronet_android_cronet_jni_registration",
+        "cronet_aml_components_cronet_cronet_buildflags",
+        "cronet_aml_components_cronet_cronet_version_header_action",
+        "cronet_aml_third_party_metrics_proto_metrics_proto_gen_headers",
+        "cronet_aml_url_buildflags",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DGOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0",
+        "-DGOOGLE_PROTOBUF_NO_RTTI",
+        "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
+        "-DHAVE_PTHREAD",
+        "-DHAVE_SYS_UIO_H",
+        "-DLIBCXXABI_SILENT_TERMINATE",
+        "-DLIBCXX_BUILDING_LIBCXXABI",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_BUILDING_LIBRARY",
+        "-D_LIBCPP_CONSTINIT=constinit",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCPP_OVERRIDABLE_FUNC_VIS=__attribute__((__visibility__(\"default\")))",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBUNWIND_IS_NATIVE_ONLY",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++/trunk/src/",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "buildtools/third_party/libunwind/trunk/include/",
+        "components/cronet/native/generated/",
+        "components/cronet/native/include/",
+        "components/grpc_support/include/",
+        "net/third_party/quiche/overrides/",
+        "net/third_party/quiche/src/",
+        "net/third_party/quiche/src/quiche/common/platform/default/",
+        "third_party/abseil-cpp/",
+        "third_party/boringssl/src/include/",
+        "third_party/zlib/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    header_libs: [
+        "jni_headers",
+    ],
+    cpp_std: "c++20",
+    cppflags: [
+        "-fexceptions",
+    ],
+    rtti: true,
+}
+
+// GN: //components/cronet/android:cronet_jni_headers
+genrule {
+    name: "cronet_aml_components_cronet_android_cronet_jni_headers",
+    srcs: [
+        "components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java",
+        "components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java",
+        "components/cronet/android/java/src/org/chromium/net/impl/CronetUploadDataStream.java",
+        "components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java",
+        "components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java",
+    ],
+    cmd: "$(location base/android/jni_generator/jni_generator.py) --ptr_type " +
+         "long " +
+         " " +
+         " " +
+         "--output_dir " +
+         "$(genDir)/components/cronet/android/cronet_jni_headers " +
+         "--includes " +
+         "base/android/jni_generator/jni_generator_helper.h " +
+         "--use_proxy_hash " +
+         "--output_name " +
+         "CronetBidirectionalStream_jni.h " +
+         "--output_name " +
+         "CronetLibraryLoader_jni.h " +
+         "--output_name " +
+         "CronetUploadDataStream_jni.h " +
+         "--output_name " +
+         "CronetUrlRequest_jni.h " +
+         "--output_name " +
+         "CronetUrlRequestContext_jni.h " +
+         "--input_file " +
+         "$(location components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java) " +
+         "--input_file " +
+         "$(location components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java) " +
+         "--input_file " +
+         "$(location components/cronet/android/java/src/org/chromium/net/impl/CronetUploadDataStream.java) " +
+         "--input_file " +
+         "$(location components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java) " +
+         "--input_file " +
+         "$(location components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java)",
+    out: [
+        "components/cronet/android/cronet_jni_headers/CronetBidirectionalStream_jni.h",
+        "components/cronet/android/cronet_jni_headers/CronetLibraryLoader_jni.h",
+        "components/cronet/android/cronet_jni_headers/CronetUploadDataStream_jni.h",
+        "components/cronet/android/cronet_jni_headers/CronetUrlRequestContext_jni.h",
+        "components/cronet/android/cronet_jni_headers/CronetUrlRequest_jni.h",
+    ],
+    tool_files: [
+        "base/android/jni_generator/android_jar.classes",
+        "base/android/jni_generator/jni_generator.py",
+        "build/android/gyp/util/__init__.py",
+        "build/android/gyp/util/build_utils.py",
+        "build/gn_helpers.py",
+    ],
+}
+
+// GN: //components/cronet/android:cronet_jni_registration
+genrule {
+    name: "cronet_aml_components_cronet_android_cronet_jni_registration",
+    srcs: [
+        "base/android/java/src/org/chromium/base/JniException.java",
+        "base/android/java/src/org/chromium/base/JniStaticTestMocker.java",
+        "base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java",
+        "base/android/java/src/org/chromium/base/annotations/AccessedByNative.java",
+        "base/android/java/src/org/chromium/base/annotations/CalledByNative.java",
+        "base/android/java/src/org/chromium/base/annotations/CalledByNativeForTesting.java",
+        "base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java",
+        "base/android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java",
+        "base/android/java/src/org/chromium/base/annotations/JNINamespace.java",
+        "base/android/java/src/org/chromium/base/annotations/JniIgnoreNatives.java",
+        "base/android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java",
+        "base/android/java/src/org/chromium/base/annotations/NativeMethods.java",
+        "build/android/java/src/org/chromium/build/annotations/AlwaysInline.java",
+        "build/android/java/src/org/chromium/build/annotations/CheckDiscard.java",
+        "build/android/java/src/org/chromium/build/annotations/DoNotClassMerge.java",
+        "build/android/java/src/org/chromium/build/annotations/DoNotInline.java",
+        "build/android/java/src/org/chromium/build/annotations/IdentifierNameString.java",
+        "build/android/java/src/org/chromium/build/annotations/MainDex.java",
+        "build/android/java/src/org/chromium/build/annotations/MockedInTests.java",
+        "build/android/java/src/org/chromium/build/annotations/UsedByReflection.java",
+        "components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java",
+        "url/android/java/src/org/chromium/url/IDNStringUtil.java",
+    ],
+    cmd: "current_dir=`basename \\`pwd\\``; " +
+         "for f in $(in); " +
+         "do " +
+         "echo \"../$$current_dir/$$f\" >> $(genDir)/java.sources; " +
+         "done; " +
+         "python3 $(location base/android/jni_generator/jni_registration_generator.py) --srcjar-path " +
+         "$(genDir)/components/cronet/android/cronet_jni_registration.srcjar " +
+         "--depfile " +
+         "$(genDir)/components/cronet/android/cronet_jni_registration.d " +
+         "--sources-files " +
+         "$(genDir)/java.sources " +
+         "--include_test_only " +
+         "--use_proxy_hash " +
+         "--header-path " +
+         "$(genDir)/components/cronet/android/cronet_jni_registration.h " +
+         "--manual_jni_registration " +
+         " " +
+         " " +
+         ";sed -i -e 's/OUT_SOONG_.TEMP_SBOX_.*_OUT/GEN/g'  " +
+         "$(genDir)/components/cronet/android/cronet_jni_registration.h",
+    out: [
+        "components/cronet/android/cronet_jni_registration.h",
+        "components/cronet/android/cronet_jni_registration.srcjar",
+    ],
+    tool_files: [
+        "base/android/jni_generator/jni_generator.py",
+        "base/android/jni_generator/jni_registration_generator.py",
+        "build/android/gyp/util/__init__.py",
+        "build/android/gyp/util/build_utils.py",
+        "build/gn_helpers.py",
+    ],
+}
+
+// GN: //components/cronet/android:cronet_static
+filegroup {
+    name: "cronet_aml_components_cronet_android_cronet_static",
+    srcs: [
+        "components/cronet/android/cronet_bidirectional_stream_adapter.cc",
+        "components/cronet/android/cronet_context_adapter.cc",
+        "components/cronet/android/cronet_library_loader.cc",
+        "components/cronet/android/cronet_upload_data_stream_adapter.cc",
+        "components/cronet/android/cronet_url_request_adapter.cc",
+        "components/cronet/android/io_buffer_with_byte_buffer.cc",
+        "components/cronet/android/url_request_error.cc",
+    ],
+}
+
+// GN: //components/cronet:cronet_buildflags
+genrule {
+    name: "cronet_aml_components_cronet_cronet_buildflags",
+    cmd: "echo '--flags DISABLE_HISTOGRAM_SUPPORT=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//components/cronet:cronet_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "components/cronet/cronet_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //components/cronet:cronet_common
+filegroup {
+    name: "cronet_aml_components_cronet_cronet_common",
+    srcs: [
+        "components/cronet/cronet_context.cc",
+        "components/cronet/cronet_prefs_manager.cc",
+        "components/cronet/cronet_upload_data_stream.cc",
+        "components/cronet/cronet_url_request.cc",
+        "components/cronet/host_cache_persistence_manager.cc",
+        "components/cronet/stale_host_resolver.cc",
+        "components/cronet/url_request_context_config.cc",
+    ],
+}
+
+// GN: //components/cronet:cronet_version_header
+filegroup {
+    name: "cronet_aml_components_cronet_cronet_version_header",
+}
+
+// GN: //components/cronet:cronet_version_header_action
+genrule {
+    name: "cronet_aml_components_cronet_cronet_version_header_action",
+    cmd: "$(location build/util/version.py) -f " +
+         "$(location chrome/VERSION) " +
+         "-e " +
+         "VERSION_FULL='\"%s.%s.%s.%s\" % (MAJOR,MINOR,BUILD,PATCH)' " +
+         " " +
+         "-o " +
+         "$(out) " +
+         "$(location components/cronet/version.h.in)",
+    out: [
+        "components/cronet/version.h",
+    ],
+    tool_files: [
+        "build/util/LASTCHANGE",
+        "build/util/android_chrome_version.py",
+        "build/util/version.py",
+        "chrome/VERSION",
+        "components/cronet/version.h.in",
+    ],
+}
+
+// GN: //components/cronet:metrics_util
+filegroup {
+    name: "cronet_aml_components_cronet_metrics_util",
+    srcs: [
+        "components/cronet/metrics_util.cc",
+    ],
+}
+
+// GN: //components/cronet/native:cronet_native_headers
+filegroup {
+    name: "cronet_aml_components_cronet_native_cronet_native_headers",
+}
+
+// GN: //components/cronet/native:cronet_native_impl
+filegroup {
+    name: "cronet_aml_components_cronet_native_cronet_native_impl",
+    srcs: [
+        "components/cronet/native/buffer.cc",
+        "components/cronet/native/engine.cc",
+        "components/cronet/native/generated/cronet.idl_impl_interface.cc",
+        "components/cronet/native/generated/cronet.idl_impl_struct.cc",
+        "components/cronet/native/io_buffer_with_cronet_buffer.cc",
+        "components/cronet/native/native_metrics_util.cc",
+        "components/cronet/native/runnables.cc",
+        "components/cronet/native/upload_data_sink.cc",
+        "components/cronet/native/url_request.cc",
+    ],
+}
+
+// GN: //components/grpc_support:grpc_support
+filegroup {
+    name: "cronet_aml_components_grpc_support_grpc_support",
+    srcs: [
+        "components/grpc_support/bidirectional_stream.cc",
+        "components/grpc_support/bidirectional_stream_c.cc",
+    ],
+}
+
+// GN: //components/grpc_support:headers
+filegroup {
+    name: "cronet_aml_components_grpc_support_headers",
+}
+
+// GN: //components/metrics:library_support
+filegroup {
+    name: "cronet_aml_components_metrics_library_support",
+    srcs: [
+        "components/metrics/histogram_encoder.cc",
+        "components/metrics/library_support/histogram_manager.cc",
+    ],
+}
+
+// GN: //components/prefs/android:jni_headers
+genrule {
+    name: "cronet_aml_components_prefs_android_jni_headers",
+    srcs: [
+        "components/prefs/android/java/src/org/chromium/components/prefs/PrefService.java",
+    ],
+    cmd: "$(location base/android/jni_generator/jni_generator.py) --ptr_type " +
+         "long " +
+         " " +
+         " " +
+         "--output_dir " +
+         "$(genDir)/components/prefs/android/jni_headers " +
+         "--includes " +
+         "base/android/jni_generator/jni_generator_helper.h " +
+         "--use_proxy_hash " +
+         "--output_name " +
+         "PrefService_jni.h " +
+         "--input_file " +
+         "$(location components/prefs/android/java/src/org/chromium/components/prefs/PrefService.java)",
+    out: [
+        "components/prefs/android/jni_headers/PrefService_jni.h",
+    ],
+    tool_files: [
+        "base/android/jni_generator/android_jar.classes",
+        "base/android/jni_generator/jni_generator.py",
+        "build/android/gyp/util/__init__.py",
+        "build/android/gyp/util/build_utils.py",
+        "build/gn_helpers.py",
+    ],
+}
+
+// GN: //components/prefs:prefs
+cc_library_static {
+    name: "cronet_aml_components_prefs_prefs",
+    srcs: [
+        "components/prefs/android/pref_service_android.cc",
+        "components/prefs/command_line_pref_store.cc",
+        "components/prefs/default_pref_store.cc",
+        "components/prefs/in_memory_pref_store.cc",
+        "components/prefs/json_pref_store.cc",
+        "components/prefs/overlay_user_pref_store.cc",
+        "components/prefs/persistent_pref_store.cc",
+        "components/prefs/pref_change_registrar.cc",
+        "components/prefs/pref_member.cc",
+        "components/prefs/pref_notifier_impl.cc",
+        "components/prefs/pref_registry.cc",
+        "components/prefs/pref_registry_simple.cc",
+        "components/prefs/pref_service.cc",
+        "components/prefs/pref_service_factory.cc",
+        "components/prefs/pref_store.cc",
+        "components/prefs/pref_value_map.cc",
+        "components/prefs/pref_value_store.cc",
+        "components/prefs/scoped_user_pref_update.cc",
+        "components/prefs/segregated_pref_store.cc",
+        "components/prefs/value_map_pref_store.cc",
+        "components/prefs/writeable_pref_store.cc",
+    ],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+    ],
+    static_libs: [
+        "cronet_aml_base_base",
+    ],
+    generated_headers: [
+        "cronet_aml_base_debugging_buildflags",
+        "cronet_aml_base_logging_buildflags",
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_components_prefs_android_jni_headers",
+    ],
+    export_generated_headers: [
+        "cronet_aml_base_debugging_buildflags",
+        "cronet_aml_base_logging_buildflags",
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_components_prefs_android_jni_headers",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCOMPONENTS_PREFS_IMPLEMENTATION",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/abseil-cpp/",
+        "third_party/boringssl/src/include/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    header_libs: [
+        "jni_headers",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //crypto:buildflags
+genrule {
+    name: "cronet_aml_crypto_buildflags",
+    cmd: "echo '--flags USE_NSS_CERTS=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//crypto:buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "crypto/crypto_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //crypto:crypto
+cc_library_static {
+    name: "cronet_aml_crypto_crypto",
+    srcs: [
+        "crypto/aead.cc",
+        "crypto/ec_private_key.cc",
+        "crypto/ec_signature_creator.cc",
+        "crypto/ec_signature_creator_impl.cc",
+        "crypto/encryptor.cc",
+        "crypto/hkdf.cc",
+        "crypto/hmac.cc",
+        "crypto/openssl_util.cc",
+        "crypto/p224_spake.cc",
+        "crypto/random.cc",
+        "crypto/rsa_private_key.cc",
+        "crypto/secure_hash.cc",
+        "crypto/secure_util.cc",
+        "crypto/sha2.cc",
+        "crypto/signature_creator.cc",
+        "crypto/signature_verifier.cc",
+        "crypto/symmetric_key.cc",
+        "crypto/unexportable_key.cc",
+        "crypto/unexportable_key_metrics.cc",
+    ],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+    ],
+    static_libs: [
+        "cronet_aml_base_base",
+        "cronet_aml_base_third_party_dynamic_annotations_dynamic_annotations",
+        "libssl",
+    ],
+    generated_headers: [
+        "cronet_aml_crypto_buildflags",
+    ],
+    export_generated_headers: [
+        "cronet_aml_crypto_buildflags",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCRYPTO_IMPLEMENTATION",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/abseil-cpp/",
+        "third_party/boringssl/src/include/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //gn:default_deps
+cc_defaults {
+    name: "cronet_aml_defaults",
+    cflags: [
+        "-O2",
+        "-Wno-deprecated-non-prototype",
+        "-Wno-error=return-type",
+        "-Wno-macro-redefined",
+        "-Wno-missing-field-initializers",
+        "-Wno-non-virtual-dtor",
+        "-Wno-sign-compare",
+        "-Wno-sign-promo",
+        "-Wno-unused-parameter",
+        "-fvisibility=hidden",
+    ],
+    stl: "none",
+}
+
+// GN: //ipc:param_traits
+filegroup {
+    name: "cronet_aml_ipc_param_traits",
+}
+
+// GN: //gn:java
+java_library {
+    name: "cronet_aml_java",
+    srcs: [
+        "base/android/java/src/org/chromium/base/JniException.java",
+        "base/android/java/src/org/chromium/base/JniStaticTestMocker.java",
+        "base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java",
+        "base/android/java/src/org/chromium/base/annotations/AccessedByNative.java",
+        "base/android/java/src/org/chromium/base/annotations/CalledByNative.java",
+        "base/android/java/src/org/chromium/base/annotations/CalledByNativeForTesting.java",
+        "base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java",
+        "base/android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java",
+        "base/android/java/src/org/chromium/base/annotations/JNINamespace.java",
+        "base/android/java/src/org/chromium/base/annotations/JniIgnoreNatives.java",
+        "base/android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java",
+        "base/android/java/src/org/chromium/base/annotations/NativeMethods.java",
+        "build/android/java/src/org/chromium/build/annotations/AlwaysInline.java",
+        "build/android/java/src/org/chromium/build/annotations/CheckDiscard.java",
+        "build/android/java/src/org/chromium/build/annotations/DoNotClassMerge.java",
+        "build/android/java/src/org/chromium/build/annotations/DoNotInline.java",
+        "build/android/java/src/org/chromium/build/annotations/IdentifierNameString.java",
+        "build/android/java/src/org/chromium/build/annotations/MainDex.java",
+        "build/android/java/src/org/chromium/build/annotations/MockedInTests.java",
+        "build/android/java/src/org/chromium/build/annotations/UsedByReflection.java",
+        "url/android/java/src/org/chromium/url/IDNStringUtil.java",
+    ],
+}
+
+// GN: //net/base/registry_controlled_domains:registry_controlled_domains
+genrule {
+    name: "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains",
+    cmd: "$(location net/tools/dafsa/make_dafsa.py) --reverse " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names.gperf) " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names-reversed-inc.cc) " +
+         "&& python3 $(location net/tools/dafsa/make_dafsa.py) " +
+         "--reverse " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest1.gperf) " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest1-reversed-inc.cc) " +
+         "&& python3 $(location net/tools/dafsa/make_dafsa.py) " +
+         "--reverse " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest2.gperf) " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest2-reversed-inc.cc) " +
+         "&& python3 $(location net/tools/dafsa/make_dafsa.py) " +
+         "--reverse " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest3.gperf) " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest3-reversed-inc.cc) " +
+         "&& python3 $(location net/tools/dafsa/make_dafsa.py) " +
+         "--reverse " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest4.gperf) " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest4-reversed-inc.cc) " +
+         "&& python3 $(location net/tools/dafsa/make_dafsa.py) " +
+         "--reverse " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest5.gperf) " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest5-reversed-inc.cc) " +
+         "&& python3 $(location net/tools/dafsa/make_dafsa.py) " +
+         "--reverse " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest6.gperf) " +
+         "$(location net/base/registry_controlled_domains/effective_tld_names_unittest6-reversed-inc.cc)",
+    out: [
+        "net/base/registry_controlled_domains/effective_tld_names-reversed-inc.cc",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest1-reversed-inc.cc",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest2-reversed-inc.cc",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest3-reversed-inc.cc",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest4-reversed-inc.cc",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest5-reversed-inc.cc",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest6-reversed-inc.cc",
+    ],
+    tool_files: [
+        "net/base/registry_controlled_domains/effective_tld_names.gperf",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest1.gperf",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest2.gperf",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest3.gperf",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest4.gperf",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest5.gperf",
+        "net/base/registry_controlled_domains/effective_tld_names_unittest6.gperf",
+        "net/tools/dafsa/make_dafsa.py",
+    ],
+}
+
+// GN: //net:buildflags
+genrule {
+    name: "cronet_aml_net_buildflags",
+    cmd: "echo '--flags POSIX_BYPASS_MMAP=\"true\" DISABLE_FILE_SUPPORT=\"true\" ENABLE_MDNS=\"false\" ENABLE_REPORTING=\"true\" ENABLE_WEBSOCKETS=\"false\" INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST=\"false\" USE_KERBEROS=\"true\" USE_EXTERNAL_GSSAPI=\"false\" TRIAL_COMPARISON_CERT_VERIFIER_SUPPORTED=\"false\" CHROME_ROOT_STORE_SUPPORTED=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//net:buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "net/net_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //net/cert:root_store_proto_full
+genrule {
+    name: "cronet_aml_net_cert_root_store_proto_full_gen",
+    srcs: [
+        "net/cert/root_store.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/net/cert --cpp_out=lite=true:$(genDir)/external/chromium_org/net/cert/ $(in)",
+    out: [
+        "external/chromium_org/net/cert/root_store.pb.cc",
+    ],
+}
+
+// GN: //net/cert:root_store_proto_full
+genrule {
+    name: "cronet_aml_net_cert_root_store_proto_full_gen_headers",
+    srcs: [
+        "net/cert/root_store.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/net/cert --cpp_out=lite=true:$(genDir)/external/chromium_org/net/cert/ $(in)",
+    out: [
+        "external/chromium_org/net/cert/root_store.pb.h",
+    ],
+    export_include_dirs: [
+        ".",
+        "net/cert",
+        "protos",
+    ],
+}
+
+// GN: //net:constants
+filegroup {
+    name: "cronet_aml_net_constants",
+}
+
+// GN: //net/data/ssl/chrome_root_store:gen_root_store_inc
+genrule {
+    name: "cronet_aml_net_data_ssl_chrome_root_store_gen_root_store_inc",
+    cmd: "$(location build/gn_run_binary.py) clang_x64/root_store_tool " +
+         "--root-store " +
+         "../../net/data/ssl/chrome_root_store/root_store.textproto " +
+         "--certs " +
+         "../../net/data/ssl/chrome_root_store/root_store.certs " +
+         "--write-cpp-root-store " +
+         "gen/net/data/ssl/chrome_root_store/chrome-root-store-inc.cc " +
+         "--write-cpp-ev-roots " +
+         "gen/net/data/ssl/chrome_root_store/chrome-ev-roots-inc.cc",
+    out: [
+        "net/data/ssl/chrome_root_store/chrome-ev-roots-inc.cc",
+        "net/data/ssl/chrome_root_store/chrome-root-store-inc.cc",
+    ],
+    tool_files: [
+        "build/gn_run_binary.py",
+        "net/data/ssl/chrome_root_store/root_store.certs",
+        "net/data/ssl/chrome_root_store/root_store.textproto",
+    ],
+}
+
+// GN: //net/dns:dns
+filegroup {
+    name: "cronet_aml_net_dns_dns",
+    srcs: [
+        "net/dns/address_info.cc",
+        "net/dns/address_sorter_posix.cc",
+        "net/dns/context_host_resolver.cc",
+        "net/dns/dns_alias_utility.cc",
+        "net/dns/dns_client.cc",
+        "net/dns/dns_config.cc",
+        "net/dns/dns_config_service.cc",
+        "net/dns/dns_config_service_android.cc",
+        "net/dns/dns_hosts.cc",
+        "net/dns/dns_query.cc",
+        "net/dns/dns_reloader.cc",
+        "net/dns/dns_response.cc",
+        "net/dns/dns_response_result_extractor.cc",
+        "net/dns/dns_server_iterator.cc",
+        "net/dns/dns_session.cc",
+        "net/dns/dns_transaction.cc",
+        "net/dns/dns_udp_tracker.cc",
+        "net/dns/dns_util.cc",
+        "net/dns/host_cache.cc",
+        "net/dns/host_resolver.cc",
+        "net/dns/host_resolver_manager.cc",
+        "net/dns/host_resolver_mdns_listener_impl.cc",
+        "net/dns/host_resolver_mdns_task.cc",
+        "net/dns/host_resolver_nat64_task.cc",
+        "net/dns/host_resolver_proc.cc",
+        "net/dns/host_resolver_system_task.cc",
+        "net/dns/https_record_rdata.cc",
+        "net/dns/httpssvc_metrics.cc",
+        "net/dns/mapped_host_resolver.cc",
+        "net/dns/nsswitch_reader.cc",
+        "net/dns/opt_record_rdata.cc",
+        "net/dns/record_parsed.cc",
+        "net/dns/record_rdata.cc",
+        "net/dns/resolve_context.cc",
+        "net/dns/serial_worker.cc",
+        "net/dns/system_dns_config_change_notifier.cc",
+        "net/dns/test_dns_config_service.cc",
+    ],
+}
+
+// GN: //net/dns:dns_client
+filegroup {
+    name: "cronet_aml_net_dns_dns_client",
+}
+
+// GN: //net/dns:host_resolver
+filegroup {
+    name: "cronet_aml_net_dns_host_resolver",
+}
+
+// GN: //net/dns:host_resolver_manager
+filegroup {
+    name: "cronet_aml_net_dns_host_resolver_manager",
+}
+
+// GN: //net/dns:mdns_client
+filegroup {
+    name: "cronet_aml_net_dns_mdns_client",
+}
+
+// GN: //net/dns/public:public
+filegroup {
+    name: "cronet_aml_net_dns_public_public",
+    srcs: [
+        "net/dns/public/dns_config_overrides.cc",
+        "net/dns/public/dns_over_https_config.cc",
+        "net/dns/public/dns_over_https_server_config.cc",
+        "net/dns/public/dns_query_type.cc",
+        "net/dns/public/doh_provider_entry.cc",
+        "net/dns/public/host_resolver_results.cc",
+        "net/dns/public/resolve_error_info.cc",
+        "net/dns/public/util.cc",
+    ],
+}
+
+// GN: //net/http:transport_security_state_generated_files
+filegroup {
+    name: "cronet_aml_net_http_transport_security_state_generated_files",
+    srcs: [
+        "net/http/transport_security_state.cc",
+    ],
+}
+
+// GN: //net:ios_cronet_buildflags
+genrule {
+    name: "cronet_aml_net_ios_cronet_buildflags",
+    cmd: "echo '--flags CRONET_BUILD=\"false\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//net:ios_cronet_buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "net/socket/ios_cronet_buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //net:isolation_info_proto
+genrule {
+    name: "cronet_aml_net_isolation_info_proto_gen",
+    srcs: [
+        "net/base/isolation_info.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/net/base --cpp_out=lite=true:$(genDir)/external/chromium_org/net/base/ $(in)",
+    out: [
+        "external/chromium_org/net/base/isolation_info.pb.cc",
+    ],
+}
+
+// GN: //net:isolation_info_proto
+genrule {
+    name: "cronet_aml_net_isolation_info_proto_gen_headers",
+    srcs: [
+        "net/base/isolation_info.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/net/base --cpp_out=lite=true:$(genDir)/external/chromium_org/net/base/ $(in)",
+    out: [
+        "external/chromium_org/net/base/isolation_info.pb.h",
+    ],
+    export_include_dirs: [
+        ".",
+        "net/base",
+        "protos",
+    ],
+}
+
+// GN: //net:net
+cc_library_static {
+    name: "cronet_aml_net_net",
+    srcs: [
+        ":cronet_aml_net_constants",
+        ":cronet_aml_net_dns_dns",
+        ":cronet_aml_net_dns_dns_client",
+        ":cronet_aml_net_dns_host_resolver",
+        ":cronet_aml_net_dns_host_resolver_manager",
+        ":cronet_aml_net_dns_mdns_client",
+        ":cronet_aml_net_dns_public_public",
+        ":cronet_aml_net_http_transport_security_state_generated_files",
+        ":cronet_aml_net_isolation_info_proto_gen",
+        ":cronet_aml_net_net_deps",
+        ":cronet_aml_net_net_export_header",
+        ":cronet_aml_net_net_nqe_proto_gen",
+        ":cronet_aml_net_net_public_deps",
+        ":cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen",
+        ":cronet_aml_net_traffic_annotation_traffic_annotation",
+        "net/android/android_http_util.cc",
+        "net/android/cert_verify_result_android.cc",
+        "net/android/gurl_utils.cc",
+        "net/android/http_auth_negotiate_android.cc",
+        "net/android/keystore.cc",
+        "net/android/network_change_notifier_android.cc",
+        "net/android/network_change_notifier_delegate_android.cc",
+        "net/android/network_change_notifier_factory_android.cc",
+        "net/android/network_library.cc",
+        "net/android/radio_activity_tracker.cc",
+        "net/android/traffic_stats.cc",
+        "net/base/address_family.cc",
+        "net/base/address_list.cc",
+        "net/base/address_tracker_linux.cc",
+        "net/base/auth.cc",
+        "net/base/backoff_entry.cc",
+        "net/base/backoff_entry_serializer.cc",
+        "net/base/cache_metrics.cc",
+        "net/base/chunked_upload_data_stream.cc",
+        "net/base/connection_endpoint_metadata.cc",
+        "net/base/data_url.cc",
+        "net/base/datagram_buffer.cc",
+        "net/base/elements_upload_data_stream.cc",
+        "net/base/features.cc",
+        "net/base/file_stream.cc",
+        "net/base/file_stream_context.cc",
+        "net/base/file_stream_context_posix.cc",
+        "net/base/filename_util.cc",
+        "net/base/filename_util_internal.cc",
+        "net/base/hash_value.cc",
+        "net/base/hex_utils.cc",
+        "net/base/host_mapping_rules.cc",
+        "net/base/host_port_pair.cc",
+        "net/base/io_buffer.cc",
+        "net/base/ip_address.cc",
+        "net/base/ip_endpoint.cc",
+        "net/base/isolation_info.cc",
+        "net/base/load_timing_info.cc",
+        "net/base/logging_network_change_observer.cc",
+        "net/base/lookup_string_in_fixed_set.cc",
+        "net/base/mime_sniffer.cc",
+        "net/base/mime_util.cc",
+        "net/base/net_errors.cc",
+        "net/base/net_errors_posix.cc",
+        "net/base/net_module.cc",
+        "net/base/net_string_util_icu_alternatives_android.cc",
+        "net/base/network_activity_monitor.cc",
+        "net/base/network_anonymization_key.cc",
+        "net/base/network_change_notifier.cc",
+        "net/base/network_change_notifier_posix.cc",
+        "net/base/network_delegate.cc",
+        "net/base/network_delegate_impl.cc",
+        "net/base/network_interfaces.cc",
+        "net/base/network_interfaces_getifaddrs.cc",
+        "net/base/network_interfaces_getifaddrs_android.cc",
+        "net/base/network_interfaces_linux.cc",
+        "net/base/network_interfaces_posix.cc",
+        "net/base/network_isolation_key.cc",
+        "net/base/parse_number.cc",
+        "net/base/platform_mime_util_linux.cc",
+        "net/base/port_util.cc",
+        "net/base/prioritized_dispatcher.cc",
+        "net/base/prioritized_task_runner.cc",
+        "net/base/privacy_mode.cc",
+        "net/base/proxy_server.cc",
+        "net/base/proxy_string_util.cc",
+        "net/base/registry_controlled_domains/registry_controlled_domain.cc",
+        "net/base/request_priority.cc",
+        "net/base/scheme_host_port_matcher.cc",
+        "net/base/scheme_host_port_matcher_rule.cc",
+        "net/base/schemeful_site.cc",
+        "net/base/sockaddr_storage.cc",
+        "net/base/sockaddr_util_posix.cc",
+        "net/base/transport_info.cc",
+        "net/base/upload_bytes_element_reader.cc",
+        "net/base/upload_data_stream.cc",
+        "net/base/upload_element_reader.cc",
+        "net/base/upload_file_element_reader.cc",
+        "net/base/url_util.cc",
+        "net/cert/asn1_util.cc",
+        "net/cert/caching_cert_verifier.cc",
+        "net/cert/cert_and_ct_verifier.cc",
+        "net/cert/cert_database.cc",
+        "net/cert/cert_status_flags.cc",
+        "net/cert/cert_verifier.cc",
+        "net/cert/cert_verify_proc.cc",
+        "net/cert/cert_verify_proc_android.cc",
+        "net/cert/cert_verify_proc_builtin.cc",
+        "net/cert/cert_verify_result.cc",
+        "net/cert/coalescing_cert_verifier.cc",
+        "net/cert/crl_set.cc",
+        "net/cert/ct_log_response_parser.cc",
+        "net/cert/ct_log_verifier.cc",
+        "net/cert/ct_log_verifier_util.cc",
+        "net/cert/ct_objects_extractor.cc",
+        "net/cert/ct_policy_enforcer.cc",
+        "net/cert/ct_sct_to_string.cc",
+        "net/cert/ct_serialization.cc",
+        "net/cert/ct_signed_certificate_timestamp_log_param.cc",
+        "net/cert/do_nothing_ct_verifier.cc",
+        "net/cert/ev_root_ca_metadata.cc",
+        "net/cert/internal/cert_issuer_source_aia.cc",
+        "net/cert/internal/revocation_checker.cc",
+        "net/cert/internal/system_trust_store.cc",
+        "net/cert/known_roots.cc",
+        "net/cert/merkle_audit_proof.cc",
+        "net/cert/merkle_consistency_proof.cc",
+        "net/cert/merkle_tree_leaf.cc",
+        "net/cert/multi_log_ct_verifier.cc",
+        "net/cert/multi_threaded_cert_verifier.cc",
+        "net/cert/ocsp_verify_result.cc",
+        "net/cert/pem.cc",
+        "net/cert/pki/cert_error_id.cc",
+        "net/cert/pki/cert_error_params.cc",
+        "net/cert/pki/cert_errors.cc",
+        "net/cert/pki/cert_issuer_source_static.cc",
+        "net/cert/pki/certificate_policies.cc",
+        "net/cert/pki/common_cert_errors.cc",
+        "net/cert/pki/crl.cc",
+        "net/cert/pki/extended_key_usage.cc",
+        "net/cert/pki/general_names.cc",
+        "net/cert/pki/name_constraints.cc",
+        "net/cert/pki/ocsp.cc",
+        "net/cert/pki/parse_certificate.cc",
+        "net/cert/pki/parse_name.cc",
+        "net/cert/pki/parsed_certificate.cc",
+        "net/cert/pki/path_builder.cc",
+        "net/cert/pki/revocation_util.cc",
+        "net/cert/pki/signature_algorithm.cc",
+        "net/cert/pki/simple_path_builder_delegate.cc",
+        "net/cert/pki/string_util.cc",
+        "net/cert/pki/trust_store.cc",
+        "net/cert/pki/trust_store_collection.cc",
+        "net/cert/pki/trust_store_in_memory.cc",
+        "net/cert/pki/verify_certificate_chain.cc",
+        "net/cert/pki/verify_name_match.cc",
+        "net/cert/pki/verify_signed_data.cc",
+        "net/cert/sct_status_flags.cc",
+        "net/cert/signed_certificate_timestamp.cc",
+        "net/cert/signed_certificate_timestamp_and_status.cc",
+        "net/cert/signed_tree_head.cc",
+        "net/cert/symantec_certs.cc",
+        "net/cert/test_root_certs.cc",
+        "net/cert/test_root_certs_android.cc",
+        "net/cert/trial_comparison_cert_verifier_util.cc",
+        "net/cert/x509_cert_types.cc",
+        "net/cert/x509_certificate.cc",
+        "net/cert/x509_certificate_net_log_param.cc",
+        "net/cert/x509_util.cc",
+        "net/cert/x509_util_android.cc",
+        "net/cert_net/cert_net_fetcher_url_request.cc",
+        "net/cookies/canonical_cookie.cc",
+        "net/cookies/cookie_access_delegate.cc",
+        "net/cookies/cookie_access_result.cc",
+        "net/cookies/cookie_change_dispatcher.cc",
+        "net/cookies/cookie_constants.cc",
+        "net/cookies/cookie_deletion_info.cc",
+        "net/cookies/cookie_inclusion_status.cc",
+        "net/cookies/cookie_monster.cc",
+        "net/cookies/cookie_monster_change_dispatcher.cc",
+        "net/cookies/cookie_monster_netlog_params.cc",
+        "net/cookies/cookie_options.cc",
+        "net/cookies/cookie_partition_key.cc",
+        "net/cookies/cookie_partition_key_collection.cc",
+        "net/cookies/cookie_store.cc",
+        "net/cookies/cookie_util.cc",
+        "net/cookies/parsed_cookie.cc",
+        "net/cookies/site_for_cookies.cc",
+        "net/cookies/static_cookie_policy.cc",
+        "net/der/encode_values.cc",
+        "net/der/input.cc",
+        "net/der/parse_values.cc",
+        "net/der/parser.cc",
+        "net/der/tag.cc",
+        "net/disk_cache/backend_cleanup_tracker.cc",
+        "net/disk_cache/blockfile/addr.cc",
+        "net/disk_cache/blockfile/backend_impl.cc",
+        "net/disk_cache/blockfile/bitmap.cc",
+        "net/disk_cache/blockfile/block_files.cc",
+        "net/disk_cache/blockfile/disk_format.cc",
+        "net/disk_cache/blockfile/entry_impl.cc",
+        "net/disk_cache/blockfile/eviction.cc",
+        "net/disk_cache/blockfile/file.cc",
+        "net/disk_cache/blockfile/file_lock.cc",
+        "net/disk_cache/blockfile/file_posix.cc",
+        "net/disk_cache/blockfile/in_flight_backend_io.cc",
+        "net/disk_cache/blockfile/in_flight_io.cc",
+        "net/disk_cache/blockfile/mapped_file.cc",
+        "net/disk_cache/blockfile/mapped_file_bypass_mmap_posix.cc",
+        "net/disk_cache/blockfile/rankings.cc",
+        "net/disk_cache/blockfile/sparse_control.cc",
+        "net/disk_cache/blockfile/stats.cc",
+        "net/disk_cache/cache_util.cc",
+        "net/disk_cache/cache_util_posix.cc",
+        "net/disk_cache/disk_cache.cc",
+        "net/disk_cache/memory/mem_backend_impl.cc",
+        "net/disk_cache/memory/mem_entry_impl.cc",
+        "net/disk_cache/net_log_parameters.cc",
+        "net/disk_cache/simple/post_doom_waiter.cc",
+        "net/disk_cache/simple/simple_backend_impl.cc",
+        "net/disk_cache/simple/simple_entry_format.cc",
+        "net/disk_cache/simple/simple_entry_impl.cc",
+        "net/disk_cache/simple/simple_entry_operation.cc",
+        "net/disk_cache/simple/simple_file_enumerator.cc",
+        "net/disk_cache/simple/simple_file_tracker.cc",
+        "net/disk_cache/simple/simple_index.cc",
+        "net/disk_cache/simple/simple_index_file.cc",
+        "net/disk_cache/simple/simple_net_log_parameters.cc",
+        "net/disk_cache/simple/simple_synchronous_entry.cc",
+        "net/disk_cache/simple/simple_util.cc",
+        "net/disk_cache/simple/simple_util_posix.cc",
+        "net/disk_cache/simple/simple_version_upgrade.cc",
+        "net/filter/brotli_source_stream.cc",
+        "net/filter/filter_source_stream.cc",
+        "net/filter/gzip_header.cc",
+        "net/filter/gzip_source_stream.cc",
+        "net/filter/source_stream.cc",
+        "net/first_party_sets/addition_overlaps_union_find.cc",
+        "net/first_party_sets/first_party_set_entry.cc",
+        "net/first_party_sets/first_party_set_metadata.cc",
+        "net/first_party_sets/first_party_sets_cache_filter.cc",
+        "net/first_party_sets/first_party_sets_context_config.cc",
+        "net/first_party_sets/global_first_party_sets.cc",
+        "net/first_party_sets/same_party_context.cc",
+        "net/http/alternative_service.cc",
+        "net/http/bidirectional_stream.cc",
+        "net/http/bidirectional_stream_impl.cc",
+        "net/http/bidirectional_stream_request_info.cc",
+        "net/http/broken_alternative_services.cc",
+        "net/http/http_auth.cc",
+        "net/http/http_auth_cache.cc",
+        "net/http/http_auth_challenge_tokenizer.cc",
+        "net/http/http_auth_controller.cc",
+        "net/http/http_auth_filter.cc",
+        "net/http/http_auth_handler.cc",
+        "net/http/http_auth_handler_basic.cc",
+        "net/http/http_auth_handler_digest.cc",
+        "net/http/http_auth_handler_factory.cc",
+        "net/http/http_auth_handler_negotiate.cc",
+        "net/http/http_auth_handler_ntlm.cc",
+        "net/http/http_auth_handler_ntlm_portable.cc",
+        "net/http/http_auth_multi_round_parse.cc",
+        "net/http/http_auth_ntlm_mechanism.cc",
+        "net/http/http_auth_preferences.cc",
+        "net/http/http_auth_scheme.cc",
+        "net/http/http_basic_state.cc",
+        "net/http/http_basic_stream.cc",
+        "net/http/http_byte_range.cc",
+        "net/http/http_cache.cc",
+        "net/http/http_cache_lookup_manager.cc",
+        "net/http/http_cache_transaction.cc",
+        "net/http/http_cache_writers.cc",
+        "net/http/http_chunked_decoder.cc",
+        "net/http/http_content_disposition.cc",
+        "net/http/http_log_util.cc",
+        "net/http/http_network_layer.cc",
+        "net/http/http_network_session.cc",
+        "net/http/http_network_session_peer.cc",
+        "net/http/http_network_transaction.cc",
+        "net/http/http_proxy_client_socket.cc",
+        "net/http/http_proxy_connect_job.cc",
+        "net/http/http_raw_request_headers.cc",
+        "net/http/http_request_headers.cc",
+        "net/http/http_request_info.cc",
+        "net/http/http_response_body_drainer.cc",
+        "net/http/http_response_headers.cc",
+        "net/http/http_response_info.cc",
+        "net/http/http_security_headers.cc",
+        "net/http/http_server_properties.cc",
+        "net/http/http_server_properties_manager.cc",
+        "net/http/http_status_code.cc",
+        "net/http/http_stream_factory.cc",
+        "net/http/http_stream_factory_job.cc",
+        "net/http/http_stream_factory_job_controller.cc",
+        "net/http/http_stream_parser.cc",
+        "net/http/http_stream_request.cc",
+        "net/http/http_util.cc",
+        "net/http/http_vary_data.cc",
+        "net/http/partial_data.cc",
+        "net/http/proxy_client_socket.cc",
+        "net/http/proxy_fallback.cc",
+        "net/http/transport_security_persister.cc",
+        "net/http/transport_security_state_source.cc",
+        "net/http/url_security_manager.cc",
+        "net/http/url_security_manager_posix.cc",
+        "net/http/webfonts_histogram.cc",
+        "net/log/file_net_log_observer.cc",
+        "net/log/net_log.cc",
+        "net/log/net_log_capture_mode.cc",
+        "net/log/net_log_entry.cc",
+        "net/log/net_log_event_type.cc",
+        "net/log/net_log_source.cc",
+        "net/log/net_log_util.cc",
+        "net/log/net_log_values.cc",
+        "net/log/net_log_with_source.cc",
+        "net/log/trace_net_log_observer.cc",
+        "net/network_error_logging/network_error_logging_service.cc",
+        "net/nqe/cached_network_quality.cc",
+        "net/nqe/effective_connection_type.cc",
+        "net/nqe/event_creator.cc",
+        "net/nqe/network_id.cc",
+        "net/nqe/network_qualities_prefs_manager.cc",
+        "net/nqe/network_quality.cc",
+        "net/nqe/network_quality_estimator.cc",
+        "net/nqe/network_quality_estimator_params.cc",
+        "net/nqe/network_quality_estimator_util.cc",
+        "net/nqe/network_quality_observation.cc",
+        "net/nqe/network_quality_store.cc",
+        "net/nqe/observation_buffer.cc",
+        "net/nqe/pref_names.cc",
+        "net/nqe/socket_watcher.cc",
+        "net/nqe/socket_watcher_factory.cc",
+        "net/nqe/throughput_analyzer.cc",
+        "net/ntlm/ntlm.cc",
+        "net/ntlm/ntlm_buffer_reader.cc",
+        "net/ntlm/ntlm_buffer_writer.cc",
+        "net/ntlm/ntlm_client.cc",
+        "net/ntlm/ntlm_constants.cc",
+        "net/proxy_resolution/configured_proxy_resolution_request.cc",
+        "net/proxy_resolution/configured_proxy_resolution_service.cc",
+        "net/proxy_resolution/dhcp_pac_file_fetcher.cc",
+        "net/proxy_resolution/multi_threaded_proxy_resolver.cc",
+        "net/proxy_resolution/network_delegate_error_observer.cc",
+        "net/proxy_resolution/pac_file_data.cc",
+        "net/proxy_resolution/pac_file_decider.cc",
+        "net/proxy_resolution/pac_file_fetcher.cc",
+        "net/proxy_resolution/pac_file_fetcher_impl.cc",
+        "net/proxy_resolution/polling_proxy_config_service.cc",
+        "net/proxy_resolution/proxy_bypass_rules.cc",
+        "net/proxy_resolution/proxy_config.cc",
+        "net/proxy_resolution/proxy_config_service.cc",
+        "net/proxy_resolution/proxy_config_service_android.cc",
+        "net/proxy_resolution/proxy_config_service_fixed.cc",
+        "net/proxy_resolution/proxy_config_with_annotation.cc",
+        "net/proxy_resolution/proxy_info.cc",
+        "net/proxy_resolution/proxy_list.cc",
+        "net/proxy_resolution/proxy_resolver_factory.cc",
+        "net/quic/bidirectional_stream_quic_impl.cc",
+        "net/quic/crypto/proof_source_chromium.cc",
+        "net/quic/crypto/proof_verifier_chromium.cc",
+        "net/quic/dedicated_web_transport_http3_client.cc",
+        "net/quic/network_connection.cc",
+        "net/quic/platform/impl/quic_chromium_clock.cc",
+        "net/quic/properties_based_quic_server_info.cc",
+        "net/quic/quic_address_mismatch.cc",
+        "net/quic/quic_chromium_alarm_factory.cc",
+        "net/quic/quic_chromium_client_session.cc",
+        "net/quic/quic_chromium_client_stream.cc",
+        "net/quic/quic_chromium_connection_helper.cc",
+        "net/quic/quic_chromium_packet_reader.cc",
+        "net/quic/quic_chromium_packet_writer.cc",
+        "net/quic/quic_clock_skew_detector.cc",
+        "net/quic/quic_connection_logger.cc",
+        "net/quic/quic_connectivity_monitor.cc",
+        "net/quic/quic_context.cc",
+        "net/quic/quic_crypto_client_config_handle.cc",
+        "net/quic/quic_crypto_client_stream_factory.cc",
+        "net/quic/quic_event_logger.cc",
+        "net/quic/quic_http3_logger.cc",
+        "net/quic/quic_http_stream.cc",
+        "net/quic/quic_http_utils.cc",
+        "net/quic/quic_proxy_client_socket.cc",
+        "net/quic/quic_server_info.cc",
+        "net/quic/quic_session_key.cc",
+        "net/quic/quic_stream_factory.cc",
+        "net/quic/set_quic_flag.cc",
+        "net/quic/web_transport_client.cc",
+        "net/quic/web_transport_error.cc",
+        "net/reporting/reporting_browsing_data_remover.cc",
+        "net/reporting/reporting_cache.cc",
+        "net/reporting/reporting_cache_impl.cc",
+        "net/reporting/reporting_cache_observer.cc",
+        "net/reporting/reporting_context.cc",
+        "net/reporting/reporting_delegate.cc",
+        "net/reporting/reporting_delivery_agent.cc",
+        "net/reporting/reporting_endpoint.cc",
+        "net/reporting/reporting_endpoint_manager.cc",
+        "net/reporting/reporting_garbage_collector.cc",
+        "net/reporting/reporting_header_parser.cc",
+        "net/reporting/reporting_network_change_observer.cc",
+        "net/reporting/reporting_policy.cc",
+        "net/reporting/reporting_report.cc",
+        "net/reporting/reporting_service.cc",
+        "net/reporting/reporting_uploader.cc",
+        "net/socket/client_socket_factory.cc",
+        "net/socket/client_socket_handle.cc",
+        "net/socket/client_socket_pool.cc",
+        "net/socket/client_socket_pool_manager.cc",
+        "net/socket/client_socket_pool_manager_impl.cc",
+        "net/socket/connect_job.cc",
+        "net/socket/connect_job_factory.cc",
+        "net/socket/network_binding_client_socket_factory.cc",
+        "net/socket/next_proto.cc",
+        "net/socket/server_socket.cc",
+        "net/socket/socket.cc",
+        "net/socket/socket_bio_adapter.cc",
+        "net/socket/socket_descriptor.cc",
+        "net/socket/socket_net_log_params.cc",
+        "net/socket/socket_options.cc",
+        "net/socket/socket_posix.cc",
+        "net/socket/socket_tag.cc",
+        "net/socket/socks5_client_socket.cc",
+        "net/socket/socks_client_socket.cc",
+        "net/socket/socks_connect_job.cc",
+        "net/socket/ssl_client_socket.cc",
+        "net/socket/ssl_client_socket_impl.cc",
+        "net/socket/ssl_connect_job.cc",
+        "net/socket/ssl_server_socket_impl.cc",
+        "net/socket/stream_socket.cc",
+        "net/socket/tcp_client_socket.cc",
+        "net/socket/tcp_server_socket.cc",
+        "net/socket/tcp_socket_posix.cc",
+        "net/socket/transport_client_socket.cc",
+        "net/socket/transport_client_socket_pool.cc",
+        "net/socket/transport_connect_job.cc",
+        "net/socket/transport_connect_sub_job.cc",
+        "net/socket/udp_client_socket.cc",
+        "net/socket/udp_net_log_parameters.cc",
+        "net/socket/udp_server_socket.cc",
+        "net/socket/udp_socket_global_limits.cc",
+        "net/socket/udp_socket_posix.cc",
+        "net/socket/unix_domain_client_socket_posix.cc",
+        "net/socket/unix_domain_server_socket_posix.cc",
+        "net/socket/websocket_endpoint_lock_manager.cc",
+        "net/socket/websocket_transport_client_socket_pool.cc",
+        "net/spdy/alps_decoder.cc",
+        "net/spdy/bidirectional_stream_spdy_impl.cc",
+        "net/spdy/buffered_spdy_framer.cc",
+        "net/spdy/header_coalescer.cc",
+        "net/spdy/http2_priority_dependencies.cc",
+        "net/spdy/http2_push_promise_index.cc",
+        "net/spdy/multiplexed_http_stream.cc",
+        "net/spdy/multiplexed_session.cc",
+        "net/spdy/spdy_buffer.cc",
+        "net/spdy/spdy_buffer_producer.cc",
+        "net/spdy/spdy_http_stream.cc",
+        "net/spdy/spdy_http_utils.cc",
+        "net/spdy/spdy_log_util.cc",
+        "net/spdy/spdy_proxy_client_socket.cc",
+        "net/spdy/spdy_read_queue.cc",
+        "net/spdy/spdy_session.cc",
+        "net/spdy/spdy_session_key.cc",
+        "net/spdy/spdy_session_pool.cc",
+        "net/spdy/spdy_stream.cc",
+        "net/spdy/spdy_write_queue.cc",
+        "net/ssl/cert_compression.cc",
+        "net/ssl/client_cert_identity.cc",
+        "net/ssl/openssl_ssl_util.cc",
+        "net/ssl/ssl_cert_request_info.cc",
+        "net/ssl/ssl_cipher_suite_names.cc",
+        "net/ssl/ssl_client_auth_cache.cc",
+        "net/ssl/ssl_client_session_cache.cc",
+        "net/ssl/ssl_config.cc",
+        "net/ssl/ssl_config_service.cc",
+        "net/ssl/ssl_config_service_defaults.cc",
+        "net/ssl/ssl_info.cc",
+        "net/ssl/ssl_key_logger.cc",
+        "net/ssl/ssl_key_logger_impl.cc",
+        "net/ssl/ssl_platform_key_android.cc",
+        "net/ssl/ssl_platform_key_util.cc",
+        "net/ssl/ssl_private_key.cc",
+        "net/ssl/ssl_server_config.cc",
+        "net/ssl/threaded_ssl_private_key.cc",
+        "net/url_request/redirect_info.cc",
+        "net/url_request/redirect_util.cc",
+        "net/url_request/report_sender.cc",
+        "net/url_request/static_http_user_agent_settings.cc",
+        "net/url_request/url_request.cc",
+        "net/url_request/url_request_context.cc",
+        "net/url_request/url_request_context_builder.cc",
+        "net/url_request/url_request_context_getter.cc",
+        "net/url_request/url_request_error_job.cc",
+        "net/url_request/url_request_filter.cc",
+        "net/url_request/url_request_http_job.cc",
+        "net/url_request/url_request_interceptor.cc",
+        "net/url_request/url_request_job.cc",
+        "net/url_request/url_request_job_factory.cc",
+        "net/url_request/url_request_netlog_params.cc",
+        "net/url_request/url_request_redirect_job.cc",
+        "net/url_request/url_request_throttler_entry.cc",
+        "net/url_request/url_request_throttler_manager.cc",
+        "net/url_request/view_cache_helper.cc",
+        "net/url_request/websocket_handshake_userdata_key.cc",
+    ],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+        "libprotobuf-cpp-lite",
+    ],
+    static_libs: [
+        "cronet_aml_base_base",
+        "cronet_aml_base_third_party_dynamic_annotations_dynamic_annotations",
+        "cronet_aml_crypto_crypto",
+        "cronet_aml_net_preload_decoder",
+        "cronet_aml_net_third_party_quiche_quiche",
+        "cronet_aml_net_uri_template",
+        "cronet_aml_third_party_brotli_dec",
+        "cronet_aml_third_party_zlib_zlib",
+        "cronet_aml_url_url",
+        "libssl",
+    ],
+    whole_static_libs: [
+        "cronet_aml_base_base",
+        "cronet_aml_crypto_crypto",
+        "cronet_aml_net_third_party_quiche_quiche",
+        "libssl",
+    ],
+    generated_headers: [
+        "cronet_aml_base_debugging_buildflags",
+        "cronet_aml_base_logging_buildflags",
+        "cronet_aml_build_branding_buildflags",
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains",
+        "cronet_aml_net_buildflags",
+        "cronet_aml_net_ios_cronet_buildflags",
+        "cronet_aml_net_isolation_info_proto_gen_headers",
+        "cronet_aml_net_net_jni_headers",
+        "cronet_aml_net_net_nqe_proto_gen_headers",
+        "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_headers",
+        "cronet_aml_url_buildflags",
+    ],
+    export_generated_headers: [
+        "cronet_aml_base_debugging_buildflags",
+        "cronet_aml_base_logging_buildflags",
+        "cronet_aml_build_branding_buildflags",
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains",
+        "cronet_aml_net_buildflags",
+        "cronet_aml_net_ios_cronet_buildflags",
+        "cronet_aml_net_isolation_info_proto_gen_headers",
+        "cronet_aml_net_net_jni_headers",
+        "cronet_aml_net_net_nqe_proto_gen_headers",
+        "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_headers",
+        "cronet_aml_url_buildflags",
+    ],
+    export_static_lib_headers: [
+        "cronet_aml_crypto_crypto",
+        "cronet_aml_net_third_party_quiche_quiche",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DENABLE_BUILT_IN_DNS",
+        "-DGOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0",
+        "-DGOOGLE_PROTOBUF_NO_RTTI",
+        "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
+        "-DHAVE_PTHREAD",
+        "-DHAVE_SYS_UIO_H",
+        "-DNET_IMPLEMENTATION",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "net/third_party/quiche/overrides/",
+        "net/third_party/quiche/src/",
+        "net/third_party/quiche/src/quiche/common/platform/default/",
+        "third_party/abseil-cpp/",
+        "third_party/boringssl/src/include/",
+        "third_party/brotli/include/",
+        "third_party/zlib/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    header_libs: [
+        "jni_headers",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //net:net_deps
+filegroup {
+    name: "cronet_aml_net_net_deps",
+}
+
+// GN: //net:net_export_header
+filegroup {
+    name: "cronet_aml_net_net_export_header",
+}
+
+// GN: //net:net_jni_headers
+genrule {
+    name: "cronet_aml_net_net_jni_headers",
+    srcs: [
+        "net/android/java/src/org/chromium/net/AndroidCertVerifyResult.java",
+        "net/android/java/src/org/chromium/net/AndroidKeyStore.java",
+        "net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java",
+        "net/android/java/src/org/chromium/net/AndroidTrafficStats.java",
+        "net/android/java/src/org/chromium/net/DnsStatus.java",
+        "net/android/java/src/org/chromium/net/GURLUtils.java",
+        "net/android/java/src/org/chromium/net/HttpNegotiateAuthenticator.java",
+        "net/android/java/src/org/chromium/net/HttpUtil.java",
+        "net/android/java/src/org/chromium/net/NetStringUtil.java",
+        "net/android/java/src/org/chromium/net/NetworkActiveNotifier.java",
+        "net/android/java/src/org/chromium/net/NetworkChangeNotifier.java",
+        "net/android/java/src/org/chromium/net/ProxyChangeListener.java",
+        "net/android/java/src/org/chromium/net/X509Util.java",
+    ],
+    cmd: "$(location base/android/jni_generator/jni_generator.py) --ptr_type " +
+         "long " +
+         " " +
+         " " +
+         "--output_dir " +
+         "$(genDir)/net/net_jni_headers " +
+         "--includes " +
+         "base/android/jni_generator/jni_generator_helper.h " +
+         "--use_proxy_hash " +
+         "--output_name " +
+         "AndroidCertVerifyResult_jni.h " +
+         "--output_name " +
+         "AndroidKeyStore_jni.h " +
+         "--output_name " +
+         "AndroidNetworkLibrary_jni.h " +
+         "--output_name " +
+         "AndroidTrafficStats_jni.h " +
+         "--output_name " +
+         "DnsStatus_jni.h " +
+         "--output_name " +
+         "GURLUtils_jni.h " +
+         "--output_name " +
+         "HttpNegotiateAuthenticator_jni.h " +
+         "--output_name " +
+         "HttpUtil_jni.h " +
+         "--output_name " +
+         "NetStringUtil_jni.h " +
+         "--output_name " +
+         "NetworkActiveNotifier_jni.h " +
+         "--output_name " +
+         "NetworkChangeNotifier_jni.h " +
+         "--output_name " +
+         "ProxyChangeListener_jni.h " +
+         "--output_name " +
+         "X509Util_jni.h " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/AndroidCertVerifyResult.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/AndroidKeyStore.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/AndroidTrafficStats.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/DnsStatus.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/GURLUtils.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/HttpNegotiateAuthenticator.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/HttpUtil.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/NetStringUtil.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/NetworkActiveNotifier.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/NetworkChangeNotifier.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/ProxyChangeListener.java) " +
+         "--input_file " +
+         "$(location net/android/java/src/org/chromium/net/X509Util.java)",
+    out: [
+        "net/net_jni_headers/AndroidCertVerifyResult_jni.h",
+        "net/net_jni_headers/AndroidKeyStore_jni.h",
+        "net/net_jni_headers/AndroidNetworkLibrary_jni.h",
+        "net/net_jni_headers/AndroidTrafficStats_jni.h",
+        "net/net_jni_headers/DnsStatus_jni.h",
+        "net/net_jni_headers/GURLUtils_jni.h",
+        "net/net_jni_headers/HttpNegotiateAuthenticator_jni.h",
+        "net/net_jni_headers/HttpUtil_jni.h",
+        "net/net_jni_headers/NetStringUtil_jni.h",
+        "net/net_jni_headers/NetworkActiveNotifier_jni.h",
+        "net/net_jni_headers/NetworkChangeNotifier_jni.h",
+        "net/net_jni_headers/ProxyChangeListener_jni.h",
+        "net/net_jni_headers/X509Util_jni.h",
+    ],
+    tool_files: [
+        "base/android/jni_generator/android_jar.classes",
+        "base/android/jni_generator/jni_generator.py",
+        "build/android/gyp/util/__init__.py",
+        "build/android/gyp/util/build_utils.py",
+        "build/gn_helpers.py",
+    ],
+}
+
+// GN: //net:net_nqe_proto
+genrule {
+    name: "cronet_aml_net_net_nqe_proto_gen",
+    srcs: [
+        "net/nqe/proto/network_id_proto.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/net/nqe/proto --cpp_out=lite=true:$(genDir)/external/chromium_org/net/nqe/proto/ $(in)",
+    out: [
+        "external/chromium_org/net/nqe/proto/network_id_proto.pb.cc",
+    ],
+}
+
+// GN: //net:net_nqe_proto
+genrule {
+    name: "cronet_aml_net_net_nqe_proto_gen_headers",
+    srcs: [
+        "net/nqe/proto/network_id_proto.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/net/nqe/proto --cpp_out=lite=true:$(genDir)/external/chromium_org/net/nqe/proto/ $(in)",
+    out: [
+        "external/chromium_org/net/nqe/proto/network_id_proto.pb.h",
+    ],
+    export_include_dirs: [
+        ".",
+        "net/nqe/proto",
+        "protos",
+    ],
+}
+
+// GN: //net:net_public_deps
+filegroup {
+    name: "cronet_aml_net_net_public_deps",
+}
+
+// GN: //net:preload_decoder
+cc_library_static {
+    name: "cronet_aml_net_preload_decoder",
+    srcs: [
+        "net/extras/preload_data/decoder.cc",
+    ],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+    ],
+    static_libs: [
+        "cronet_aml_base_base",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/abseil-cpp/",
+        "third_party/boringssl/src/include/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //net/third_party/quiche:net_quic_proto
+genrule {
+    name: "cronet_aml_net_third_party_quiche_net_quic_proto_gen",
+    srcs: [
+        "net/third_party/quiche/src/quiche/quic/core/proto/cached_network_parameters.proto",
+        "net/third_party/quiche/src/quiche/quic/core/proto/crypto_server_config.proto",
+        "net/third_party/quiche/src/quiche/quic/core/proto/source_address_token.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/net/third_party/quiche/src --cpp_out=lite=true:$(genDir)/external/chromium_org/net/third_party/quiche/src/ $(in)",
+    out: [
+        "external/chromium_org/net/third_party/quiche/src/quiche/quic/core/proto/cached_network_parameters.pb.cc",
+        "external/chromium_org/net/third_party/quiche/src/quiche/quic/core/proto/crypto_server_config.pb.cc",
+        "external/chromium_org/net/third_party/quiche/src/quiche/quic/core/proto/source_address_token.pb.cc",
+    ],
+}
+
+// GN: //net/third_party/quiche:net_quic_proto
+genrule {
+    name: "cronet_aml_net_third_party_quiche_net_quic_proto_gen_headers",
+    srcs: [
+        "net/third_party/quiche/src/quiche/quic/core/proto/cached_network_parameters.proto",
+        "net/third_party/quiche/src/quiche/quic/core/proto/crypto_server_config.proto",
+        "net/third_party/quiche/src/quiche/quic/core/proto/source_address_token.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/net/third_party/quiche/src --cpp_out=lite=true:$(genDir)/external/chromium_org/net/third_party/quiche/src/ $(in)",
+    out: [
+        "external/chromium_org/net/third_party/quiche/src/quiche/quic/core/proto/cached_network_parameters.pb.h",
+        "external/chromium_org/net/third_party/quiche/src/quiche/quic/core/proto/crypto_server_config.pb.h",
+        "external/chromium_org/net/third_party/quiche/src/quiche/quic/core/proto/source_address_token.pb.h",
+    ],
+    export_include_dirs: [
+        ".",
+        "net/third_party/quiche/src",
+        "protos",
+    ],
+}
+
+// GN: //net/third_party/quiche:net_quic_test_tools_proto
+genrule {
+    name: "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen",
+    srcs: [
+        "net/third_party/quiche/src/quiche/quic/test_tools/send_algorithm_test_result.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/net/third_party/quiche/src/quiche/quic/test_tools --cpp_out=lite=true:$(genDir)/external/chromium_org/net/third_party/quiche/src/quiche/quic/test_tools/ $(in)",
+    out: [
+        "external/chromium_org/net/third_party/quiche/src/quiche/quic/test_tools/send_algorithm_test_result.pb.cc",
+    ],
+}
+
+// GN: //net/third_party/quiche:net_quic_test_tools_proto
+genrule {
+    name: "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_headers",
+    srcs: [
+        "net/third_party/quiche/src/quiche/quic/test_tools/send_algorithm_test_result.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/net/third_party/quiche/src/quiche/quic/test_tools --cpp_out=lite=true:$(genDir)/external/chromium_org/net/third_party/quiche/src/quiche/quic/test_tools/ $(in)",
+    out: [
+        "external/chromium_org/net/third_party/quiche/src/quiche/quic/test_tools/send_algorithm_test_result.pb.h",
+    ],
+    export_include_dirs: [
+        ".",
+        "net/third_party/quiche/src/quiche/quic/test_tools",
+        "protos",
+    ],
+}
+
+// GN: //net/third_party/quiche:quiche
+cc_library_static {
+    name: "cronet_aml_net_third_party_quiche_quiche",
+    srcs: [
+        ":cronet_aml_net_third_party_quiche_net_quic_proto_gen",
+        ":cronet_aml_third_party_abseil_cpp_absl",
+        ":cronet_aml_third_party_abseil_cpp_absl_algorithm_algorithm",
+        ":cronet_aml_third_party_abseil_cpp_absl_algorithm_container",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_atomic_hook",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_base",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_base_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_config",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_core_headers",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_cycleclock_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_dynamic_annotations",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_endian",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_errno_saver",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_fast_type_id",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_log_severity",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_malloc_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_prefetch",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_raw_logging_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_spinlock_wait",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_strerror",
+        ":cronet_aml_third_party_abseil_cpp_absl_base_throw_delegate",
+        ":cronet_aml_third_party_abseil_cpp_absl_cleanup_cleanup",
+        ":cronet_aml_third_party_abseil_cpp_absl_cleanup_cleanup_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_btree",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_common",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_common_policy_traits",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_compressed_tuple",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_container_memory",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_fixed_array",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_flat_hash_map",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_flat_hash_set",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_hash_function_defaults",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_hash_policy_traits",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_hashtable_debug_hooks",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_hashtablez_sampler",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_inlined_vector",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_inlined_vector_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_layout",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_node_hash_map",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_node_hash_set",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_node_slot_policy",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_raw_hash_map",
+        ":cronet_aml_third_party_abseil_cpp_absl_container_raw_hash_set",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_debugging_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_demangle_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_examine_stack",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_failure_signal_handler",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_stacktrace",
+        ":cronet_aml_third_party_abseil_cpp_absl_debugging_symbolize",
+        ":cronet_aml_third_party_abseil_cpp_absl_functional_any_invocable",
+        ":cronet_aml_third_party_abseil_cpp_absl_functional_bind_front",
+        ":cronet_aml_third_party_abseil_cpp_absl_functional_function_ref",
+        ":cronet_aml_third_party_abseil_cpp_absl_hash_city",
+        ":cronet_aml_third_party_abseil_cpp_absl_hash_hash",
+        ":cronet_aml_third_party_abseil_cpp_absl_hash_low_level_hash",
+        ":cronet_aml_third_party_abseil_cpp_absl_memory_memory",
+        ":cronet_aml_third_party_abseil_cpp_absl_meta_type_traits",
+        ":cronet_aml_third_party_abseil_cpp_absl_numeric_bits",
+        ":cronet_aml_third_party_abseil_cpp_absl_numeric_int128",
+        ":cronet_aml_third_party_abseil_cpp_absl_numeric_representation",
+        ":cronet_aml_third_party_abseil_cpp_absl_profiling_exponential_biased",
+        ":cronet_aml_third_party_abseil_cpp_absl_profiling_sample_recorder",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_distributions",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_distribution_caller",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_fast_uniform_bits",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_fastmath",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_generate_real",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_iostream_state_saver",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_nonsecure_base",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_pcg_engine",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_platform",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_pool_urbg",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_randen",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_engine",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_hwaes",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_hwaes_impl",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_slow",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_salted_seed_seq",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_seed_material",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_traits",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_uniform_helper",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_internal_wide_multiply",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_random",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_seed_gen_exception",
+        ":cronet_aml_third_party_abseil_cpp_absl_random_seed_sequences",
+        ":cronet_aml_third_party_abseil_cpp_absl_status_status",
+        ":cronet_aml_third_party_abseil_cpp_absl_status_statusor",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cord",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cord_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_functions",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_handle",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_info",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_statistics",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_update_scope",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_cordz_update_tracker",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_str_format",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_str_format_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_strings_strings",
+        ":cronet_aml_third_party_abseil_cpp_absl_synchronization_graphcycles_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_synchronization_kernel_timeout_internal",
+        ":cronet_aml_third_party_abseil_cpp_absl_synchronization_synchronization",
+        ":cronet_aml_third_party_abseil_cpp_absl_time_internal_cctz_civil_time",
+        ":cronet_aml_third_party_abseil_cpp_absl_time_internal_cctz_time_zone",
+        ":cronet_aml_third_party_abseil_cpp_absl_time_time",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_bad_optional_access",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_compare",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_optional",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_span",
+        ":cronet_aml_third_party_abseil_cpp_absl_types_variant",
+        ":cronet_aml_third_party_abseil_cpp_absl_utility_utility",
+        "net/third_party/quiche/overrides/quiche_platform_impl/quiche_mutex_impl.cc",
+        "net/third_party/quiche/overrides/quiche_platform_impl/quiche_time_utils_impl.cc",
+        "net/third_party/quiche/overrides/quiche_platform_impl/quiche_url_utils_impl.cc",
+        "net/third_party/quiche/src/quiche/common/platform/api/quiche_hostname_utils.cc",
+        "net/third_party/quiche/src/quiche/common/platform/api/quiche_mutex.cc",
+        "net/third_party/quiche/src/quiche/common/platform/default/quiche_platform_impl/quiche_flags_impl.cc",
+        "net/third_party/quiche/src/quiche/common/quiche_buffer_allocator.cc",
+        "net/third_party/quiche/src/quiche/common/quiche_crypto_logging.cc",
+        "net/third_party/quiche/src/quiche/common/quiche_data_reader.cc",
+        "net/third_party/quiche/src/quiche/common/quiche_data_writer.cc",
+        "net/third_party/quiche/src/quiche/common/quiche_ip_address.cc",
+        "net/third_party/quiche/src/quiche/common/quiche_ip_address_family.cc",
+        "net/third_party/quiche/src/quiche/common/quiche_mem_slice_storage.cc",
+        "net/third_party/quiche/src/quiche/common/quiche_random.cc",
+        "net/third_party/quiche/src/quiche/common/quiche_text_utils.cc",
+        "net/third_party/quiche/src/quiche/common/simple_buffer_allocator.cc",
+        "net/third_party/quiche/src/quiche/common/structured_headers.cc",
+        "net/third_party/quiche/src/quiche/http2/adapter/event_forwarder.cc",
+        "net/third_party/quiche/src/quiche/http2/adapter/header_validator.cc",
+        "net/third_party/quiche/src/quiche/http2/adapter/http2_protocol.cc",
+        "net/third_party/quiche/src/quiche/http2/adapter/http2_util.cc",
+        "net/third_party/quiche/src/quiche/http2/adapter/noop_header_validator.cc",
+        "net/third_party/quiche/src/quiche/http2/adapter/oghttp2_adapter.cc",
+        "net/third_party/quiche/src/quiche/http2/adapter/oghttp2_session.cc",
+        "net/third_party/quiche/src/quiche/http2/adapter/oghttp2_util.cc",
+        "net/third_party/quiche/src/quiche/http2/adapter/window_manager.cc",
+        "net/third_party/quiche/src/quiche/http2/core/http2_trace_logging.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/decode_buffer.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/decode_http2_structures.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/decode_status.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/frame_decoder_state.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/http2_frame_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/http2_frame_decoder_listener.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/http2_structure_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/altsvc_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/continuation_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/data_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/goaway_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/headers_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/ping_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/priority_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/priority_update_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/push_promise_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/rst_stream_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/settings_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/unknown_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/decoder/payload_decoders/window_update_payload_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_block_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder_listener.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder_state.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder_string_buffer.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder_tables.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoding_error.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_entry_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_entry_decoder_listener.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_entry_type_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_string_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_string_decoder_listener.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_whole_entry_buffer.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_whole_entry_listener.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/http2_hpack_constants.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/huffman/hpack_huffman_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/huffman/hpack_huffman_encoder.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/huffman/huffman_spec_tables.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/varint/hpack_varint_decoder.cc",
+        "net/third_party/quiche/src/quiche/http2/hpack/varint/hpack_varint_encoder.cc",
+        "net/third_party/quiche/src/quiche/http2/http2_constants.cc",
+        "net/third_party/quiche/src/quiche/http2/http2_structures.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/bandwidth_sampler.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/bbr2_drain.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/bbr2_misc.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/bbr2_probe_bw.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/bbr2_probe_rtt.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/bbr2_sender.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/bbr2_startup.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/bbr_sender.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/cubic_bytes.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/general_loss_algorithm.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/hybrid_slow_start.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/pacing_sender.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/prr_sender.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/rtt_stats.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/send_algorithm_interface.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/tcp_cubic_sender_bytes.cc",
+        "net/third_party/quiche/src/quiche/quic/core/congestion_control/uber_loss_algorithm.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/aead_base_decrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/aead_base_encrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/aes_128_gcm_12_decrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/aes_128_gcm_12_encrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/aes_128_gcm_decrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/aes_128_gcm_encrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/aes_256_gcm_decrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/aes_256_gcm_encrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/aes_base_decrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/aes_base_encrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/cert_compressor.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/certificate_util.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/certificate_view.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/chacha20_poly1305_decrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/chacha20_poly1305_encrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/chacha20_poly1305_tls_decrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/chacha20_poly1305_tls_encrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/chacha_base_decrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/chacha_base_encrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/channel_id.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/client_proof_source.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/crypto_framer.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/crypto_handshake.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/crypto_handshake_message.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/crypto_secret_boxer.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/crypto_utils.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/curve25519_key_exchange.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/key_exchange.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/null_decrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/null_encrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/p256_key_exchange.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/proof_source.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/proof_source_x509.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/quic_client_session_cache.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/quic_compressed_certs_cache.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/quic_crypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/quic_crypto_client_config.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/quic_crypto_proof.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/quic_crypto_server_config.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/quic_decrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/quic_encrypter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/quic_hkdf.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/tls_client_connection.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/tls_connection.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/tls_server_connection.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/transport_parameters.cc",
+        "net/third_party/quiche/src/quiche/quic/core/crypto/web_transport_fingerprint_proof_verifier.cc",
+        "net/third_party/quiche/src/quiche/quic/core/deterministic_connection_id_generator.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_ack_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_ack_frequency_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_blocked_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_connection_close_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_crypto_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_goaway_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_handshake_done_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_max_streams_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_message_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_new_connection_id_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_new_token_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_padding_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_path_challenge_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_path_response_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_ping_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_retire_connection_id_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_rst_stream_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_stop_sending_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_stop_waiting_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_stream_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_streams_blocked_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/frames/quic_window_update_frame.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/capsule.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/http_constants.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/http_decoder.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/http_encoder.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_client_promised_info.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_client_push_promise_index.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_header_list.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_headers_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_receive_control_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_send_control_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_server_initiated_spdy_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_server_session_base.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_client_session.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_client_session_base.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_client_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_session.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_stream_body_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/spdy_server_push_utils.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/spdy_utils.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/web_transport_http3.cc",
+        "net/third_party/quiche/src/quiche/quic/core/http/web_transport_stream_adapter.cc",
+        "net/third_party/quiche/src/quiche/quic/core/legacy_quic_stream_id_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_blocking_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_decoded_headers_accumulator.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_decoder.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_decoder_stream_receiver.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_decoder_stream_sender.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_encoder.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_encoder_stream_receiver.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_encoder_stream_sender.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_header_table.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_index_conversions.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_instruction_decoder.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_instruction_encoder.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_instructions.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_progressive_decoder.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_receive_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_required_insert_count.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_send_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_static_table.cc",
+        "net/third_party/quiche/src/quiche/quic/core/qpack/value_splitting_header_list.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_ack_listener_interface.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_alarm.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_bandwidth.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_chaos_protector.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_clock.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_coalesced_packet.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_config.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_connection.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_connection_context.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_connection_id.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_connection_id_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_connection_stats.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_constants.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_control_frame_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_crypto_client_handshaker.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_crypto_client_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_crypto_handshaker.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_crypto_server_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_crypto_server_stream_base.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_crypto_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_data_reader.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_data_writer.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_datagram_queue.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_error_codes.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_flow_controller.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_framer.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_idle_network_detector.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_mtu_discovery.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_network_blackhole_detector.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_packet_creator.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_packet_number.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_packets.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_path_validator.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_ping_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_received_packet_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_sent_packet_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_server_id.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_session.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_socket_address_coder.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_stream.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_stream_id_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_stream_send_buffer.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_stream_sequencer.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_stream_sequencer_buffer.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_sustained_bandwidth_recorder.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_tag.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_time.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_transmission_info.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_types.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_unacked_packet_map.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_utils.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_version_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_versions.cc",
+        "net/third_party/quiche/src/quiche/quic/core/quic_write_blocked_list.cc",
+        "net/third_party/quiche/src/quiche/quic/core/tls_client_handshaker.cc",
+        "net/third_party/quiche/src/quiche/quic/core/tls_handshaker.cc",
+        "net/third_party/quiche/src/quiche/quic/core/tls_server_handshaker.cc",
+        "net/third_party/quiche/src/quiche/quic/core/uber_quic_stream_id_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/core/uber_received_packet_manager.cc",
+        "net/third_party/quiche/src/quiche/quic/platform/api/quic_socket_address.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/array_output_buffer.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_constants.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_decoder_adapter.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_encoder.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_entry.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_header_table.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_output_stream.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_static_table.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/http2_frame_decoder_adapter.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/http2_header_block.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/http2_header_storage.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/recording_headers_handler.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/spdy_alt_svc_wire_format.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/spdy_frame_builder.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/spdy_framer.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/spdy_no_op_visitor.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/spdy_pinnable_buffer_piece.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/spdy_prefixed_buffer_reader.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.cc",
+        "net/third_party/quiche/src/quiche/spdy/core/spdy_simple_arena.cc",
+    ],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+        "libprotobuf-cpp-lite",
+    ],
+    static_libs: [
+        "cronet_aml_base_base",
+        "cronet_aml_net_uri_template",
+        "cronet_aml_third_party_zlib_zlib",
+        "cronet_aml_url_url",
+        "libssl",
+    ],
+    generated_headers: [
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_net_third_party_quiche_net_quic_proto_gen_headers",
+    ],
+    export_generated_headers: [
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_net_third_party_quiche_net_quic_proto_gen_headers",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DABSL_ALLOCATOR_NOTHROW=1",
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DGOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0",
+        "-DGOOGLE_PROTOBUF_NO_RTTI",
+        "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
+        "-DHAVE_PTHREAD",
+        "-DHAVE_SYS_UIO_H",
+        "-DIS_QUICHE_IMPL",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "net/third_party/quiche/overrides/",
+        "net/third_party/quiche/src/",
+        "net/third_party/quiche/src/quiche/common/platform/default/",
+        "third_party/abseil-cpp/",
+        "third_party/boringssl/src/include/",
+        "third_party/zlib/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //net/tools/root_store_tool:root_store_tool
+cc_binary {
+    name: "cronet_aml_net_tools_root_store_tool_root_store_tool",
+    srcs: [
+        ":cronet_aml_buildtools_third_party_libc___libc__",
+        ":cronet_aml_buildtools_third_party_libc__abi_libc__abi",
+        ":cronet_aml_net_cert_root_store_proto_full_gen",
+        "net/tools/root_store_tool/root_store_tool.cc",
+    ],
+    shared_libs: [
+        "libprotobuf-cpp-lite",
+    ],
+    static_libs: [
+        "cronet_aml_base_base",
+        "cronet_aml_crypto_crypto",
+        "libssl",
+    ],
+    generated_headers: [
+        "cronet_aml_net_cert_root_store_proto_full_gen_headers",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DCR_SYSROOT_KEY=20220331T153654Z-0",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DGOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0",
+        "-DGOOGLE_PROTOBUF_NO_RTTI",
+        "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
+        "-DHAVE_PTHREAD",
+        "-DLIBCXXABI_SILENT_TERMINATE",
+        "-DLIBCXX_BUILDING_LIBCXXABI",
+        "-DUSE_AURA=1",
+        "-DUSE_OZONE=1",
+        "-DUSE_UDEV",
+        "-D_DEBUG",
+        "-D_FILE_OFFSET_BITS=64",
+        "-D_GNU_SOURCE",
+        "-D_LARGEFILE64_SOURCE",
+        "-D_LARGEFILE_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_BUILDING_LIBRARY",
+        "-D_LIBCPP_CONSTINIT=constinit",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCPP_OVERRIDABLE_FUNC_VIS=__attribute__((__visibility__(\"default\")))",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++/trunk/src/",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/abseil-cpp/",
+        "third_party/boringssl/src/include/",
+        "build/linux/debian_bullseye_amd64-sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //net/traffic_annotation:traffic_annotation
+filegroup {
+    name: "cronet_aml_net_traffic_annotation_traffic_annotation",
+    srcs: [
+        "net/traffic_annotation/network_traffic_annotation_android.cc",
+    ],
+}
+
+// GN: //net:uri_template
+cc_library_static {
+    name: "cronet_aml_net_uri_template",
+    srcs: [
+        "net/third_party/uri_template/uri_template.cc",
+    ],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+    ],
+    static_libs: [
+        "cronet_aml_base_base",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-DIS_URI_TEMPLATE_IMPL",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/abseil-cpp/",
+        "third_party/boringssl/src/include/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //third_party/abseil-cpp:absl
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl",
+}
+
+// GN: //third_party/abseil-cpp/absl/algorithm:algorithm
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_algorithm_algorithm",
+}
+
+// GN: //third_party/abseil-cpp/absl/algorithm:container
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_algorithm_container",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:atomic_hook
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_atomic_hook",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:base
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_base",
+    srcs: [
+        "third_party/abseil-cpp/absl/base/internal/cycleclock.cc",
+        "third_party/abseil-cpp/absl/base/internal/spinlock.cc",
+        "third_party/abseil-cpp/absl/base/internal/sysinfo.cc",
+        "third_party/abseil-cpp/absl/base/internal/thread_identity.cc",
+        "third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/base:base_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_base_internal",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:config
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_config",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:core_headers
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_core_headers",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:cycleclock_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_cycleclock_internal",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:dynamic_annotations
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_dynamic_annotations",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:endian
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_endian",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:errno_saver
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_errno_saver",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:fast_type_id
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_fast_type_id",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:log_severity
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_log_severity",
+    srcs: [
+        "third_party/abseil-cpp/absl/base/log_severity.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/base:malloc_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_malloc_internal",
+    srcs: [
+        "third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/base:prefetch
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_prefetch",
+}
+
+// GN: //third_party/abseil-cpp/absl/base:raw_logging_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_raw_logging_internal",
+    srcs: [
+        "third_party/abseil-cpp/absl/base/internal/raw_logging.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/base:spinlock_wait
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_spinlock_wait",
+    srcs: [
+        "third_party/abseil-cpp/absl/base/internal/spinlock_wait.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/base:strerror
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_strerror",
+    srcs: [
+        "third_party/abseil-cpp/absl/base/internal/strerror.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/base:throw_delegate
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_base_throw_delegate",
+    srcs: [
+        "third_party/abseil-cpp/absl/base/internal/throw_delegate.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/cleanup:cleanup
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_cleanup_cleanup",
+}
+
+// GN: //third_party/abseil-cpp/absl/cleanup:cleanup_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_cleanup_cleanup_internal",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:btree
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_btree",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:common
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_common",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:common_policy_traits
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_common_policy_traits",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:compressed_tuple
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_compressed_tuple",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:container_memory
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_container_memory",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:fixed_array
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_fixed_array",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:flat_hash_map
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_flat_hash_map",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:flat_hash_set
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_flat_hash_set",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:hash_function_defaults
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_hash_function_defaults",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:hash_policy_traits
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_hash_policy_traits",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:hashtable_debug_hooks
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_hashtable_debug_hooks",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:hashtablez_sampler
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_hashtablez_sampler",
+    srcs: [
+        "third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc",
+        "third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/container:inlined_vector
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_inlined_vector",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:inlined_vector_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_inlined_vector_internal",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:layout
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_layout",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:node_hash_map
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_node_hash_map",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:node_hash_set
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_node_hash_set",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:node_slot_policy
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_node_slot_policy",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:raw_hash_map
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_raw_hash_map",
+}
+
+// GN: //third_party/abseil-cpp/absl/container:raw_hash_set
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_container_raw_hash_set",
+    srcs: [
+        "third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/debugging:debugging_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_debugging_debugging_internal",
+    srcs: [
+        "third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc",
+        "third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc",
+        "third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/debugging:demangle_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_debugging_demangle_internal",
+    srcs: [
+        "third_party/abseil-cpp/absl/debugging/internal/demangle.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/debugging:examine_stack
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_debugging_examine_stack",
+    srcs: [
+        "third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/debugging:failure_signal_handler
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_debugging_failure_signal_handler",
+    srcs: [
+        "third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/debugging:stacktrace
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_debugging_stacktrace",
+    srcs: [
+        "third_party/abseil-cpp/absl/debugging/stacktrace.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/debugging:symbolize
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_debugging_symbolize",
+    srcs: [
+        "third_party/abseil-cpp/absl/debugging/symbolize.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/functional:any_invocable
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_functional_any_invocable",
+}
+
+// GN: //third_party/abseil-cpp/absl/functional:bind_front
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_functional_bind_front",
+}
+
+// GN: //third_party/abseil-cpp/absl/functional:function_ref
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_functional_function_ref",
+}
+
+// GN: //third_party/abseil-cpp/absl/hash:city
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_hash_city",
+    srcs: [
+        "third_party/abseil-cpp/absl/hash/internal/city.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/hash:hash
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_hash_hash",
+    srcs: [
+        "third_party/abseil-cpp/absl/hash/internal/hash.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/hash:low_level_hash
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_hash_low_level_hash",
+    srcs: [
+        "third_party/abseil-cpp/absl/hash/internal/low_level_hash.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/memory:memory
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_memory_memory",
+}
+
+// GN: //third_party/abseil-cpp/absl/meta:type_traits
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_meta_type_traits",
+}
+
+// GN: //third_party/abseil-cpp/absl/numeric:bits
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_numeric_bits",
+}
+
+// GN: //third_party/abseil-cpp/absl/numeric:int128
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_numeric_int128",
+    srcs: [
+        "third_party/abseil-cpp/absl/numeric/int128.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/numeric:representation
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_numeric_representation",
+}
+
+// GN: //third_party/abseil-cpp/absl/profiling:exponential_biased
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_profiling_exponential_biased",
+    srcs: [
+        "third_party/abseil-cpp/absl/profiling/internal/exponential_biased.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/profiling:sample_recorder
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_profiling_sample_recorder",
+}
+
+// GN: //third_party/abseil-cpp/absl/random:distributions
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_distributions",
+    srcs: [
+        "third_party/abseil-cpp/absl/random/discrete_distribution.cc",
+        "third_party/abseil-cpp/absl/random/gaussian_distribution.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:distribution_caller
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_distribution_caller",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:fast_uniform_bits
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_fast_uniform_bits",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:fastmath
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_fastmath",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:generate_real
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_generate_real",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:iostream_state_saver
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_iostream_state_saver",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:nonsecure_base
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_nonsecure_base",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:pcg_engine
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_pcg_engine",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:platform
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_platform",
+    srcs: [
+        "third_party/abseil-cpp/absl/random/internal/randen_round_keys.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:pool_urbg
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_pool_urbg",
+    srcs: [
+        "third_party/abseil-cpp/absl/random/internal/pool_urbg.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:randen
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_randen",
+    srcs: [
+        "third_party/abseil-cpp/absl/random/internal/randen.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:randen_engine
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_engine",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:randen_hwaes
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_hwaes",
+    srcs: [
+        "third_party/abseil-cpp/absl/random/internal/randen_detect.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:randen_hwaes_impl
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_hwaes_impl",
+    srcs: [
+        "third_party/abseil-cpp/absl/random/internal/randen_hwaes.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:randen_slow
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_slow",
+    srcs: [
+        "third_party/abseil-cpp/absl/random/internal/randen_slow.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:salted_seed_seq
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_salted_seed_seq",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:seed_material
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_seed_material",
+    srcs: [
+        "third_party/abseil-cpp/absl/random/internal/seed_material.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:traits
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_traits",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:uniform_helper
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_uniform_helper",
+}
+
+// GN: //third_party/abseil-cpp/absl/random/internal:wide_multiply
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_wide_multiply",
+}
+
+// GN: //third_party/abseil-cpp/absl/random:random
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_random",
+}
+
+// GN: //third_party/abseil-cpp/absl/random:seed_gen_exception
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_seed_gen_exception",
+    srcs: [
+        "third_party/abseil-cpp/absl/random/seed_gen_exception.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/random:seed_sequences
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_random_seed_sequences",
+    srcs: [
+        "third_party/abseil-cpp/absl/random/seed_sequences.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/status:status
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_status_status",
+    srcs: [
+        "third_party/abseil-cpp/absl/status/status.cc",
+        "third_party/abseil-cpp/absl/status/status_payload_printer.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/status:statusor
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_status_statusor",
+    srcs: [
+        "third_party/abseil-cpp/absl/status/statusor.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:cord
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_cord",
+    srcs: [
+        "third_party/abseil-cpp/absl/strings/cord.cc",
+        "third_party/abseil-cpp/absl/strings/cord_analysis.cc",
+        "third_party/abseil-cpp/absl/strings/cord_buffer.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:cord_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_cord_internal",
+    srcs: [
+        "third_party/abseil-cpp/absl/strings/internal/cord_internal.cc",
+        "third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.cc",
+        "third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.cc",
+        "third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.cc",
+        "third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.cc",
+        "third_party/abseil-cpp/absl/strings/internal/cord_rep_crc.cc",
+        "third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:cordz_functions
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_functions",
+    srcs: [
+        "third_party/abseil-cpp/absl/strings/internal/cordz_functions.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:cordz_handle
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_handle",
+    srcs: [
+        "third_party/abseil-cpp/absl/strings/internal/cordz_handle.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:cordz_info
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_info",
+    srcs: [
+        "third_party/abseil-cpp/absl/strings/internal/cordz_info.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:cordz_statistics
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_statistics",
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:cordz_update_scope
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_update_scope",
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:cordz_update_tracker
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_update_tracker",
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_internal",
+    srcs: [
+        "third_party/abseil-cpp/absl/strings/internal/escaping.cc",
+        "third_party/abseil-cpp/absl/strings/internal/ostringstream.cc",
+        "third_party/abseil-cpp/absl/strings/internal/utf8.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:str_format
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_str_format",
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:str_format_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_str_format_internal",
+    srcs: [
+        "third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc",
+        "third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc",
+        "third_party/abseil-cpp/absl/strings/internal/str_format/extension.cc",
+        "third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc",
+        "third_party/abseil-cpp/absl/strings/internal/str_format/output.cc",
+        "third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/strings:strings
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_strings_strings",
+    srcs: [
+        "third_party/abseil-cpp/absl/strings/ascii.cc",
+        "third_party/abseil-cpp/absl/strings/charconv.cc",
+        "third_party/abseil-cpp/absl/strings/escaping.cc",
+        "third_party/abseil-cpp/absl/strings/internal/charconv_bigint.cc",
+        "third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc",
+        "third_party/abseil-cpp/absl/strings/internal/damerau_levenshtein_distance.cc",
+        "third_party/abseil-cpp/absl/strings/internal/memutil.cc",
+        "third_party/abseil-cpp/absl/strings/match.cc",
+        "third_party/abseil-cpp/absl/strings/numbers.cc",
+        "third_party/abseil-cpp/absl/strings/str_cat.cc",
+        "third_party/abseil-cpp/absl/strings/str_replace.cc",
+        "third_party/abseil-cpp/absl/strings/str_split.cc",
+        "third_party/abseil-cpp/absl/strings/string_view.cc",
+        "third_party/abseil-cpp/absl/strings/substitute.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/synchronization:graphcycles_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_synchronization_graphcycles_internal",
+    srcs: [
+        "third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/synchronization:kernel_timeout_internal
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_synchronization_kernel_timeout_internal",
+}
+
+// GN: //third_party/abseil-cpp/absl/synchronization:synchronization
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_synchronization_synchronization",
+    srcs: [
+        "third_party/abseil-cpp/absl/synchronization/barrier.cc",
+        "third_party/abseil-cpp/absl/synchronization/blocking_counter.cc",
+        "third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc",
+        "third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc",
+        "third_party/abseil-cpp/absl/synchronization/internal/waiter.cc",
+        "third_party/abseil-cpp/absl/synchronization/mutex.cc",
+        "third_party/abseil-cpp/absl/synchronization/notification.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/time/internal/cctz:civil_time
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_time_internal_cctz_civil_time",
+    srcs: [
+        "third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_detail.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/time/internal/cctz:time_zone
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_time_internal_cctz_time_zone",
+    srcs: [
+        "third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc",
+        "third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc",
+        "third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_if.cc",
+        "third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_impl.cc",
+        "third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc",
+        "third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc",
+        "third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc",
+        "third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_posix.cc",
+        "third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/time:time
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_time_time",
+    srcs: [
+        "third_party/abseil-cpp/absl/time/civil_time.cc",
+        "third_party/abseil-cpp/absl/time/clock.cc",
+        "third_party/abseil-cpp/absl/time/duration.cc",
+        "third_party/abseil-cpp/absl/time/format.cc",
+        "third_party/abseil-cpp/absl/time/time.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/types:bad_optional_access
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_types_bad_optional_access",
+    srcs: [
+        "third_party/abseil-cpp/absl/types/bad_optional_access.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/types:bad_variant_access
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access",
+    srcs: [
+        "third_party/abseil-cpp/absl/types/bad_variant_access.cc",
+    ],
+}
+
+// GN: //third_party/abseil-cpp/absl/types:compare
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_types_compare",
+}
+
+// GN: //third_party/abseil-cpp/absl/types:optional
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_types_optional",
+}
+
+// GN: //third_party/abseil-cpp/absl/types:span
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_types_span",
+}
+
+// GN: //third_party/abseil-cpp/absl/types:variant
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_types_variant",
+}
+
+// GN: //third_party/abseil-cpp/absl/utility:utility
+filegroup {
+    name: "cronet_aml_third_party_abseil_cpp_absl_utility_utility",
+}
+
+// GN: //third_party/android_ndk:cpu_features
+filegroup {
+    name: "cronet_aml_third_party_android_ndk_cpu_features",
+    srcs: [
+        "third_party/android_ndk/sources/android/cpufeatures/cpu-features.c",
+    ],
+}
+
+// GN: //third_party/ashmem:ashmem
+filegroup {
+    name: "cronet_aml_third_party_ashmem_ashmem",
+    srcs: [
+        "third_party/ashmem/ashmem-dev.c",
+    ],
+}
+
+// GN: //third_party/brotli:common
+cc_library_static {
+    name: "cronet_aml_third_party_brotli_common",
+    srcs: [
+        ":cronet_aml_third_party_brotli_headers",
+        "third_party/brotli/common/constants.c",
+        "third_party/brotli/common/context.c",
+        "third_party/brotli/common/dictionary.c",
+        "third_party/brotli/common/platform.c",
+        "third_party/brotli/common/shared_dictionary.c",
+        "third_party/brotli/common/transform.c",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/brotli/include/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //third_party/brotli:dec
+cc_library_static {
+    name: "cronet_aml_third_party_brotli_dec",
+    srcs: [
+        ":cronet_aml_third_party_brotli_headers",
+        "third_party/brotli/dec/bit_reader.c",
+        "third_party/brotli/dec/decode.c",
+        "third_party/brotli/dec/huffman.c",
+        "third_party/brotli/dec/state.c",
+    ],
+    static_libs: [
+        "cronet_aml_third_party_brotli_common",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/brotli/include/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //third_party/brotli:headers
+filegroup {
+    name: "cronet_aml_third_party_brotli_headers",
+}
+
+// GN: //third_party/icu:icui18n
+cc_library_static {
+    name: "cronet_aml_third_party_icu_icui18n",
+    srcs: [
+        "third_party/icu/source/i18n/alphaindex.cpp",
+        "third_party/icu/source/i18n/anytrans.cpp",
+        "third_party/icu/source/i18n/astro.cpp",
+        "third_party/icu/source/i18n/basictz.cpp",
+        "third_party/icu/source/i18n/bocsu.cpp",
+        "third_party/icu/source/i18n/brktrans.cpp",
+        "third_party/icu/source/i18n/buddhcal.cpp",
+        "third_party/icu/source/i18n/calendar.cpp",
+        "third_party/icu/source/i18n/casetrn.cpp",
+        "third_party/icu/source/i18n/cecal.cpp",
+        "third_party/icu/source/i18n/chnsecal.cpp",
+        "third_party/icu/source/i18n/choicfmt.cpp",
+        "third_party/icu/source/i18n/coleitr.cpp",
+        "third_party/icu/source/i18n/coll.cpp",
+        "third_party/icu/source/i18n/collation.cpp",
+        "third_party/icu/source/i18n/collationbuilder.cpp",
+        "third_party/icu/source/i18n/collationcompare.cpp",
+        "third_party/icu/source/i18n/collationdata.cpp",
+        "third_party/icu/source/i18n/collationdatabuilder.cpp",
+        "third_party/icu/source/i18n/collationdatareader.cpp",
+        "third_party/icu/source/i18n/collationdatawriter.cpp",
+        "third_party/icu/source/i18n/collationfastlatin.cpp",
+        "third_party/icu/source/i18n/collationfastlatinbuilder.cpp",
+        "third_party/icu/source/i18n/collationfcd.cpp",
+        "third_party/icu/source/i18n/collationiterator.cpp",
+        "third_party/icu/source/i18n/collationkeys.cpp",
+        "third_party/icu/source/i18n/collationroot.cpp",
+        "third_party/icu/source/i18n/collationrootelements.cpp",
+        "third_party/icu/source/i18n/collationruleparser.cpp",
+        "third_party/icu/source/i18n/collationsets.cpp",
+        "third_party/icu/source/i18n/collationsettings.cpp",
+        "third_party/icu/source/i18n/collationtailoring.cpp",
+        "third_party/icu/source/i18n/collationweights.cpp",
+        "third_party/icu/source/i18n/compactdecimalformat.cpp",
+        "third_party/icu/source/i18n/coptccal.cpp",
+        "third_party/icu/source/i18n/cpdtrans.cpp",
+        "third_party/icu/source/i18n/csdetect.cpp",
+        "third_party/icu/source/i18n/csmatch.cpp",
+        "third_party/icu/source/i18n/csr2022.cpp",
+        "third_party/icu/source/i18n/csrecog.cpp",
+        "third_party/icu/source/i18n/csrmbcs.cpp",
+        "third_party/icu/source/i18n/csrsbcs.cpp",
+        "third_party/icu/source/i18n/csrucode.cpp",
+        "third_party/icu/source/i18n/csrutf8.cpp",
+        "third_party/icu/source/i18n/curramt.cpp",
+        "third_party/icu/source/i18n/currfmt.cpp",
+        "third_party/icu/source/i18n/currpinf.cpp",
+        "third_party/icu/source/i18n/currunit.cpp",
+        "third_party/icu/source/i18n/dangical.cpp",
+        "third_party/icu/source/i18n/datefmt.cpp",
+        "third_party/icu/source/i18n/dayperiodrules.cpp",
+        "third_party/icu/source/i18n/dcfmtsym.cpp",
+        "third_party/icu/source/i18n/decContext.cpp",
+        "third_party/icu/source/i18n/decNumber.cpp",
+        "third_party/icu/source/i18n/decimfmt.cpp",
+        "third_party/icu/source/i18n/double-conversion-bignum-dtoa.cpp",
+        "third_party/icu/source/i18n/double-conversion-bignum.cpp",
+        "third_party/icu/source/i18n/double-conversion-cached-powers.cpp",
+        "third_party/icu/source/i18n/double-conversion-double-to-string.cpp",
+        "third_party/icu/source/i18n/double-conversion-fast-dtoa.cpp",
+        "third_party/icu/source/i18n/double-conversion-string-to-double.cpp",
+        "third_party/icu/source/i18n/double-conversion-strtod.cpp",
+        "third_party/icu/source/i18n/dtfmtsym.cpp",
+        "third_party/icu/source/i18n/dtitvfmt.cpp",
+        "third_party/icu/source/i18n/dtitvinf.cpp",
+        "third_party/icu/source/i18n/dtptngen.cpp",
+        "third_party/icu/source/i18n/dtrule.cpp",
+        "third_party/icu/source/i18n/erarules.cpp",
+        "third_party/icu/source/i18n/esctrn.cpp",
+        "third_party/icu/source/i18n/ethpccal.cpp",
+        "third_party/icu/source/i18n/fmtable.cpp",
+        "third_party/icu/source/i18n/fmtable_cnv.cpp",
+        "third_party/icu/source/i18n/format.cpp",
+        "third_party/icu/source/i18n/formatted_string_builder.cpp",
+        "third_party/icu/source/i18n/formattedval_iterimpl.cpp",
+        "third_party/icu/source/i18n/formattedval_sbimpl.cpp",
+        "third_party/icu/source/i18n/formattedvalue.cpp",
+        "third_party/icu/source/i18n/fphdlimp.cpp",
+        "third_party/icu/source/i18n/fpositer.cpp",
+        "third_party/icu/source/i18n/funcrepl.cpp",
+        "third_party/icu/source/i18n/gender.cpp",
+        "third_party/icu/source/i18n/gregocal.cpp",
+        "third_party/icu/source/i18n/gregoimp.cpp",
+        "third_party/icu/source/i18n/hebrwcal.cpp",
+        "third_party/icu/source/i18n/indiancal.cpp",
+        "third_party/icu/source/i18n/inputext.cpp",
+        "third_party/icu/source/i18n/islamcal.cpp",
+        "third_party/icu/source/i18n/japancal.cpp",
+        "third_party/icu/source/i18n/listformatter.cpp",
+        "third_party/icu/source/i18n/measfmt.cpp",
+        "third_party/icu/source/i18n/measunit.cpp",
+        "third_party/icu/source/i18n/measunit_extra.cpp",
+        "third_party/icu/source/i18n/measure.cpp",
+        "third_party/icu/source/i18n/msgfmt.cpp",
+        "third_party/icu/source/i18n/name2uni.cpp",
+        "third_party/icu/source/i18n/nfrs.cpp",
+        "third_party/icu/source/i18n/nfrule.cpp",
+        "third_party/icu/source/i18n/nfsubs.cpp",
+        "third_party/icu/source/i18n/nortrans.cpp",
+        "third_party/icu/source/i18n/nultrans.cpp",
+        "third_party/icu/source/i18n/number_affixutils.cpp",
+        "third_party/icu/source/i18n/number_asformat.cpp",
+        "third_party/icu/source/i18n/number_capi.cpp",
+        "third_party/icu/source/i18n/number_compact.cpp",
+        "third_party/icu/source/i18n/number_currencysymbols.cpp",
+        "third_party/icu/source/i18n/number_decimalquantity.cpp",
+        "third_party/icu/source/i18n/number_decimfmtprops.cpp",
+        "third_party/icu/source/i18n/number_fluent.cpp",
+        "third_party/icu/source/i18n/number_formatimpl.cpp",
+        "third_party/icu/source/i18n/number_grouping.cpp",
+        "third_party/icu/source/i18n/number_integerwidth.cpp",
+        "third_party/icu/source/i18n/number_longnames.cpp",
+        "third_party/icu/source/i18n/number_mapper.cpp",
+        "third_party/icu/source/i18n/number_modifiers.cpp",
+        "third_party/icu/source/i18n/number_multiplier.cpp",
+        "third_party/icu/source/i18n/number_notation.cpp",
+        "third_party/icu/source/i18n/number_output.cpp",
+        "third_party/icu/source/i18n/number_padding.cpp",
+        "third_party/icu/source/i18n/number_patternmodifier.cpp",
+        "third_party/icu/source/i18n/number_patternstring.cpp",
+        "third_party/icu/source/i18n/number_rounding.cpp",
+        "third_party/icu/source/i18n/number_scientific.cpp",
+        "third_party/icu/source/i18n/number_skeletons.cpp",
+        "third_party/icu/source/i18n/number_symbolswrapper.cpp",
+        "third_party/icu/source/i18n/number_usageprefs.cpp",
+        "third_party/icu/source/i18n/number_utils.cpp",
+        "third_party/icu/source/i18n/numfmt.cpp",
+        "third_party/icu/source/i18n/numparse_affixes.cpp",
+        "third_party/icu/source/i18n/numparse_compositions.cpp",
+        "third_party/icu/source/i18n/numparse_currency.cpp",
+        "third_party/icu/source/i18n/numparse_decimal.cpp",
+        "third_party/icu/source/i18n/numparse_impl.cpp",
+        "third_party/icu/source/i18n/numparse_parsednumber.cpp",
+        "third_party/icu/source/i18n/numparse_scientific.cpp",
+        "third_party/icu/source/i18n/numparse_symbols.cpp",
+        "third_party/icu/source/i18n/numparse_validators.cpp",
+        "third_party/icu/source/i18n/numrange_capi.cpp",
+        "third_party/icu/source/i18n/numrange_fluent.cpp",
+        "third_party/icu/source/i18n/numrange_impl.cpp",
+        "third_party/icu/source/i18n/numsys.cpp",
+        "third_party/icu/source/i18n/olsontz.cpp",
+        "third_party/icu/source/i18n/persncal.cpp",
+        "third_party/icu/source/i18n/pluralranges.cpp",
+        "third_party/icu/source/i18n/plurfmt.cpp",
+        "third_party/icu/source/i18n/plurrule.cpp",
+        "third_party/icu/source/i18n/quant.cpp",
+        "third_party/icu/source/i18n/quantityformatter.cpp",
+        "third_party/icu/source/i18n/rbnf.cpp",
+        "third_party/icu/source/i18n/rbt.cpp",
+        "third_party/icu/source/i18n/rbt_data.cpp",
+        "third_party/icu/source/i18n/rbt_pars.cpp",
+        "third_party/icu/source/i18n/rbt_rule.cpp",
+        "third_party/icu/source/i18n/rbt_set.cpp",
+        "third_party/icu/source/i18n/rbtz.cpp",
+        "third_party/icu/source/i18n/regexcmp.cpp",
+        "third_party/icu/source/i18n/regeximp.cpp",
+        "third_party/icu/source/i18n/regexst.cpp",
+        "third_party/icu/source/i18n/regextxt.cpp",
+        "third_party/icu/source/i18n/region.cpp",
+        "third_party/icu/source/i18n/reldatefmt.cpp",
+        "third_party/icu/source/i18n/reldtfmt.cpp",
+        "third_party/icu/source/i18n/rematch.cpp",
+        "third_party/icu/source/i18n/remtrans.cpp",
+        "third_party/icu/source/i18n/repattrn.cpp",
+        "third_party/icu/source/i18n/rulebasedcollator.cpp",
+        "third_party/icu/source/i18n/scientificnumberformatter.cpp",
+        "third_party/icu/source/i18n/scriptset.cpp",
+        "third_party/icu/source/i18n/search.cpp",
+        "third_party/icu/source/i18n/selfmt.cpp",
+        "third_party/icu/source/i18n/sharedbreakiterator.cpp",
+        "third_party/icu/source/i18n/simpletz.cpp",
+        "third_party/icu/source/i18n/smpdtfmt.cpp",
+        "third_party/icu/source/i18n/smpdtfst.cpp",
+        "third_party/icu/source/i18n/sortkey.cpp",
+        "third_party/icu/source/i18n/standardplural.cpp",
+        "third_party/icu/source/i18n/string_segment.cpp",
+        "third_party/icu/source/i18n/strmatch.cpp",
+        "third_party/icu/source/i18n/strrepl.cpp",
+        "third_party/icu/source/i18n/stsearch.cpp",
+        "third_party/icu/source/i18n/taiwncal.cpp",
+        "third_party/icu/source/i18n/timezone.cpp",
+        "third_party/icu/source/i18n/titletrn.cpp",
+        "third_party/icu/source/i18n/tmunit.cpp",
+        "third_party/icu/source/i18n/tmutamt.cpp",
+        "third_party/icu/source/i18n/tmutfmt.cpp",
+        "third_party/icu/source/i18n/tolowtrn.cpp",
+        "third_party/icu/source/i18n/toupptrn.cpp",
+        "third_party/icu/source/i18n/translit.cpp",
+        "third_party/icu/source/i18n/transreg.cpp",
+        "third_party/icu/source/i18n/tridpars.cpp",
+        "third_party/icu/source/i18n/tzfmt.cpp",
+        "third_party/icu/source/i18n/tzgnames.cpp",
+        "third_party/icu/source/i18n/tznames.cpp",
+        "third_party/icu/source/i18n/tznames_impl.cpp",
+        "third_party/icu/source/i18n/tzrule.cpp",
+        "third_party/icu/source/i18n/tztrans.cpp",
+        "third_party/icu/source/i18n/ucal.cpp",
+        "third_party/icu/source/i18n/ucln_in.cpp",
+        "third_party/icu/source/i18n/ucol.cpp",
+        "third_party/icu/source/i18n/ucol_res.cpp",
+        "third_party/icu/source/i18n/ucol_sit.cpp",
+        "third_party/icu/source/i18n/ucoleitr.cpp",
+        "third_party/icu/source/i18n/ucsdet.cpp",
+        "third_party/icu/source/i18n/udat.cpp",
+        "third_party/icu/source/i18n/udateintervalformat.cpp",
+        "third_party/icu/source/i18n/udatpg.cpp",
+        "third_party/icu/source/i18n/ufieldpositer.cpp",
+        "third_party/icu/source/i18n/uitercollationiterator.cpp",
+        "third_party/icu/source/i18n/ulistformatter.cpp",
+        "third_party/icu/source/i18n/ulocdata.cpp",
+        "third_party/icu/source/i18n/umsg.cpp",
+        "third_party/icu/source/i18n/unesctrn.cpp",
+        "third_party/icu/source/i18n/uni2name.cpp",
+        "third_party/icu/source/i18n/units_complexconverter.cpp",
+        "third_party/icu/source/i18n/units_converter.cpp",
+        "third_party/icu/source/i18n/units_data.cpp",
+        "third_party/icu/source/i18n/units_router.cpp",
+        "third_party/icu/source/i18n/unum.cpp",
+        "third_party/icu/source/i18n/unumsys.cpp",
+        "third_party/icu/source/i18n/upluralrules.cpp",
+        "third_party/icu/source/i18n/uregex.cpp",
+        "third_party/icu/source/i18n/uregexc.cpp",
+        "third_party/icu/source/i18n/uregion.cpp",
+        "third_party/icu/source/i18n/usearch.cpp",
+        "third_party/icu/source/i18n/uspoof.cpp",
+        "third_party/icu/source/i18n/uspoof_build.cpp",
+        "third_party/icu/source/i18n/uspoof_conf.cpp",
+        "third_party/icu/source/i18n/uspoof_impl.cpp",
+        "third_party/icu/source/i18n/utf16collationiterator.cpp",
+        "third_party/icu/source/i18n/utf8collationiterator.cpp",
+        "third_party/icu/source/i18n/utmscale.cpp",
+        "third_party/icu/source/i18n/utrans.cpp",
+        "third_party/icu/source/i18n/vtzone.cpp",
+        "third_party/icu/source/i18n/vzone.cpp",
+        "third_party/icu/source/i18n/windtfmt.cpp",
+        "third_party/icu/source/i18n/winnmfmt.cpp",
+        "third_party/icu/source/i18n/wintzimpl.cpp",
+        "third_party/icu/source/i18n/zonemeta.cpp",
+        "third_party/icu/source/i18n/zrule.cpp",
+        "third_party/icu/source/i18n/ztrans.cpp",
+    ],
+    static_libs: [
+        "cronet_aml_third_party_icu_icuuc_private",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_DLOPEN=0",
+        "-DHAVE_SYS_UIO_H",
+        "-DICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE",
+        "-DUCONFIG_ONLY_HTML_CONVERSION=1",
+        "-DUCONFIG_USE_WINDOWS_LCID_MAPPING_API=0",
+        "-DUSE_CHROMIUM_ICU=1",
+        "-DU_CHARSET_IS_UTF8=1",
+        "-DU_ENABLE_DYLOAD=0",
+        "-DU_ENABLE_RESOURCE_TRACING=0",
+        "-DU_ENABLE_TRACING=1",
+        "-DU_I18N_IMPLEMENTATION",
+        "-DU_STATIC_IMPLEMENTATION",
+        "-DU_USING_ICU_NAMESPACE=0",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/icu/source/common/",
+        "third_party/icu/source/i18n/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //third_party/icu:icuuc_private
+cc_library_static {
+    name: "cronet_aml_third_party_icu_icuuc_private",
+    srcs: [
+        ":cronet_aml_third_party_icu_icuuc_public",
+        "third_party/icu/source/common/appendable.cpp",
+        "third_party/icu/source/common/bmpset.cpp",
+        "third_party/icu/source/common/brkeng.cpp",
+        "third_party/icu/source/common/brkiter.cpp",
+        "third_party/icu/source/common/bytesinkutil.cpp",
+        "third_party/icu/source/common/bytestream.cpp",
+        "third_party/icu/source/common/bytestrie.cpp",
+        "third_party/icu/source/common/bytestriebuilder.cpp",
+        "third_party/icu/source/common/bytestrieiterator.cpp",
+        "third_party/icu/source/common/caniter.cpp",
+        "third_party/icu/source/common/characterproperties.cpp",
+        "third_party/icu/source/common/chariter.cpp",
+        "third_party/icu/source/common/charstr.cpp",
+        "third_party/icu/source/common/cmemory.cpp",
+        "third_party/icu/source/common/cstr.cpp",
+        "third_party/icu/source/common/cstring.cpp",
+        "third_party/icu/source/common/cwchar.cpp",
+        "third_party/icu/source/common/dictbe.cpp",
+        "third_party/icu/source/common/dictionarydata.cpp",
+        "third_party/icu/source/common/dtintrv.cpp",
+        "third_party/icu/source/common/edits.cpp",
+        "third_party/icu/source/common/emojiprops.cpp",
+        "third_party/icu/source/common/errorcode.cpp",
+        "third_party/icu/source/common/filteredbrk.cpp",
+        "third_party/icu/source/common/filterednormalizer2.cpp",
+        "third_party/icu/source/common/icudataver.cpp",
+        "third_party/icu/source/common/icuplug.cpp",
+        "third_party/icu/source/common/loadednormalizer2impl.cpp",
+        "third_party/icu/source/common/localebuilder.cpp",
+        "third_party/icu/source/common/localematcher.cpp",
+        "third_party/icu/source/common/localeprioritylist.cpp",
+        "third_party/icu/source/common/locavailable.cpp",
+        "third_party/icu/source/common/locbased.cpp",
+        "third_party/icu/source/common/locdispnames.cpp",
+        "third_party/icu/source/common/locdistance.cpp",
+        "third_party/icu/source/common/locdspnm.cpp",
+        "third_party/icu/source/common/locid.cpp",
+        "third_party/icu/source/common/loclikely.cpp",
+        "third_party/icu/source/common/loclikelysubtags.cpp",
+        "third_party/icu/source/common/locmap.cpp",
+        "third_party/icu/source/common/locresdata.cpp",
+        "third_party/icu/source/common/locutil.cpp",
+        "third_party/icu/source/common/lsr.cpp",
+        "third_party/icu/source/common/lstmbe.cpp",
+        "third_party/icu/source/common/messagepattern.cpp",
+        "third_party/icu/source/common/normalizer2.cpp",
+        "third_party/icu/source/common/normalizer2impl.cpp",
+        "third_party/icu/source/common/normlzr.cpp",
+        "third_party/icu/source/common/parsepos.cpp",
+        "third_party/icu/source/common/patternprops.cpp",
+        "third_party/icu/source/common/pluralmap.cpp",
+        "third_party/icu/source/common/propname.cpp",
+        "third_party/icu/source/common/propsvec.cpp",
+        "third_party/icu/source/common/punycode.cpp",
+        "third_party/icu/source/common/putil.cpp",
+        "third_party/icu/source/common/rbbi.cpp",
+        "third_party/icu/source/common/rbbi_cache.cpp",
+        "third_party/icu/source/common/rbbidata.cpp",
+        "third_party/icu/source/common/rbbinode.cpp",
+        "third_party/icu/source/common/rbbirb.cpp",
+        "third_party/icu/source/common/rbbiscan.cpp",
+        "third_party/icu/source/common/rbbisetb.cpp",
+        "third_party/icu/source/common/rbbistbl.cpp",
+        "third_party/icu/source/common/rbbitblb.cpp",
+        "third_party/icu/source/common/resbund.cpp",
+        "third_party/icu/source/common/resbund_cnv.cpp",
+        "third_party/icu/source/common/resource.cpp",
+        "third_party/icu/source/common/restrace.cpp",
+        "third_party/icu/source/common/ruleiter.cpp",
+        "third_party/icu/source/common/schriter.cpp",
+        "third_party/icu/source/common/serv.cpp",
+        "third_party/icu/source/common/servlk.cpp",
+        "third_party/icu/source/common/servlkf.cpp",
+        "third_party/icu/source/common/servls.cpp",
+        "third_party/icu/source/common/servnotf.cpp",
+        "third_party/icu/source/common/servrbf.cpp",
+        "third_party/icu/source/common/servslkf.cpp",
+        "third_party/icu/source/common/sharedobject.cpp",
+        "third_party/icu/source/common/simpleformatter.cpp",
+        "third_party/icu/source/common/static_unicode_sets.cpp",
+        "third_party/icu/source/common/stringpiece.cpp",
+        "third_party/icu/source/common/stringtriebuilder.cpp",
+        "third_party/icu/source/common/uarrsort.cpp",
+        "third_party/icu/source/common/ubidi.cpp",
+        "third_party/icu/source/common/ubidi_props.cpp",
+        "third_party/icu/source/common/ubidiln.cpp",
+        "third_party/icu/source/common/ubiditransform.cpp",
+        "third_party/icu/source/common/ubidiwrt.cpp",
+        "third_party/icu/source/common/ubrk.cpp",
+        "third_party/icu/source/common/ucase.cpp",
+        "third_party/icu/source/common/ucasemap.cpp",
+        "third_party/icu/source/common/ucasemap_titlecase_brkiter.cpp",
+        "third_party/icu/source/common/ucat.cpp",
+        "third_party/icu/source/common/uchar.cpp",
+        "third_party/icu/source/common/ucharstrie.cpp",
+        "third_party/icu/source/common/ucharstriebuilder.cpp",
+        "third_party/icu/source/common/ucharstrieiterator.cpp",
+        "third_party/icu/source/common/uchriter.cpp",
+        "third_party/icu/source/common/ucln_cmn.cpp",
+        "third_party/icu/source/common/ucmndata.cpp",
+        "third_party/icu/source/common/ucnv.cpp",
+        "third_party/icu/source/common/ucnv2022.cpp",
+        "third_party/icu/source/common/ucnv_bld.cpp",
+        "third_party/icu/source/common/ucnv_cb.cpp",
+        "third_party/icu/source/common/ucnv_cnv.cpp",
+        "third_party/icu/source/common/ucnv_ct.cpp",
+        "third_party/icu/source/common/ucnv_err.cpp",
+        "third_party/icu/source/common/ucnv_ext.cpp",
+        "third_party/icu/source/common/ucnv_io.cpp",
+        "third_party/icu/source/common/ucnv_lmb.cpp",
+        "third_party/icu/source/common/ucnv_set.cpp",
+        "third_party/icu/source/common/ucnv_u16.cpp",
+        "third_party/icu/source/common/ucnv_u32.cpp",
+        "third_party/icu/source/common/ucnv_u7.cpp",
+        "third_party/icu/source/common/ucnv_u8.cpp",
+        "third_party/icu/source/common/ucnvbocu.cpp",
+        "third_party/icu/source/common/ucnvdisp.cpp",
+        "third_party/icu/source/common/ucnvhz.cpp",
+        "third_party/icu/source/common/ucnvisci.cpp",
+        "third_party/icu/source/common/ucnvlat1.cpp",
+        "third_party/icu/source/common/ucnvmbcs.cpp",
+        "third_party/icu/source/common/ucnvscsu.cpp",
+        "third_party/icu/source/common/ucnvsel.cpp",
+        "third_party/icu/source/common/ucol_swp.cpp",
+        "third_party/icu/source/common/ucptrie.cpp",
+        "third_party/icu/source/common/ucurr.cpp",
+        "third_party/icu/source/common/udata.cpp",
+        "third_party/icu/source/common/udatamem.cpp",
+        "third_party/icu/source/common/udataswp.cpp",
+        "third_party/icu/source/common/uenum.cpp",
+        "third_party/icu/source/common/uhash.cpp",
+        "third_party/icu/source/common/uhash_us.cpp",
+        "third_party/icu/source/common/uidna.cpp",
+        "third_party/icu/source/common/uinit.cpp",
+        "third_party/icu/source/common/uinvchar.cpp",
+        "third_party/icu/source/common/uiter.cpp",
+        "third_party/icu/source/common/ulist.cpp",
+        "third_party/icu/source/common/uloc.cpp",
+        "third_party/icu/source/common/uloc_keytype.cpp",
+        "third_party/icu/source/common/uloc_tag.cpp",
+        "third_party/icu/source/common/umapfile.cpp",
+        "third_party/icu/source/common/umath.cpp",
+        "third_party/icu/source/common/umutablecptrie.cpp",
+        "third_party/icu/source/common/umutex.cpp",
+        "third_party/icu/source/common/unames.cpp",
+        "third_party/icu/source/common/unifiedcache.cpp",
+        "third_party/icu/source/common/unifilt.cpp",
+        "third_party/icu/source/common/unifunct.cpp",
+        "third_party/icu/source/common/uniset.cpp",
+        "third_party/icu/source/common/uniset_closure.cpp",
+        "third_party/icu/source/common/uniset_props.cpp",
+        "third_party/icu/source/common/unisetspan.cpp",
+        "third_party/icu/source/common/unistr.cpp",
+        "third_party/icu/source/common/unistr_case.cpp",
+        "third_party/icu/source/common/unistr_case_locale.cpp",
+        "third_party/icu/source/common/unistr_cnv.cpp",
+        "third_party/icu/source/common/unistr_props.cpp",
+        "third_party/icu/source/common/unistr_titlecase_brkiter.cpp",
+        "third_party/icu/source/common/unorm.cpp",
+        "third_party/icu/source/common/unormcmp.cpp",
+        "third_party/icu/source/common/uobject.cpp",
+        "third_party/icu/source/common/uprops.cpp",
+        "third_party/icu/source/common/ures_cnv.cpp",
+        "third_party/icu/source/common/uresbund.cpp",
+        "third_party/icu/source/common/uresdata.cpp",
+        "third_party/icu/source/common/usc_impl.cpp",
+        "third_party/icu/source/common/uscript.cpp",
+        "third_party/icu/source/common/uscript_props.cpp",
+        "third_party/icu/source/common/uset.cpp",
+        "third_party/icu/source/common/uset_props.cpp",
+        "third_party/icu/source/common/usetiter.cpp",
+        "third_party/icu/source/common/ushape.cpp",
+        "third_party/icu/source/common/usprep.cpp",
+        "third_party/icu/source/common/ustack.cpp",
+        "third_party/icu/source/common/ustr_cnv.cpp",
+        "third_party/icu/source/common/ustr_titlecase_brkiter.cpp",
+        "third_party/icu/source/common/ustr_wcs.cpp",
+        "third_party/icu/source/common/ustrcase.cpp",
+        "third_party/icu/source/common/ustrcase_locale.cpp",
+        "third_party/icu/source/common/ustrenum.cpp",
+        "third_party/icu/source/common/ustrfmt.cpp",
+        "third_party/icu/source/common/ustring.cpp",
+        "third_party/icu/source/common/ustrtrns.cpp",
+        "third_party/icu/source/common/utext.cpp",
+        "third_party/icu/source/common/utf_impl.cpp",
+        "third_party/icu/source/common/util.cpp",
+        "third_party/icu/source/common/util_props.cpp",
+        "third_party/icu/source/common/utrace.cpp",
+        "third_party/icu/source/common/utrie.cpp",
+        "third_party/icu/source/common/utrie2.cpp",
+        "third_party/icu/source/common/utrie2_builder.cpp",
+        "third_party/icu/source/common/utrie_swap.cpp",
+        "third_party/icu/source/common/uts46.cpp",
+        "third_party/icu/source/common/utypes.cpp",
+        "third_party/icu/source/common/uvector.cpp",
+        "third_party/icu/source/common/uvectr32.cpp",
+        "third_party/icu/source/common/uvectr64.cpp",
+        "third_party/icu/source/common/wintz.cpp",
+        "third_party/icu/source/stubdata/stubdata.cpp",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_DLOPEN=0",
+        "-DHAVE_SYS_UIO_H",
+        "-DICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE",
+        "-DUCONFIG_ONLY_HTML_CONVERSION=1",
+        "-DUCONFIG_USE_WINDOWS_LCID_MAPPING_API=0",
+        "-DUSE_CHROMIUM_ICU=1",
+        "-DU_CHARSET_IS_UTF8=1",
+        "-DU_COMMON_IMPLEMENTATION",
+        "-DU_ENABLE_DYLOAD=0",
+        "-DU_ENABLE_RESOURCE_TRACING=0",
+        "-DU_ENABLE_TRACING=1",
+        "-DU_ICUDATAENTRY_IN_COMMON",
+        "-DU_STATIC_IMPLEMENTATION",
+        "-DU_USING_ICU_NAMESPACE=0",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/icu/source/common/",
+        "third_party/icu/source/i18n/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //third_party/icu:icuuc_public
+filegroup {
+    name: "cronet_aml_third_party_icu_icuuc_public",
+}
+
+// GN: //third_party/libevent:libevent
+cc_library_static {
+    name: "cronet_aml_third_party_libevent_libevent",
+    srcs: [
+        "third_party/libevent/buffer.c",
+        "third_party/libevent/epoll.c",
+        "third_party/libevent/evbuffer.c",
+        "third_party/libevent/evdns.c",
+        "third_party/libevent/event.c",
+        "third_party/libevent/event_tagging.c",
+        "third_party/libevent/evrpc.c",
+        "third_party/libevent/evutil.c",
+        "third_party/libevent/http.c",
+        "third_party/libevent/log.c",
+        "third_party/libevent/poll.c",
+        "third_party/libevent/select.c",
+        "third_party/libevent/signal.c",
+        "third_party/libevent/strlcpy.c",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_CONFIG_H",
+        "-DHAVE_SYS_UIO_H",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/libevent/android/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //third_party/metrics_proto:metrics_proto
+genrule {
+    name: "cronet_aml_third_party_metrics_proto_metrics_proto_gen",
+    srcs: [
+        "third_party/metrics_proto/call_stack_profile.proto",
+        "third_party/metrics_proto/cast_logs.proto",
+        "third_party/metrics_proto/chrome_os_app_list_launch_event.proto",
+        "third_party/metrics_proto/chrome_searchbox_stats.proto",
+        "third_party/metrics_proto/chrome_user_metrics_extension.proto",
+        "third_party/metrics_proto/custom_tab_session.proto",
+        "third_party/metrics_proto/execution_context.proto",
+        "third_party/metrics_proto/extension_install.proto",
+        "third_party/metrics_proto/histogram_event.proto",
+        "third_party/metrics_proto/omnibox_event.proto",
+        "third_party/metrics_proto/omnibox_focus_type.proto",
+        "third_party/metrics_proto/omnibox_input_type.proto",
+        "third_party/metrics_proto/perf_data.proto",
+        "third_party/metrics_proto/perf_stat.proto",
+        "third_party/metrics_proto/printer_event.proto",
+        "third_party/metrics_proto/reporting_info.proto",
+        "third_party/metrics_proto/sampled_profile.proto",
+        "third_party/metrics_proto/structured_data.proto",
+        "third_party/metrics_proto/system_profile.proto",
+        "third_party/metrics_proto/trace_log.proto",
+        "third_party/metrics_proto/translate_event.proto",
+        "third_party/metrics_proto/ukm/aggregate.proto",
+        "third_party/metrics_proto/ukm/entry.proto",
+        "third_party/metrics_proto/ukm/report.proto",
+        "third_party/metrics_proto/ukm/source.proto",
+        "third_party/metrics_proto/user_action_event.proto",
+        "third_party/metrics_proto/user_demographics.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/third_party/metrics_proto --cpp_out=lite=true:$(genDir)/external/chromium_org/third_party/metrics_proto/ $(in)",
+    out: [
+        "external/chromium_org/third_party/metrics_proto/call_stack_profile.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/cast_logs.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/chrome_os_app_list_launch_event.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/chrome_searchbox_stats.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/chrome_user_metrics_extension.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/custom_tab_session.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/execution_context.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/extension_install.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/histogram_event.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/omnibox_event.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/omnibox_focus_type.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/omnibox_input_type.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/perf_data.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/perf_stat.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/printer_event.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/reporting_info.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/sampled_profile.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/structured_data.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/system_profile.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/trace_log.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/translate_event.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/ukm/aggregate.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/ukm/entry.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/ukm/report.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/ukm/source.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/user_action_event.pb.cc",
+        "external/chromium_org/third_party/metrics_proto/user_demographics.pb.cc",
+    ],
+}
+
+// GN: //third_party/metrics_proto:metrics_proto
+genrule {
+    name: "cronet_aml_third_party_metrics_proto_metrics_proto_gen_headers",
+    srcs: [
+        "third_party/metrics_proto/call_stack_profile.proto",
+        "third_party/metrics_proto/cast_logs.proto",
+        "third_party/metrics_proto/chrome_os_app_list_launch_event.proto",
+        "third_party/metrics_proto/chrome_searchbox_stats.proto",
+        "third_party/metrics_proto/chrome_user_metrics_extension.proto",
+        "third_party/metrics_proto/custom_tab_session.proto",
+        "third_party/metrics_proto/execution_context.proto",
+        "third_party/metrics_proto/extension_install.proto",
+        "third_party/metrics_proto/histogram_event.proto",
+        "third_party/metrics_proto/omnibox_event.proto",
+        "third_party/metrics_proto/omnibox_focus_type.proto",
+        "third_party/metrics_proto/omnibox_input_type.proto",
+        "third_party/metrics_proto/perf_data.proto",
+        "third_party/metrics_proto/perf_stat.proto",
+        "third_party/metrics_proto/printer_event.proto",
+        "third_party/metrics_proto/reporting_info.proto",
+        "third_party/metrics_proto/sampled_profile.proto",
+        "third_party/metrics_proto/structured_data.proto",
+        "third_party/metrics_proto/system_profile.proto",
+        "third_party/metrics_proto/trace_log.proto",
+        "third_party/metrics_proto/translate_event.proto",
+        "third_party/metrics_proto/ukm/aggregate.proto",
+        "third_party/metrics_proto/ukm/entry.proto",
+        "third_party/metrics_proto/ukm/report.proto",
+        "third_party/metrics_proto/ukm/source.proto",
+        "third_party/metrics_proto/user_action_event.proto",
+        "third_party/metrics_proto/user_demographics.proto",
+    ],
+    tools: [
+        "aprotoc",
+    ],
+    cmd: "$(location aprotoc) --proto_path=external/chromium_org/third_party/metrics_proto --cpp_out=lite=true:$(genDir)/external/chromium_org/third_party/metrics_proto/ $(in)",
+    out: [
+        "external/chromium_org/third_party/metrics_proto/call_stack_profile.pb.h",
+        "external/chromium_org/third_party/metrics_proto/cast_logs.pb.h",
+        "external/chromium_org/third_party/metrics_proto/chrome_os_app_list_launch_event.pb.h",
+        "external/chromium_org/third_party/metrics_proto/chrome_searchbox_stats.pb.h",
+        "external/chromium_org/third_party/metrics_proto/chrome_user_metrics_extension.pb.h",
+        "external/chromium_org/third_party/metrics_proto/custom_tab_session.pb.h",
+        "external/chromium_org/third_party/metrics_proto/execution_context.pb.h",
+        "external/chromium_org/third_party/metrics_proto/extension_install.pb.h",
+        "external/chromium_org/third_party/metrics_proto/histogram_event.pb.h",
+        "external/chromium_org/third_party/metrics_proto/omnibox_event.pb.h",
+        "external/chromium_org/third_party/metrics_proto/omnibox_focus_type.pb.h",
+        "external/chromium_org/third_party/metrics_proto/omnibox_input_type.pb.h",
+        "external/chromium_org/third_party/metrics_proto/perf_data.pb.h",
+        "external/chromium_org/third_party/metrics_proto/perf_stat.pb.h",
+        "external/chromium_org/third_party/metrics_proto/printer_event.pb.h",
+        "external/chromium_org/third_party/metrics_proto/reporting_info.pb.h",
+        "external/chromium_org/third_party/metrics_proto/sampled_profile.pb.h",
+        "external/chromium_org/third_party/metrics_proto/structured_data.pb.h",
+        "external/chromium_org/third_party/metrics_proto/system_profile.pb.h",
+        "external/chromium_org/third_party/metrics_proto/trace_log.pb.h",
+        "external/chromium_org/third_party/metrics_proto/translate_event.pb.h",
+        "external/chromium_org/third_party/metrics_proto/ukm/aggregate.pb.h",
+        "external/chromium_org/third_party/metrics_proto/ukm/entry.pb.h",
+        "external/chromium_org/third_party/metrics_proto/ukm/report.pb.h",
+        "external/chromium_org/third_party/metrics_proto/ukm/source.pb.h",
+        "external/chromium_org/third_party/metrics_proto/user_action_event.pb.h",
+        "external/chromium_org/third_party/metrics_proto/user_demographics.pb.h",
+    ],
+    export_include_dirs: [
+        ".",
+        "protos",
+        "third_party/metrics_proto",
+    ],
+}
+
+// GN: //third_party/modp_b64:modp_b64
+cc_library_static {
+    name: "cronet_aml_third_party_modp_b64_modp_b64",
+    srcs: [
+        "third_party/modp_b64/modp_b64.cc",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //third_party/zlib:zlib
+cc_library_static {
+    name: "cronet_aml_third_party_zlib_zlib",
+    srcs: [
+        ":cronet_aml_third_party_android_ndk_cpu_features",
+        ":cronet_aml_third_party_zlib_zlib_adler32_simd",
+        ":cronet_aml_third_party_zlib_zlib_common_headers",
+        ":cronet_aml_third_party_zlib_zlib_crc32_simd",
+        ":cronet_aml_third_party_zlib_zlib_inflate_chunk_simd",
+        ":cronet_aml_third_party_zlib_zlib_slide_hash_simd",
+        "third_party/zlib/adler32.c",
+        "third_party/zlib/compress.c",
+        "third_party/zlib/cpu_features.c",
+        "third_party/zlib/crc32.c",
+        "third_party/zlib/deflate.c",
+        "third_party/zlib/gzclose.c",
+        "third_party/zlib/gzlib.c",
+        "third_party/zlib/gzread.c",
+        "third_party/zlib/gzwrite.c",
+        "third_party/zlib/infback.c",
+        "third_party/zlib/inffast.c",
+        "third_party/zlib/inftrees.c",
+        "third_party/zlib/trees.c",
+        "third_party/zlib/uncompr.c",
+        "third_party/zlib/zutil.c",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DADLER32_SIMD_SSSE3",
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCRC32_SIMD_SSE42_PCLMUL",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDEFLATE_SLIDE_HASH_SSE2",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-DINFLATE_CHUNK_READ_64LE",
+        "-DINFLATE_CHUNK_SIMD_SSE2",
+        "-DX86_NOT_WINDOWS",
+        "-DZLIB_DEBUG",
+        "-DZLIB_IMPLEMENTATION",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/android_ndk/sources/android/cpufeatures/",
+        "third_party/zlib/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //third_party/zlib:zlib_adler32_simd
+filegroup {
+    name: "cronet_aml_third_party_zlib_zlib_adler32_simd",
+    srcs: [
+        "third_party/zlib/adler32_simd.c",
+    ],
+}
+
+// GN: //third_party/zlib:zlib_common_headers
+filegroup {
+    name: "cronet_aml_third_party_zlib_zlib_common_headers",
+}
+
+// GN: //third_party/zlib:zlib_crc32_simd
+filegroup {
+    name: "cronet_aml_third_party_zlib_zlib_crc32_simd",
+    srcs: [
+        "third_party/zlib/crc32_simd.c",
+        "third_party/zlib/crc_folding.c",
+    ],
+}
+
+// GN: //third_party/zlib:zlib_inflate_chunk_simd
+filegroup {
+    name: "cronet_aml_third_party_zlib_zlib_inflate_chunk_simd",
+    srcs: [
+        "third_party/zlib/contrib/optimizations/inffast_chunk.c",
+        "third_party/zlib/contrib/optimizations/inflate.c",
+    ],
+}
+
+// GN: //third_party/zlib:zlib_slide_hash_simd
+filegroup {
+    name: "cronet_aml_third_party_zlib_zlib_slide_hash_simd",
+}
+
+// GN: //url:buildflags
+genrule {
+    name: "cronet_aml_url_buildflags",
+    cmd: "echo '--flags USE_PLATFORM_ICU_ALTERNATIVES=\"true\"' | " +
+         "$(location build/write_buildflag_header.py) --output " +
+         "$(out) " +
+         "--rulename " +
+         "//url:buildflags " +
+         "--gen-dir " +
+         ". " +
+         "--definitions " +
+         "/dev/stdin",
+    out: [
+        "url/buildflags.h",
+    ],
+    tool_files: [
+        "build/write_buildflag_header.py",
+    ],
+}
+
+// GN: //url:url
+cc_library_static {
+    name: "cronet_aml_url_url",
+    srcs: [
+        ":cronet_aml_ipc_param_traits",
+        "url/gurl.cc",
+        "url/origin.cc",
+        "url/scheme_host_port.cc",
+        "url/third_party/mozilla/url_parse.cc",
+        "url/url_canon.cc",
+        "url/url_canon_etc.cc",
+        "url/url_canon_filesystemurl.cc",
+        "url/url_canon_fileurl.cc",
+        "url/url_canon_host.cc",
+        "url/url_canon_internal.cc",
+        "url/url_canon_ip.cc",
+        "url/url_canon_mailtourl.cc",
+        "url/url_canon_path.cc",
+        "url/url_canon_pathurl.cc",
+        "url/url_canon_query.cc",
+        "url/url_canon_relative.cc",
+        "url/url_canon_stdstring.cc",
+        "url/url_canon_stdurl.cc",
+        "url/url_constants.cc",
+        "url/url_idna_icu_alternatives_android.cc",
+        "url/url_parse_file.cc",
+        "url/url_util.cc",
+    ],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+    ],
+    static_libs: [
+        "cronet_aml_base_base",
+        "cronet_aml_base_third_party_dynamic_annotations_dynamic_annotations",
+    ],
+    generated_headers: [
+        "cronet_aml_base_debugging_buildflags",
+        "cronet_aml_base_logging_buildflags",
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_url_buildflags",
+        "cronet_aml_url_url_jni_headers",
+    ],
+    export_generated_headers: [
+        "cronet_aml_base_debugging_buildflags",
+        "cronet_aml_base_logging_buildflags",
+        "cronet_aml_build_chromeos_buildflags",
+        "cronet_aml_url_buildflags",
+        "cronet_aml_url_url_jni_headers",
+    ],
+    defaults: [
+        "cronet_aml_defaults",
+    ],
+    cflags: [
+        "-DANDROID",
+        "-DANDROID_NDK_VERSION_ROLL=r23_1",
+        "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"",
+        "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc",
+        "-DDCHECK_ALWAYS_ON=1",
+        "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+        "-DHAVE_SYS_UIO_H",
+        "-DIS_URL_IMPL",
+        "-D_DEBUG",
+        "-D_GNU_SOURCE",
+        "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1",
+        "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1",
+        "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+    local_include_dirs: [
+        "./",
+        "buildtools/third_party/libc++/",
+        "buildtools/third_party/libc++/trunk/include",
+        "buildtools/third_party/libc++abi/trunk/include",
+        "third_party/abseil-cpp/",
+        "third_party/boringssl/src/include/",
+        "third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include",
+    ],
+    header_libs: [
+        "jni_headers",
+    ],
+    cpp_std: "c++20",
+}
+
+// GN: //url:url_jni_headers
+genrule {
+    name: "cronet_aml_url_url_jni_headers",
+    srcs: [
+        "url/android/java/src/org/chromium/url/IDNStringUtil.java",
+        "url/android/java/src/org/chromium/url/Origin.java",
+    ],
+    cmd: "$(location base/android/jni_generator/jni_generator.py) --ptr_type " +
+         "long " +
+         " " +
+         " " +
+         "--output_dir " +
+         "$(genDir)/url/url_jni_headers " +
+         "--includes " +
+         "base/android/jni_generator/jni_generator_helper.h " +
+         "--use_proxy_hash " +
+         "--output_name " +
+         "IDNStringUtil_jni.h " +
+         "--output_name " +
+         "Origin_jni.h " +
+         "--input_file " +
+         "$(location url/android/java/src/org/chromium/url/IDNStringUtil.java) " +
+         "--input_file " +
+         "$(location url/android/java/src/org/chromium/url/Origin.java)",
+    out: [
+        "url/url_jni_headers/IDNStringUtil_jni.h",
+        "url/url_jni_headers/Origin_jni.h",
+    ],
+    tool_files: [
+        "base/android/jni_generator/android_jar.classes",
+        "base/android/jni_generator/jni_generator.py",
+        "build/android/gyp/util/__init__.py",
+        "build/android/gyp/util/build_utils.py",
+        "build/gn_helpers.py",
+    ],
+}
+
diff --git a/tools/gn2bp/desc.json b/tools/gn2bp/desc.json
new file mode 100644
index 0000000..5648519
--- /dev/null
+++ b/tools/gn2bp/desc.json
Binary files differ
diff --git a/tools/gn2bp/gen_android_bp b/tools/gn2bp/gen_android_bp
new file mode 100755
index 0000000..c46095a
--- /dev/null
+++ b/tools/gn2bp/gen_android_bp
@@ -0,0 +1,1396 @@
+#!/usr/bin/env python3
+# 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.
+
+# This tool translates a collection of BUILD.gn files into a mostly equivalent
+# Android.bp file for the Android Soong build system. The input to the tool is a
+# JSON description of the GN build definition generated with the following
+# command:
+#
+#   gn desc out --format=json --all-toolchains "//*" > desc.json
+#
+# The tool is then given a list of GN labels for which to generate Android.bp
+# build rules. The dependencies for the GN labels are squashed to the generated
+# Android.bp target, except for actions which get their own genrule. Some
+# libraries are also mapped to their Android equivalents -- see |builtin_deps|.
+
+import argparse
+import collections
+import json
+import logging as log
+import os
+import re
+import sys
+import copy
+
+import gn_utils
+
+ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+# Default targets to translate to the blueprint file.
+default_targets = [
+    '//components/cronet/android:cronet',
+]
+
+# Defines a custom init_rc argument to be applied to the corresponding output
+# blueprint target.
+target_initrc = {
+    # TODO: this can probably be removed.
+}
+
+target_host_supported = [
+    # TODO: remove if this is not useful for the cronet build.
+]
+
+# Proto target groups which will be made public.
+proto_groups = {
+    # TODO: remove if this is not used for the cronet build.
+}
+
+# All module names are prefixed with this string to avoid collisions.
+module_prefix = 'cronet_aml_'
+
+# Shared libraries which are directly translated to Android system equivalents.
+shared_library_allowlist = [
+    'android',
+    'android.hardware.atrace@1.0',
+    'android.hardware.health@2.0',
+    'android.hardware.health-V1-ndk',
+    'android.hardware.power.stats@1.0',
+    "android.hardware.power.stats-V1-cpp",
+    'base',
+    'binder',
+    'binder_ndk',
+    'cutils',
+    'hidlbase',
+    'hidltransport',
+    'hwbinder',
+    'incident',
+    'log',
+    'services',
+    'statssocket',
+    "tracingproxy",
+    'utils',
+]
+
+# Static libraries which are directly translated to Android system equivalents.
+static_library_allowlist = [
+    'statslog_perfetto',
+]
+
+# Include directories that will be removed from all targets.
+local_include_dirs_denylist = [
+    'third_party/protobuf/src/',
+]
+
+# Name of the module which settings such as compiler flags for all other
+# modules.
+defaults_module = module_prefix + 'defaults'
+
+# Location of the project in the Android source tree.
+tree_path = 'external/chromium_org'
+
+# Path for the protobuf sources in the standalone build.
+buildtools_protobuf_src = '//buildtools/protobuf/src'
+
+# Location of the protobuf src dir in the Android source tree.
+android_protobuf_src = 'external/protobuf/src'
+
+# Compiler flags which are passed through to the blueprint.
+cflag_allowlist = r'^-DPERFETTO.*$'
+
+# Additional arguments to apply to Android.bp rules.
+additional_args = {
+    # TODO: remove if not needed.
+    'cronet_aml_net_net': [
+        ('export_static_lib_headers', {
+            'cronet_aml_net_third_party_quiche_quiche',
+            'cronet_aml_crypto_crypto',
+        }),
+        ('whole_static_libs', {
+            'cronet_aml_net_third_party_quiche_quiche',
+            'cronet_aml_base_base',
+            "cronet_aml_crypto_crypto",
+            "libssl",
+        }),
+    ],
+    'cronet_aml_components_cronet_android_cronet': [
+        ('rtti', True),
+        ('cppflags', {
+            # TODO: figure out if there is no way around this and if this is
+            # allowed for platform code.
+            "-fexceptions",
+        })
+    ]
+}
+
+
+def enable_gtest_and_gmock(module):
+  module.static_libs.add('libgmock')
+  module.static_libs.add('libgtest')
+  if module.name != 'perfetto_gtest_logcat_printer':
+    module.whole_static_libs.add('perfetto_gtest_logcat_printer')
+
+
+def enable_protobuf_full(module):
+  if module.type == 'cc_binary_host':
+    module.static_libs.add('libprotobuf-cpp-full')
+  elif module.host_supported:
+    module.host.static_libs.add('libprotobuf-cpp-full')
+    module.android.shared_libs.add('libprotobuf-cpp-full')
+  elif module.type not in ['genrule', 'filegroup']:
+    module.shared_libs.add('libprotobuf-cpp-full')
+
+
+def enable_protobuf_lite(module):
+  if module.type not in ['genrule', 'filegroup']:
+    module.shared_libs.add('libprotobuf-cpp-lite')
+
+
+def enable_protoc_lib(module):
+  if module.type == 'cc_binary_host':
+    module.static_libs.add('libprotoc')
+  else:
+    module.shared_libs.add('libprotoc')
+
+
+def enable_libunwindstack(module):
+  if module.name != 'heapprofd_standalone_client':
+    module.shared_libs.add('libunwindstack')
+    module.shared_libs.add('libprocinfo')
+    module.shared_libs.add('libbase')
+  else:
+    module.static_libs.add('libunwindstack')
+    module.static_libs.add('libprocinfo')
+    module.static_libs.add('libbase')
+    module.static_libs.add('liblzma')
+    module.static_libs.add('libdexfile_support')
+    module.runtime_libs.add('libdexfile')  # libdexfile_support dependency
+
+
+def enable_libunwind(module):
+  # libunwind is disabled on Darwin so we cannot depend on it.
+  pass
+
+
+def enable_sqlite(module):
+  if module.type == 'cc_binary_host':
+    module.static_libs.add('libsqlite')
+    module.static_libs.add('sqlite_ext_percentile')
+  elif module.host_supported:
+    # Copy what the sqlite3 command line tool does.
+    module.android.shared_libs.add('libsqlite')
+    module.android.shared_libs.add('libicu')
+    module.android.shared_libs.add('liblog')
+    module.android.shared_libs.add('libutils')
+    module.android.static_libs.add('sqlite_ext_percentile')
+    module.host.static_libs.add('libsqlite')
+    module.host.static_libs.add('sqlite_ext_percentile')
+  else:
+    module.shared_libs.add('libsqlite')
+    module.shared_libs.add('libicu')
+    module.shared_libs.add('liblog')
+    module.shared_libs.add('libutils')
+    module.static_libs.add('sqlite_ext_percentile')
+
+
+def enable_zlib(module):
+  if module.type == 'cc_binary_host':
+    module.static_libs.add('libz')
+  elif module.host_supported:
+    module.android.shared_libs.add('libz')
+    module.host.static_libs.add('libz')
+  else:
+    module.shared_libs.add('libz')
+
+
+def enable_uapi_headers(module):
+  module.include_dirs.add('bionic/libc/kernel')
+
+
+def enable_bionic_libc_platform_headers_on_android(module):
+  module.header_libs.add('bionic_libc_platform_headers')
+
+
+def enable_boringssl(module):
+  if module.type not in ['genrule', 'filegroup']:
+    module.static_libs.add('libssl')
+
+
+# Android equivalents for third-party libraries that the upstream project
+# depends on.
+builtin_deps = {
+    '//gn:default_deps':
+        lambda x: None,
+    '//gn:gtest_main':
+        lambda x: None,
+    '//gn:gtest_and_gmock':
+        enable_gtest_and_gmock,
+    '//gn:libunwind':
+        enable_libunwind,
+    '//gn:libunwindstack':
+        enable_libunwindstack,
+    '//gn:sqlite':
+        enable_sqlite,
+    '//gn:zlib':
+        enable_zlib,
+    '//gn:bionic_kernel_uapi_headers':
+        enable_uapi_headers,
+    '//src/profiling/memory:bionic_libc_platform_headers_on_android':
+        enable_bionic_libc_platform_headers_on_android,
+    '//third_party/protobuf:protoc':
+      lambda x: None,
+    '//third_party/protobuf:protobuf_full':
+        enable_protobuf_full,
+    '//third_party/protobuf:protobuf_lite':
+        enable_protobuf_lite,
+    '//third_party/protobuf:protoc_lib':
+        enable_protoc_lib,
+    '//third_party/boringssl:boringssl':
+        enable_boringssl,
+}
+
+# ----------------------------------------------------------------------------
+# End of configuration.
+# ----------------------------------------------------------------------------
+
+
+class Error(Exception):
+  pass
+
+
+class ThrowingArgumentParser(argparse.ArgumentParser):
+
+  def __init__(self, context):
+    super(ThrowingArgumentParser, self).__init__()
+    self.context = context
+
+  def error(self, message):
+    raise Error('%s: %s' % (self.context, message))
+
+
+def write_blueprint_key_value(output, name, value, sort=True):
+  """Writes a Blueprint key-value pair to the output"""
+
+  if isinstance(value, bool):
+    if value:
+      output.append('    %s: true,' % name)
+    else:
+      output.append('    %s: false,' % name)
+    return
+  if not value:
+    return
+  if isinstance(value, set):
+    value = sorted(value)
+  if isinstance(value, list):
+    output.append('    %s: [' % name)
+    for item in sorted(value) if sort else value:
+      output.append('        "%s",' % item)
+    output.append('    ],')
+    return
+  if isinstance(value, Target):
+    value.to_string(output)
+    return
+  if isinstance(value, dict):
+    kv_output = []
+    for k, v in value.items():
+      write_blueprint_key_value(kv_output, k, v)
+
+    output.append('    %s: {' % name)
+    for line in kv_output:
+      output.append('    %s' % line)
+    output.append('    },')
+    return
+  output.append('    %s: "%s",' % (name, value))
+
+
+class Target(object):
+  """A target-scoped part of a module"""
+
+  def __init__(self, name):
+    self.name = name
+    self.shared_libs = set()
+    self.static_libs = set()
+    self.whole_static_libs = set()
+    self.cflags = set()
+    self.dist = dict()
+    self.strip = dict()
+    self.stl = None
+
+  def to_string(self, output):
+    nested_out = []
+    self._output_field(nested_out, 'shared_libs')
+    self._output_field(nested_out, 'static_libs')
+    self._output_field(nested_out, 'whole_static_libs')
+    self._output_field(nested_out, 'cflags')
+    self._output_field(nested_out, 'stl')
+    self._output_field(nested_out, 'dist')
+    self._output_field(nested_out, 'strip')
+
+    if nested_out:
+      output.append('    %s: {' % self.name)
+      for line in nested_out:
+        output.append('    %s' % line)
+      output.append('    },')
+
+  def _output_field(self, output, name, sort=True):
+    value = getattr(self, name)
+    return write_blueprint_key_value(output, name, value, sort)
+
+
+class Module(object):
+  """A single module (e.g., cc_binary, cc_test) in a blueprint."""
+
+  def __init__(self, mod_type, name, gn_target):
+    self.type = mod_type
+    self.gn_target = gn_target
+    self.name = name
+    self.srcs = set()
+    self.comment = 'GN: ' + gn_utils.label_without_toolchain(gn_target)
+    self.shared_libs = set()
+    self.static_libs = set()
+    self.whole_static_libs = set()
+    self.runtime_libs = set()
+    self.tools = set()
+    self.cmd = None
+    self.host_supported = False
+    self.vendor_available = False
+    self.init_rc = set()
+    self.out = set()
+    self.export_include_dirs = set()
+    self.generated_headers = set()
+    self.export_generated_headers = set()
+    self.export_static_lib_headers = set()
+    self.defaults = set()
+    self.cflags = set()
+    self.include_dirs = set()
+    self.local_include_dirs = []
+    self.header_libs = set()
+    self.required = set()
+    self.tool_files = set()
+    self.android = Target('android')
+    self.host = Target('host')
+    self.stl = None
+    self.cpp_std = None
+    self.dist = dict()
+    self.strip = dict()
+    self.data = set()
+    self.apex_available = set()
+    self.min_sdk_version = None
+    self.proto = dict()
+    # The genrule_XXX below are properties that must to be propagated back
+    # on the module(s) that depend on the genrule.
+    self.genrule_headers = set()
+    self.genrule_srcs = set()
+    self.genrule_shared_libs = set()
+    self.genrule_header_libs = set()
+    self.version_script = None
+    self.test_suites = set()
+    self.test_config = None
+    self.stubs = {}
+    self.cppflags = set()
+    self.rtti = False
+
+  def to_string(self, output):
+    if self.comment:
+      output.append('// %s' % self.comment)
+    output.append('%s {' % self.type)
+    self._output_field(output, 'name')
+    self._output_field(output, 'srcs')
+    self._output_field(output, 'shared_libs')
+    self._output_field(output, 'static_libs')
+    self._output_field(output, 'whole_static_libs')
+    self._output_field(output, 'runtime_libs')
+    self._output_field(output, 'tools')
+    self._output_field(output, 'cmd', sort=False)
+    if self.host_supported:
+      self._output_field(output, 'host_supported')
+    if self.vendor_available:
+      self._output_field(output, 'vendor_available')
+    self._output_field(output, 'init_rc')
+    self._output_field(output, 'out')
+    self._output_field(output, 'export_include_dirs')
+    self._output_field(output, 'generated_headers')
+    self._output_field(output, 'export_generated_headers')
+    self._output_field(output, 'export_static_lib_headers')
+    self._output_field(output, 'defaults')
+    self._output_field(output, 'cflags')
+    self._output_field(output, 'include_dirs')
+    self._output_field(output, 'local_include_dirs', sort=False)
+    self._output_field(output, 'header_libs')
+    self._output_field(output, 'required')
+    self._output_field(output, 'dist')
+    self._output_field(output, 'strip')
+    self._output_field(output, 'tool_files')
+    self._output_field(output, 'data')
+    self._output_field(output, 'stl')
+    self._output_field(output, 'cpp_std')
+    self._output_field(output, 'apex_available')
+    self._output_field(output, 'min_sdk_version')
+    self._output_field(output, 'version_script')
+    self._output_field(output, 'test_suites')
+    self._output_field(output, 'test_config')
+    self._output_field(output, 'stubs')
+    self._output_field(output, 'proto')
+    self._output_field(output, 'cppflags')
+    if self.rtti:
+      self._output_field(output, 'rtti')
+
+    target_out = []
+    self._output_field(target_out, 'android')
+    self._output_field(target_out, 'host')
+    if target_out:
+      output.append('    target: {')
+      for line in target_out:
+        output.append('    %s' % line)
+      output.append('    },')
+
+    output.append('}')
+    output.append('')
+
+  def add_android_static_lib(self, lib):
+    if self.type == 'cc_binary_host':
+      raise Exception('Adding Android static lib for host tool is unsupported')
+    elif self.host_supported:
+      self.android.static_libs.add(lib)
+    else:
+      self.static_libs.add(lib)
+
+  def add_android_shared_lib(self, lib):
+    if self.type == 'cc_binary_host':
+      raise Exception('Adding Android shared lib for host tool is unsupported')
+    elif self.host_supported:
+      self.android.shared_libs.add(lib)
+    else:
+      self.shared_libs.add(lib)
+
+  def _output_field(self, output, name, sort=True):
+    value = getattr(self, name)
+    return write_blueprint_key_value(output, name, value, sort)
+
+
+class Blueprint(object):
+  """In-memory representation of an Android.bp file."""
+
+  def __init__(self):
+    self.modules = {}
+
+  def add_module(self, module):
+    """Adds a new module to the blueprint, replacing any existing module
+        with the same name.
+
+        Args:
+            module: Module instance.
+        """
+    self.modules[module.name] = module
+
+  def to_string(self, output):
+    for m in sorted(self.modules.values(), key=lambda m: m.name):
+      m.to_string(output)
+
+
+def label_to_module_name(label):
+  """Turn a GN label (e.g., //:perfetto_tests) into a module name."""
+  # If the label is explicibly listed in the default target list, don't prefix
+  # its name and return just the target name. This is so tools like
+  # "traceconv" stay as such in the Android tree.
+  label_without_toolchain = gn_utils.label_without_toolchain(label)
+  module = re.sub(r'^//:?', '', label_without_toolchain)
+  module = re.sub(r'[^a-zA-Z0-9_]', '_', module)
+  if not module.startswith(module_prefix):
+    return module_prefix + module
+  return module
+
+
+def is_supported_source_file(name):
+  """Returns True if |name| can appear in a 'srcs' list."""
+  return os.path.splitext(name)[1] in ['.c', '.cc', '.cpp', '.java', '.proto', '.S']
+
+
+def create_proto_modules(blueprint, gn, target):
+  """Generate genrules for a proto GN target.
+
+    GN actions are used to dynamically generate files during the build. The
+    Soong equivalent is a genrule. This function turns a specific kind of
+    genrule which turns .proto files into source and header files into a pair
+    equivalent genrules.
+
+    Args:
+        blueprint: Blueprint instance which is being generated.
+        target: gn_utils.Target object.
+
+    Returns:
+        The source_genrule module.
+    """
+  assert (target.type == 'proto_library')
+
+  tools = {'aprotoc'}
+  cpp_out_dir = '$(genDir)/%s/%s/' % (tree_path, target.proto_in_dir)
+  target_module_name = label_to_module_name(target.name)
+
+  # In GN builds the proto path is always relative to the output directory
+  # (out/tmp.xxx).
+  cmd = ['$(location aprotoc)']
+  cmd += ['--proto_path=%s/%s' % (tree_path, target.proto_in_dir)]
+
+  if buildtools_protobuf_src in target.proto_paths:
+    cmd += ['--proto_path=%s' % android_protobuf_src]
+
+  # We don't generate any targets for source_set proto modules because
+  # they will be inlined into other modules if required.
+  if target.proto_plugin == 'source_set':
+    return None
+
+  # Descriptor targets only generate a single target.
+  if target.proto_plugin == 'descriptor':
+    out = '{}.bin'.format(target_module_name)
+
+    cmd += ['--descriptor_set_out=$(out)']
+    cmd += ['$(in)']
+
+    descriptor_module = Module('genrule', target_module_name, target.name)
+    descriptor_module.cmd = ' '.join(cmd)
+    descriptor_module.out = [out]
+    descriptor_module.tools = tools
+    blueprint.add_module(descriptor_module)
+
+    # Recursively extract the .proto files of all the dependencies and
+    # add them to srcs.
+    descriptor_module.srcs.update(
+        gn_utils.label_to_path(src) for src in target.sources)
+    for dep in target.transitive_proto_deps:
+      current_target = gn.get_target(dep)
+      descriptor_module.srcs.update(
+          gn_utils.label_to_path(src) for src in current_target.sources)
+
+    return descriptor_module
+
+  # We create two genrules for each proto target: one for the headers and
+  # another for the sources. This is because the module that depends on the
+  # generated files needs to declare two different types of dependencies --
+  # source files in 'srcs' and headers in 'generated_headers' -- and it's not
+  # valid to generate .h files from a source dependency and vice versa.
+  source_module_name = target_module_name + '_gen'
+  source_module = Module('genrule', source_module_name, target.name)
+  blueprint.add_module(source_module)
+  source_module.srcs.update(
+      gn_utils.label_to_path(src) for src in target.sources)
+
+  header_module = Module('genrule', source_module_name + '_headers',
+                         target.name)
+  blueprint.add_module(header_module)
+  header_module.srcs = set(source_module.srcs)
+
+  # TODO(primiano): at some point we should remove this. This was introduced
+  # by aosp/1108421 when adding "protos/" to .proto include paths, in order to
+  # avoid doing multi-repo changes and allow old clients in the android tree
+  # to still do the old #include "perfetto/..." rather than
+  # #include "protos/perfetto/...".
+  header_module.export_include_dirs = {'.', 'protos'}
+  # Since the .cc file and .h get created by a different gerule target, they
+  # are not put in the same intermediate path, so local includes do not work
+  # without explictily exporting the include dir.
+  header_module.export_include_dirs.add(target.proto_in_dir)
+
+  source_module.genrule_srcs.add(':' + source_module.name)
+  source_module.genrule_headers.add(header_module.name)
+
+  if target.proto_plugin == 'proto':
+    suffixes = ['pb']
+    source_module.genrule_shared_libs.add('libprotobuf-cpp-lite')
+    cmd += ['--cpp_out=lite=true:' + cpp_out_dir]
+  elif target.proto_plugin == 'protozero':
+    suffixes = ['pbzero']
+    plugin = create_modules_from_target(blueprint, gn, protozero_plugin)
+    tools.add(plugin.name)
+    cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
+    cmd += ['--plugin_out=wrapper_namespace=pbzero:' + cpp_out_dir]
+  elif target.proto_plugin == 'cppgen':
+    suffixes = ['gen']
+    plugin = create_modules_from_target(blueprint, gn, cppgen_plugin)
+    tools.add(plugin.name)
+    cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
+    cmd += ['--plugin_out=wrapper_namespace=gen:' + cpp_out_dir]
+  elif target.proto_plugin == 'ipc':
+    suffixes = ['ipc']
+    plugin = create_modules_from_target(blueprint, gn, ipc_plugin)
+    tools.add(plugin.name)
+    cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
+    cmd += ['--plugin_out=wrapper_namespace=gen:' + cpp_out_dir]
+  else:
+    raise Error('Unsupported proto plugin: %s' % target.proto_plugin)
+
+  cmd += ['$(in)']
+  source_module.cmd = ' '.join(cmd)
+  header_module.cmd = source_module.cmd
+  source_module.tools = tools
+  header_module.tools = tools
+
+  for sfx in suffixes:
+    source_module.out.update('%s/%s' %
+                             (tree_path, src.replace('.proto', '.%s.cc' % sfx))
+                             for src in source_module.srcs)
+    header_module.out.update('%s/%s' %
+                             (tree_path, src.replace('.proto', '.%s.h' % sfx))
+                             for src in header_module.srcs)
+  return source_module
+
+
+def create_amalgamated_sql_metrics_module(blueprint, target):
+  bp_module_name = label_to_module_name(target.name)
+  module = Module('genrule', bp_module_name, target.name)
+  module.tool_files.add('tools/gen_amalgamated_sql_metrics.py')
+  module.cmd = ' '.join([
+      '$(location tools/gen_amalgamated_sql_metrics.py)',
+      '--cpp_out=$(out)',
+      '$(in)',
+  ])
+  module.genrule_headers.add(module.name)
+  module.out.update(target.outputs)
+  module.srcs.update(gn_utils.label_to_path(src) for src in target.inputs)
+  blueprint.add_module(module)
+  return module
+
+
+def create_cc_proto_descriptor_module(blueprint, target):
+  bp_module_name = label_to_module_name(target.name)
+  module = Module('genrule', bp_module_name, target.name)
+  module.tool_files.add('tools/gen_cc_proto_descriptor.py')
+  module.cmd = ' '.join([
+      '$(location tools/gen_cc_proto_descriptor.py)', '--gen_dir=$(genDir)',
+      '--cpp_out=$(out)', '$(in)'
+  ])
+  module.genrule_headers.add(module.name)
+  module.srcs.update(
+      ':' + label_to_module_name(dep) for dep in target.proto_deps)
+  module.srcs.update(
+      gn_utils.label_to_path(src)
+      for src in target.inputs
+      if "tmp.gn_utils" not in src)
+  module.out.update(target.outputs)
+  blueprint.add_module(module)
+  return module
+
+
+def create_gen_version_module(blueprint, target, bp_module_name):
+  module = Module('genrule', bp_module_name, gn_utils.GEN_VERSION_TARGET)
+  script_path = gn_utils.label_to_path(target.script)
+  module.genrule_headers.add(bp_module_name)
+  module.tool_files.add(script_path)
+  module.out.update(target.outputs)
+  module.srcs.update(gn_utils.label_to_path(src) for src in target.inputs)
+  module.cmd = ' '.join([
+      'python3 $(location %s)' % script_path, '--no_git',
+      '--changelog=$(location CHANGELOG)', '--cpp_out=$(out)'
+  ])
+  blueprint.add_module(module)
+  return module
+
+
+def create_proto_group_modules(blueprint, gn, module_name, target_names):
+  # TODO(lalitm): today, we're only adding a Java lite module because that's
+  # the only one used in practice. In the future, if we need other target types
+  # (e.g. C++, Java full etc.) add them here.
+  bp_module_name = label_to_module_name(module_name) + '_java_protos'
+  module = Module('java_library', bp_module_name, bp_module_name)
+  module.comment = f'''GN: [{', '.join(target_names)}]'''
+  module.proto = {'type': 'lite', 'canonical_path_from_root': False}
+
+  for name in target_names:
+    target = gn.get_target(name)
+    module.srcs.update(gn_utils.label_to_path(src) for src in target.sources)
+    for dep_label in target.transitive_proto_deps:
+      dep = gn.get_target(dep_label)
+      module.srcs.update(gn_utils.label_to_path(src) for src in dep.sources)
+
+  blueprint.add_module(module)
+
+# HACK: Need to support build_cofig_gen flexibly instead of hardcoding
+# build_config_gen generates srcjar by executing gcc via gcc_preprocess.py but gcc is not
+# available in genrule sandbox. Also gcc path is not configurable.
+# Under the //net:net, gcc_preprocess.py is only used for build_config_gen.
+# So, for now, hardcoding BuildConfig.java and generates srcjar by soong_zip.
+def override_build_config_gen(module):
+  module.tool_files.clear()
+  module.tools.add("soong_zip")
+  cmd = [
+    "echo",
+    "\\\"package org.chromium.build;\\n",
+    "public class BuildConfig {\\n",
+    "public static boolean IS_MULTIDEX_ENABLED ;\\n",
+    "public static boolean ENABLE_ASSERTS = true;\\n",
+    "public static boolean IS_UBSAN ;\\n",
+    "public static boolean IS_CHROME_BRANDED ;\\n",
+    "public static int R_STRING_PRODUCT_VERSION ;\\n",
+    "public static int MIN_SDK_VERSION = 1;\\n",
+    "public static boolean BUNDLES_SUPPORTED ;\\n",
+    "public static boolean IS_INCREMENTAL_INSTALL ;\\n",
+    "public static boolean ISOLATED_SPLITS_ENABLED ;\\n",
+    "public static boolean IS_FOR_TEST ;\\n",
+    "}\\n\\\"",
+    "> $(genDir)/BuildConfig.java &&",
+    "$(location soong_zip) -o $(out) -srcjar -f $(genDir)/BuildConfig.java"
+  ]
+  NEWLINE = ' " +\n         "'
+  module.cmd = NEWLINE.join(cmd)
+  return module
+
+def create_action_foreach_modules(blueprint, target):
+  """ The following assumes that rebase_path exists in the args.
+  The args of an action_foreach contains hints about which output files are generated
+  by which source files.
+  This is copied directly from the args
+  "gen/net/base/registry_controlled_domains/{{source_name_part}}-reversed-inc.cc"
+  So each source file will generate an output whose name is the {source_name-reversed-inc.cc}
+  """
+  new_args = []
+  for i, src in enumerate(sorted(target.sources)):
+    # don't add script arg for the first source -- create_action_module
+    # already does this.
+    if i != 0:
+      new_args.append('&& python3 $(location %s)' %
+                   gn_utils.label_to_path(target.script))
+    for arg in target.args:
+      if '{{source}}' in arg:
+        new_args.append('$(location %s)' % (gn_utils.label_to_path(src)))
+      elif '{{source_name_part}}' in arg:
+        source_name_part = src.split("/")[-1] # Get the file name only
+        source_name_part = source_name_part.split(".")[0] # Remove the extension (Ex: .cc)
+        file_name = arg.replace('{{source_name_part}}', source_name_part).split("/")[-1]
+        # file_name represent the output file name. But we need the whole path
+        # This can be found from target.outputs.
+        for out in target.outputs:
+          if out.endswith(file_name):
+            new_args.append('$(location %s)' % out)
+      else:
+        new_args.append(arg)
+
+  target.args = new_args
+  return create_action_module(blueprint, target)
+
+def create_action_module(blueprint, target):
+  bp_module_name = label_to_module_name(target.name)
+  module = Module('genrule', bp_module_name, target.name)
+
+  # Convert ['--param=value'] to ['--param', 'value'] for consistency.
+  # TODO: we may want to only do this for python scripts arguments. If argparse
+  # is used, this transformation is safe.
+  target.args = [str for it in target.args for str in it.split('=')]
+
+  if target.script == "//build/write_buildflag_header.py":
+    # write_buildflag_header.py writes result to args.genDir/args.output
+    # So, override args.genDir by '.' so that args.output=$(out) works
+    for i, val in enumerate(target.args):
+      if val == '--gen-dir':
+        target.args[i + 1] = '.'
+      elif val == '--output':
+        target.args[i + 1] = '$(out)'
+
+  elif target.script == '//build/write_build_date_header.py':
+    target.args[0] = '$(out)'
+
+  elif target.script == '//base/android/jni_generator/jni_generator.py':
+    # chromium builds against a prebuilt ndk that contains the jni_headers, so
+    # a dependency is never explicitly created.
+    module.genrule_header_libs.add('jni_headers')
+    needs_javap = False
+    for i, val in enumerate(target.args):
+      if val == '--output_dir':
+        # replace --output_dir gen/jni_headers/... with --output_dir $(genDir)/...
+        target.args[i + 1] = re.sub('^gen/jni_headers', '$(genDir)', target.args[i + 1])
+      elif val == '--input_file':
+        # --input_file supports both .class specifiers or source files as arguments.
+        # Only source files need to be wrapped inside a $(location <label>) tag.
+        if re.match('.*\.class$', target.args[i + 1]):
+          continue
+        # replace --input_file ../../... with --input_file $(location ...)
+        # TODO: put inside function
+        filename = re.sub('^\.\./\.\./', '', target.args[i + 1])
+        target.args[i + 1] = '$(location %s)' % filename
+      elif val == '--includes' and 'jni_generator_helper' in target.args[i + 1]:
+        # delete all leading ../
+        target.args[i + 1] = re.sub('^(\.\./)+', '', target.args[i + 1])
+      elif val == '--prev_output_dir':
+        # this is not needed for aosp builds.
+        target.args[i] = ''
+        target.args[i + 1] = ''
+      elif val == '--jar_file':
+        # delete leading ../../ and add path to javap
+        filename = re.sub('^\.\./\.\./', '', target.args[i + 1])
+        target.args[i + 1] = '$(location %s)' % filename
+        needs_javap = True
+
+    if needs_javap:
+      target.args.append('--javap')
+      target.args.append('$$(find out/.path -name javap)')
+    # fix target.output directory to match #include statements.
+    target.outputs = [re.sub('^jni_headers/', '', out) for out in target.outputs]
+
+  elif target.script == '//base/android/jni_generator/jni_registration_generator.py':
+    # jni_registration_generator.py pulls in some config dependencies that we
+    # do not handle. Remove them.
+    # TODO: find a better way to do this.
+    target.deps.clear()
+
+    target.inputs = [file for file in target.inputs if not file.startswith('//out/')]
+    for i, val in enumerate(target.args):
+      if val in ['--depfile', '--srcjar-path', '--header-path']:
+        target.args[i + 1] = re.sub('^gen', '$(genDir)', target.args[i + 1])
+      if val == '--sources-files':
+        target.args[i + 1] = '$(genDir)/java.sources'
+      elif val == '--sources-exclusions':
+        # update_jni_registration_module removes them from the srcs of the module
+        # It might be better to remove sources by '--sources-exclusions'
+        target.args[i] = ''
+        target.args[i + 1] = ''
+
+  elif target.script == '//build/android/gyp/write_build_config.py':
+    for i, val in enumerate(target.args):
+      if val == '--depfile':
+        # Depfile is not used, so no need to generate it.
+        target.args[i] = ''
+        target.args[i + 1] = ''
+      elif val in ['--deps-configs', '--bundled-srcjars']:
+        args = target.args[i + 1]
+        if args == '[]':
+          continue
+        # strip surrounding [] and split by ", "
+        args = args.strip('[]').split(', ')
+        # strip surrounding ""
+        args = [arg.strip('"') for arg in args]
+        # remove leading gen/
+        args = [re.sub('^gen/', '', arg) for arg in args]
+        # wrap filename in \"$(location filename)\"
+        args = ['\"$(location %s)\"' % arg for arg in args]
+        # join args with ", " and wrap in []
+        target.args[i + 1] = '[%s]' % ', '.join(args)
+
+      elif val == '--public-deps-configs':
+        # TODO: implement.
+        pass
+
+      elif val == '--build-config':
+        # json output of this script
+        target.args[i + 1] = re.sub('^gen', '$(genDir)', target.args[i + 1])
+
+      elif val in ['--unprocessed-jar-path', '--interface-jar-path',
+                   '--device-jar-path', '--host-jar-path']:
+        # jar path can be within sources (../../) or output generated by
+        # another genrule (obj/)
+        filename = re.sub('^\.\./\.\./', '', target.args[i + 1])
+        filename = re.sub('^obj/', '', target.args[i + 1])
+        target.args[i + 1] = '$(location %s)' % filename
+
+      elif val == '--proguard-configs':
+        args = target.args[i + 1]
+        if args == '[]':
+          continue
+        # TODO: consider adding helpers to deal with argument lists
+        # strip surrounding [] and split by ", ", then strip surrounding ""
+        args = args.strip('[]').split(', ')
+        args = [arg.strip('"') for arg in args]
+        # remove leading ../../
+        args = [re.sub('^\.\./\.\./', '', arg) for arg in args]
+        # add dependency on proguard config file, so a $(location) wrapper can be used.
+        module.tool_files.update(args)
+        # wrap filename in \"$(location filename)\"
+        args = ['$(location %s)' % arg for arg in args]
+        target.args[i + 1] = '[%s]' % ', '.join(args)
+  elif target.script == "//build/android/gyp/write_native_libraries_java.py":
+    for i, val in enumerate(target.args):
+      if val == '--output':
+        target.args[i + 1] = '$(out)'
+  elif target.script == "//tools/grit/stamp_grit_sources.py":
+    target.outputs = [re.sub('^\/\/', '', out) for out in target.outputs]
+    # Directory that contains grit scripts
+    target.args[0] = '`dirname $(location tools/grit/grit.py)`'
+    # Path to the stamp file
+    target.args[1] = '$(out)'
+    # Script tries to create args[2] file but this is not in the output.
+    # Specifying file under $(genDir) so that parent directory exists.
+    # If this file is used by other module, we may need to add this file to the outputs.
+    target.args[2] = '$(genDir)/' + target.args[2].split('/')[-1]
+  elif target.script == "//tools/grit/grit.py":
+    for i, val in enumerate(target.args):
+      if val == '-i':
+        # Delete leading ../..
+        filename = re.sub('^\.\./\.\./', '', target.args[i + 1])
+        target.args[i + 1] = '$(location %s)' % filename
+      elif val == '-o':
+        filename = re.sub('^gen/', '', target.args[i + 1])
+        if filename == "net":
+          # This is a directory not a file
+          target.args[i + 1] = '$(genDir)/net'
+        else:
+          # This is an output fil
+          target.args[i + 1] = '$(location %s)' % filename
+      elif val == '--depfile':
+        # The depfile is replaced by adding /tools/**/*.py to the tools_files
+        # This is basically just globbing all the needed sources by hardcoding.
+        module.tool_files.update([
+            "tools/grit/**/*.py",
+            "third_party/six/src/six.py" # This is not picked up by default. Must be added
+        ])
+
+        # Delete the depfile argument
+        target.args[i] = ' '
+        target.args[i + 1] = ' '
+      elif val == '--input':
+        # Delete leading ../..
+        filename = re.sub('^\.\./\.\./', '', target.args[i + 1])
+        # This is an output file so use $(location %s)
+        target.args[i + 1] = '$(location %s)' % filename
+  elif target.script == "//net/tools/dafsa/make_dafsa.py":
+    # This script generates .cc files but source (registry_controlled_domain.cc) in the target that
+    # depends on this target includes .cc file this script generates.
+    module.genrule_headers.add(module.name)
+  elif target.script == "//build/util/version.py":
+    # android_chrome_version.py is not specified in anywhere but version.py imports this file
+    module.tool_files.add('build/util/android_chrome_version.py')
+    for i, val in enumerate(target.args):
+      if val.startswith('../../'):
+        filename = re.sub('^\.\./\.\./', '', val)
+        target.args[i] = '$(location %s)' % filename
+      elif val == '-e':
+        # arg for -e EVAL option should be passed in -e PATCH_HI=int(PATCH)//256 format.
+        target.args[i + 1] = '%s=\'%s\'' % (target.args[i + 1], target.args[i + 2])
+        target.args[i + 2] = ''
+      elif val == '-o':
+        target.args[i + 1] = '$(out)'
+
+  script = gn_utils.label_to_path(target.script)
+  module.tool_files.add(script)
+
+  # Handle passing parameters via response file by piping them into the script
+  # and reading them from /dev/stdin.
+  response_file = '{{response_file_name}}'
+  use_response_file = response_file in target.args
+  if use_response_file:
+    # Replace {{response_file_contents}} with /dev/stdin
+    target.args = ['/dev/stdin' if it == response_file else it for it in target.args]
+
+  # escape " and \$ in target.args.
+  # once all actions are properly implemented, this may not be necessary anymore.
+  # TODO: is this the right place to do this?
+  target.args = [arg.replace('"', r'\"') for arg in target.args]
+  target.args = [arg.replace(r'\$', r'\\$') for arg in target.args]
+
+  # put all args on a new line for better diffs.
+  NEWLINE = ' " +\n         "'
+  arg_string = NEWLINE.join(target.args)
+  module.cmd = '$(location %s) %s' % (script, arg_string)
+
+  if use_response_file:
+    # Pipe response file contents into script
+    module.cmd = 'echo \'%s\' |%s%s' % (target.response_file_contents, NEWLINE, module.cmd)
+
+  if any(os.path.splitext(it)[1] == '.h' for it in target.outputs):
+    module.genrule_headers.add(bp_module_name)
+
+  # gn treats inputs and sources for actions equally.
+  # soong only supports source files inside srcs, non-source files are added as
+  # tool_files dependency.
+  for it in target.sources or target.inputs:
+    if is_supported_source_file(it):
+      module.srcs.add(gn_utils.label_to_path(it))
+    else:
+      module.tool_files.add(gn_utils.label_to_path(it))
+
+  # Actions using template "action_with_pydeps" also put script inside inputs.
+  # TODO: it might make sense to filter inputs inside GnParser.
+  if script in module.srcs:
+    module.srcs.remove(script)
+
+  module.out.update(target.outputs)
+
+  if target.name == "//build/android:build_config_gen":
+    module = override_build_config_gen(module)
+  elif target.script == "//tools/grit/stamp_grit_sources.py":
+    # stamp_grit_sources.py is not executable
+    module.cmd = "python " + module.cmd
+  elif target.script == "//base/android/jni_generator/jni_generator.py":
+    # android_jar.classes should be part of the tools as it list implicit classes
+    # for the script to generate JNI headers.
+    module.tool_files.add("base/android/jni_generator/android_jar.classes")
+  elif target.script == '//base/android/jni_generator/jni_registration_generator.py':
+    # jni_registration_generator.py doesn't work with python2
+    module.cmd = "python3 " + module.cmd
+    # Path in the original sources file does not work in genrule.
+    # So creating sources file in cmd based on the srcs of this target.
+    # Adding ../$(current_dir)/ to the head because jni_registration_generator.py uses the files
+    # whose path startswith(..)
+    commands = ["current_dir=`basename \\\`pwd\\\``;",
+                "for f in $(in);",
+                "do",
+                "echo \\\"../$$current_dir/$$f\\\" >> $(genDir)/java.sources;",
+                "done;",
+                module.cmd]
+
+    # .h file jni_registration_generator.py generates has #define with directory name.
+    # With the genrule env that contains "." which is invalid. So replace that at the end of cmd.
+    commands.append(";sed -i -e 's/OUT_SOONG_.TEMP_SBOX_.*_OUT/GEN/g' ")
+    commands.append("$(genDir)/components/cronet/android/cronet_jni_registration.h")
+    module.cmd = NEWLINE.join(commands)
+
+  blueprint.add_module(module)
+  return module
+
+
+
+def _get_cflags(target):
+  cflags = {flag for flag in target.cflags if re.match(cflag_allowlist, flag)}
+  # Consider proper allowlist or denylist if needed
+  cflags |= set("-D%s" % define.replace("\"", "\\\"") for define in target.defines)
+  return cflags
+
+
+def create_modules_from_target(blueprint, gn, gn_target_name):
+  """Generate module(s) for a given GN target.
+
+    Given a GN target name, generate one or more corresponding modules into a
+    blueprint. The only case when this generates >1 module is proto libraries.
+
+    Args:
+        blueprint: Blueprint instance which is being generated.
+        gn: gn_utils.GnParser object.
+        gn_target_name: GN target for module generation.
+    """
+  bp_module_name = label_to_module_name(gn_target_name)
+  if bp_module_name in blueprint.modules:
+    return blueprint.modules[bp_module_name]
+  target = gn.get_target(gn_target_name)
+  log.info('create modules for %s (%s)', target.name, target.type)
+
+  name_without_toolchain = gn_utils.label_without_toolchain(target.name)
+  if target.type == 'executable':
+    if target.toolchain == gn_utils.HOST_TOOLCHAIN:
+      module_type = 'cc_binary_host'
+    elif target.testonly:
+      module_type = 'cc_test'
+    else:
+      module_type = 'cc_binary'
+    module = Module(module_type, bp_module_name, gn_target_name)
+  elif target.type == 'static_library':
+    module = Module('cc_library_static', bp_module_name, gn_target_name)
+  elif target.type == 'shared_library':
+    module = Module('cc_library_shared', bp_module_name, gn_target_name)
+  elif target.type == 'source_set':
+    module = Module('filegroup', bp_module_name, gn_target_name)
+  elif target.type == 'group':
+    # "group" targets are resolved recursively by gn_utils.get_target().
+    # There's nothing we need to do at this level for them.
+    return None
+  elif target.type == 'proto_library':
+    module = create_proto_modules(blueprint, gn, target)
+    if module is None:
+      return None
+  elif target.type == 'action':
+    if 'gen_amalgamated_sql_metrics' in target.name:
+      module = create_amalgamated_sql_metrics_module(blueprint, target)
+    elif re.match('.*gen_cc_.*_descriptor$', name_without_toolchain):
+      module = create_cc_proto_descriptor_module(blueprint, target)
+    elif target.type == 'action' and \
+        name_without_toolchain == gn_utils.GEN_VERSION_TARGET:
+      module = create_gen_version_module(blueprint, target, bp_module_name)
+    else:
+      module = create_action_module(blueprint, target)
+  elif target.type == 'action_foreach':
+    module = create_action_foreach_modules(blueprint, target)
+  elif target.type == 'copy':
+    # TODO: careful now! copy targets are not supported yet, but this will stop
+    # traversing the dependency tree. For //base:base, this is not a big
+    # problem as libicu contains the only copy target which happens to be a
+    # leaf node.
+    return None
+  elif target.type == 'java_group':
+    # Java targets are handled outside of create_modules_from_target.
+    return None
+  else:
+    raise Error('Unknown target %s (%s)' % (target.name, target.type))
+
+  blueprint.add_module(module)
+  module.host_supported = (name_without_toolchain in target_host_supported)
+  module.init_rc = target_initrc.get(target.name, [])
+  module.srcs.update(
+      gn_utils.label_to_path(src)
+      for src in target.sources
+      if is_supported_source_file(src) and not src.startswith("//out/test"))
+
+  local_include_dirs_set = set()
+  if target.type in gn_utils.LINKER_UNIT_TYPES:
+    module.cflags.update(_get_cflags(target))
+    # TODO: implement proper cflag parsing.
+    for flag in target.cflags:
+      if '-std=' in flag:
+        module.cpp_std = flag[len('-std='):]
+      if '-isystem' in flag:
+        local_include_dirs_set.add(flag[len('-isystem../../'):])
+
+    # Adding local_include_dirs is necessary due to source_sets / filegroups
+    # which do not properly propagate include directories.
+    # Filter any directory inside //out as a) this directory does not exist for
+    # aosp / soong builds and b) the include directory should already be
+    # configured via library dependency.
+    local_include_dirs_set.update([gn_utils.label_to_path(d)
+                                      for d in target.include_dirs
+                                      if not re.match('^//out/.*', d)])
+    module.local_include_dirs = sorted(list(local_include_dirs_set))
+
+    # Order matters for some targets. For example, base/time/time_exploded_icu.cc
+    # in //base:base needs to have sysroot include after icu/source/common
+    # include. So adding sysroot include at the end.
+    for flag in target.cflags:
+      if '--sysroot' in flag:
+        module.local_include_dirs.append(flag[len('--sysroot=../../'):] + "/usr/include")
+
+  module_is_compiled = module.type not in ('genrule', 'filegroup')
+  if module_is_compiled:
+    # Don't try to inject library/source dependencies into genrules or
+    # filegroups because they are not compiled in the traditional sense.
+    module.defaults = [defaults_module]
+    for lib in target.libs:
+      # Generally library names should be mangled as 'libXXX', unless they
+      # are HAL libraries (e.g., android.hardware.health@2.0) or AIDL c++ / NDK
+      # libraries (e.g. "android.hardware.power.stats-V1-cpp")
+      android_lib = lib if '@' in lib or "-cpp" in lib or "-ndk" in lib \
+        else 'lib' + lib
+      if lib in shared_library_allowlist:
+        module.add_android_shared_lib(android_lib)
+      if lib in static_library_allowlist:
+        module.add_android_static_lib(android_lib)
+
+    # Remove prohibited include directories
+    module.local_include_dirs = [d for d in module.local_include_dirs
+                                 if d not in local_include_dirs_denylist]
+
+
+  # If the module is a static library, export all the generated headers.
+  if module.type == 'cc_library_static':
+    module.export_generated_headers = module.generated_headers
+
+  # dep_name is an unmangled GN target name (e.g. //foo:bar(toolchain)).
+  # Currently, only one module is generated from target even target has multiple toolchains.
+  # And module is generated based on the first visited target.
+  # Sort deps before iteration to make result deterministic.
+  all_deps = sorted(target.deps | target.source_set_deps | target.transitive_proto_deps)
+  for dep_name in all_deps:
+    # |builtin_deps| override GN deps with Android-specific ones. See the
+    # config in the top of this file.
+    if gn_utils.label_without_toolchain(dep_name) in builtin_deps:
+      builtin_deps[gn_utils.label_without_toolchain(dep_name)](module)
+      continue
+
+    dep_module = create_modules_from_target(blueprint, gn, dep_name)
+
+    # TODO: Proper dependency check for genrule.
+    # Currently, only propagating genrule dependencies.
+    # Also, currently, all the dependencies are propagated upwards.
+    # in gn, public_deps should be propagated but deps should not.
+    # Not sure this information is available in the desc.json.
+    # Following rule works for adding android_runtime_jni_headers to base:base.
+    # If this doesn't work for other target, hardcoding for specific target
+    # might be better.
+    if module.type == "genrule" and dep_module.type == "genrule":
+        module.genrule_headers.add(dep_module.name)
+        module.genrule_headers.update(dep_module.genrule_headers)
+
+    # For filegroups and genrule, recurse but don't apply the deps.
+    if not module_is_compiled:
+      continue
+
+    if dep_module is None:
+      continue
+    if dep_module.type == 'cc_library_shared':
+      module.shared_libs.add(dep_module.name)
+    elif dep_module.type == 'cc_library_static':
+      module.static_libs.add(dep_module.name)
+    elif dep_module.type == 'filegroup':
+      module.srcs.add(':' + dep_module.name)
+    elif dep_module.type == 'genrule':
+      module.generated_headers.update(dep_module.genrule_headers)
+      module.srcs.update(dep_module.genrule_srcs)
+      module.shared_libs.update(dep_module.genrule_shared_libs)
+      module.header_libs.update(dep_module.genrule_header_libs)
+    elif dep_module.type == 'cc_binary':
+      continue  # Ignore executables deps (used by cmdline integration tests).
+    else:
+      raise Error('Unknown dep %s (%s) for target %s' %
+                  (dep_module.name, dep_module.type, module.name))
+
+  return module
+
+def create_java_module(blueprint, gn):
+  bp_module_name = module_prefix + 'java'
+  module = Module('java_library', bp_module_name, '//gn:java')
+  module.srcs.update([gn_utils.label_to_path(source) for source in gn.java_sources])
+  blueprint.add_module(module)
+
+def update_jni_registration_module(blueprint, gn):
+  bp_module_name = label_to_module_name('//components/cronet/android:cronet_jni_registration')
+  if bp_module_name not in blueprint.modules:
+    # To support building targets that might not create the cronet_jni_registration.
+    return
+  module = blueprint.modules[bp_module_name]
+
+  # TODO: deny list is in the arg of jni_registration_generator.py. Should not be hardcoded
+  deny_list = [
+    '//base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java',
+    '//base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java',
+    '//base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java',
+    '//base/android/java/src/org/chromium/base/SysUtils.java']
+
+  # TODO: java_sources might not contain all the required java files
+  module.srcs.update([gn_utils.label_to_path(source)
+                      for source in gn.java_sources if source not in deny_list])
+
+  # TODO: Remove hardcoded file addition to srcs
+  # jni_registration_generator.py generates empty .h file if native methods are not found in the
+  # java files. But android:cronet depends on `RegisterNonMainDexNatives` which is in the template
+  # of .h file. To make script generate non empty .h file, adding java file which contains native
+  # method. Once all the required java files are added to the srcs, this can be removed.
+  module.srcs.update([
+    "components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java"])
+
+def create_blueprint_for_targets(gn, desc, targets):
+  """Generate a blueprint for a list of GN targets."""
+  blueprint = Blueprint()
+
+  # Default settings used by all modules.
+  defaults = Module('cc_defaults', defaults_module, '//gn:default_deps')
+  defaults.cflags = [
+      '-Wno-error=return-type',
+      '-Wno-non-virtual-dtor',
+      '-Wno-macro-redefined',
+      '-Wno-missing-field-initializers',
+      '-Wno-sign-compare',
+      '-Wno-sign-promo',
+      '-Wno-unused-parameter',
+      '-Wno-deprecated-non-prototype', # needed for zlib
+      '-fvisibility=hidden',
+      '-O2',
+  ]
+  defaults.stl = 'none'
+  blueprint.add_module(defaults)
+
+  for target in targets:
+    create_modules_from_target(blueprint, gn, target)
+
+  create_java_module(blueprint, gn)
+  update_jni_registration_module(blueprint, gn)
+
+  # Merge in additional hardcoded arguments.
+  for module in blueprint.modules.values():
+    for key, add_val in additional_args.get(module.name, []):
+      curr = getattr(module, key)
+      if add_val and isinstance(add_val, set) and isinstance(curr, set):
+        curr.update(add_val)
+      elif isinstance(add_val, str) and (not curr or isinstance(curr, str)):
+        setattr(module, key, add_val)
+      elif isinstance(add_val, bool) and (not curr or isinstance(curr, bool)):
+        setattr(module, key, add_val)
+      elif isinstance(add_val, dict) and isinstance(curr, dict):
+        curr.update(add_val)
+      elif isinstance(add_val, dict) and isinstance(curr, Target):
+        curr.__dict__.update(add_val)
+      else:
+        raise Error('Unimplemented type %r of additional_args: %r' %
+                    (type(add_val), key))
+
+  return blueprint
+
+
+def main():
+  parser = argparse.ArgumentParser(
+      description='Generate Android.bp from a GN description.')
+  parser.add_argument(
+      '--desc',
+      help='GN description (e.g., gn desc out --format=json --all-toolchains "//*"',
+      required=True
+  )
+  parser.add_argument(
+      '--extras',
+      help='Extra targets to include at the end of the Blueprint file',
+      default=os.path.join(gn_utils.repo_root(), 'Android.bp.extras'),
+  )
+  parser.add_argument(
+      '--output',
+      help='Blueprint file to create',
+      default=os.path.join(gn_utils.repo_root(), 'Android.bp'),
+  )
+  parser.add_argument(
+      '-v',
+      '--verbose',
+      help='Print debug logs.',
+      action='store_true',
+  )
+  parser.add_argument(
+      'targets',
+      nargs=argparse.REMAINDER,
+      help='Targets to include in the blueprint (e.g., "//:perfetto_tests")'
+  )
+  args = parser.parse_args()
+
+  if args.verbose:
+    log.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', level=log.DEBUG)
+
+  with open(args.desc) as f:
+    desc = json.load(f)
+
+  gn = gn_utils.GnParser(desc)
+  blueprint = create_blueprint_for_targets(gn, desc, args.targets or default_targets)
+  project_root = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
+  tool_name = os.path.relpath(os.path.abspath(__file__), project_root)
+
+  # Add any proto groups to the blueprint.
+  for l_name, t_names in proto_groups.items():
+    create_proto_group_modules(blueprint, gn, l_name, t_names)
+
+  output = [
+      """// 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.
+//
+// This file is automatically generated by %s. Do not edit.
+""" % (tool_name)
+  ]
+  blueprint.to_string(output)
+  if os.path.exists(args.extras):
+    with open(args.extras, 'r') as r:
+      for line in r:
+        output.append(line.rstrip("\n\r"))
+
+  out_files = []
+
+  # Generate the Android.bp file.
+  out_files.append(args.output + '.swp')
+  with open(out_files[-1], 'w') as f:
+    f.write('\n'.join(output))
+    # Text files should have a trailing EOL.
+    f.write('\n')
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/gn2bp/gn_utils.py b/tools/gn2bp/gn_utils.py
new file mode 100644
index 0000000..e90b500
--- /dev/null
+++ b/tools/gn2bp/gn_utils.py
@@ -0,0 +1,373 @@
+# 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.
+
+# A collection of utilities for extracting build rule information from GN
+# projects.
+
+from __future__ import print_function
+import collections
+import errno
+import filecmp
+import json
+import logging as log
+import os
+import re
+import shutil
+import subprocess
+import sys
+
+BUILDFLAGS_TARGET = '//gn:gen_buildflags'
+GEN_VERSION_TARGET = '//src/base:version_gen_h'
+TARGET_TOOLCHAIN = '//gn/standalone/toolchain:gcc_like_host'
+HOST_TOOLCHAIN = '//gn/standalone/toolchain:gcc_like_host'
+LINKER_UNIT_TYPES = ('executable', 'shared_library', 'static_library')
+
+# TODO(primiano): investigate these, they require further componentization.
+ODR_VIOLATION_IGNORE_TARGETS = {
+    '//test/cts:perfetto_cts_deps',
+    '//:perfetto_integrationtests',
+}
+
+
+def repo_root():
+  """Returns an absolute path to the repository root."""
+  return os.path.join(
+      os.path.realpath(os.path.dirname(__file__)), os.path.pardir)
+
+
+def label_to_path(label):
+  """Turn a GN output label (e.g., //some_dir/file.cc) into a path."""
+  assert label.startswith('//')
+  return label[2:] or "./"
+
+
+def label_without_toolchain(label):
+  """Strips the toolchain from a GN label.
+
+    Return a GN label (e.g //buildtools:protobuf(//gn/standalone/toolchain:
+    gcc_like_host) without the parenthesised toolchain part.
+    """
+  return label.split('(')[0]
+
+
+def label_to_target_name_with_path(label):
+  """
+  Turn a GN label into a target name involving the full path.
+  e.g., //src/perfetto:tests -> src_perfetto_tests
+  """
+  name = re.sub(r'^//:?', '', label)
+  name = re.sub(r'[^a-zA-Z0-9_]', '_', name)
+  return name
+
+
+class GnParser(object):
+  """A parser with some cleverness for GN json desc files
+
+    The main goals of this parser are:
+    1) Deal with the fact that other build systems don't have an equivalent
+       notion to GN's source_set. Conversely to Bazel's and Soong's filegroups,
+       GN source_sets expect that dependencies, cflags and other source_set
+       properties propagate up to the linker unit (static_library, executable or
+       shared_library). This parser simulates the same behavior: when a
+       source_set is encountered, some of its variables (cflags and such) are
+       copied up to the dependent targets. This is to allow gen_xxx to create
+       one filegroup for each source_set and then squash all the other flags
+       onto the linker unit.
+    2) Detect and special-case protobuf targets, figuring out the protoc-plugin
+       being used.
+    """
+
+  class Target(object):
+    """Reperesents A GN target.
+
+        Maked properties are propagated up the dependency chain when a
+        source_set dependency is encountered.
+        """
+
+    def __init__(self, name, type):
+      self.name = name  # e.g. //src/ipc:ipc
+
+      VALID_TYPES = ('static_library', 'shared_library', 'executable', 'group',
+                     'action', 'source_set', 'proto_library', 'copy', 'action_foreach')
+      assert (type in VALID_TYPES)
+      self.type = type
+      self.testonly = False
+      self.toolchain = None
+
+      # These are valid only for type == proto_library.
+      # This is typically: 'proto', 'protozero', 'ipc'.
+      self.proto_plugin = None
+      self.proto_paths = set()
+      self.proto_exports = set()
+      self.proto_in_dir = ""
+
+      self.sources = set()
+      # TODO(primiano): consider whether the public section should be part of
+      # bubbled-up sources.
+      self.public_headers = set()  # 'public'
+
+      # These are valid only for type == 'action'
+      self.inputs = set()
+      self.outputs = set()
+      self.script = None
+      self.args = []
+      self.response_file_contents = None
+
+      # These variables are propagated up when encountering a dependency
+      # on a source_set target.
+      self.cflags = set()
+      self.defines = set()
+      self.deps = set()
+      self.libs = set()
+      self.include_dirs = set()
+      self.ldflags = set()
+      self.source_set_deps = set()  # Transitive set of source_set deps.
+      self.proto_deps = set()
+      self.transitive_proto_deps = set()
+
+      # Deps on //gn:xxx have this flag set to True. These dependencies
+      # are special because they pull third_party code from buildtools/.
+      # We don't want to keep recursing into //buildtools in generators,
+      # this flag is used to stop the recursion and create an empty
+      # placeholder target once we hit //gn:protoc or similar.
+      self.is_third_party_dep_ = False
+
+    def __lt__(self, other):
+      if isinstance(other, self.__class__):
+        return self.name < other.name
+      raise TypeError(
+          '\'<\' not supported between instances of \'%s\' and \'%s\'' %
+          (type(self).__name__, type(other).__name__))
+
+    def __repr__(self):
+      return json.dumps({
+          k: (list(sorted(v)) if isinstance(v, set) else v)
+          for (k, v) in self.__dict__.items()
+      },
+                        indent=4,
+                        sort_keys=True)
+
+    def update(self, other):
+      for key in ('cflags', 'defines', 'deps', 'include_dirs', 'ldflags',
+                  'source_set_deps', 'proto_deps', 'transitive_proto_deps',
+                  'libs', 'proto_paths'):
+        self.__dict__[key].update(other.__dict__.get(key, []))
+
+  def __init__(self, gn_desc):
+    self.gn_desc_ = gn_desc
+    self.all_targets = {}
+    self.linker_units = {}  # Executables, shared or static libraries.
+    self.source_sets = {}
+    self.actions = {}
+    self.proto_libs = {}
+    self.java_sources = set()
+
+  def _get_response_file_contents(self, action_desc):
+    # response_file_contents are formatted as:
+    # ['--flags', '--flag=true && false'] and need to be formatted as:
+    # '--flags --flag=\"true && false\"'
+    flags = action_desc.get('response_file_contents', [])
+    formatted_flags = []
+    for flag in flags:
+      if '=' in flag:
+        key, val = flag.split('=')
+        formatted_flags.append('%s=\\"%s\\"' % (key, val))
+      else:
+        formatted_flags.append(flag)
+
+    return ' '.join(formatted_flags)
+
+  def _is_java_target(self, target):
+    # Per https://chromium.googlesource.com/chromium/src/build/+/HEAD/android/docs/java_toolchain.md
+    # java target names must end in "_java".
+    # TODO: There are some other possible variations we might need to support.
+    return target.type == 'group' and re.match('.*_java$', target.name)
+
+
+  def get_target(self, gn_target_name):
+    """Returns a Target object from the fully qualified GN target name.
+
+        It bubbles up variables from source_set dependencies as described in the
+        class-level comments.
+        """
+    target = self.all_targets.get(gn_target_name)
+    if target is not None:
+      return target  # Target already processed.
+
+    desc = self.gn_desc_[gn_target_name]
+    target = GnParser.Target(gn_target_name, desc['type'])
+    target.testonly = desc.get('testonly', False)
+    target.toolchain = desc.get('toolchain', None)
+    self.all_targets[gn_target_name] = target
+
+    # TODO: determine if below comment should apply for cronet builds in Android.
+    # We should never have GN targets directly depend on buidtools. They
+    # should hop via //gn:xxx, so we can give generators an opportunity to
+    # override them.
+    # Specifically allow targets to depend on libc++ and libunwind.
+    if not any(match in gn_target_name for match in ['libc++', 'libunwind']):
+      assert (not gn_target_name.startswith('//buildtools'))
+
+
+    # Don't descend further into third_party targets. Genrators are supposed
+    # to either ignore them or route to other externally-provided targets.
+    if gn_target_name.startswith('//gn'):
+      target.is_third_party_dep_ = True
+      return target
+
+    proto_target_type, proto_desc = self.get_proto_target_type(target)
+    if proto_target_type is not None:
+      self.proto_libs[target.name] = target
+      target.type = 'proto_library'
+      target.proto_plugin = proto_target_type
+      target.proto_paths.update(self.get_proto_paths(proto_desc))
+      target.proto_exports.update(self.get_proto_exports(proto_desc))
+      target.proto_in_dir = self.get_proto_in_dir(proto_desc)
+      target.sources.update(proto_desc.get('sources', []))
+      assert (all(x.endswith('.proto') for x in target.sources))
+    elif target.type == 'source_set':
+      self.source_sets[gn_target_name] = target
+      target.sources.update(desc.get('sources', []))
+    elif target.type in LINKER_UNIT_TYPES:
+      self.linker_units[gn_target_name] = target
+      target.sources.update(desc.get('sources', []))
+    elif target.type in ['action', 'action_foreach']:
+      self.actions[gn_target_name] = target
+      target.inputs.update(desc.get('inputs', []))
+      target.sources.update(desc.get('sources', []))
+      outs = [re.sub('^//out/.+?/gen/', '', x) for x in desc['outputs']]
+      target.outputs.update(outs)
+      target.script = desc['script']
+      target.args = desc['args']
+      target.response_file_contents = self._get_response_file_contents(desc)
+    elif target.type == 'copy':
+      # TODO: copy rules are not currently implemented.
+      self.actions[gn_target_name] = target
+    elif self._is_java_target(target):
+      # java_group identifies the group target generated by the android_library
+      # or java_library template. A java_group must not be added as a dependency, but sources are collected
+      log.debug('Found java target %s', target.name)
+      target.type = 'java_group'
+
+    # Default for 'public' is //* - all headers in 'sources' are public.
+    # TODO(primiano): if a 'public' section is specified (even if empty), then
+    # the rest of 'sources' is considered inaccessible by gn. Consider
+    # emulating that, so that generated build files don't end up with overly
+    # accessible headers.
+    public_headers = [x for x in desc.get('public', []) if x != '*']
+    target.public_headers.update(public_headers)
+
+    target.cflags.update(desc.get('cflags', []) + desc.get('cflags_cc', []))
+    target.libs.update(desc.get('libs', []))
+    target.ldflags.update(desc.get('ldflags', []))
+    target.defines.update(desc.get('defines', []))
+    target.include_dirs.update(desc.get('include_dirs', []))
+
+    # Recurse in dependencies.
+    for dep_name in desc.get('deps', []):
+      dep = self.get_target(dep_name)
+      if dep.is_third_party_dep_:
+        target.deps.add(dep_name)
+      elif dep.type == 'proto_library':
+        target.proto_deps.add(dep_name)
+        target.transitive_proto_deps.add(dep_name)
+        target.proto_paths.update(dep.proto_paths)
+        target.transitive_proto_deps.update(dep.transitive_proto_deps)
+      elif dep.type == 'source_set':
+        target.source_set_deps.add(dep_name)
+        target.update(dep)  # Bubble up source set's cflags/ldflags etc.
+      elif dep.type == 'group':
+        target.update(dep)  # Bubble up groups's cflags/ldflags etc.
+      elif dep.type in ['action', 'action_foreach', 'copy']:
+        if proto_target_type is None:
+          target.deps.add(dep_name)
+      elif dep.type in LINKER_UNIT_TYPES:
+        target.deps.add(dep_name)
+      elif dep.type == 'java_group':
+        # Explicitly break dependency chain when a java_group is added.
+        # Java sources are collected and eventually compiled as one large
+        # java_library.
+        pass
+
+      # Collect java sources. Java sources are kept inside the __compile_java target.
+      # This target can be used for both host and target compilation; only add
+      # the sources if they are destined for the target (i.e. they are a
+      # dependency of the __dex target)
+      # Note: this skips prebuilt java dependencies. These will have to be
+      # added manually when building the jar.
+      if re.match('.*__dex$', target.name):
+        if re.match('.*__compile_java$', dep.name):
+          log.debug('Adding java sources for %s', dep.name)
+          java_srcs = [src for src in dep.inputs if os.path.splitext(src)[1] == '.java']
+          self.java_sources.update(java_srcs)
+
+    return target
+
+  def get_proto_exports(self, proto_desc):
+    # exports in metadata will be available for source_set targets.
+    metadata = proto_desc.get('metadata', {})
+    return metadata.get('exports', [])
+
+  def get_proto_paths(self, proto_desc):
+    # import_dirs in metadata will be available for source_set targets.
+    metadata = proto_desc.get('metadata', {})
+    return metadata.get('import_dirs', [])
+
+
+  def get_proto_in_dir(self, proto_desc):
+    args = proto_desc.get('args')
+    return re.sub('^\.\./\.\./', '', args[args.index('--proto-in-dir') + 1])
+
+  def get_proto_target_type(self, target):
+    """ Checks if the target is a proto library and return the plugin.
+
+        Returns:
+            (None, None): if the target is not a proto library.
+            (plugin, proto_desc) where |plugin| is 'proto' in the default (lite)
+            case or 'protozero' or 'ipc' or 'descriptor'; |proto_desc| is the GN
+            json desc of the target with the .proto sources (_gen target for
+            non-descriptor types or the target itself for descriptor type).
+        """
+    parts = target.name.split('(', 1)
+    name = parts[0]
+    toolchain = '(' + parts[1] if len(parts) > 1 else ''
+
+    # Descriptor targets don't have a _gen target; instead we look for the
+    # characteristic flag in the args of the target itself.
+    desc = self.gn_desc_.get(target.name)
+    if '--descriptor_set_out' in desc.get('args', []):
+      return 'descriptor', desc
+
+    # Source set proto targets have a non-empty proto_library_sources in the
+    # metadata of the description.
+    metadata = desc.get('metadata', {})
+    if 'proto_library_sources' in metadata:
+      return 'source_set', desc
+
+    # In all other cases, we want to look at the _gen target as that has the
+    # important information.
+    gen_desc = self.gn_desc_.get('%s_gen%s' % (name, toolchain))
+    if gen_desc is None or gen_desc['type'] != 'action':
+      return None, None
+    if gen_desc['script'] != '//tools/protoc_wrapper/protoc_wrapper.py':
+      return None, None
+    plugin = 'proto'
+    args = gen_desc.get('args', [])
+    for arg in (arg for arg in args if arg.startswith('--plugin=')):
+      # |arg| at this point looks like:
+      #  --plugin=protoc-gen-plugin=gcc_like_host/protozero_plugin
+      # or
+      #  --plugin=protoc-gen-plugin=protozero_plugin
+      plugin = arg.split('=')[-1].split('/')[-1].replace('_plugin', '')
+    return plugin, gen_desc
diff --git a/tools/gn2bp/update_results.sh b/tools/gn2bp/update_results.sh
new file mode 100755
index 0000000..f9321d9
--- /dev/null
+++ b/tools/gn2bp/update_results.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# This script is expected to run after gen_android_bp is modified.
+#
+#   ./update_result.sh
+#
+# TARGETS contains targets which are supported by gen_android_bp and
+# this script generates Android.bp.swp from TARGETS.
+# This makes it easy to realize unintended impact/degression on
+# previously supported targets.
+
+set -eux
+
+TARGETS=(
+  "//components/cronet/android:cronet"
+)
+
+BASEDIR=$(dirname "$0")
+$BASEDIR/gen_android_bp --desc $BASEDIR/desc.json --out $BASEDIR/Android.bp ${TARGETS[@]}