commit | f9f9784d4cd9ad3c83ec3c13052990ae90057119 | [log] [tgz] |
---|---|---|
author | Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> | Wed May 31 05:35:20 2023 +0000 |
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | Wed May 31 05:35:20 2023 +0000 |
tree | 6b67c4094d8ff4173e36dcae4cbcc00443d5b2dd | |
parent | ae9b229b7e63cbae85019eed2b37a94918d55838 [diff] | |
parent | 2c1b9b8e80c6cb017a03211667b51ee5b1234d1c [diff] |
Merge "Only allow libconnectivity_native usage on U+"
diff --git a/Cronet/Android.bp b/Cronet/Android.bp deleted file mode 100644 index 3ce88ef..0000000 --- a/Cronet/Android.bp +++ /dev/null
@@ -1,106 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - default_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/TEST_MAPPING b/Cronet/TEST_MAPPING deleted file mode 100644 index 815d496..0000000 --- a/Cronet/TEST_MAPPING +++ /dev/null
@@ -1,7 +0,0 @@ -{ - "postsubmit": [ - { - "name": "CronetApiTest" - } - ] -}
diff --git a/Cronet/apex/Android.bp b/Cronet/apex/Android.bp deleted file mode 100644 index 180dafb..0000000 --- a/Cronet/apex/Android.bp +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - default_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 deleted file mode 100644 index 650badc..0000000 --- a/Cronet/apex/AndroidManifest.xml +++ /dev/null
@@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - --> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="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 deleted file mode 100644 index 38aebe0..0000000 --- a/Cronet/apex/com.android.cronet.avbpubkey +++ /dev/null Binary files differ
diff --git a/Cronet/apex/com.android.cronet.pem b/Cronet/apex/com.android.cronet.pem deleted file mode 100644 index 438653f..0000000 --- a/Cronet/apex/com.android.cronet.pem +++ /dev/null
@@ -1,51 +0,0 @@ ------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 deleted file mode 100644 index a63d761..0000000 --- a/Cronet/apex/com.android.cronet.pk8 +++ /dev/null Binary files differ
diff --git a/Cronet/apex/com.android.cronet.x509.pem b/Cronet/apex/com.android.cronet.x509.pem deleted file mode 100644 index c9cd874..0000000 --- a/Cronet/apex/com.android.cronet.x509.pem +++ /dev/null
@@ -1,35 +0,0 @@ ------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 deleted file mode 100644 index 0301e9f..0000000 --- a/Cronet/apex/manifest.json +++ /dev/null
@@ -1,4 +0,0 @@ -{ - "name": "com.android.cronet", - "version": 1 -}
diff --git a/Cronet/api/current.txt b/Cronet/api/current.txt deleted file mode 100644 index 21779bc..0000000 --- a/Cronet/api/current.txt +++ /dev/null
@@ -1,175 +0,0 @@ -// 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 deleted file mode 100644 index 0e2f25b..0000000 --- a/Cronet/api/lint-baseline.txt +++ /dev/null
@@ -1,263 +0,0 @@ -// 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 deleted file mode 100644 index d802177..0000000 --- a/Cronet/api/module-lib-current.txt +++ /dev/null
@@ -1 +0,0 @@ -// Signature format: 2.0
diff --git a/Cronet/api/removed.txt b/Cronet/api/removed.txt deleted file mode 100644 index d802177..0000000 --- a/Cronet/api/removed.txt +++ /dev/null
@@ -1 +0,0 @@ -// Signature format: 2.0
diff --git a/Cronet/api/system-current.txt b/Cronet/api/system-current.txt deleted file mode 100644 index d802177..0000000 --- a/Cronet/api/system-current.txt +++ /dev/null
@@ -1 +0,0 @@ -// Signature format: 2.0
diff --git a/Cronet/api/test-current.txt b/Cronet/api/test-current.txt deleted file mode 100644 index d802177..0000000 --- a/Cronet/api/test-current.txt +++ /dev/null
@@ -1 +0,0 @@ -// Signature format: 2.0
diff --git a/Cronet/api/test-removed.txt b/Cronet/api/test-removed.txt deleted file mode 100644 index d802177..0000000 --- a/Cronet/api/test-removed.txt +++ /dev/null
@@ -1 +0,0 @@ -// Signature format: 2.0
diff --git a/Cronet/jarjar-rules.txt b/Cronet/jarjar-rules.txt deleted file mode 100644 index 7111ebc..0000000 --- a/Cronet/jarjar-rules.txt +++ /dev/null
@@ -1,3 +0,0 @@ -rule androidx.** com.android.cronet.@0 -rule android.support.** com.android.cronet.@0 -
diff --git a/Cronet/prebuilt/VERSION b/Cronet/prebuilt/VERSION deleted file mode 100644 index c16ab94..0000000 --- a/Cronet/prebuilt/VERSION +++ /dev/null
@@ -1,4 +0,0 @@ -MAJOR=80 -MINOR=0 -BUILD=3986 -PATCH=0
diff --git a/Cronet/prebuilt/api_version.txt b/Cronet/prebuilt/api_version.txt deleted file mode 100644 index 48082f7..0000000 --- a/Cronet/prebuilt/api_version.txt +++ /dev/null
@@ -1 +0,0 @@ -12
diff --git a/Cronet/prebuilt/cronet_api-src.jar b/Cronet/prebuilt/cronet_api-src.jar deleted file mode 100644 index 924b877..0000000 --- a/Cronet/prebuilt/cronet_api-src.jar +++ /dev/null Binary files differ
diff --git a/Cronet/prebuilt/cronet_api.jar b/Cronet/prebuilt/cronet_api.jar deleted file mode 100644 index 977b28d..0000000 --- a/Cronet/prebuilt/cronet_api.jar +++ /dev/null Binary files differ
diff --git a/Cronet/prebuilt/cronet_impl_common_java.jar b/Cronet/prebuilt/cronet_impl_common_java.jar deleted file mode 100644 index fa71bf3..0000000 --- a/Cronet/prebuilt/cronet_impl_common_java.jar +++ /dev/null Binary files differ
diff --git a/Cronet/prebuilt/cronet_impl_native_java.jar b/Cronet/prebuilt/cronet_impl_native_java.jar deleted file mode 100644 index 4cdd6f3..0000000 --- a/Cronet/prebuilt/cronet_impl_native_java.jar +++ /dev/null Binary files differ
diff --git a/Cronet/prebuilt/cronet_impl_platform_java.jar b/Cronet/prebuilt/cronet_impl_platform_java.jar deleted file mode 100644 index 6d6042f..0000000 --- a/Cronet/prebuilt/cronet_impl_platform_java.jar +++ /dev/null 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 deleted file mode 100644 index 7f2540a..0000000 --- a/Cronet/prebuilt/libs/arm64-v8a/libcronet.107.0.5284.2.so +++ /dev/null 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 deleted file mode 100644 index 115429a..0000000 --- a/Cronet/prebuilt/libs/armeabi-v7a/libcronet.107.0.5284.2.so +++ /dev/null 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 deleted file mode 100644 index 27923f7..0000000 --- a/Cronet/prebuilt/libs/x86/libcronet.107.0.5284.2.so +++ /dev/null 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 deleted file mode 100644 index 803e5cd..0000000 --- a/Cronet/prebuilt/libs/x86_64/libcronet.107.0.5284.2.so +++ /dev/null Binary files differ
diff --git a/Cronet/tests/OWNERS b/Cronet/tests/OWNERS new file mode 100644 index 0000000..acb6ee6 --- /dev/null +++ b/Cronet/tests/OWNERS
@@ -0,0 +1,8 @@ +# Bug component: 31808 + +set noparent +file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking_xts + +# TODO: Temp ownership to develop cronet CTS +colibie@google.com #{LAST_RESORT_SUGGESTION} +prohr@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/Cronet/tests/common/Android.bp b/Cronet/tests/common/Android.bp new file mode 100644 index 0000000..e17081a --- /dev/null +++ b/Cronet/tests/common/Android.bp
@@ -0,0 +1,42 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Tests in this folder are included both in unit tests and CTS. +// They must be fast and stable, and exercise public or test APIs. + +package { + // See: http://go/android-license-faq + default_applicable_licenses: ["Android-Apache-2.0"], +} + +// TODO: Consider merging with ConnectivityCoverageTests which is a collection of all +// Connectivity tests being used for coverage. This will depend on how far we decide to +// go with merging NetHttp and Tethering targets. +android_test { + name: "NetHttpCoverageTests", + enforce_default_target_sdk_version: true, + min_sdk_version: "30", + test_suites: ["general-tests", "mts-tethering"], + static_libs: [ + "modules-utils-native-coverage-listener", + "CtsNetHttpTestsLib", + "NetHttpTestsLibPreJarJar", + ], + jarjar_rules: ":net-http-test-jarjar-rules", + compile_multilib: "both", // Include both the 32 and 64 bit versions + jni_libs: [ + "cronet_aml_components_cronet_android_cronet_tests__testing" + ], +}
diff --git a/Cronet/tests/common/AndroidManifest.xml b/Cronet/tests/common/AndroidManifest.xml new file mode 100644 index 0000000..b00fc90 --- /dev/null +++ b/Cronet/tests/common/AndroidManifest.xml
@@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.android.net.http.tests.coverage"> + + <!-- NetHttpCoverageTests combines CtsNetHttpTestCases and NetHttpTests targets, + so permissions and others are declared in their respective manifests --> + <application tools:replace="android:label" + android:label="NetHttp coverage tests"> + <uses-library android:name="android.test.runner" /> + </application> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.net.http.tests.coverage" + android:label="NetHttp coverage tests"> + </instrumentation> +</manifest>
diff --git a/Cronet/tests/common/AndroidTest.xml b/Cronet/tests/common/AndroidTest.xml new file mode 100644 index 0000000..2ac418f --- /dev/null +++ b/Cronet/tests/common/AndroidTest.xml
@@ -0,0 +1,36 @@ +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Runs coverage tests for NetHttp"> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="test-file-name" value="NetHttpCoverageTests.apk" /> + <option name="install-arg" value="-t" /> + </target_preparer> + <option name="test-tag" value="NetHttpCoverageTests" /> + <!-- Tethering/Connectivity is a SDK 30+ module --> + <!-- TODO Switch back to Sdk30 when b/270049141 is fixed --> + <object type="module_controller" + class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> + <option name="config-descriptor:metadata" key="mainline-param" + value="CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.net.http.tests.coverage" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + <option + name="device-listeners" + value="com.android.modules.utils.testing.NativeCoverageHackInstrumentationListener" /> + </test> +</configuration>
diff --git a/Cronet/tests/cts/Android.bp b/Cronet/tests/cts/Android.bp index e71c707..1e0adef 100644 --- a/Cronet/tests/cts/Android.bp +++ b/Cronet/tests/cts/Android.bp
@@ -18,29 +18,49 @@ default_applicable_licenses: ["Android-Apache-2.0"], } -java_library { - name: "CronetApiCommonTests", - srcs: ["src/**/*.java"], +android_library { + name: "CtsNetHttpTestsLib", + defaults: [ + "cts_defaults", + ], + sdk_version: "test_current", + min_sdk_version: "30", + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], static_libs: [ - "androidx.test.rules", - "androidx.core_core", + "androidx.test.ext.junit", + "ctstestrunner-axt", + "ctstestserver", + "hamcrest-library", "junit", + "kotlin-test", + "mockito-target", + "truth", ], libs: [ - "android.test.runner", "android.test.base", - "android.test.mock", "androidx.annotation_annotation", - "framework-cronet", + "framework-connectivity", + "org.apache.http.legacy", ], + lint: { test: true } } android_test { - name: "CronetApiTest", + name: "CtsNetHttpTestCases", + defaults: [ + "cts_defaults", + ], + enforce_default_target_sdk_version: true, sdk_version: "test_current", - test_suites: ["device-tests"], - certificate: "platform", - static_libs: [ - "CronetApiCommonTests", + min_sdk_version: "30", + static_libs: ["CtsNetHttpTestsLib"], + // Tag this as a cts test artifact + test_suites: [ + "cts", + "general-tests", + "mts-tethering" ], }
diff --git a/Cronet/tests/cts/AndroidManifest.xml b/Cronet/tests/cts/AndroidManifest.xml index db0f0b3..26900b2 100644 --- a/Cronet/tests/cts/AndroidManifest.xml +++ b/Cronet/tests/cts/AndroidManifest.xml
@@ -18,18 +18,18 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="org.chromium.net.test"> + package="android.net.http.cts"> <uses-permission android:name="android.permission.INTERNET"/> - <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> - <application> - <uses-library android:name="android.test.runner" /> - <uses-library android:name="framework-cronet" /> + <application android:networkSecurityConfig="@xml/network_security_config"> + <uses-library android:name="android.test.runner"/> </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 + android:targetPackage="android.net.http.cts" + android:label="CTS tests of android.net.http"> + </instrumentation> +</manifest>
diff --git a/Cronet/tests/cts/AndroidTest.xml b/Cronet/tests/cts/AndroidTest.xml new file mode 100644 index 0000000..e0421fd --- /dev/null +++ b/Cronet/tests/cts/AndroidTest.xml
@@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Config for CTS Cronet test cases"> + <option name="test-suite-tag" value="cts" /> + <option name="config-descriptor:metadata" key="component" value="networking" /> + <!-- Instant apps cannot create sockets. See b/264248246 --> + <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" /> + <option name="config-descriptor:metadata" key="parameter" value="multi_abi" /> + <option name="config-descriptor:metadata" key="parameter" value="secondary_user" /> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="CtsNetHttpTestCases.apk" /> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="android.net.http.cts" /> + <option name="runtime-hint" value="10s" /> + </test> + + <!-- Only run CtsNetHttpTestCases in MTS if the Tethering Mainline module is installed. --> + <object type="module_controller" + class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController"> + <option name="mainline-module-package-name" value="com.google.android.tethering" /> + </object> +</configuration>
diff --git a/Cronet/tests/cts/assets/html/hello_world.html b/Cronet/tests/cts/assets/html/hello_world.html new file mode 100644 index 0000000..ea62ce2 --- /dev/null +++ b/Cronet/tests/cts/assets/html/hello_world.html
@@ -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. + --> + +<html> +<head> + <title>hello world</title> +</head> +<body> +<h3>hello world</h3><br> +</body> +</html> \ No newline at end of file
diff --git a/Cronet/tests/cts/res/xml/network_security_config.xml b/Cronet/tests/cts/res/xml/network_security_config.xml new file mode 100644 index 0000000..7d7530b --- /dev/null +++ b/Cronet/tests/cts/res/xml/network_security_config.xml
@@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<network-security-config> + <domain-config cleartextTrafficPermitted="true"> + <domain includeSubdomains="true">localhost</domain> + </domain-config> +</network-security-config> \ No newline at end of file
diff --git a/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt b/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt new file mode 100644 index 0000000..bead1f8 --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/BidirectionalStreamTest.kt
@@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts + +import android.content.Context +import android.net.http.BidirectionalStream +import android.net.http.HttpEngine +import android.net.http.cts.util.TestBidirectionalStreamCallback +import android.net.http.cts.util.TestBidirectionalStreamCallback.ResponseStep +import android.net.http.cts.util.assumeOKStatusCode +import android.net.http.cts.util.skipIfNoInternetConnection +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlin.test.Test +import kotlin.test.assertEquals +import org.hamcrest.MatcherAssert +import org.hamcrest.Matchers +import org.junit.After +import org.junit.Before +import org.junit.runner.RunWith + +private const val URL = "https://source.android.com" + +/** + * This tests uses a non-hermetic server. Instead of asserting, assume the next callback. This way, + * if the request were to fail, the test would just be skipped instead of failing. + */ +@RunWith(AndroidJUnit4::class) +class BidirectionalStreamTest { + private val context: Context = ApplicationProvider.getApplicationContext() + private val callback = TestBidirectionalStreamCallback() + private val httpEngine = HttpEngine.Builder(context).build() + private var stream: BidirectionalStream? = null + + @Before + fun setUp() { + skipIfNoInternetConnection(context) + } + + @After + @Throws(Exception::class) + fun tearDown() { + // cancel active requests to enable engine shutdown. + stream?.let { + it.cancel() + callback.blockForDone() + } + httpEngine.shutdown() + } + + private fun createBidirectionalStreamBuilder(url: String): BidirectionalStream.Builder { + return httpEngine.newBidirectionalStreamBuilder(url, callback.executor, callback) + } + + @Test + @Throws(Exception::class) + fun testBidirectionalStream_GetStream_CompletesSuccessfully() { + stream = createBidirectionalStreamBuilder(URL).setHttpMethod("GET").build() + stream!!.start() + callback.assumeCallback(ResponseStep.ON_SUCCEEDED) + val info = callback.mResponseInfo + assumeOKStatusCode(info) + MatcherAssert.assertThat( + "Received byte count must be > 0", info.receivedByteCount, Matchers.greaterThan(0L)) + assertEquals("h2", info.negotiatedProtocol) + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt new file mode 100644 index 0000000..749389e --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt
@@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts + +import android.content.Context +import android.net.http.CallbackException +import android.net.http.HttpEngine +import android.net.http.cts.util.HttpCtsTestServer +import android.net.http.cts.util.TestUrlRequestCallback +import android.net.http.cts.util.TestUrlRequestCallback.FailureType +import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertSame +import kotlin.test.assertTrue +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class CallbackExceptionTest { + + @Test + fun testCallbackException_returnsInputParameters() { + val message = "failed" + val cause = Throwable("exception") + val callbackException = object : CallbackException(message, cause) {} + + assertEquals(message, callbackException.message) + assertSame(cause, callbackException.cause) + } + + @Test + fun testCallbackException_thrownFromUrlRequest() { + val context: Context = ApplicationProvider.getApplicationContext() + val server = HttpCtsTestServer(context) + val httpEngine = HttpEngine.Builder(context).build() + val callback = TestUrlRequestCallback() + callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_RESPONSE_STARTED) + val request = httpEngine + .newUrlRequestBuilder(server.successUrl, callback.executor, callback) + .build() + + request.start() + callback.blockForDone() + + assertTrue(request.isDone) + assertIs<CallbackException>(callback.mError) + server.shutdown() + httpEngine.shutdown() + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/ConnectionMigrationOptionsTest.kt b/Cronet/tests/cts/src/android/net/http/cts/ConnectionMigrationOptionsTest.kt new file mode 100644 index 0000000..219db61 --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/ConnectionMigrationOptionsTest.kt
@@ -0,0 +1,68 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts + +import android.net.http.ConnectionMigrationOptions +import android.net.http.ConnectionMigrationOptions.MIGRATION_OPTION_ENABLED +import android.net.http.ConnectionMigrationOptions.MIGRATION_OPTION_UNSPECIFIED +import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlin.test.Test +import kotlin.test.assertEquals +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ConnectionMigrationOptionsTest { + + @Test + fun testConnectionMigrationOptions_defaultValues() { + val options = + ConnectionMigrationOptions.Builder().build() + + assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.allowNonDefaultNetworkUsage) + assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.defaultNetworkMigration) + assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.pathDegradationMigration) + } + + @Test + fun testConnectionMigrationOptions_enableDefaultNetworkMigration_returnSetValue() { + val options = + ConnectionMigrationOptions.Builder() + .setDefaultNetworkMigration(MIGRATION_OPTION_ENABLED) + .build() + + assertEquals(MIGRATION_OPTION_ENABLED, options.defaultNetworkMigration) + } + + @Test + fun testConnectionMigrationOptions_enablePathDegradationMigration_returnSetValue() { + val options = + ConnectionMigrationOptions.Builder() + .setPathDegradationMigration(MIGRATION_OPTION_ENABLED) + .build() + + assertEquals(MIGRATION_OPTION_ENABLED, options.pathDegradationMigration) + } + + @Test + fun testConnectionMigrationOptions_allowNonDefaultNetworkUsage_returnSetValue() { + val options = + ConnectionMigrationOptions.Builder() + .setAllowNonDefaultNetworkUsage(MIGRATION_OPTION_ENABLED).build() + + assertEquals(MIGRATION_OPTION_ENABLED, options.allowNonDefaultNetworkUsage) + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/DnsOptionsTest.kt b/Cronet/tests/cts/src/android/net/http/cts/DnsOptionsTest.kt new file mode 100644 index 0000000..6f4a979 --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/DnsOptionsTest.kt
@@ -0,0 +1,150 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts + +import android.net.http.DnsOptions +import android.net.http.DnsOptions.DNS_OPTION_ENABLED +import android.net.http.DnsOptions.DNS_OPTION_UNSPECIFIED +import androidx.test.ext.junit.runners.AndroidJUnit4 +import java.time.Duration +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class DnsOptionsTest { + + @Test + fun testDnsOptions_defaultValues() { + val options = DnsOptions.Builder().build() + + assertEquals(DNS_OPTION_UNSPECIFIED, options.persistHostCache) + assertNull(options.persistHostCachePeriod) + assertEquals(DNS_OPTION_UNSPECIFIED, options.staleDns) + assertNull(options.staleDnsOptions) + assertEquals(DNS_OPTION_UNSPECIFIED, options.useHttpStackDnsResolver) + assertEquals(DNS_OPTION_UNSPECIFIED, + options.preestablishConnectionsToStaleDnsResults) + } + + @Test + fun testDnsOptions_persistHostCache_returnSetValue() { + val options = DnsOptions.Builder() + .setPersistHostCache(DNS_OPTION_ENABLED) + .build() + + assertEquals(DNS_OPTION_ENABLED, options.persistHostCache) + } + + @Test + fun testDnsOptions_persistHostCachePeriod_returnSetValue() { + val period = Duration.ofMillis(12345) + val options = DnsOptions.Builder().setPersistHostCachePeriod(period).build() + + assertEquals(period, options.persistHostCachePeriod) + } + + @Test + fun testDnsOptions_enableStaleDns_returnSetValue() { + val options = DnsOptions.Builder() + .setStaleDns(DNS_OPTION_ENABLED) + .build() + + assertEquals(DNS_OPTION_ENABLED, options.staleDns) + } + + @Test + fun testDnsOptions_useHttpStackDnsResolver_returnsSetValue() { + val options = DnsOptions.Builder() + .setUseHttpStackDnsResolver(DNS_OPTION_ENABLED) + .build() + + assertEquals(DNS_OPTION_ENABLED, options.useHttpStackDnsResolver) + } + + @Test + fun testDnsOptions_preestablishConnectionsToStaleDnsResults_returnsSetValue() { + val options = DnsOptions.Builder() + .setPreestablishConnectionsToStaleDnsResults(DNS_OPTION_ENABLED) + .build() + + assertEquals(DNS_OPTION_ENABLED, + options.preestablishConnectionsToStaleDnsResults) + } + + @Test + fun testDnsOptions_setStaleDnsOptions_returnsSetValues() { + val staleOptions = DnsOptions.StaleDnsOptions.Builder() + .setAllowCrossNetworkUsage(DNS_OPTION_ENABLED) + .setFreshLookupTimeout(Duration.ofMillis(1234)) + .build() + val options = DnsOptions.Builder() + .setStaleDns(DNS_OPTION_ENABLED) + .setStaleDnsOptions(staleOptions) + .build() + + assertEquals(DNS_OPTION_ENABLED, options.staleDns) + assertEquals(staleOptions, options.staleDnsOptions) + } + + @Test + fun testStaleDnsOptions_defaultValues() { + val options = DnsOptions.StaleDnsOptions.Builder().build() + + assertEquals(DNS_OPTION_UNSPECIFIED, options.allowCrossNetworkUsage) + assertNull(options.freshLookupTimeout) + assertNull(options.maxExpiredDelay) + assertEquals(DNS_OPTION_UNSPECIFIED, options.useStaleOnNameNotResolved) + } + + @Test + fun testStaleDnsOptions_allowCrossNetworkUsage_returnsSetValue() { + val options = DnsOptions.StaleDnsOptions.Builder() + .setAllowCrossNetworkUsage(DNS_OPTION_ENABLED).build() + + assertEquals(DNS_OPTION_ENABLED, options.allowCrossNetworkUsage) + } + + @Test + fun testStaleDnsOptions_freshLookupTimeout_returnsSetValue() { + val duration = Duration.ofMillis(12345) + val options = DnsOptions.StaleDnsOptions.Builder().setFreshLookupTimeout(duration).build() + + assertNotNull(options.freshLookupTimeout) + assertEquals(duration, options.freshLookupTimeout!!) + } + + @Test + fun testStaleDnsOptions_useStaleOnNameNotResolved_returnsSetValue() { + val options = DnsOptions.StaleDnsOptions.Builder() + .setUseStaleOnNameNotResolved(DNS_OPTION_ENABLED) + .build() + + assertEquals(DNS_OPTION_ENABLED, options.useStaleOnNameNotResolved) + } + + @Test + fun testStaleDnsOptions_maxExpiredDelayMillis_returnsSetValue() { + val duration = Duration.ofMillis(12345) + val options = DnsOptions.StaleDnsOptions.Builder().setMaxExpiredDelay(duration).build() + + assertNotNull(options.maxExpiredDelay) + assertEquals(duration, options.maxExpiredDelay!!) + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java b/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java new file mode 100644 index 0000000..31990fb --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
@@ -0,0 +1,402 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts; + +import static android.net.http.cts.util.TestUtilsKt.assertOKStatusCode; +import static android.net.http.cts.util.TestUtilsKt.assumeOKStatusCode; +import static android.net.http.cts.util.TestUtilsKt.skipIfNoInternetConnection; + +import static com.google.common.truth.Truth.assertThat; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.net.Network; +import android.net.http.ConnectionMigrationOptions; +import android.net.http.DnsOptions; +import android.net.http.HttpEngine; +import android.net.http.QuicOptions; +import android.net.http.UrlRequest; +import android.net.http.UrlResponseInfo; +import android.net.http.cts.util.HttpCtsTestServer; +import android.net.http.cts.util.TestUrlRequestCallback; +import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +import java.time.Instant; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +public class HttpEngineTest { + private static final String HOST = "source.android.com"; + private static final String URL = "https://" + HOST; + + private HttpEngine.Builder mEngineBuilder; + private TestUrlRequestCallback mCallback; + private HttpCtsTestServer mTestServer; + private UrlRequest mRequest; + private HttpEngine mEngine; + private Context mContext; + + @Before + public void setUp() throws Exception { + mContext = ApplicationProvider.getApplicationContext(); + skipIfNoInternetConnection(mContext); + mEngineBuilder = new HttpEngine.Builder(mContext); + mCallback = new TestUrlRequestCallback(); + mTestServer = new HttpCtsTestServer(mContext); + } + + @After + public void tearDown() throws Exception { + if (mRequest != null) { + mRequest.cancel(); + mCallback.blockForDone(); + } + if (mEngine != null) { + mEngine.shutdown(); + } + if (mTestServer != null) { + mTestServer.shutdown(); + } + } + + private boolean isQuic(String negotiatedProtocol) { + return negotiatedProtocol.startsWith("http/2+quic") || negotiatedProtocol.startsWith("h3"); + } + + @Test + public void testHttpEngine_Default() throws Exception { + mEngine = mEngineBuilder.build(); + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + + // This tests uses a non-hermetic server. Instead of asserting, assume the next callback. + // This way, if the request were to fail, the test would just be skipped instead of failing. + mCallback.assumeCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + assertEquals("h2", info.getNegotiatedProtocol()); + } + + @Test + public void testHttpEngine_EnableHttpCache() { + String url = mTestServer.getCacheableTestDownloadUrl( + /* downloadId */ "cacheable-download", + /* numBytes */ 10); + mEngine = + mEngineBuilder + .setStoragePath(mContext.getApplicationInfo().dataDir) + .setEnableHttpCache( + HttpEngine.Builder.HTTP_CACHE_DISK, /* maxSize */ 100 * 1024) + .build(); + + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assumeOKStatusCode(info); + assertFalse(info.wasCached()); + + mCallback = new TestUrlRequestCallback(); + builder = mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + info = mCallback.mResponseInfo; + assertOKStatusCode(info); + assertTrue(info.wasCached()); + } + + @Test + public void testHttpEngine_DisableHttp2() throws Exception { + mEngine = mEngineBuilder.setEnableHttp2(false).build(); + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + + // This tests uses a non-hermetic server. Instead of asserting, assume the next callback. + // This way, if the request were to fail, the test would just be skipped instead of failing. + mCallback.assumeCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + assertEquals("http/1.1", info.getNegotiatedProtocol()); + } + + @Test + public void testHttpEngine_EnablePublicKeyPinningBypassForLocalTrustAnchors() { + String url = mTestServer.getSuccessUrl(); + // For known hosts, requests should succeed whether we're bypassing the local trust anchor + // or not. + mEngine = mEngineBuilder.setEnablePublicKeyPinningBypassForLocalTrustAnchors(false).build(); + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + + mEngine.shutdown(); + mEngine = mEngineBuilder.setEnablePublicKeyPinningBypassForLocalTrustAnchors(true).build(); + mCallback = new TestUrlRequestCallback(); + builder = mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + + // TODO(b/270918920): We should also test with a certificate not present in the device's + // trusted store. + // This requires either: + // * Mocking the underlying CertificateVerifier. + // * Or, having the server return a root certificate not present in the device's trusted + // store. + // The former doesn't make sense for a CTS test as it would depend on the underlying + // implementation. The latter is something we should support once we write a proper test + // server. + } + + private byte[] generateSha256() { + byte[] sha256 = new byte[32]; + Arrays.fill(sha256, (byte) 58); + return sha256; + } + + private Instant instantInFuture(int secondsIntoFuture) { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.SECOND, secondsIntoFuture); + return cal.getTime().toInstant(); + } + + @Test + public void testHttpEngine_AddPublicKeyPins() { + // CtsTestServer, when set in SslMode.NO_CLIENT_AUTH (required to trigger + // certificate verification, needed by this test), uses a certificate that + // doesn't match the hostname. For this reason, CtsTestServer cannot be used + // by this test. + Instant expirationInstant = instantInFuture(/* secondsIntoFuture */ 100); + boolean includeSubdomains = true; + Set<byte[]> pinsSha256 = Set.of(generateSha256()); + mEngine = mEngineBuilder.addPublicKeyPins( + HOST, pinsSha256, includeSubdomains, expirationInstant).build(); + + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + mCallback.expectCallback(ResponseStep.ON_FAILED); + assertNotNull("Expected an error", mCallback.mError); + } + + @Test + public void testHttpEngine_EnableQuic() throws Exception { + String url = mTestServer.getSuccessUrl(); + mEngine = mEngineBuilder.setEnableQuic(true).addQuicHint(HOST, 443, 443).build(); + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + } + + @Test + public void testHttpEngine_GetDefaultUserAgent() throws Exception { + assertThat(mEngineBuilder.getDefaultUserAgent(), containsString("AndroidHttpClient")); + assertThat(mEngineBuilder.getDefaultUserAgent()).contains(HttpEngine.getVersionString()); + } + + @Test + public void testHttpEngine_requestUsesDefaultUserAgent() throws Exception { + mEngine = mEngineBuilder.build(); + HttpCtsTestServer server = + new HttpCtsTestServer(ApplicationProvider.getApplicationContext()); + + String url = server.getUserAgentUrl(); + UrlRequest request = + mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback).build(); + request.start(); + + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + String receivedUserAgent = extractUserAgent(mCallback.mResponseAsString); + + assertThat(receivedUserAgent).isEqualTo(mEngineBuilder.getDefaultUserAgent()); + } + + @Test + public void testHttpEngine_requestUsesCustomUserAgent() throws Exception { + String userAgent = "CtsTests User Agent"; + HttpCtsTestServer server = + new HttpCtsTestServer(ApplicationProvider.getApplicationContext()); + mEngine = + new HttpEngine.Builder(ApplicationProvider.getApplicationContext()) + .setUserAgent(userAgent) + .build(); + + String url = server.getUserAgentUrl(); + UrlRequest request = + mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback).build(); + request.start(); + + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + String receivedUserAgent = extractUserAgent(mCallback.mResponseAsString); + + assertThat(receivedUserAgent).isEqualTo(userAgent); + } + + private static String extractUserAgent(String userAgentResponseBody) { + // If someone wants to be evil and have the title HTML tag a part of the user agent, + // they'll have to fix this method :) + return userAgentResponseBody.replaceFirst(".*<title>", "").replaceFirst("</title>.*", ""); + } + + @Test + public void testHttpEngine_bindToNetwork() throws Exception { + // Create a fake Android.net.Network. Since that network doesn't exist, binding to + // that should end up in a failed request. + Network mockNetwork = Mockito.mock(Network.class); + Mockito.when(mockNetwork.getNetworkHandle()).thenReturn(123L); + String url = mTestServer.getSuccessUrl(); + + mEngine = mEngineBuilder.build(); + mEngine.bindToNetwork(mockNetwork); + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + + mCallback.expectCallback(ResponseStep.ON_FAILED); + } + + @Test + public void testHttpEngine_unbindFromNetwork() throws Exception { + // Create a fake Android.net.Network. Since that network doesn't exist, binding to + // that should end up in a failed request. + Network mockNetwork = Mockito.mock(Network.class); + Mockito.when(mockNetwork.getNetworkHandle()).thenReturn(123L); + String url = mTestServer.getSuccessUrl(); + + mEngine = mEngineBuilder.build(); + // Bind to the fake network but then unbind. This should result in a successful + // request. + mEngine.bindToNetwork(mockNetwork); + mEngine.bindToNetwork(null); + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + } + + @Test + public void testHttpEngine_setConnectionMigrationOptions_requestSucceeds() { + ConnectionMigrationOptions options = new ConnectionMigrationOptions.Builder().build(); + mEngine = mEngineBuilder.setConnectionMigrationOptions(options).build(); + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder( + mTestServer.getSuccessUrl(), mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + } + + @Test + public void testHttpEngine_setDnsOptions_requestSucceeds() { + DnsOptions options = new DnsOptions.Builder().build(); + mEngine = mEngineBuilder.setDnsOptions(options).build(); + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder( + mTestServer.getSuccessUrl(), mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + } + + @Test + public void getVersionString_notEmpty() { + assertThat(HttpEngine.getVersionString()).isNotEmpty(); + } + + @Test + public void testHttpEngine_SetQuicOptions_RequestSucceedsWithQuic() throws Exception { + String url = mTestServer.getSuccessUrl(); + QuicOptions options = new QuicOptions.Builder().build(); + mEngine = mEngineBuilder + .setEnableQuic(true) + .addQuicHint(HOST, 443, 443) + .setQuicOptions(options) + .build(); + UrlRequest.Builder builder = + mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback); + mRequest = builder.build(); + mRequest.start(); + + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + + } + + @Test + public void testHttpEngine_enableBrotli_brotliAdvertised() { + mEngine = mEngineBuilder.setEnableBrotli(true).build(); + mRequest = + mEngine.newUrlRequestBuilder( + mTestServer.getEchoHeadersUrl(), mCallback.getExecutor(), mCallback) + .build(); + mRequest.start(); + + mCallback.assumeCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertThat(info.getHeaders().getAsMap().get("x-request-header-Accept-Encoding").toString()) + .contains("br"); + assertOKStatusCode(info); + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt new file mode 100644 index 0000000..dd4cf0d --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt
@@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts + +import android.net.http.HttpEngine +import android.net.http.NetworkException +import android.net.http.cts.util.TestUrlRequestCallback +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertSame +import kotlin.test.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class NetworkExceptionTest { + + @Test + fun testNetworkException_returnsInputParameters() { + val message = "failed" + val cause = Throwable("thrown") + val networkException = + object : NetworkException(message, cause) { + override fun getErrorCode() = 0 + override fun isImmediatelyRetryable() = false + } + + assertEquals(message, networkException.message) + assertSame(cause, networkException.cause) + } + + @Test + fun testNetworkException_thrownFromUrlRequest() { + val httpEngine = HttpEngine.Builder(ApplicationProvider.getApplicationContext()).build() + val callback = TestUrlRequestCallback() + val request = + httpEngine.newUrlRequestBuilder("http://localhost", callback.executor, callback).build() + + request.start() + callback.blockForDone() + + assertTrue(request.isDone) + assertIs<NetworkException>(callback.mError) + httpEngine.shutdown() + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/QuicExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/QuicExceptionTest.kt new file mode 100644 index 0000000..4b7aa14 --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/QuicExceptionTest.kt
@@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts + +import android.net.http.QuicException +import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlin.test.Test +import kotlin.test.assertEquals +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class QuicExceptionTest { + + @Test + fun testQuicException_returnsInputParameters() { + val message = "failed" + val cause = Throwable("thrown") + val quicException = + object : QuicException(message, cause) { + override fun getErrorCode() = 0 + override fun isImmediatelyRetryable() = false + } + + assertEquals(message, quicException.message) + assertEquals(cause, quicException.cause) + } + + // TODO: add test for QuicException triggered from HttpEngine +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/QuicOptionsTest.kt b/Cronet/tests/cts/src/android/net/http/cts/QuicOptionsTest.kt new file mode 100644 index 0000000..0b02aa7 --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/QuicOptionsTest.kt
@@ -0,0 +1,84 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net.http.cts + +import android.net.http.QuicOptions +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import java.time.Duration +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class QuicOptionsTest { + @Test + fun testQuicOptions_defaultValues() { + val quicOptions = QuicOptions.Builder().build() + assertThat(quicOptions.allowedQuicHosts).isEmpty() + assertThat(quicOptions.handshakeUserAgent).isNull() + assertThat(quicOptions.idleConnectionTimeout).isNull() + assertFalse(quicOptions.hasInMemoryServerConfigsCacheSize()) + assertFailsWith(IllegalStateException::class) { + quicOptions.inMemoryServerConfigsCacheSize + } + } + + @Test + fun testQuicOptions_quicHostAllowlist_returnsAddedValues() { + val quicOptions = QuicOptions.Builder() + .addAllowedQuicHost("foo") + .addAllowedQuicHost("bar") + .addAllowedQuicHost("foo") + .addAllowedQuicHost("baz") + .build() + assertThat(quicOptions.allowedQuicHosts) + .containsExactly("foo", "bar", "baz") + .inOrder() + } + + @Test + fun testQuicOptions_idleConnectionTimeout_returnsSetValue() { + val timeout = Duration.ofMinutes(10) + val quicOptions = QuicOptions.Builder() + .setIdleConnectionTimeout(timeout) + .build() + assertThat(quicOptions.idleConnectionTimeout) + .isEqualTo(timeout) + } + + @Test + fun testQuicOptions_inMemoryServerConfigsCacheSize_returnsSetValue() { + val quicOptions = QuicOptions.Builder() + .setInMemoryServerConfigsCacheSize(42) + .build() + assertTrue(quicOptions.hasInMemoryServerConfigsCacheSize()) + assertThat(quicOptions.inMemoryServerConfigsCacheSize) + .isEqualTo(42) + } + + @Test + fun testQuicOptions_handshakeUserAgent_returnsSetValue() { + val userAgent = "test" + val quicOptions = QuicOptions.Builder() + .setHandshakeUserAgent(userAgent) + .build() + assertThat(quicOptions.handshakeUserAgent) + .isEqualTo(userAgent) + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java b/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java new file mode 100644 index 0000000..422f4d5 --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/UrlRequestTest.java
@@ -0,0 +1,412 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts; + +import static android.net.http.cts.util.TestUtilsKt.assertOKStatusCode; +import static android.net.http.cts.util.TestUtilsKt.skipIfNoInternetConnection; + +import static com.google.common.truth.Truth.assertThat; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.net.http.HeaderBlock; +import android.net.http.HttpEngine; +import android.net.http.HttpException; +import android.net.http.InlineExecutionProhibitedException; +import android.net.http.UploadDataProvider; +import android.net.http.UrlRequest; +import android.net.http.UrlRequest.Status; +import android.net.http.UrlResponseInfo; +import android.net.http.cts.util.HttpCtsTestServer; +import android.net.http.cts.util.TestStatusListener; +import android.net.http.cts.util.TestUrlRequestCallback; +import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep; +import android.net.http.cts.util.UploadDataProviders; +import android.webkit.cts.CtsTestServer; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.google.common.base.Strings; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.URLEncoder; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@RunWith(AndroidJUnit4.class) +public class UrlRequestTest { + private static final Executor DIRECT_EXECUTOR = Runnable::run; + + private TestUrlRequestCallback mCallback; + private HttpCtsTestServer mTestServer; + private HttpEngine mHttpEngine; + + @Before + public void setUp() throws Exception { + Context context = ApplicationProvider.getApplicationContext(); + skipIfNoInternetConnection(context); + HttpEngine.Builder builder = new HttpEngine.Builder(context); + mHttpEngine = builder.build(); + mCallback = new TestUrlRequestCallback(); + mTestServer = new HttpCtsTestServer(context); + } + + @After + public void tearDown() throws Exception { + if (mHttpEngine != null) { + mHttpEngine.shutdown(); + } + if (mTestServer != null) { + mTestServer.shutdown(); + } + } + + private UrlRequest.Builder createUrlRequestBuilder(String url) { + return mHttpEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback); + } + + @Test + public void testUrlRequestGet_CompletesSuccessfully() throws Exception { + String url = mTestServer.getSuccessUrl(); + UrlRequest request = createUrlRequestBuilder(url).build(); + request.start(); + + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + assertThat("Received byte count must be > 0", info.getReceivedByteCount(), greaterThan(0L)); + } + + @Test + public void testUrlRequestStatus_InvalidBeforeRequestStarts() throws Exception { + UrlRequest request = createUrlRequestBuilder(mTestServer.getSuccessUrl()).build(); + // Calling before request is started should give Status.INVALID, + // since the native adapter is not created. + TestStatusListener statusListener = new TestStatusListener(); + request.getStatus(statusListener); + statusListener.expectStatus(Status.INVALID); + } + + @Test + public void testUrlRequestCancel_CancelCalled() throws Exception { + UrlRequest request = createUrlRequestBuilder(mTestServer.getSuccessUrl()).build(); + mCallback.setAutoAdvance(false); + + request.start(); + mCallback.waitForNextStep(); + assertSame(mCallback.mResponseStep, ResponseStep.ON_RESPONSE_STARTED); + + request.cancel(); + mCallback.expectCallback(ResponseStep.ON_CANCELED); + } + + @Test + public void testUrlRequestPost_EchoRequestBody() { + String testData = "test"; + UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getEchoBodyUrl()); + + UploadDataProvider dataProvider = UploadDataProviders.create(testData); + builder.setUploadDataProvider(dataProvider, mCallback.getExecutor()); + builder.addHeader("Content-Type", "text/html"); + builder.build().start(); + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + + assertOKStatusCode(mCallback.mResponseInfo); + assertEquals(testData, mCallback.mResponseAsString); + } + + @Test + public void testUrlRequestFail_FailedCalled() { + createUrlRequestBuilder("http://0.0.0.0:0/").build().start(); + mCallback.expectCallback(ResponseStep.ON_FAILED); + } + + @Test + public void testUrlRequest_directExecutor_allowed() throws InterruptedException { + TestUrlRequestCallback callback = new TestUrlRequestCallback(); + callback.setAllowDirectExecutor(true); + UrlRequest.Builder builder = mHttpEngine.newUrlRequestBuilder( + mTestServer.getEchoBodyUrl(), DIRECT_EXECUTOR, callback); + UploadDataProvider dataProvider = UploadDataProviders.create("test"); + builder.setUploadDataProvider(dataProvider, DIRECT_EXECUTOR); + builder.addHeader("Content-Type", "text/plain;charset=UTF-8"); + builder.setDirectExecutorAllowed(true); + builder.build().start(); + callback.blockForDone(); + + if (callback.mOnErrorCalled) { + throw new AssertionError("Expected no exception", callback.mError); + } + + assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); + assertEquals("test", callback.mResponseAsString); + } + + @Test + public void testUrlRequest_directExecutor_disallowed_uploadDataProvider() throws Exception { + TestUrlRequestCallback callback = new TestUrlRequestCallback(); + // This applies just locally to the test callback, not to SUT + callback.setAllowDirectExecutor(true); + + UrlRequest.Builder builder = mHttpEngine.newUrlRequestBuilder( + mTestServer.getEchoBodyUrl(), Executors.newSingleThreadExecutor(), callback); + UploadDataProvider dataProvider = UploadDataProviders.create("test"); + + builder.setUploadDataProvider(dataProvider, DIRECT_EXECUTOR) + .addHeader("Content-Type", "text/plain;charset=UTF-8") + .build() + .start(); + callback.blockForDone(); + + assertTrue(callback.mOnErrorCalled); + assertTrue(callback.mError.getCause() instanceof InlineExecutionProhibitedException); + } + + @Test + public void testUrlRequest_directExecutor_disallowed_responseCallback() throws Exception { + TestUrlRequestCallback callback = new TestUrlRequestCallback(); + // This applies just locally to the test callback, not to SUT + callback.setAllowDirectExecutor(true); + + UrlRequest.Builder builder = mHttpEngine.newUrlRequestBuilder( + mTestServer.getEchoBodyUrl(), DIRECT_EXECUTOR, callback); + UploadDataProvider dataProvider = UploadDataProviders.create("test"); + + builder.setUploadDataProvider(dataProvider, Executors.newSingleThreadExecutor()) + .addHeader("Content-Type", "text/plain;charset=UTF-8") + .build() + .start(); + callback.blockForDone(); + + assertTrue(callback.mOnErrorCalled); + assertTrue(callback.mError.getCause() instanceof InlineExecutionProhibitedException); + } + + @Test + public void testUrlRequest_nonDirectByteBuffer() throws Exception { + BlockingQueue<HttpException> onFailedException = new ArrayBlockingQueue<>(1); + + UrlRequest request = + mHttpEngine + .newUrlRequestBuilder( + mTestServer.getSuccessUrl(), + Executors.newSingleThreadExecutor(), + new StubUrlRequestCallback() { + @Override + public void onResponseStarted( + UrlRequest request, UrlResponseInfo info) { + // note: allocate, not allocateDirect + request.read(ByteBuffer.allocate(1024)); + } + + @Override + public void onFailed( + UrlRequest request, + UrlResponseInfo info, + HttpException error) { + onFailedException.add(error); + } + }) + .build(); + request.start(); + + HttpException e = onFailedException.poll(5, TimeUnit.SECONDS); + assertNotNull(e); + assertTrue(e.getCause() instanceof IllegalArgumentException); + assertTrue(e.getCause().getMessage().contains("direct")); + } + + @Test + public void testUrlRequest_fullByteBuffer() throws Exception { + BlockingQueue<HttpException> onFailedException = new ArrayBlockingQueue<>(1); + + UrlRequest request = + mHttpEngine + .newUrlRequestBuilder( + mTestServer.getSuccessUrl(), + Executors.newSingleThreadExecutor(), + new StubUrlRequestCallback() { + @Override + public void onResponseStarted( + UrlRequest request, UrlResponseInfo info) { + ByteBuffer bb = ByteBuffer.allocateDirect(1024); + bb.position(bb.limit()); + request.read(bb); + } + + @Override + public void onFailed( + UrlRequest request, + UrlResponseInfo info, + HttpException error) { + onFailedException.add(error); + } + }) + .build(); + request.start(); + + HttpException e = onFailedException.poll(5, TimeUnit.SECONDS); + assertNotNull(e); + assertTrue(e.getCause() instanceof IllegalArgumentException); + assertTrue(e.getCause().getMessage().contains("full")); + } + + @Test + public void testUrlRequest_redirects() throws Exception { + int expectedNumRedirects = 5; + String url = + mTestServer.getRedirectingAssetUrl("html/hello_world.html", expectedNumRedirects); + + UrlRequest request = createUrlRequestBuilder(url).build(); + request.start(); + + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + UrlResponseInfo info = mCallback.mResponseInfo; + assertOKStatusCode(info); + assertThat(mCallback.mResponseAsString).contains("hello world"); + assertThat(info.getUrlChain()).hasSize(expectedNumRedirects + 1); + assertThat(info.getUrlChain().get(0)).isEqualTo(url); + assertThat(info.getUrlChain().get(expectedNumRedirects)).isEqualTo(info.getUrl()); + } + + @Test + public void testUrlRequestPost_withRedirect() throws Exception { + String body = Strings.repeat( + "Hello, this is a really interesting body, so write this 100 times.", 100); + + String redirectUrlParameter = + URLEncoder.encode(mTestServer.getEchoBodyUrl(), "UTF-8"); + createUrlRequestBuilder( + String.format( + "%s/alt_redirect?dest=%s&statusCode=307", + mTestServer.getBaseUri(), + redirectUrlParameter)) + .setHttpMethod("POST") + .addHeader("Content-Type", "text/plain") + .setUploadDataProvider( + UploadDataProviders.create(body.getBytes(StandardCharsets.UTF_8)), + mCallback.getExecutor()) + .build() + .start(); + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + + assertOKStatusCode(mCallback.mResponseInfo); + assertThat(mCallback.mResponseAsString).isEqualTo(body); + } + + @Test + public void testUrlRequest_customHeaders() throws Exception { + UrlRequest.Builder builder = createUrlRequestBuilder(mTestServer.getEchoHeadersUrl()); + + List<Map.Entry<String, String>> expectedHeaders = Arrays.asList( + Map.entry("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="), + Map.entry("Max-Forwards", "10"), + Map.entry("X-Client-Data", "random custom header content")); + + for (Map.Entry<String, String> header : expectedHeaders) { + builder.addHeader(header.getKey(), header.getValue()); + } + + builder.build().start(); + mCallback.expectCallback(ResponseStep.ON_SUCCEEDED); + + assertOKStatusCode(mCallback.mResponseInfo); + + List<Map.Entry<String, String>> echoedHeaders = + extractEchoedHeaders(mCallback.mResponseInfo.getHeaders()); + + // The implementation might decide to add more headers like accepted encodings it handles + // internally so the server is likely to see more headers than explicitly set + // by the developer. + assertThat(echoedHeaders) + .containsAtLeastElementsIn(expectedHeaders); + } + + private static List<Map.Entry<String, String>> extractEchoedHeaders(HeaderBlock headers) { + return headers.getAsList() + .stream() + .flatMap(input -> { + if (input.getKey().startsWith(CtsTestServer.ECHOED_RESPONSE_HEADER_PREFIX)) { + String strippedKey = + input.getKey().substring( + CtsTestServer.ECHOED_RESPONSE_HEADER_PREFIX.length()); + return Stream.of(Map.entry(strippedKey, input.getValue())); + } else { + return Stream.empty(); + } + }) + .collect(Collectors.toList()); + } + + private static class StubUrlRequestCallback implements UrlRequest.Callback { + + @Override + public void onRedirectReceived( + UrlRequest request, UrlResponseInfo info, String newLocationUrl) { + throw new UnsupportedOperationException(); + } + + @Override + public void onResponseStarted(UrlRequest request, UrlResponseInfo info) { + throw new UnsupportedOperationException(); + } + + @Override + public void onReadCompleted( + UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) { + throw new UnsupportedOperationException(); + } + + @Override + public void onSucceeded(UrlRequest request, UrlResponseInfo info) { + throw new UnsupportedOperationException(); + } + + @Override + public void onFailed(UrlRequest request, UrlResponseInfo info, HttpException error) { + throw new UnsupportedOperationException(error); + } + + @Override + public void onCanceled(@NonNull UrlRequest request, @Nullable UrlResponseInfo info) { + throw new UnsupportedOperationException(); + } + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/UrlResponseInfoTest.kt b/Cronet/tests/cts/src/android/net/http/cts/UrlResponseInfoTest.kt new file mode 100644 index 0000000..38da9c5 --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/UrlResponseInfoTest.kt
@@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts + +import android.content.Context +import android.net.http.HttpEngine +import android.net.http.cts.util.HttpCtsTestServer +import android.net.http.cts.util.TestUrlRequestCallback +import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class UrlResponseInfoTest { + + @Test + fun testUrlResponseInfo_apisReturnCorrectInfo() { + // start the engine and send a request + val context: Context = ApplicationProvider.getApplicationContext() + val server = HttpCtsTestServer(context) + val httpEngine = HttpEngine.Builder(context).build() + val callback = TestUrlRequestCallback() + val url = server.successUrl + val request = httpEngine.newUrlRequestBuilder(url, callback.executor, callback).build() + + request.start() + callback.expectCallback(ResponseStep.ON_SUCCEEDED) + + val info = callback.mResponseInfo + assertFalse(info.headers.asList.isEmpty()) + assertEquals(200, info.httpStatusCode) + assertTrue(info.receivedByteCount > 0) + assertEquals(url, info.url) + assertEquals(listOf(url), info.urlChain) + assertFalse(info.wasCached()) + + // TODO Current test server does not set these values. Uncomment when we use one that does. + // assertEquals("OK", info.httpStatusText) + // assertEquals("http/1.1", info.negotiatedProtocol) + + // cronet defaults to port 0 when no proxy is specified. + // This is not a behaviour we want to enforce since null is reasonable too. + // assertEquals(":0", info.proxyServer) + + server.shutdown() + httpEngine.shutdown() + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/util/HttpCtsTestServer.kt b/Cronet/tests/cts/src/android/net/http/cts/util/HttpCtsTestServer.kt new file mode 100644 index 0000000..5196544 --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/util/HttpCtsTestServer.kt
@@ -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 android.net.http.cts.util + +import android.content.Context +import android.webkit.cts.CtsTestServer +import java.net.URI +import org.apache.http.HttpEntityEnclosingRequest +import org.apache.http.HttpRequest +import org.apache.http.HttpResponse +import org.apache.http.HttpStatus +import org.apache.http.HttpVersion +import org.apache.http.message.BasicHttpResponse + +private const val ECHO_BODY_PATH = "/echo_body" + +/** Extends CtsTestServer to handle POST requests and other test specific requests */ +class HttpCtsTestServer(context: Context) : CtsTestServer(context) { + + val echoBodyUrl: String = baseUri + ECHO_BODY_PATH + val successUrl: String = getAssetUrl("html/hello_world.html") + + override fun onPost(req: HttpRequest): HttpResponse? { + val path = URI.create(req.requestLine.uri).path + var response: HttpResponse? = null + + if (path.startsWith(ECHO_BODY_PATH)) { + if (req !is HttpEntityEnclosingRequest) { + return BasicHttpResponse( + HttpVersion.HTTP_1_0, + HttpStatus.SC_INTERNAL_SERVER_ERROR, + "Expected req to be of type HttpEntityEnclosingRequest but got ${req.javaClass}" + ) + } + + response = BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, null) + response.entity = req.entity + response.addHeader("Content-Length", req.entity.contentLength.toString()) + } + + return response + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/util/TestBidirectionalStreamCallback.java b/Cronet/tests/cts/src/android/net/http/cts/util/TestBidirectionalStreamCallback.java new file mode 100644 index 0000000..1e7333c --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/util/TestBidirectionalStreamCallback.java
@@ -0,0 +1,485 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts.util; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeThat; +import static org.junit.Assume.assumeTrue; + +import android.net.http.BidirectionalStream; +import android.net.http.HeaderBlock; +import android.net.http.HttpException; +import android.net.http.UrlResponseInfo; +import android.os.ConditionVariable; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +/** + * Callback that tracks information from different callbacks and has a method to block thread until + * the stream completes on another thread. Allows to cancel, block stream or throw an exception from + * an arbitrary step. + */ +public class TestBidirectionalStreamCallback implements BidirectionalStream.Callback { + private static final int TIMEOUT_MS = 12_000; + public UrlResponseInfo mResponseInfo; + public HttpException mError; + + public ResponseStep mResponseStep = ResponseStep.NOTHING; + + public boolean mOnErrorCalled; + public boolean mOnCanceledCalled; + + public int mHttpResponseDataLength; + public String mResponseAsString = ""; + + public HeaderBlock mTrailers; + + private static final int READ_BUFFER_SIZE = 32 * 1024; + + // When false, the consumer is responsible for all calls into the stream + // that advance it. + private boolean mAutoAdvance = true; + + // Conditionally fail on certain steps. + private FailureType mFailureType = FailureType.NONE; + private ResponseStep mFailureStep = ResponseStep.NOTHING; + + // Signals when the stream is done either successfully or not. + private final ConditionVariable mDone = new ConditionVariable(); + + // Signaled on each step when mAutoAdvance is false. + private final ConditionVariable mReadStepBlock = new ConditionVariable(); + private final ConditionVariable mWriteStepBlock = new ConditionVariable(); + + // Executor Service for Cronet callbacks. + private final ExecutorService mExecutorService = + Executors.newSingleThreadExecutor(new ExecutorThreadFactory()); + private Thread mExecutorThread; + + // position() of ByteBuffer prior to read() call. + private int mBufferPositionBeforeRead; + + // Data to write. + private final ArrayList<WriteBuffer> mWriteBuffers = new ArrayList<WriteBuffer>(); + + // Buffers that we yet to receive the corresponding onWriteCompleted callback. + private final ArrayList<WriteBuffer> mWriteBuffersToBeAcked = new ArrayList<WriteBuffer>(); + + // Whether to use a direct executor. + private final boolean mUseDirectExecutor; + private final DirectExecutor mDirectExecutor; + + private class ExecutorThreadFactory implements ThreadFactory { + @Override + public Thread newThread(Runnable r) { + mExecutorThread = new Thread(r); + return mExecutorThread; + } + } + + private static class WriteBuffer { + final ByteBuffer mBuffer; + final boolean mFlush; + + WriteBuffer(ByteBuffer buffer, boolean flush) { + mBuffer = buffer; + mFlush = flush; + } + } + + private static class DirectExecutor implements Executor { + @Override + public void execute(Runnable task) { + task.run(); + } + } + + public enum ResponseStep { + NOTHING, + ON_STREAM_READY, + ON_RESPONSE_STARTED, + ON_READ_COMPLETED, + ON_WRITE_COMPLETED, + ON_TRAILERS, + ON_CANCELED, + ON_FAILED, + ON_SUCCEEDED, + } + + public enum FailureType { + NONE, + CANCEL_SYNC, + CANCEL_ASYNC, + // Same as above, but continues to advance the stream after posting + // the cancellation task. + CANCEL_ASYNC_WITHOUT_PAUSE, + THROW_SYNC + } + + private boolean isTerminalCallback(ResponseStep step) { + switch (step) { + case ON_SUCCEEDED: + case ON_CANCELED: + case ON_FAILED: + return true; + default: + return false; + } + } + + public TestBidirectionalStreamCallback() { + mUseDirectExecutor = false; + mDirectExecutor = null; + } + + public TestBidirectionalStreamCallback(boolean useDirectExecutor) { + mUseDirectExecutor = useDirectExecutor; + mDirectExecutor = new DirectExecutor(); + } + + public void setAutoAdvance(boolean autoAdvance) { + mAutoAdvance = autoAdvance; + } + + public void setFailure(FailureType failureType, ResponseStep failureStep) { + mFailureStep = failureStep; + mFailureType = failureType; + } + + public boolean blockForDone() { + return mDone.block(TIMEOUT_MS); + } + + /** + * Waits for a terminal callback to complete execution before failing if the callback is not the + * expected one + * + * @param expectedStep the expected callback step + */ + public void expectCallback(ResponseStep expectedStep) { + if (isTerminalCallback(expectedStep)) { + assertTrue(String.format( + "Request timed out. Expected %s callback. Current callback is %s", + expectedStep, mResponseStep), + blockForDone()); + } + assertSame(expectedStep, mResponseStep); + } + + /** + * Waits for a terminal callback to complete execution before skipping the test if the callback + * is not the expected one + * + * @param expectedStep the expected callback step + */ + public void assumeCallback(ResponseStep expectedStep) { + if (isTerminalCallback(expectedStep)) { + assumeTrue( + String.format( + "Request timed out. Expected %s callback. Current callback is %s", + expectedStep, mResponseStep), + blockForDone()); + } + assumeThat(expectedStep, equalTo(mResponseStep)); + } + + public void waitForNextReadStep() { + mReadStepBlock.block(); + mReadStepBlock.close(); + } + + public void waitForNextWriteStep() { + mWriteStepBlock.block(); + mWriteStepBlock.close(); + } + + public Executor getExecutor() { + if (mUseDirectExecutor) { + return mDirectExecutor; + } + return mExecutorService; + } + + public void shutdownExecutor() { + if (mUseDirectExecutor) { + throw new UnsupportedOperationException("DirectExecutor doesn't support shutdown"); + } + mExecutorService.shutdown(); + } + + public void addWriteData(byte[] data) { + addWriteData(data, true); + } + + public void addWriteData(byte[] data, boolean flush) { + ByteBuffer writeBuffer = ByteBuffer.allocateDirect(data.length); + writeBuffer.put(data); + writeBuffer.flip(); + mWriteBuffers.add(new WriteBuffer(writeBuffer, flush)); + mWriteBuffersToBeAcked.add(new WriteBuffer(writeBuffer, flush)); + } + + @Override + public void onStreamReady(BidirectionalStream stream) { + checkOnValidThread(); + assertFalse(stream.isDone()); + assertEquals(ResponseStep.NOTHING, mResponseStep); + assertNull(mError); + mResponseStep = ResponseStep.ON_STREAM_READY; + if (maybeThrowCancelOrPause(stream, mWriteStepBlock)) { + return; + } + startNextWrite(stream); + } + + @Override + public void onResponseHeadersReceived(BidirectionalStream stream, UrlResponseInfo info) { + checkOnValidThread(); + assertFalse(stream.isDone()); + assertTrue( + mResponseStep == ResponseStep.NOTHING + || mResponseStep == ResponseStep.ON_STREAM_READY + || mResponseStep == ResponseStep.ON_WRITE_COMPLETED); + assertNull(mError); + + mResponseStep = ResponseStep.ON_RESPONSE_STARTED; + mResponseInfo = info; + if (maybeThrowCancelOrPause(stream, mReadStepBlock)) { + return; + } + startNextRead(stream); + } + + @Override + public void onReadCompleted( + BidirectionalStream stream, + UrlResponseInfo info, + ByteBuffer byteBuffer, + boolean endOfStream) { + checkOnValidThread(); + assertFalse(stream.isDone()); + assertTrue( + mResponseStep == ResponseStep.ON_RESPONSE_STARTED + || mResponseStep == ResponseStep.ON_READ_COMPLETED + || mResponseStep == ResponseStep.ON_WRITE_COMPLETED + || mResponseStep == ResponseStep.ON_TRAILERS); + assertNull(mError); + + mResponseStep = ResponseStep.ON_READ_COMPLETED; + mResponseInfo = info; + + final int bytesRead = byteBuffer.position() - mBufferPositionBeforeRead; + mHttpResponseDataLength += bytesRead; + final byte[] lastDataReceivedAsBytes = new byte[bytesRead]; + // Rewind byteBuffer.position() to pre-read() position. + byteBuffer.position(mBufferPositionBeforeRead); + // This restores byteBuffer.position() to its value on entrance to + // this function. + byteBuffer.get(lastDataReceivedAsBytes); + + mResponseAsString += new String(lastDataReceivedAsBytes); + + if (maybeThrowCancelOrPause(stream, mReadStepBlock)) { + return; + } + // Do not read if EOF has been reached. + if (!endOfStream) { + startNextRead(stream); + } + } + + @Override + public void onWriteCompleted( + BidirectionalStream stream, + UrlResponseInfo info, + ByteBuffer buffer, + boolean endOfStream) { + checkOnValidThread(); + assertFalse(stream.isDone()); + assertNull(mError); + mResponseStep = ResponseStep.ON_WRITE_COMPLETED; + mResponseInfo = info; + if (!mWriteBuffersToBeAcked.isEmpty()) { + assertEquals(buffer, mWriteBuffersToBeAcked.get(0).mBuffer); + mWriteBuffersToBeAcked.remove(0); + } + if (maybeThrowCancelOrPause(stream, mWriteStepBlock)) { + return; + } + startNextWrite(stream); + } + + @Override + public void onResponseTrailersReceived( + BidirectionalStream stream, + UrlResponseInfo info, + HeaderBlock trailers) { + checkOnValidThread(); + assertFalse(stream.isDone()); + assertNull(mError); + mResponseStep = ResponseStep.ON_TRAILERS; + mResponseInfo = info; + mTrailers = trailers; + if (maybeThrowCancelOrPause(stream, mReadStepBlock)) { + return; + } + } + + @Override + public void onSucceeded(BidirectionalStream stream, UrlResponseInfo info) { + checkOnValidThread(); + assertTrue(stream.isDone()); + assertTrue( + mResponseStep == ResponseStep.ON_RESPONSE_STARTED + || mResponseStep == ResponseStep.ON_READ_COMPLETED + || mResponseStep == ResponseStep.ON_WRITE_COMPLETED + || mResponseStep == ResponseStep.ON_TRAILERS); + assertFalse(mOnErrorCalled); + assertFalse(mOnCanceledCalled); + assertNull(mError); + assertEquals(0, mWriteBuffers.size()); + assertEquals(0, mWriteBuffersToBeAcked.size()); + + mResponseStep = ResponseStep.ON_SUCCEEDED; + mResponseInfo = info; + openDone(); + maybeThrowCancelOrPause(stream, mReadStepBlock); + } + + @Override + public void onFailed(BidirectionalStream stream, UrlResponseInfo info, HttpException error) { + checkOnValidThread(); + assertTrue(stream.isDone()); + // Shouldn't happen after success. + assertTrue(mResponseStep != ResponseStep.ON_SUCCEEDED); + // Should happen at most once for a single stream. + assertFalse(mOnErrorCalled); + assertFalse(mOnCanceledCalled); + assertNull(mError); + mResponseStep = ResponseStep.ON_FAILED; + mResponseInfo = info; + + mOnErrorCalled = true; + mError = error; + openDone(); + maybeThrowCancelOrPause(stream, mReadStepBlock); + } + + @Override + public void onCanceled(BidirectionalStream stream, UrlResponseInfo info) { + checkOnValidThread(); + assertTrue(stream.isDone()); + // Should happen at most once for a single stream. + assertFalse(mOnCanceledCalled); + assertFalse(mOnErrorCalled); + assertNull(mError); + mResponseStep = ResponseStep.ON_CANCELED; + mResponseInfo = info; + + mOnCanceledCalled = true; + openDone(); + maybeThrowCancelOrPause(stream, mReadStepBlock); + } + + public void startNextRead(BidirectionalStream stream) { + startNextRead(stream, ByteBuffer.allocateDirect(READ_BUFFER_SIZE)); + } + + public void startNextRead(BidirectionalStream stream, ByteBuffer buffer) { + mBufferPositionBeforeRead = buffer.position(); + stream.read(buffer); + } + + public void startNextWrite(BidirectionalStream stream) { + if (!mWriteBuffers.isEmpty()) { + Iterator<WriteBuffer> iterator = mWriteBuffers.iterator(); + while (iterator.hasNext()) { + WriteBuffer b = iterator.next(); + stream.write(b.mBuffer, !iterator.hasNext()); + iterator.remove(); + if (b.mFlush) { + stream.flush(); + break; + } + } + } + } + + public boolean isDone() { + // It's not mentioned by the Android docs, but block(0) seems to block + // indefinitely, so have to block for one millisecond to get state + // without blocking. + return mDone.block(1); + } + + /** Returns the number of pending Writes. */ + public int numPendingWrites() { + return mWriteBuffers.size(); + } + + protected void openDone() { + mDone.open(); + } + + /** Returns {@code false} if the callback should continue to advance the stream. */ + private boolean maybeThrowCancelOrPause( + final BidirectionalStream stream, ConditionVariable stepBlock) { + if (mResponseStep != mFailureStep || mFailureType == FailureType.NONE) { + if (!mAutoAdvance) { + stepBlock.open(); + return true; + } + return false; + } + + if (mFailureType == FailureType.THROW_SYNC) { + throw new IllegalStateException("Callback Exception."); + } + Runnable task = + new Runnable() { + @Override + public void run() { + stream.cancel(); + } + }; + if (mFailureType == FailureType.CANCEL_ASYNC + || mFailureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE) { + getExecutor().execute(task); + } else { + task.run(); + } + return mFailureType != FailureType.CANCEL_ASYNC_WITHOUT_PAUSE; + } + + /** Checks whether callback methods are invoked on the correct thread. */ + private void checkOnValidThread() { + if (!mUseDirectExecutor) { + assertEquals(mExecutorThread, Thread.currentThread()); + } + } +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/util/TestStatusListener.kt b/Cronet/tests/cts/src/android/net/http/cts/util/TestStatusListener.kt new file mode 100644 index 0000000..3a4486f --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/util/TestStatusListener.kt
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts.util + +import android.net.http.UrlRequest.StatusListener +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit +import org.junit.Assert.assertSame + +private const val TIMEOUT_MS = 12000L + +/** Test status listener for requests */ +class TestStatusListener : StatusListener { + private val statusFuture = CompletableFuture<Int>() + + override fun onStatus(status: Int) { + statusFuture.complete(status) + } + + /** Fails if the expected status is not the returned status */ + fun expectStatus(expected: Int) { + assertSame(expected, statusFuture.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)) + } +}
diff --git a/Cronet/tests/cts/src/org/chromium/net/test/util/TestUrlRequestCallback.java b/Cronet/tests/cts/src/android/net/http/cts/util/TestUrlRequestCallback.java similarity index 88% rename from Cronet/tests/cts/src/org/chromium/net/test/util/TestUrlRequestCallback.java rename to Cronet/tests/cts/src/android/net/http/cts/util/TestUrlRequestCallback.java index 3c7c001..28443b7 100644 --- a/Cronet/tests/cts/src/org/chromium/net/test/util/TestUrlRequestCallback.java +++ b/Cronet/tests/cts/src/android/net/http/cts/util/TestUrlRequestCallback.java
@@ -14,25 +14,30 @@ * limitations under the License. */ -package org.chromium.net.test.util; +package android.net.http.cts.util; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.core.AnyOf.anyOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeThat; +import static org.junit.Assume.assumeTrue; +import android.net.http.CallbackException; +import android.net.http.HttpException; +import android.net.http.InlineExecutionProhibitedException; +import android.net.http.UrlRequest; +import android.net.http.UrlResponseInfo; import android.os.ConditionVariable; import android.os.StrictMode; -import org.chromium.net.CallbackException; -import org.chromium.net.CronetException; -import org.chromium.net.InlineExecutionProhibitedException; -import org.chromium.net.UrlRequest; -import org.chromium.net.UrlResponseInfo; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.concurrent.ExecutorService; @@ -45,12 +50,12 @@ * method to block thread until the request completes on another thread. * Allows us to cancel, block request or throw an exception from an arbitrary step. */ -public class TestUrlRequestCallback extends UrlRequest.Callback { +public class TestUrlRequestCallback implements UrlRequest.Callback { private static final int TIMEOUT_MS = 12_000; public ArrayList<UrlResponseInfo> mRedirectResponseInfoList = new ArrayList<>(); public ArrayList<String> mRedirectUrlList = new ArrayList<>(); public UrlResponseInfo mResponseInfo; - public CronetException mError; + public HttpException mError; public ResponseStep mResponseStep = ResponseStep.NOTHING; @@ -89,7 +94,7 @@ // Signaled on each step when mAutoAdvance is false. private final ConditionVariable mStepBlock = new ConditionVariable(); - // Executor Service for Cronet callbacks. + // Executor Service for Http callbacks. private final ExecutorService mExecutorService; private Thread mExecutorThread; @@ -233,6 +238,19 @@ } /** + * Waits for a terminal callback to complete execution before skipping the test if the + * callback is not the expected one + * + * @param expectedStep the expected callback step + */ + public void assumeCallback(ResponseStep expectedStep) { + if (isTerminalCallback(expectedStep)) { + assumeTrue("Did not receive terminal callback before timeout", blockForDone()); + } + assumeThat(expectedStep, equalTo(mResponseStep)); + } + + /** * Blocks the calling thread until one of the final states has been called. * This is called before the callback has finished executed. */ @@ -273,8 +291,9 @@ UrlRequest request, UrlResponseInfo info, String newLocationUrl) { checkExecutorThread(); assertFalse(request.isDone()); - assertTrue(mResponseStep == ResponseStep.NOTHING - || mResponseStep == ResponseStep.ON_RECEIVED_REDIRECT); + assertThat(mResponseStep, anyOf( + equalTo(ResponseStep.NOTHING), + equalTo(ResponseStep.ON_RECEIVED_REDIRECT))); assertNull(mError); mResponseStep = ResponseStep.ON_RECEIVED_REDIRECT; @@ -291,8 +310,9 @@ public void onResponseStarted(UrlRequest request, UrlResponseInfo info) { checkExecutorThread(); assertFalse(request.isDone()); - assertTrue(mResponseStep == ResponseStep.NOTHING - || mResponseStep == ResponseStep.ON_RECEIVED_REDIRECT); + assertThat(mResponseStep, anyOf( + equalTo(ResponseStep.NOTHING), + equalTo(ResponseStep.ON_RECEIVED_REDIRECT))); assertNull(mError); mResponseStep = ResponseStep.ON_RESPONSE_STARTED; @@ -307,8 +327,9 @@ public void onReadCompleted(UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) { checkExecutorThread(); assertFalse(request.isDone()); - assertTrue(mResponseStep == ResponseStep.ON_RESPONSE_STARTED - || mResponseStep == ResponseStep.ON_READ_COMPLETED); + assertThat(mResponseStep, anyOf( + equalTo(ResponseStep.ON_RESPONSE_STARTED), + equalTo(ResponseStep.ON_READ_COMPLETED))); assertNull(mError); mResponseStep = ResponseStep.ON_READ_COMPLETED; @@ -334,8 +355,9 @@ public void onSucceeded(UrlRequest request, UrlResponseInfo info) { checkExecutorThread(); assertTrue(request.isDone()); - assertTrue(mResponseStep == ResponseStep.ON_RESPONSE_STARTED - || mResponseStep == ResponseStep.ON_READ_COMPLETED); + assertThat(mResponseStep, anyOf( + equalTo(ResponseStep.ON_RESPONSE_STARTED), + equalTo(ResponseStep.ON_READ_COMPLETED))); assertFalse(mOnErrorCalled); assertFalse(mOnCanceledCalled); assertNull(mError); @@ -349,7 +371,7 @@ } @Override - public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { + public void onFailed(UrlRequest request, UrlResponseInfo info, HttpException error) { // If the failure is because of prohibited direct execution, the test shouldn't fail // since the request already did. if (error.getCause() instanceof InlineExecutionProhibitedException) { @@ -358,7 +380,7 @@ checkExecutorThread(); assertTrue(request.isDone()); // Shouldn't happen after success. - assertTrue(mResponseStep != ResponseStep.ON_SUCCEEDED); + assertNotEquals(ResponseStep.ON_SUCCEEDED, mResponseStep); // Should happen at most once for a single request. assertFalse(mOnErrorCalled); assertFalse(mOnCanceledCalled);
diff --git a/Cronet/tests/cts/src/android/net/http/cts/util/TestUtils.kt b/Cronet/tests/cts/src/android/net/http/cts/util/TestUtils.kt new file mode 100644 index 0000000..7fc005a --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/util/TestUtils.kt
@@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts.util + +import android.content.Context +import android.net.ConnectivityManager +import android.net.http.UrlResponseInfo +import org.hamcrest.Matchers.equalTo +import org.junit.Assert.assertEquals +import org.junit.Assume.assumeNotNull +import org.junit.Assume.assumeThat + +fun skipIfNoInternetConnection(context: Context) { + val connectivityManager = context.getSystemService(ConnectivityManager::class.java) + assumeNotNull( + "This test requires a working Internet connection", connectivityManager!!.activeNetwork + ) +} + +fun assertOKStatusCode(info: UrlResponseInfo) { + assertEquals("Status code must be 200 OK", 200, info.httpStatusCode) +} + +fun assumeOKStatusCode(info: UrlResponseInfo) { + assumeThat("Status code must be 200 OK", info.httpStatusCode, equalTo(200)) +}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/util/UploadDataProviders.java b/Cronet/tests/cts/src/android/net/http/cts/util/UploadDataProviders.java new file mode 100644 index 0000000..3b90fa0 --- /dev/null +++ b/Cronet/tests/cts/src/android/net/http/cts/util/UploadDataProviders.java
@@ -0,0 +1,209 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.http.cts.util; + +import android.net.http.UploadDataProvider; +import android.net.http.UploadDataSink; +import android.os.ParcelFileDescriptor; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; + +/** + * Provides implementations of {@link UploadDataProvider} for common use cases. Corresponds to + * {@code android.net.http.apihelpers.UploadDataProviders} which is not an exposed API. + */ +public final class UploadDataProviders { + /** + * Uploads an entire file. + * + * @param file The file to upload + * @return A new UploadDataProvider for the given file + */ + public static UploadDataProvider create(final File file) { + return new FileUploadProvider(() -> new FileInputStream(file).getChannel()); + } + + /** + * Uploads an entire file, closing the descriptor when it is no longer needed. + * + * @param fd The file descriptor to upload + * @throws IllegalArgumentException if {@code fd} is not a file. + * @return A new UploadDataProvider for the given file descriptor + */ + public static UploadDataProvider create(final ParcelFileDescriptor fd) { + return new FileUploadProvider(() -> { + if (fd.getStatSize() != -1) { + return new ParcelFileDescriptor.AutoCloseInputStream(fd).getChannel(); + } else { + fd.close(); + throw new IllegalArgumentException("Not a file: " + fd); + } + }); + } + + /** + * Uploads a ByteBuffer, from the current {@code buffer.position()} to {@code buffer.limit()} + * + * @param buffer The data to upload + * @return A new UploadDataProvider for the given buffer + */ + public static UploadDataProvider create(ByteBuffer buffer) { + return new ByteBufferUploadProvider(buffer.slice()); + } + + /** + * Uploads {@code length} bytes from {@code data}, starting from {@code offset} + * + * @param data Array containing data to upload + * @param offset Offset within data to start with + * @param length Number of bytes to upload + * @return A new UploadDataProvider for the given data + */ + public static UploadDataProvider create(byte[] data, int offset, int length) { + return new ByteBufferUploadProvider(ByteBuffer.wrap(data, offset, length).slice()); + } + + /** + * Uploads the contents of {@code data} + * + * @param data Array containing data to upload + * @return A new UploadDataProvider for the given data + */ + public static UploadDataProvider create(byte[] data) { + return create(data, 0, data.length); + } + + /** + * Uploads the UTF-8 representation of {@code data} + * + * @param data String containing data to upload + * @return A new UploadDataProvider for the given data + */ + public static UploadDataProvider create(String data) { + return create(data.getBytes(StandardCharsets.UTF_8)); + } + + private interface FileChannelProvider { + FileChannel getChannel() throws IOException; + } + + private static final class FileUploadProvider extends UploadDataProvider { + private volatile FileChannel mChannel; + private final FileChannelProvider mProvider; + /** Guards initialization of {@code mChannel} */ + private final Object mLock = new Object(); + + private FileUploadProvider(FileChannelProvider provider) { + this.mProvider = provider; + } + + @Override + public long getLength() throws IOException { + return getChannel().size(); + } + + @Override + public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) throws IOException { + if (!byteBuffer.hasRemaining()) { + throw new IllegalStateException("Cronet passed a buffer with no bytes remaining"); + } + FileChannel channel = getChannel(); + int bytesRead = 0; + while (bytesRead == 0) { + int read = channel.read(byteBuffer); + if (read == -1) { + break; + } else { + bytesRead += read; + } + } + uploadDataSink.onReadSucceeded(false); + } + + @Override + public void rewind(UploadDataSink uploadDataSink) throws IOException { + getChannel().position(0); + uploadDataSink.onRewindSucceeded(); + } + + /** + * Lazily initializes the channel so that a blocking operation isn't performed + * on a non-executor thread. + */ + private FileChannel getChannel() throws IOException { + if (mChannel == null) { + synchronized (mLock) { + if (mChannel == null) { + mChannel = mProvider.getChannel(); + } + } + } + return mChannel; + } + + @Override + public void close() throws IOException { + FileChannel channel = mChannel; + if (channel != null) { + channel.close(); + } + } + } + + private static final class ByteBufferUploadProvider extends UploadDataProvider { + private final ByteBuffer mUploadBuffer; + + private ByteBufferUploadProvider(ByteBuffer uploadBuffer) { + this.mUploadBuffer = uploadBuffer; + } + + @Override + public long getLength() { + return mUploadBuffer.limit(); + } + + @Override + public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) { + if (!byteBuffer.hasRemaining()) { + throw new IllegalStateException("Cronet passed a buffer with no bytes remaining"); + } + if (byteBuffer.remaining() >= mUploadBuffer.remaining()) { + byteBuffer.put(mUploadBuffer); + } else { + int oldLimit = mUploadBuffer.limit(); + mUploadBuffer.limit(mUploadBuffer.position() + byteBuffer.remaining()); + byteBuffer.put(mUploadBuffer); + mUploadBuffer.limit(oldLimit); + } + uploadDataSink.onReadSucceeded(false); + } + + @Override + public void rewind(UploadDataSink uploadDataSink) { + mUploadBuffer.position(0); + uploadDataSink.onRewindSucceeded(); + } + } + + // Prevent instantiation + private UploadDataProviders() {} +}
diff --git a/Cronet/tests/cts/src/org/chromium/net/test/CronetUrlRequestTest.java b/Cronet/tests/cts/src/org/chromium/net/test/CronetUrlRequestTest.java deleted file mode 100644 index 7dd9a9a..0000000 --- a/Cronet/tests/cts/src/org/chromium/net/test/CronetUrlRequestTest.java +++ /dev/null
@@ -1,91 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.chromium.net.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.content.Context; -import android.net.ConnectivityManager; - -import androidx.annotation.NonNull; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.chromium.net.CronetEngine; -import org.chromium.net.UrlRequest; -import org.chromium.net.UrlResponseInfo; -import org.chromium.net.test.util.TestUrlRequestCallback; -import org.chromium.net.test.util.TestUrlRequestCallback.ResponseStep; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.Random; - -@RunWith(AndroidJUnit4.class) -public class CronetUrlRequestTest { - private static final String TAG = CronetUrlRequestTest.class.getSimpleName(); - private static final String HTTPS_PREFIX = "https://"; - - private final String[] mTestDomains = {"www.google.com", "www.android.com"}; - @NonNull private CronetEngine mCronetEngine; - @NonNull private ConnectivityManager mCm; - - @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(); - } - - private static 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]; - } - - @Test - public void testUrlRequestGet_CompletesSuccessfully() throws Exception { - assertHasTestableNetworks(); - String url = HTTPS_PREFIX + getRandomDomain(); - TestUrlRequestCallback callback = new TestUrlRequestCallback(); - UrlRequest.Builder builder = mCronetEngine.newUrlRequestBuilder(url, callback, - callback.getExecutor()); - builder.build().start(); - - callback.expectCallback(ResponseStep.ON_SUCCEEDED); - - UrlResponseInfo info = callback.mResponseInfo; - assertEquals("Unexpected http status code from " + url + ".", 200, - info.getHttpStatusCode()); - assertGreaterThan( - "Received byte from " + url + " is 0.", (int) info.getReceivedByteCount(), 0); - } -}
diff --git a/Cronet/tests/mts/Android.bp b/Cronet/tests/mts/Android.bp new file mode 100644 index 0000000..4e4251c --- /dev/null +++ b/Cronet/tests/mts/Android.bp
@@ -0,0 +1,61 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + default_applicable_licenses: ["Android-Apache-2.0"], +} + +java_genrule { + name: "net-http-test-jarjar-rules", + tool_files: [ + ":NetHttpTestsLibPreJarJar{.jar}", + "jarjar_excludes.txt", + ], + tools: [ + "jarjar-rules-generator", + ], + out: ["net_http_test_jarjar_rules.txt"], + cmd: "$(location jarjar-rules-generator) " + + "$(location :NetHttpTestsLibPreJarJar{.jar}) " + + "--prefix android.net.connectivity " + + "--excludes $(location jarjar_excludes.txt) " + + "--output $(out)", +} + +// Library to be used in coverage tests. cronet_java_tests can't be used directly because the common +// tests need to inherit the NetHttpTests manifest. +android_library { + name: "NetHttpTestsLibPreJarJar", + static_libs: ["cronet_java_tests"], + sdk_version: "module_current", + min_sdk_version: "30", +} + +android_test { + name: "NetHttpTests", + defaults: [ + "mts-target-sdk-version-current", + ], + static_libs: ["NetHttpTestsLibPreJarJar"], + jarjar_rules: ":net-http-test-jarjar-rules", + jni_libs: [ + "cronet_aml_components_cronet_android_cronet_tests__testing" + ], + test_suites: [ + "general-tests", + "mts-tethering", + ], +} +
diff --git a/Cronet/tests/mts/AndroidManifest.xml b/Cronet/tests/mts/AndroidManifest.xml new file mode 100644 index 0000000..f597134 --- /dev/null +++ b/Cronet/tests/mts/AndroidManifest.xml
@@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.net.http.mts"> + + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.INTERNET"/> + + <application android:networkSecurityConfig="@xml/network_security_config"> + <uses-library android:name="android.test.runner" /> + </application> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.net.http.mts" + android:label="MTS tests of android.net.http"> + </instrumentation> + +</manifest> \ No newline at end of file
diff --git a/Cronet/tests/mts/AndroidTest.xml b/Cronet/tests/mts/AndroidTest.xml new file mode 100644 index 0000000..0d780a1 --- /dev/null +++ b/Cronet/tests/mts/AndroidTest.xml
@@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Runs NetHttp Mainline Tests."> + <!-- Only run tests if the device under test is SDK version 30 or above. --> + <!-- TODO Switch back to Sdk30 when b/270049141 is fixed --> + <object type="module_controller" + class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="test-file-name" value="NetHttpTests.apk" /> + </target_preparer> + + <option name="test-tag" value="NetHttpTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="android.net.http.mts" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> + + <!-- Only run NetHttpTests in MTS if the Tethering Mainline module is installed. --> + <object type="module_controller" + class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController"> + <option name="mainline-module-package-name" value="com.google.android.tethering" /> + </object> +</configuration> \ No newline at end of file
diff --git a/Cronet/tests/mts/jarjar_excludes.txt b/Cronet/tests/mts/jarjar_excludes.txt new file mode 100644 index 0000000..a3e86de --- /dev/null +++ b/Cronet/tests/mts/jarjar_excludes.txt
@@ -0,0 +1,15 @@ +# It's prohibited to jarjar androidx packages +androidx\..+ +# Do not jarjar the api classes +android\.net\..+ +# cronet_tests.so is not jarjared and uses base classes. We can remove this when there's a +# separate java base target to depend on. +org\.chromium\.base\..+ +J\.cronet_tests_N(\$.+)? + +# Do not jarjar the tests and its utils as they also do JNI with cronet_tests.so +org\.chromium\.net\..*Test.*(\$.+)? +org\.chromium\.net\.NativeTestServer(\$.+)? +org\.chromium\.net\.MockUrlRequestJobFactory(\$.+)? +org\.chromium\.net\.QuicTestServer(\$.+)? +org\.chromium\.net\.MockCertVerifier(\$.+)? \ No newline at end of file
diff --git a/Cronet/tests/mts/res/xml/network_security_config.xml b/Cronet/tests/mts/res/xml/network_security_config.xml new file mode 100644 index 0000000..d44c36f --- /dev/null +++ b/Cronet/tests/mts/res/xml/network_security_config.xml
@@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<network-security-config> + <domain-config cleartextTrafficPermitted="true"> + <!-- Used as the base URL by native test server (net::EmbeddedTestServer) --> + <domain includeSubdomains="true">127.0.0.1</domain> + <!-- Used by CronetHttpURLConnectionTest#testIOExceptionInterruptRethrown --> + <domain includeSubdomains="true">localhost</domain> + <!-- Used by CronetHttpURLConnectionTest#testBadIP --> + <domain includeSubdomains="true">0.0.0.0</domain> + <!-- Used by CronetHttpURLConnectionTest#testSetUseCachesFalse --> + <domain includeSubdomains="true">host-cache-test-host</domain> + <!-- Used by CronetHttpURLConnectionTest#testBadHostname --> + <domain includeSubdomains="true">this-weird-host-name-does-not-exist</domain> + <!-- Used by CronetUrlRequestContextTest#testHostResolverRules --> + <domain includeSubdomains="true">some-weird-hostname</domain> + </domain-config> +</network-security-config> \ No newline at end of file
diff --git a/Cronet/tools/import/copy.bara.sky b/Cronet/tools/import/copy.bara.sky new file mode 100644 index 0000000..5372a4d --- /dev/null +++ b/Cronet/tools/import/copy.bara.sky
@@ -0,0 +1,119 @@ +# Copyright 2023 Google Inc. All rights reserved. +# +# 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. + +common_excludes = [ + # Exclude all Android build files + "**/Android.bp", + "**/Android.mk", + + # Exclude existing *OWNERS files + "**/*OWNERS", + "**/.git/**", + "**/.gitignore", +] + +cronet_origin_files = glob( + include = [ + "base/**", + "build/**", + "build/buildflag.h", + "chrome/VERSION", + "components/cronet/**", + "components/metrics/**", + "components/nacl/**", + "components/prefs/**", + "crypto/**", + "ipc/**", + "net/**", + # Note: Only used for tests. + "testing/**", + "url/**", + "LICENSE", + ], + exclude = common_excludes + [ + # Per aosp/2367109 + "build/android/CheckInstallApk-debug.apk", + "build/android/unused_resources/**", + "build/linux/**", + + # Per aosp/2374766 + "components/cronet/ios/**", + "components/cronet/native/**", + + # Per aosp/2399270 + "testing/buildbot/**", + + # Exclude all third-party directories. Those are specified explicitly + # below, so no dependency can accidentally creep in. + "**/third_party/**", + ], +) + glob( + # Explicitly include third-party dependencies. + # Note: some third-party dependencies include a third_party folder within + # them. So far, this has not become a problem. + include = [ + "base/third_party/cityhash/**", + "base/third_party/cityhash_v103/**", + "base/third_party/double_conversion/**", + "base/third_party/dynamic_annotations/**", + "base/third_party/icu/**", + "base/third_party/nspr/**", + "base/third_party/superfasthash/**", + "base/third_party/valgrind/**", + "buildtools/third_party/libc++/**", + "buildtools/third_party/libc++abi/**", + # Note: Only used for tests. + "net/third_party/nist-pkits/**", + "net/third_party/quiche/**", + "net/third_party/uri_template/**", + "third_party/abseil-cpp/**", + "third_party/android_ndk/sources/android/cpufeatures/**", + "third_party/ashmem/**", + "third_party/boringssl/**", + "third_party/brotli/**", + # Note: Only used for tests. + "third_party/ced/**", + # Note: Only used for tests. + "third_party/googletest/**", + "third_party/icu/**", + "third_party/libevent/**", + # Note: Only used for tests. + "third_party/libxml/**", + # Note: Only used for tests. + "third_party/lss/**", + "third_party/metrics_proto/**", + "third_party/modp_b64/**", + "third_party/protobuf/**", + # Note: Only used for tests. + "third_party/quic_trace/**", + # Note: Cronet currently uses Android's zlib + # "third_party/zlib/**", + "url/third_party/mozilla/**", + ], + exclude = common_excludes, +) + +core.workflow( + name = "import_cronet", + authoring = authoring.overwrite("Cronet Mainline Eng <cronet-mainline-eng+copybara@google.com>"), + # Origin folder is specified via source_ref argument, see import_cronet.sh + origin = folder.origin(), + origin_files = cronet_origin_files, + destination = git.destination( + # The destination URL is set by the invoking script. + url = "overwritten/by/script", + push = "upstream-import", + ), + mode = "SQUASH", +)
diff --git a/Cronet/tools/import/import_cronet.sh b/Cronet/tools/import/import_cronet.sh new file mode 100755 index 0000000..0f04af7 --- /dev/null +++ b/Cronet/tools/import/import_cronet.sh
@@ -0,0 +1,146 @@ +#!/bin/bash + +# Copyright 2023 Google Inc. All rights reserved. +# +# 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. + +# Script to invoke copybara locally to import Cronet into Android. +# Inputs: +# Environment: +# ANDROID_BUILD_TOP: path the root of the current Android directory. +# Arguments: +# -l rev: The last revision that was imported. +# Optional Arguments: +# -n rev: The new revision to import. +# -f: Force copybara to ignore a failure to find the last imported revision. + +set -e -x + +OPTSTRING=fl:n: + +usage() { + cat <<EOF +Usage: import_cronet.sh -n new-rev [-l last-rev] [-f] +EOF + exit 1 +} + +COPYBARA_FOLDER_ORIGIN="/tmp/copybara-origin" + +####################################### +# Create local upstream-import branch in external/cronet. +# Globals: +# ANDROID_BUILD_TOP +# Arguments: +# none +####################################### +setup_upstream_import_branch() { + local git_dir="${ANDROID_BUILD_TOP}/external/cronet" + + (cd "${git_dir}" && git fetch aosp upstream-import:upstream-import) +} + +####################################### +# Setup folder.origin for copybara inside /tmp +# Globals: +# COPYBARA_FOLDER_ORIGIN +# Arguments: +# new_rev, string +####################################### +setup_folder_origin() ( + local _new_rev=$1 + mkdir -p "${COPYBARA_FOLDER_ORIGIN}" + cd "${COPYBARA_FOLDER_ORIGIN}" + + if [ -d src ]; then + (cd src && git fetch --tags && git checkout "${_new_rev}") + else + # For this to work _new_rev must be a branch or a tag. + git clone --depth=1 --branch "${_new_rev}" https://chromium.googlesource.com/chromium/src.git + fi + + + cat <<EOF >.gclient +solutions = [ + { + "name": "src", + "url": "https://chromium.googlesource.com/chromium/src.git", + "managed": False, + "custom_deps": {}, + "custom_vars": {}, + }, +] +target_os = ["android"] +EOF + cd src + # Set appropriate gclient flags to speed up syncing. + gclient sync \ + --no-history \ + --shallow \ + --delete_unversioned_trees +) + +####################################### +# Runs the copybara import of Chromium +# Globals: +# ANDROID_BUILD_TOP +# COPYBARA_FOLDER_ORIGIN +# Arguments: +# last_rev, string or empty +# force, string or empty +####################################### +do_run_copybara() { + local _last_rev=$1 + local _force=$2 + + local -a flags + flags+=(--git-destination-url="file://${ANDROID_BUILD_TOP}/external/cronet") + flags+=(--repo-timeout 3m) + + # buildtools/third_party/libc++ contains an invalid symlink + flags+=(--folder-origin-ignore-invalid-symlinks) + flags+=(--git-no-verify) + + if [ ! -z "${_force}" ]; then + flags+=(--force) + fi + + if [ ! -z "${_last_rev}" ]; then + flags+=(--last-rev "${_last_rev}") + fi + + /google/bin/releases/copybara/public/copybara/copybara \ + "${flags[@]}" \ + "${ANDROID_BUILD_TOP}/packages/modules/Connectivity/Cronet/tools/import/copy.bara.sky" \ + import_cronet "${COPYBARA_FOLDER_ORIGIN}/src" +} + +while getopts $OPTSTRING opt; do + case "${opt}" in + f) force=true ;; + l) last_rev="${OPTARG}" ;; + n) new_rev="${OPTARG}" ;; + ?) usage ;; + *) echo "'${opt}' '${OPTARG}'" + esac +done + +if [ -z "${new_rev}" ]; then + echo "-n argument required" + usage +fi + +setup_upstream_import_branch +setup_folder_origin "${new_rev}" +do_run_copybara "${last_rev}" "${force}" +
diff --git a/OWNERS_core_networking b/OWNERS_core_networking index 3a08422..6d17476 100644 --- a/OWNERS_core_networking +++ b/OWNERS_core_networking
@@ -1,4 +1,3 @@ -chenbruce@google.com chiachangwang@google.com cken@google.com huangaaron@google.com @@ -19,3 +18,4 @@ waynema@google.com xiaom@google.com yumike@google.com +yuyanghuang@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING index 700a085..d2f6d6a 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING
@@ -58,6 +58,17 @@ ] }, { + "name": "CtsNetTestCasesMaxTargetSdk33", + "options": [ + { + "exclude-annotation": "com.android.testutils.SkipPresubmit" + }, + { + "exclude-annotation": "androidx.test.filters.RequiresDevice" + } + ] + }, + { "name": "bpf_existence_test" }, { @@ -83,6 +94,16 @@ }, { "name": "FrameworksNetIntegrationTests" + }, + // Runs both NetHttpTests and CtsNetHttpTestCases + { + "name": "NetHttpCoverageTests", + "options": [ + { + // These sometimes take longer than 1 min which is the presubmit timeout + "exclude-annotation": "androidx.test.filters.LargeTest" + } + ] } ], "postsubmit": [ @@ -135,6 +156,17 @@ } ] }, + { + "name": "CtsNetTestCasesMaxTargetSdk33[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]", + "options": [ + { + "exclude-annotation": "com.android.testutils.SkipPresubmit" + }, + { + "exclude-annotation": "androidx.test.filters.RequiresDevice" + } + ] + }, // Test with APK modules only, in cases where APEX is not supported, or the other modules // were simply not updated { @@ -183,6 +215,15 @@ }, { "name": "libnetworkstats_test[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]" + }, + { + "name": "NetHttpCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]", + "options": [ + { + // These sometimes take longer than 1 min which is the presubmit timeout + "exclude-annotation": "androidx.test.filters.LargeTest" + } + ] } ], "mainline-postsubmit": [
diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 829e66a..4478b1e 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp
@@ -34,6 +34,7 @@ // Libraries not including Tethering's own framework-tethering (different flavors of that one // are needed depending on the build rule) libs: [ + "connectivity-internal-api-util", "framework-configinfrastructure", "framework-connectivity.stubs.module_lib", "framework-connectivity-t.stubs.module_lib", @@ -60,9 +61,13 @@ "modules-utils-build", "modules-utils-statemachine", "networkstack-client", + // AIDL tetheroffload implementation + "android.hardware.tetheroffload-V1-java", + // HIDL tetheroffload implementation "android.hardware.tetheroffload.config-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "android.hardware.tetheroffload.control-V1.1-java", + "android.hidl.manager-V1.2-java", "net-utils-framework-common", "net-utils-device-common", "net-utils-device-common-bpf", @@ -114,7 +119,6 @@ name: "libcom_android_networkstack_tethering_util_jni", sdk_version: "30", apex_available: [ - "//apex_available:platform", // Used by InProcessTethering "com.android.tethering", ], min_sdk_version: "30", @@ -183,24 +187,6 @@ lint: { strict_updatability_linting: true }, } -// Non-updatable tethering running in the system server process for devices not using the module -android_app { - name: "InProcessTethering", - defaults: [ - "TetheringAppDefaults", - "TetheringApiLevel", - "ConnectivityNextEnableDefaults", - "TetheringReleaseTargetSdk" - ], - static_libs: ["TetheringApiCurrentLib"], - certificate: "platform", - manifest: "AndroidManifest_InProcess.xml", - // InProcessTethering is a replacement for Tethering - overrides: ["Tethering"], - apex_available: ["com.android.tethering"], - lint: { strict_updatability_linting: true }, -} - // Updatable tethering packaged for finalized API android_app { name: "Tethering", @@ -209,11 +195,7 @@ certificate: "networkstack", manifest: "AndroidManifest.xml", use_embedded_native_libs: true, - // The network stack *must* be included to ensure security of the device - required: [ - "NetworkStack", - "privapp_allowlist_com.android.tethering", - ], + privapp_allowlist: ":privapp_allowlist_com.android.tethering", apex_available: ["com.android.tethering"], lint: { strict_updatability_linting: true }, } @@ -229,11 +211,7 @@ certificate: "networkstack", manifest: "AndroidManifest.xml", use_embedded_native_libs: true, - // The network stack *must* be included to ensure security of the device - required: [ - "NetworkStackNext", - "privapp_allowlist_com.android.tethering", - ], + privapp_allowlist: ":privapp_allowlist_com.android.tethering", apex_available: ["com.android.tethering"], lint: { strict_updatability_linting: true }, } @@ -245,6 +223,9 @@ // e.g. *classpath_fragments. "com.android.tethering", ], + native_shared_libs: [ + "libnetd_updatable", + ], } java_library_static {
diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml index b832e16..6a363b0 100644 --- a/Tethering/AndroidManifest.xml +++ b/Tethering/AndroidManifest.xml
@@ -43,6 +43,7 @@ <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> + <!-- Sending non-protected broadcast from system uid is not allowed. --> <protected-broadcast android:name="com.android.server.connectivity.tethering.DISABLE_TETHERING" /> <application
diff --git a/Tethering/AndroidManifest_InProcess.xml b/Tethering/AndroidManifest_InProcess.xml deleted file mode 100644 index b1f1240..0000000 --- a/Tethering/AndroidManifest_InProcess.xml +++ /dev/null
@@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ ---> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.networkstack.tethering.inprocess" - android:sharedUserId="android.uid.system" - android:process="system"> - <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" /> - <application> - <service android:name="com.android.networkstack.tethering.TetheringService" - android:process="system" - android:permission="android.permission.MAINLINE_NETWORK_STACK" - android:exported="true"> - <intent-filter> - <action android:name="android.net.ITetheringConnector.InProcess"/> - </intent-filter> - </service> - </application> -</manifest>
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp index e59c8e4..cf9b359 100644 --- a/Tethering/apex/Android.bp +++ b/Tethering/apex/Android.bp
@@ -18,26 +18,19 @@ default_applicable_licenses: ["Android-Apache-2.0"], } -prebuilt_etc { - name: "TetheringInProcessFlag", - src: "in-process", - filename_from_src: true, - sub_dir: "flag", -} - -prebuilt_etc { - name: "TetheringOutOfProcessFlag", - src: "out-of-process", - filename_from_src: true, - sub_dir: "flag", -} - // Defaults to enable/disable java targets which uses development APIs. "enabled" may have a // different value depending on the branch. java_defaults { name: "ConnectivityNextEnableDefaults", enabled: true, } +java_defaults { + name: "NetworkStackApiShimSettingsForCurrentBranch", + // API shims to include in the networking modules built from the branch. Branches that disable + // the "next" targets must use stable shims (latest stable API level) instead of current shims + // (X_current API level). + static_libs: ["NetworkStackApiCurrentShims"], +} apex_defaults { name: "ConnectivityApexDefaults", // Tethering app to include in the AOSP apex. Branches that disable the "next" targets may use @@ -50,11 +43,30 @@ // as the above target may have different "enabled" values // depending on the branch +apex_defaults { + name: "CronetInTetheringApexDefaults", + jni_libs: [ + "cronet_aml_components_cronet_android_cronet", + "//external/cronet/third_party/boringssl:libcrypto", + "//external/cronet/third_party/boringssl:libssl", + ], + arch: { + riscv64: { + // TODO: remove this when there is a riscv64 libcronet + exclude_jni_libs: [ + "cronet_aml_components_cronet_android_cronet", + "//external/cronet/third_party/boringssl:libcrypto", + "//external/cronet/third_party/boringssl:libssl", + ], + }, + }, +} + apex { name: "com.android.tethering", defaults: [ "ConnectivityApexDefaults", - "CronetApexDefaults", + "CronetInTetheringApexDefaults", "r-launched-apex-module", ], compile_multilib: "both", @@ -100,11 +112,7 @@ "ServiceConnectivityResources", "HalfSheetUX", ], - prebuilts: [ - "current_sdkinfo", - "privapp_allowlist_com.android.tethering", - "TetheringOutOfProcessFlag", - ], + prebuilts: ["current_sdkinfo"], manifest: "manifest.json", key: "com.android.tethering.key", // Indicates that pre-installed version of this apex can be compressed. @@ -115,7 +123,6 @@ compat_configs: [ "connectivity-platform-compat-config", - "connectivity-t-platform-compat-config", ], } @@ -183,6 +190,7 @@ "android.app.usage", "android.nearby", "android.net", + "android.net.http", "android.net.netstats", "android.net.util", ], @@ -197,8 +205,10 @@ "android.nearby.aidl", "android.net.apf", "android.net.connectivity", + "android.net.http.apihelpers", "android.net.netstats.provider", "android.net.nsd", + "android.net.wear", ], }, } @@ -208,27 +218,3 @@ standalone_contents: ["service-connectivity"], apex_available: ["com.android.tethering"], } - -override_apex { - name: "com.android.tethering.inprocess", - base: "com.android.tethering", - package_name: "com.android.tethering.inprocess", - enabled: enable_tethering_next_apex, - bpfs: [ - "block.o", - "clatd.o", - "dscpPolicy.o", - "netd.o", - "offload@inprocess.o", - "test@inprocess.o", - ], - apps: [ - "ServiceConnectivityResources", - "InProcessTethering", - ], - prebuilts: [ - "current_sdkinfo", - "privapp_allowlist_com.android.tethering", - "TetheringInProcessFlag", - ], -}
diff --git a/Tethering/apex/in-process b/Tethering/apex/in-process deleted file mode 100644 index e69de29..0000000 --- a/Tethering/apex/in-process +++ /dev/null
diff --git a/Tethering/apex/out-of-process b/Tethering/apex/out-of-process deleted file mode 100644 index e69de29..0000000 --- a/Tethering/apex/out-of-process +++ /dev/null
diff --git a/Tethering/apex/permissions/Android.bp b/Tethering/apex/permissions/Android.bp index ac9ec65..69c1aa2 100644 --- a/Tethering/apex/permissions/Android.bp +++ b/Tethering/apex/permissions/Android.bp
@@ -19,10 +19,7 @@ default_visibility: ["//packages/modules/Connectivity/Tethering:__subpackages__"], } -prebuilt_etc { +filegroup { name: "privapp_allowlist_com.android.tethering", - sub_dir: "permissions", - filename: "permissions.xml", - src: "permissions.xml", - installable: false, + srcs: ["permissions.xml"], } \ No newline at end of file
diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 9ca3f14..a4db776 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp
@@ -19,9 +19,15 @@ java_sdk_library { name: "framework-tethering", - defaults: ["framework-module-defaults"], + defaults: [ + "framework-tethering-defaults", + ], impl_library_visibility: [ "//packages/modules/Connectivity/Tethering:__subpackages__", + "//packages/modules/Connectivity/framework", + "//packages/modules/Connectivity/framework-t", + "//packages/modules/Connectivity/service", + "//packages/modules/Connectivity/service-t", // Using for test only "//cts/tests/netlegacy22.api", @@ -41,42 +47,64 @@ "//packages/modules/NetworkStack/tests:__subpackages__", "//packages/modules/Wifi/service/tests/wifitests", ], - - srcs: [":framework-tethering-srcs"], - libs: ["framework-connectivity.stubs.module_lib"], stub_only_libs: ["framework-connectivity.stubs.module_lib"], + + jarjar_rules: ":framework-tethering-jarjar-rules", + installable: true, + + hostdex: true, // for hiddenapi check + permitted_packages: ["android.net"], + lint: { strict_updatability_linting: true }, +} + +java_library { + name: "framework-tethering-pre-jarjar", + defaults: [ + "framework-tethering-defaults", + ], +} + +java_genrule { + name: "framework-tethering-jarjar-rules", + tool_files: [ + ":framework-tethering-pre-jarjar{.jar}", + ":framework-tethering.stubs.module_lib{.jar}", + "jarjar-excludes.txt", + ], + tools: [ + "jarjar-rules-generator", + ], + out: ["framework_tethering_jarjar_rules.txt"], + cmd: "$(location jarjar-rules-generator) " + + "$(location :framework-tethering-pre-jarjar{.jar}) " + + "--apistubs $(location :framework-tethering.stubs.module_lib{.jar}) " + + "--prefix android.net.http.internal " + + "--excludes $(location jarjar-excludes.txt) " + + "--output $(out)", +} + +java_defaults { + name: "framework-tethering-defaults", + defaults: ["framework-module-defaults"], + srcs: [ + ":framework-tethering-srcs" + ], + libs: ["framework-connectivity.stubs.module_lib"], aidl: { include_dirs: [ "packages/modules/Connectivity/framework/aidl-export", ], }, - - jarjar_rules: "jarjar-rules.txt", - installable: true, - - hostdex: true, // for hiddenapi check apex_available: ["com.android.tethering"], - permitted_packages: ["android.net"], min_sdk_version: "30", - lint: { strict_updatability_linting: true }, } filegroup { name: "framework-tethering-srcs", + defaults: ["framework-sources-module-defaults"], srcs: [ - "src/android/net/TetheredClient.aidl", - "src/android/net/TetheredClient.java", - "src/android/net/TetheringManager.java", - "src/android/net/TetheringConstants.java", - "src/android/net/IIntResultListener.aidl", - "src/android/net/ITetheringEventCallback.aidl", - "src/android/net/ITetheringConnector.aidl", - "src/android/net/TetheringCallbackStartedParcel.aidl", - "src/android/net/TetheringConfigurationParcel.aidl", - "src/android/net/TetheringRequestParcel.aidl", - "src/android/net/TetherStatesParcel.aidl", - "src/android/net/TetheringInterface.aidl", - "src/android/net/TetheringInterface.java", + "src/**/*.aidl", + "src/**/*.java", ], path: "src" }
diff --git a/Tethering/common/TetheringLib/jarjar-excludes.txt b/Tethering/common/TetheringLib/jarjar-excludes.txt new file mode 100644 index 0000000..50bc186 --- /dev/null +++ b/Tethering/common/TetheringLib/jarjar-excludes.txt
@@ -0,0 +1,2 @@ +# Don't touch anything that's already under android.net +android\.net\..+ \ No newline at end of file
diff --git a/Tethering/common/TetheringLib/jarjar-rules.txt b/Tethering/common/TetheringLib/jarjar-rules.txt deleted file mode 100644 index e459fad..0000000 --- a/Tethering/common/TetheringLib/jarjar-rules.txt +++ /dev/null
@@ -1 +0,0 @@ -# jarjar rules for the bootclasspath tethering framework library here \ No newline at end of file
diff --git a/Cronet/AndroidManifest.xml b/Tethering/common/TetheringLib/src/android/net/wear/ICompanionDeviceManagerProxy.aidl similarity index 66% rename from Cronet/AndroidManifest.xml rename to Tethering/common/TetheringLib/src/android/net/wear/ICompanionDeviceManagerProxy.aidl index f3b3c3e..f8c39bf 100644 --- a/Cronet/AndroidManifest.xml +++ b/Tethering/common/TetheringLib/src/android/net/wear/ICompanionDeviceManagerProxy.aidl
@@ -1,7 +1,5 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -15,9 +13,12 @@ * 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> + +package android.net.wear; + +import android.companion.AssociationInfo; + +/** @hide */ +interface ICompanionDeviceManagerProxy { + List<AssociationInfo> getAllAssociations(); +}
diff --git a/Tethering/jni/com_android_networkstack_tethering_util_TetheringUtils.cpp b/Tethering/jni/com_android_networkstack_tethering_util_TetheringUtils.cpp index 6699c0d..14e4b9a 100644 --- a/Tethering/jni/com_android_networkstack_tethering_util_TetheringUtils.cpp +++ b/Tethering/jni/com_android_networkstack_tethering_util_TetheringUtils.cpp
@@ -18,21 +18,19 @@ #include <error.h> #include <jni.h> #include <linux/filter.h> +#include <linux/ipv6.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedUtfChars.h> #include <netjniutils/netjniutils.h> #include <net/if.h> #include <netinet/ether.h> -#include <netinet/ip6.h> #include <netinet/icmp6.h> #include <sys/socket.h> #include <stdio.h> -namespace android { +#include <bpf/BpfClassic.h> -static const uint32_t kIPv6NextHeaderOffset = offsetof(ip6_hdr, ip6_nxt); -static const uint32_t kIPv6PayloadStart = sizeof(ip6_hdr); -static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type); +namespace android { static void throwSocketException(JNIEnv *env, const char* msg, int error) { jniThrowExceptionFmt(env, "java/net/SocketException", "%s: %s", msg, strerror(error)); @@ -42,18 +40,14 @@ uint32_t type) { sock_filter filter_code[] = { // Check header is ICMPv6. - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeaderOffset), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3), + BPF_LOAD_IPV6_U8(nexthdr), + BPF2_REJECT_IF_NOT_EQUAL(IPPROTO_ICMPV6), // Check ICMPv6 type. - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, type, 0, 1), + BPF_LOAD_NET_RELATIVE_U8(sizeof(ipv6hdr) + offsetof(icmp6_hdr, icmp6_type)), + BPF2_REJECT_IF_NOT_EQUAL(type), - // Accept. - BPF_STMT(BPF_RET | BPF_K, 0xffff), - - // Reject. - BPF_STMT(BPF_RET | BPF_K, 0) + BPF_ACCEPT, }; const sock_fprog filter = { @@ -67,17 +61,17 @@ } } -static void com_android_networkstack_tethering_util_setupNaSocket(JNIEnv *env, jobject clazz, +static void com_android_networkstack_tethering_util_setupNaSocket(JNIEnv *env, jclass clazz, jobject javaFd) { com_android_networkstack_tethering_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_ADVERT); } -static void com_android_networkstack_tethering_util_setupNsSocket(JNIEnv *env, jobject clazz, +static void com_android_networkstack_tethering_util_setupNsSocket(JNIEnv *env, jclass clazz, jobject javaFd) { com_android_networkstack_tethering_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_SOLICIT); } -static void com_android_networkstack_tethering_util_setupRaSocket(JNIEnv *env, jobject clazz, +static void com_android_networkstack_tethering_util_setupRaSocket(JNIEnv *env, jclass clazz, jobject javaFd, jint ifIndex) { static const int kLinkLocalHopLimit = 255;
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 8cf13d3..6affb62 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java
@@ -17,6 +17,15 @@ package android.net.ip; import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; +import static android.net.TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; @@ -310,7 +319,7 @@ mDeps = deps; mTetheringMetrics = tetheringMetrics; resetLinkProperties(); - mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; + mLastError = TETHER_ERROR_NO_ERROR; mServingMode = STATE_AVAILABLE; mIpNeighborMonitor = mDeps.getIpNeighborMonitor(getHandler(), mLog, @@ -398,8 +407,8 @@ /** Internals. */ - private boolean startIPv4() { - return configureIPv4(true); + private boolean startIPv4(int scope) { + return configureIPv4(true, scope); } /** @@ -475,7 +484,7 @@ } private void handleError() { - mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; + mLastError = TETHER_ERROR_DHCPSERVER_ERROR; transitionTo(mInitialState); } } @@ -583,7 +592,7 @@ public void callback(int statusCode) { if (statusCode != STATUS_SUCCESS) { mLog.e("Error stopping DHCP server: " + statusCode); - mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; + mLastError = TETHER_ERROR_DHCPSERVER_ERROR; // Not much more we can do here } mDhcpLeases.clear(); @@ -609,7 +618,7 @@ } private void stopIPv4() { - configureIPv4(false); + configureIPv4(false /* enabled */, CONNECTIVITY_SCOPE_GLOBAL /* not used */); // NOTE: All of configureIPv4() will be refactored out of existence // into calls to InterfaceController, shared with startIPv4(). mInterfaceCtrl.clearIPv4Address(); @@ -620,11 +629,11 @@ mStaticIpv4ClientAddr = null; } - private boolean configureIPv4(boolean enabled) { + private boolean configureIPv4(boolean enabled, int scope) { if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); if (enabled) { - mIpv4Address = requestIpv4Address(true /* useLastAddress */); + mIpv4Address = requestIpv4Address(scope, true /* useLastAddress */); } if (mIpv4Address == null) { @@ -672,12 +681,12 @@ return (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) && !SdkLevel.isAtLeastT(); } - private LinkAddress requestIpv4Address(final boolean useLastAddress) { + private LinkAddress requestIpv4Address(final int scope, final boolean useLastAddress) { if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr; if (shouldNotConfigureBluetoothInterface()) return new LinkAddress(BLUETOOTH_IFACE_ADDR); - return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress); + return mPrivateAddressCoordinator.requestDownstreamAddress(this, scope, useLastAddress); } private boolean startIPv6() { @@ -991,67 +1000,6 @@ } } - private void handleNewPrefixRequest(@NonNull final IpPrefix currentPrefix) { - if (!currentPrefix.contains(mIpv4Address.getAddress()) - || currentPrefix.getPrefixLength() != mIpv4Address.getPrefixLength()) { - Log.e(TAG, "Invalid prefix: " + currentPrefix); - return; - } - - final LinkAddress deprecatedLinkAddress = mIpv4Address; - mIpv4Address = requestIpv4Address(false); - if (mIpv4Address == null) { - mLog.e("Fail to request a new downstream prefix"); - return; - } - final Inet4Address srvAddr = (Inet4Address) mIpv4Address.getAddress(); - - // Add new IPv4 address on the interface. - if (!mInterfaceCtrl.addAddress(srvAddr, currentPrefix.getPrefixLength())) { - mLog.e("Failed to add new IP " + srvAddr); - return; - } - - // Remove deprecated routes from local network. - removeRoutesFromLocalNetwork( - Collections.singletonList(getDirectConnectedRoute(deprecatedLinkAddress))); - mLinkProperties.removeLinkAddress(deprecatedLinkAddress); - - // Add new routes to local network. - addRoutesToLocalNetwork( - Collections.singletonList(getDirectConnectedRoute(mIpv4Address))); - mLinkProperties.addLinkAddress(mIpv4Address); - - // Update local DNS caching server with new IPv4 address, otherwise, dnsmasq doesn't - // listen on the interface configured with new IPv4 address, that results DNS validation - // failure of downstream client even if appropriate routes have been configured. - try { - mNetd.tetherApplyDnsInterfaces(); - } catch (ServiceSpecificException | RemoteException e) { - mLog.e("Failed to update local DNS caching server"); - return; - } - sendLinkProperties(); - - // Notify DHCP server that new prefix/route has been applied on IpServer. - final Inet4Address clientAddr = mStaticIpv4ClientAddr == null ? null : - (Inet4Address) mStaticIpv4ClientAddr.getAddress(); - final DhcpServingParamsParcel params = makeServingParams(srvAddr /* defaultRouter */, - srvAddr /* dnsServer */, mIpv4Address /* serverLinkAddress */, clientAddr); - try { - mDhcpServer.updateParams(params, new OnHandlerStatusCallback() { - @Override - public void callback(int statusCode) { - if (statusCode != STATUS_SUCCESS) { - mLog.e("Error updating DHCP serving params: " + statusCode); - } - } - }); - } catch (RemoteException e) { - mLog.e("Error updating DHCP serving params", e); - } - } - private byte getHopLimit(String upstreamIface, int adjustTTL) { try { int upstreamHopLimit = Integer.parseUnsignedInt( @@ -1134,7 +1082,7 @@ maybeLogMessage(this, message.what); switch (message.what) { case CMD_TETHER_REQUESTED: - mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; + mLastError = TETHER_ERROR_NO_ERROR; switch (message.arg1) { case STATE_LOCAL_ONLY: maybeConfigureStaticIp((TetheringRequestParcel) message.obj); @@ -1166,13 +1114,38 @@ mBpfCoordinator.stopMonitoring(this); } - class BaseServingState extends State { + abstract class BaseServingState extends State { + private final int mDesiredInterfaceState; + + BaseServingState(int interfaceState) { + mDesiredInterfaceState = interfaceState; + } + @Override public void enter() { startConntrackMonitoring(); - if (!startIPv4()) { - mLastError = TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; + startServingInterface(); + + if (mLastError != TETHER_ERROR_NO_ERROR) { + transitionTo(mInitialState); + } + + if (DBG) Log.d(TAG, getStateString(mDesiredInterfaceState) + " serve " + mIfaceName); + sendInterfaceState(mDesiredInterfaceState); + } + + private int getScope() { + if (mDesiredInterfaceState == STATE_TETHERED) { + return CONNECTIVITY_SCOPE_GLOBAL; + } + + return CONNECTIVITY_SCOPE_LOCAL; + } + + private void startServingInterface() { + if (!startIPv4(getScope())) { + mLastError = TETHER_ERROR_IFACE_CFG_ERROR; return; } @@ -1180,7 +1153,7 @@ NetdUtils.tetherInterface(mNetd, mIfaceName, asIpPrefix(mIpv4Address)); } catch (RemoteException | ServiceSpecificException | IllegalStateException e) { mLog.e("Error Tethering", e); - mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; + mLastError = TETHER_ERROR_TETHER_IFACE_ERROR; return; } @@ -1201,7 +1174,7 @@ try { NetdUtils.untetherInterface(mNetd, mIfaceName); } catch (RemoteException | ServiceSpecificException e) { - mLastError = TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; + mLastError = TETHER_ERROR_UNTETHER_IFACE_ERROR; mLog.e("Failed to untether interface: " + e); } @@ -1234,7 +1207,7 @@ case CMD_START_TETHERING_ERROR: case CMD_STOP_TETHERING_ERROR: case CMD_SET_DNS_FORWARDERS_ERROR: - mLastError = TetheringManager.TETHER_ERROR_INTERNAL_ERROR; + mLastError = TETHER_ERROR_INTERNAL_ERROR; transitionTo(mInitialState); break; case CMD_NEW_PREFIX_REQUEST: @@ -1250,6 +1223,67 @@ } return true; } + + private void handleNewPrefixRequest(@NonNull final IpPrefix currentPrefix) { + if (!currentPrefix.contains(mIpv4Address.getAddress()) + || currentPrefix.getPrefixLength() != mIpv4Address.getPrefixLength()) { + Log.e(TAG, "Invalid prefix: " + currentPrefix); + return; + } + + final LinkAddress deprecatedLinkAddress = mIpv4Address; + mIpv4Address = requestIpv4Address(getScope(), false); + if (mIpv4Address == null) { + mLog.e("Fail to request a new downstream prefix"); + return; + } + final Inet4Address srvAddr = (Inet4Address) mIpv4Address.getAddress(); + + // Add new IPv4 address on the interface. + if (!mInterfaceCtrl.addAddress(srvAddr, currentPrefix.getPrefixLength())) { + mLog.e("Failed to add new IP " + srvAddr); + return; + } + + // Remove deprecated routes from local network. + removeRoutesFromLocalNetwork( + Collections.singletonList(getDirectConnectedRoute(deprecatedLinkAddress))); + mLinkProperties.removeLinkAddress(deprecatedLinkAddress); + + // Add new routes to local network. + addRoutesToLocalNetwork( + Collections.singletonList(getDirectConnectedRoute(mIpv4Address))); + mLinkProperties.addLinkAddress(mIpv4Address); + + // Update local DNS caching server with new IPv4 address, otherwise, dnsmasq doesn't + // listen on the interface configured with new IPv4 address, that results DNS validation + // failure of downstream client even if appropriate routes have been configured. + try { + mNetd.tetherApplyDnsInterfaces(); + } catch (ServiceSpecificException | RemoteException e) { + mLog.e("Failed to update local DNS caching server"); + return; + } + sendLinkProperties(); + + // Notify DHCP server that new prefix/route has been applied on IpServer. + final Inet4Address clientAddr = mStaticIpv4ClientAddr == null ? null : + (Inet4Address) mStaticIpv4ClientAddr.getAddress(); + final DhcpServingParamsParcel params = makeServingParams(srvAddr /* defaultRouter */, + srvAddr /* dnsServer */, mIpv4Address /* serverLinkAddress */, clientAddr); + try { + mDhcpServer.updateParams(params, new OnHandlerStatusCallback() { + @Override + public void callback(int statusCode) { + if (statusCode != STATUS_SUCCESS) { + mLog.e("Error updating DHCP serving params: " + statusCode); + } + } + }); + } catch (RemoteException e) { + mLog.e("Error updating DHCP serving params", e); + } + } } // Handling errors in BaseServingState.enter() by transitioning is @@ -1258,15 +1292,8 @@ // and forwarding and NAT rules should be handled by a coordinating // functional element outside of IpServer. class LocalHotspotState extends BaseServingState { - @Override - public void enter() { - super.enter(); - if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) { - transitionTo(mInitialState); - } - - if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName); - sendInterfaceState(STATE_LOCAL_ONLY); + LocalHotspotState() { + super(STATE_LOCAL_ONLY); } @Override @@ -1294,15 +1321,8 @@ // and forwarding and NAT rules should be handled by a coordinating // functional element outside of IpServer. class TetheredState extends BaseServingState { - @Override - public void enter() { - super.enter(); - if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) { - transitionTo(mInitialState); - } - - if (DBG) Log.d(TAG, "Tethered " + mIfaceName); - sendInterfaceState(STATE_TETHERED); + TetheredState() { + super(STATE_TETHERED); } @Override @@ -1405,7 +1425,7 @@ } catch (RemoteException | ServiceSpecificException e) { mLog.e("Exception enabling NAT: " + e.toString()); cleanupUpstream(); - mLastError = TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR; + mLastError = TETHER_ERROR_ENABLE_FORWARDING_ERROR; transitionTo(mInitialState); return true; } @@ -1454,7 +1474,7 @@ @Override public void enter() { mIpNeighborMonitor.stop(); - mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; + mLastError = TETHER_ERROR_NO_ERROR; sendInterfaceState(STATE_UNAVAILABLE); } }
diff --git a/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/Tethering/src/android/net/ip/NeighborPacketForwarder.java index 8384562..04cb710 100644 --- a/Tethering/src/android/net/ip/NeighborPacketForwarder.java +++ b/Tethering/src/android/net/ip/NeighborPacketForwarder.java
@@ -18,12 +18,14 @@ import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.AF_PACKET; +import static android.system.OsConstants.ENODEV; import static android.system.OsConstants.ETH_P_IPV6; import static android.system.OsConstants.IPPROTO_RAW; import static android.system.OsConstants.SOCK_DGRAM; import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOCK_RAW; -import static android.system.OsConstants.ENODEV; + +import static com.android.net.module.util.SocketUtils.closeSocketQuietly; import android.net.util.SocketUtils; import android.os.Handler; @@ -36,7 +38,6 @@ import com.android.networkstack.tethering.util.TetheringUtils; import java.io.FileDescriptor; -import java.io.IOException; import java.net.Inet6Address; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -105,15 +106,6 @@ } } - // TODO: move NetworkStackUtils.closeSocketQuietly to - // frameworks/libs/net/common/device/com/android/net/module/util/[someclass]. - private void closeSocketQuietly(FileDescriptor fd) { - try { - SocketUtils.closeSocket(fd); - } catch (IOException ignored) { - } - } - @Override protected FileDescriptor createFd() { try {
diff --git a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java index c452e55..18c2171 100644 --- a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java +++ b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -88,13 +88,13 @@ private static final int MIN_RTR_ADV_INTERVAL_SEC = 300; private static final int MAX_RTR_ADV_INTERVAL_SEC = 600; // In general, router, prefix, and DNS lifetimes are all advised to be - // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL. Here, we double + // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL. Here, we quadruple // that to allow for multicast packet loss. // // This MAX_RTR_ADV_INTERVAL_SEC and DEFAULT_LIFETIME are also consistent // with the https://tools.ietf.org/html/rfc7772#section-4 discussion of // "approximately 7 RAs per hour". - private static final int DEFAULT_LIFETIME = 6 * MAX_RTR_ADV_INTERVAL_SEC; + private static final int DEFAULT_LIFETIME = 12 * MAX_RTR_ADV_INTERVAL_SEC; // From https://tools.ietf.org/html/rfc4861#section-10 . private static final int MIN_DELAY_BETWEEN_RAS_SEC = 3; // Both initial and final RAs, but also for changes in RA contents. @@ -129,9 +129,6 @@ // Tethered traffic will have the hop limit properly decremented. // Consequently, set the hoplimit greater by one than the upstream // unicast hop limit. - // - // TODO: Dynamically pass down the IPV6_UNICAST_HOPS value from the - // upstream interface for more correct behaviour. static final byte DEFAULT_HOPLIMIT = 65; public boolean hasDefaultRoute;
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index 51c7c9c..976f5df 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -27,6 +27,7 @@ import static android.system.OsConstants.ETH_P_IP; import static android.system.OsConstants.ETH_P_IPV6; +import static com.android.net.module.util.NetworkStackConstants.IPV4_MIN_MTU; import static com.android.net.module.util.ip.ConntrackMonitor.ConntrackEvent; import static com.android.networkstack.tethering.BpfUtils.DOWNSTREAM; import static com.android.networkstack.tethering.BpfUtils.UPSTREAM; @@ -36,6 +37,7 @@ import android.app.usage.NetworkStatsManager; import android.net.INetd; +import android.net.LinkProperties; import android.net.MacAddress; import android.net.NetworkStats; import android.net.NetworkStats.Entry; @@ -74,7 +76,7 @@ import com.android.net.module.util.ip.ConntrackMonitor.ConntrackEventConsumer; import com.android.net.module.util.netlink.ConntrackMessage; import com.android.net.module.util.netlink.NetlinkConstants; -import com.android.net.module.util.netlink.NetlinkSocket; +import com.android.net.module.util.netlink.NetlinkUtils; import com.android.networkstack.tethering.apishim.common.BpfCoordinatorShim; import com.android.networkstack.tethering.util.TetheringUtils.ForwardedStats; @@ -82,6 +84,8 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; @@ -143,6 +147,8 @@ static final int NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED = 432_000; @VisibleForTesting static final int NF_CONNTRACK_UDP_TIMEOUT_STREAM = 180; + @VisibleForTesting + static final int INVALID_MTU = 0; // List of TCP port numbers which aren't offloaded because the packets require the netfilter // conntrack helper. See also TetherController::setForwardRules in netd. @@ -263,6 +269,10 @@ // TODO: Support multi-upstream interfaces. private int mLastIPv4UpstreamIfindex = 0; + // Tracks the IPv4 upstream interface information. + @Nullable + private UpstreamInfo mIpv4UpstreamInfo = null; + // Runnable that used by scheduling next polling of stats. private final Runnable mScheduledPollingStats = () -> { updateForwardedStats(); @@ -320,6 +330,19 @@ return SdkLevel.isAtLeastS(); } + /** + * Gets the MTU of the given interface. + */ + public int getNetworkInterfaceMtu(@NonNull String iface) { + try { + final NetworkInterface networkInterface = NetworkInterface.getByName(iface); + return networkInterface == null ? INVALID_MTU : networkInterface.getMTU(); + } catch (SocketException e) { + Log.e(TAG, "Could not get MTU for interface " + iface, e); + return INVALID_MTU; + } + } + /** Get downstream4 BPF map. */ @Nullable public IBpfMap<Tether4Key, Tether4Value> getBpfDownstream4Map() { if (!isAtLeastS()) return null; @@ -856,6 +879,27 @@ return true; } + private int getMtu(@NonNull final String ifaceName, @NonNull final LinkProperties lp) { + int mtu = INVALID_MTU; + + if (ifaceName.equals(lp.getInterfaceName())) { + mtu = lp.getMtu(); + } + + // Get mtu via kernel if mtu is not found in LinkProperties. + if (mtu == INVALID_MTU) { + mtu = mDeps.getNetworkInterfaceMtu(ifaceName); + } + + // Use default mtu if can't find any. + if (mtu == INVALID_MTU) mtu = NetworkStackConstants.ETHER_MTU; + + // Clamp to minimum ipv4 mtu + if (mtu < IPV4_MIN_MTU) mtu = IPV4_MIN_MTU; + + return mtu; + } + /** * Call when UpstreamNetworkState may be changed. * If upstream has ipv4 for tethering, update this new UpstreamNetworkState @@ -868,6 +912,7 @@ if (!isUsingBpf()) return; int upstreamIndex = 0; + int mtu = INVALID_MTU; // This will not work on a network that is using 464xlat because hasIpv4Address will not be // true. @@ -877,6 +922,8 @@ final String ifaceName = ns.linkProperties.getInterfaceName(); final InterfaceParams params = mDeps.getInterfaceParams(ifaceName); final boolean isVcn = isVcnInterface(ifaceName); + mtu = getMtu(ifaceName, ns.linkProperties); + if (!isVcn && params != null && !params.hasMacAddress /* raw ip upstream only */) { upstreamIndex = params.index; } @@ -905,8 +952,11 @@ // after the upstream is lost do not incorrectly add rules pointing at the upstream. if (upstreamIndex == 0) { mIpv4UpstreamIndices.clear(); + mIpv4UpstreamInfo = null; return; } + + mIpv4UpstreamInfo = new UpstreamInfo(upstreamIndex, mtu); Collection<InetAddress> addresses = ns.linkProperties.getAddresses(); for (final InetAddress addr: addresses) { if (isValidUpstreamIpv4Address(addr)) { @@ -1051,6 +1101,9 @@ } pw.decreaseIndent(); + pw.println("IPv4 Upstream Information: " + + (mIpv4UpstreamInfo != null ? mIpv4UpstreamInfo : "<empty>")); + pw.println(); pw.println("Forwarding counters:"); pw.increaseIndent(); @@ -1258,10 +1311,10 @@ final String ageStr = (value.lastUsed == 0) ? "-" : String.format("%dms", (now - value.lastUsed) / 1_000_000); - return String.format("%s [%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %s", + return String.format("%s [%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %d %s", l4protoToString(key.l4proto), key.dstMac, key.iif, getIfName(key.iif), src4, key.srcPort, value.oif, getIfName(value.oif), - public4, publicPort, dst4, value.dstPort, value.ethDstMac, ageStr); + public4, publicPort, dst4, value.dstPort, value.ethDstMac, value.pmtu, ageStr); } private void dumpIpv4ForwardingRuleMap(long now, boolean downstream, @@ -1283,13 +1336,13 @@ try (IBpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map(); IBpfMap<Tether4Key, Tether4Value> downstreamMap = mDeps.getBpfDownstream4Map()) { pw.println("IPv4 Upstream: proto [inDstMac] iif(iface) src -> nat -> " - + "dst [outDstMac] age"); + + "dst [outDstMac] pmtu age"); pw.increaseIndent(); dumpIpv4ForwardingRuleMap(now, UPSTREAM, upstreamMap, pw); pw.decreaseIndent(); pw.println("IPv4 Downstream: proto [inDstMac] iif(iface) src -> nat -> " - + "dst [outDstMac] age"); + + "dst [outDstMac] pmtu age"); pw.increaseIndent(); dumpIpv4ForwardingRuleMap(now, DOWNSTREAM, downstreamMap, pw); pw.decreaseIndent(); @@ -1540,6 +1593,28 @@ } } + /** Upstream information class. */ + private static final class UpstreamInfo { + // TODO: add clat interface information + public final int ifIndex; + public final int mtu; + + private UpstreamInfo(final int ifIndex, final int mtu) { + this.ifIndex = ifIndex; + this.mtu = mtu; + } + + @Override + public int hashCode() { + return Objects.hash(ifIndex, mtu); + } + + @Override + public String toString() { + return String.format("ifIndex: %d, mtu: %d", ifIndex, mtu); + } + } + /** * A BPF tethering stats provider to provide network statistics to the system. * Note that this class' data may only be accessed on the handler thread. @@ -1711,20 +1786,20 @@ @NonNull private Tether4Value makeTetherUpstream4Value(@NonNull ConntrackEvent e, - int upstreamIndex) { - return new Tether4Value(upstreamIndex, + @NonNull UpstreamInfo upstreamInfo) { + return new Tether4Value(upstreamInfo.ifIndex, NULL_MAC_ADDRESS /* ethDstMac (rawip) */, NULL_MAC_ADDRESS /* ethSrcMac (rawip) */, ETH_P_IP, - NetworkStackConstants.ETHER_MTU, toIpv4MappedAddressBytes(e.tupleReply.dstIp), + upstreamInfo.mtu, toIpv4MappedAddressBytes(e.tupleReply.dstIp), toIpv4MappedAddressBytes(e.tupleReply.srcIp), e.tupleReply.dstPort, e.tupleReply.srcPort, 0 /* lastUsed, filled by bpf prog only */); } @NonNull private Tether4Value makeTetherDownstream4Value(@NonNull ConntrackEvent e, - @NonNull ClientInfo c, int upstreamIndex) { + @NonNull ClientInfo c, @NonNull UpstreamInfo upstreamInfo) { return new Tether4Value(c.downstreamIfindex, - c.clientMac, c.downstreamMac, ETH_P_IP, NetworkStackConstants.ETHER_MTU, + c.clientMac, c.downstreamMac, ETH_P_IP, upstreamInfo.mtu, toIpv4MappedAddressBytes(e.tupleOrig.dstIp), toIpv4MappedAddressBytes(e.tupleOrig.srcIp), e.tupleOrig.dstPort, e.tupleOrig.srcPort, @@ -1773,9 +1848,11 @@ return; } - final Tether4Value upstream4Value = makeTetherUpstream4Value(e, upstreamIndex); + if (mIpv4UpstreamInfo == null || mIpv4UpstreamInfo.ifIndex != upstreamIndex) return; + + final Tether4Value upstream4Value = makeTetherUpstream4Value(e, mIpv4UpstreamInfo); final Tether4Value downstream4Value = makeTetherDownstream4Value(e, tetherClient, - upstreamIndex); + mIpv4UpstreamInfo); maybeAddDevMap(upstreamIndex, tetherClient.downstreamIfindex); maybeSetLimit(upstreamIndex); @@ -2075,7 +2152,7 @@ final byte[] msg = ConntrackMessage.newIPv4TimeoutUpdateRequest( proto, src4, (int) srcPort, dst4, (int) dstPort, timeoutSec); try { - NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_NETFILTER, msg); + NetlinkUtils.sendOneShotKernelMessage(OsConstants.NETLINK_NETFILTER, msg); } catch (ErrnoException e) { // Lower the log level for the entry not existing. The conntrack entry may have been // deleted and not handled by the conntrack event monitor yet. In other words, the @@ -2179,5 +2256,13 @@ return mTetherClients; } + // Return map of upstream interface IPv4 address to interface index. + // This is used for testing only. + @NonNull + @VisibleForTesting + final HashMap<Inet4Address, Integer> getIpv4UpstreamIndicesForTesting() { + return mIpv4UpstreamIndices; + } + private static native String[] getBpfCounterNames(); }
diff --git a/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java b/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java index 8a96988..5b19c4e 100644 --- a/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java +++ b/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java
@@ -29,6 +29,8 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import com.android.modules.utils.build.SdkLevel; + import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -49,6 +51,8 @@ @NonNull private List<WifiClient> mLastWifiClients = Collections.emptyList(); @NonNull + private List<WifiClient> mLastLocalOnlyClients = Collections.emptyList(); + @NonNull private List<TetheredClient> mLastTetheredClients = Collections.emptyList(); @VisibleForTesting @@ -72,25 +76,44 @@ * * <p>The new list can be obtained through {@link #getLastTetheredClients()}. * @param ipServers The IpServers used to assign addresses to clients. - * @param wifiClients The list of L2-connected WiFi clients. Null for no change since last - * update. + * @param wifiClients The list of L2-connected WiFi clients that are connected to a global + * hotspot. Null for no change since last update. + * @param localOnlyClients The list of L2-connected WiFi clients that are connected to localOnly + * hotspot. Null for no change since last update. * @return True if the list of clients changed since the last calculation. */ public boolean updateConnectedClients( - Iterable<IpServer> ipServers, @Nullable List<WifiClient> wifiClients) { + Iterable<IpServer> ipServers, @Nullable List<WifiClient> wifiClients, + @Nullable List<WifiClient> localOnlyClients) { final long now = mClock.elapsedRealtime(); - if (wifiClients != null) { - mLastWifiClients = wifiClients; - } + if (wifiClients != null) mLastWifiClients = wifiClients; + if (localOnlyClients != null) mLastLocalOnlyClients = localOnlyClients; + final Set<MacAddress> wifiClientMacs = getClientMacs(mLastWifiClients); + final Set<MacAddress> localOnlyClientMacs = getClientMacs(mLastLocalOnlyClients); // Build the list of non-expired leases from all IpServers, grouped by mac address final Map<MacAddress, TetheredClient> clientsMap = new HashMap<>(); for (IpServer server : ipServers) { + final Set<MacAddress> connectedClientMacs; + switch (server.servingMode()) { + case IpServer.STATE_TETHERED: + connectedClientMacs = wifiClientMacs; + break; + case IpServer.STATE_LOCAL_ONLY: + // Before T, SAP and LOHS both use wifiClientMacs because + // registerLocalOnlyHotspotSoftApCallback didn't exist. + connectedClientMacs = SdkLevel.isAtLeastT() + ? localOnlyClientMacs : wifiClientMacs; + break; + default: + continue; + } + for (TetheredClient client : server.getAllLeases()) { if (client.getTetheringType() == TETHERING_WIFI - && !wifiClientMacs.contains(client.getMacAddress())) { + && !connectedClientMacs.contains(client.getMacAddress())) { // Skip leases of WiFi clients that are not (or no longer) L2-connected continue; } @@ -104,11 +127,8 @@ // TODO: add IPv6 addresses from netlink // Add connected WiFi clients that do not have any known address - for (MacAddress client : wifiClientMacs) { - if (clientsMap.containsKey(client)) continue; - clientsMap.put(client, new TetheredClient( - client, Collections.emptyList() /* addresses */, TETHERING_WIFI)); - } + addWifiClientsIfNoLeases(clientsMap, wifiClientMacs); + addWifiClientsIfNoLeases(clientsMap, localOnlyClientMacs); final HashSet<TetheredClient> clients = new HashSet<>(clientsMap.values()); final boolean clientsChanged = clients.size() != mLastTetheredClients.size() @@ -117,6 +137,15 @@ return clientsChanged; } + private static void addWifiClientsIfNoLeases( + final Map<MacAddress, TetheredClient> clientsMap, final Set<MacAddress> clientMacs) { + for (MacAddress mac : clientMacs) { + if (clientsMap.containsKey(mac)) continue; + clientsMap.put(mac, new TetheredClient( + mac, Collections.emptyList() /* addresses */, TETHERING_WIFI)); + } + } + private static void addLease(Map<MacAddress, TetheredClient> clientsMap, TetheredClient lease) { final TetheredClient aggregateClient = clientsMap.getOrDefault( lease.getMacAddress(), lease);
diff --git a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java index 6d502ce..b88b13b 100644 --- a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java +++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -459,8 +459,9 @@ } @VisibleForTesting - PendingIntent createRecheckAlarmIntent() { + PendingIntent createRecheckAlarmIntent(final String pkgName) { final Intent intent = new Intent(ACTION_PROVISIONING_ALARM); + intent.setPackage(pkgName); return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE); } @@ -470,7 +471,7 @@ final int period = config.provisioningCheckPeriod; if (period <= 0) return; - mProvisioningRecheckAlarm = createRecheckAlarmIntent(); + mProvisioningRecheckAlarm = createRecheckAlarmIntent(mContext.getPackageName()); AlarmManager alarmManager = (AlarmManager) mContext.getSystemService( Context.ALARM_SERVICE); long triggerAtMillis = SystemClock.elapsedRealtime() + (period * MS_PER_HOUR);
diff --git a/Tethering/src/com/android/networkstack/tethering/IOffloadHal.java b/Tethering/src/com/android/networkstack/tethering/IOffloadHal.java new file mode 100644 index 0000000..e66e7ae --- /dev/null +++ b/Tethering/src/com/android/networkstack/tethering/IOffloadHal.java
@@ -0,0 +1,64 @@ +/* + * 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.networkstack.tethering; + +import android.annotation.NonNull; +import android.os.NativeHandle; + +import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; +import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback; + +import java.util.ArrayList; + +/** Abstraction of Tetheroffload HAL interface */ +interface IOffloadHal { + /* + * Initialize the Tetheroffload HAL. Offload management process need to know conntrack rules to + * support NAT, but it may not have permission to create netlink netfilter sockets. Create two + * netlink netfilter sockets and share them with offload management process. + */ + boolean initOffload(@NonNull NativeHandle handle1, @NonNull NativeHandle handle2, + @NonNull OffloadHalCallback callback); + + /** Stop the Tetheroffload HAL. */ + boolean stopOffload(); + + /** Get HAL interface version number. */ + int getVersion(); + + /** Get Tx/Rx usage from last query. */ + ForwardedStats getForwardedStats(@NonNull String upstream); + + /** Set local prefixes to offload management process. */ + boolean setLocalPrefixes(@NonNull ArrayList<String> localPrefixes); + + /** Set data limit value to offload management process. */ + boolean setDataLimit(@NonNull String iface, long limit); + + /** Set data warning and limit value to offload management process. */ + boolean setDataWarningAndLimit(@NonNull String iface, long warning, long limit); + + /** Set upstream parameters to offload management process. */ + boolean setUpstreamParameters(@NonNull String iface, @NonNull String v4addr, + @NonNull String v4gateway, @NonNull ArrayList<String> v6gws); + + /** Add downstream prefix to offload management process. */ + boolean addDownstream(@NonNull String ifname, @NonNull String prefix); + + /** Remove downstream prefix from offload management process. */ + boolean removeDownstream(@NonNull String ifname, @NonNull String prefix); +}
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadController.java b/Tethering/src/com/android/networkstack/tethering/OffloadController.java index 94684af..b4c0d6a 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadController.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadController.java
@@ -26,8 +26,8 @@ import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; -import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0; -import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_1; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1; import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE; import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; @@ -55,7 +55,7 @@ import com.android.net.module.util.SharedLog; import com.android.net.module.util.netlink.ConntrackMessage; import com.android.net.module.util.netlink.NetlinkConstants; -import com.android.net.module.util.netlink.NetlinkSocket; +import com.android.net.module.util.netlink.NetlinkUtils; import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; import java.net.Inet4Address; @@ -98,9 +98,8 @@ private final OffloadTetheringStatsProvider mStatsProvider; private final SharedLog mLog; private final HashMap<String, LinkProperties> mDownstreams; - private boolean mConfigInitialized; @OffloadHardwareInterface.OffloadHalVersion - private int mControlHalVersion; + private int mOffloadHalVersion; private LinkProperties mUpstreamLinkProperties; // The complete set of offload-exempt prefixes passed in via Tethering from // all upstream and downstream sources. @@ -205,20 +204,11 @@ return false; } - if (!mConfigInitialized) { - mConfigInitialized = mHwInterface.initOffloadConfig(); - if (!mConfigInitialized) { - mLog.i("tethering offload config not supported"); - stop(); - return false; - } - } - - mControlHalVersion = mHwInterface.initOffloadControl( + mOffloadHalVersion = mHwInterface.initOffload( // OffloadHardwareInterface guarantees that these callback // methods are called on the handler passed to it, which is the // same as mHandler, as coordinated by the setup in Tethering. - new OffloadHardwareInterface.ControlCallback() { + new OffloadHardwareInterface.OffloadHalCallback() { @Override public void onStarted() { if (!started()) return; @@ -305,11 +295,11 @@ final boolean isStarted = started(); if (!isStarted) { - mLog.i("tethering offload control not supported"); + mLog.i("tethering offload not supported"); stop(); } else { mLog.log("tethering offload started, version: " - + OffloadHardwareInterface.halVerToString(mControlHalVersion)); + + OffloadHardwareInterface.halVerToString(mOffloadHalVersion)); mNatUpdateCallbacksReceived = 0; mNatUpdateNetlinkErrors = 0; maybeSchedulePollingStats(); @@ -325,9 +315,8 @@ final boolean wasStarted = started(); updateStatsForCurrentUpstream(); mUpstreamLinkProperties = null; - mHwInterface.stopOffloadControl(); - mControlHalVersion = OFFLOAD_HAL_VERSION_NONE; - mConfigInitialized = false; + mHwInterface.stopOffload(); + mOffloadHalVersion = OFFLOAD_HAL_VERSION_NONE; if (mHandler.hasCallbacks(mScheduledPollingTask)) { mHandler.removeCallbacks(mScheduledPollingTask); } @@ -335,7 +324,7 @@ } private boolean started() { - return mConfigInitialized && mControlHalVersion != OFFLOAD_HAL_VERSION_NONE; + return mOffloadHalVersion != OFFLOAD_HAL_VERSION_NONE; } @VisibleForTesting @@ -528,7 +517,7 @@ } private boolean useStatsPolling() { - return mControlHalVersion == OFFLOAD_HAL_VERSION_1_0; + return mOffloadHalVersion == OFFLOAD_HAL_VERSION_HIDL_1_0; } private boolean maybeUpdateDataWarningAndLimit(String iface) { @@ -540,7 +529,7 @@ final InterfaceQuota quota = mInterfaceQuotas.getOrDefault(iface, InterfaceQuota.MAX_VALUE); final boolean ret; - if (mControlHalVersion >= OFFLOAD_HAL_VERSION_1_1) { + if (mOffloadHalVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { ret = mHwInterface.setDataWarningAndLimit(iface, quota.warningBytes, quota.limitBytes); } else { ret = mHwInterface.setDataLimit(iface, quota.limitBytes); @@ -611,7 +600,7 @@ for (RouteInfo ri : oldRoutes) { if (shouldIgnoreDownstreamRoute(ri)) continue; if (!newRoutes.contains(ri)) { - mHwInterface.removeDownstreamPrefix(ifname, ri.getDestination().toString()); + mHwInterface.removeDownstream(ifname, ri.getDestination().toString()); } } @@ -619,7 +608,7 @@ for (RouteInfo ri : newRoutes) { if (shouldIgnoreDownstreamRoute(ri)) continue; if (!oldRoutes.contains(ri)) { - mHwInterface.addDownstreamPrefix(ifname, ri.getDestination().toString()); + mHwInterface.addDownstream(ifname, ri.getDestination().toString()); } } } @@ -639,7 +628,7 @@ for (RouteInfo route : lp.getRoutes()) { if (shouldIgnoreDownstreamRoute(route)) continue; - mHwInterface.removeDownstreamPrefix(ifname, route.getDestination().toString()); + mHwInterface.removeDownstream(ifname, route.getDestination().toString()); } } @@ -768,11 +757,21 @@ final boolean isStarted = started(); pw.println("Offload HALs " + (isStarted ? "started" : "not started")); pw.println("Offload Control HAL version: " - + OffloadHardwareInterface.halVerToString(mControlHalVersion)); + + OffloadHardwareInterface.halVerToString(mOffloadHalVersion)); LinkProperties lp = mUpstreamLinkProperties; String upstream = (lp != null) ? lp.getInterfaceName() : null; pw.println("Current upstream: " + upstream); pw.println("Exempt prefixes: " + mLastLocalPrefixStrs); + pw.println("ForwardedStats:"); + pw.increaseIndent(); + if (mForwardedStats.isEmpty()) { + pw.println("<empty>"); + } else { + for (final Map.Entry<String, ForwardedStats> kv : mForwardedStats.entrySet()) { + pw.println(kv.getKey() + ": " + kv.getValue()); + } + } + pw.decreaseIndent(); pw.println("NAT timeout update callbacks received during the " + (isStarted ? "current" : "last") + " offload session: " @@ -825,7 +824,7 @@ proto, src, srcPort, dst, dstPort, timeoutSec); try { - NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_NETFILTER, msg); + NetlinkUtils.sendOneShotKernelMessage(OsConstants.NETLINK_NETFILTER, msg); } catch (ErrnoException e) { mNatUpdateNetlinkErrors++; mLog.e("Error updating NAT conntrack entry >" + natDescription + "<: " + e
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHalAidlImpl.java b/Tethering/src/com/android/networkstack/tethering/OffloadHalAidlImpl.java new file mode 100644 index 0000000..e7dc757 --- /dev/null +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHalAidlImpl.java
@@ -0,0 +1,304 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.networkstack.tethering; + +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_AIDL; + +import android.annotation.NonNull; +import android.hardware.tetheroffload.ForwardedStats; +import android.hardware.tetheroffload.IOffload; +import android.hardware.tetheroffload.ITetheringOffloadCallback; +import android.hardware.tetheroffload.NatTimeoutUpdate; +import android.hardware.tetheroffload.NetworkProtocol; +import android.hardware.tetheroffload.OffloadCallbackEvent; +import android.os.Handler; +import android.os.NativeHandle; +import android.os.ParcelFileDescriptor; +import android.os.ServiceManager; +import android.system.OsConstants; + +import com.android.modules.utils.build.SdkLevel; +import com.android.net.module.util.SharedLog; +import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback; + +import java.util.ArrayList; + +/** + * The implementation of IOffloadHal which based on Stable AIDL interface + */ +public class OffloadHalAidlImpl implements IOffloadHal { + private static final String TAG = OffloadHalAidlImpl.class.getSimpleName(); + private static final String HAL_INSTANCE_NAME = IOffload.DESCRIPTOR + "/default"; + + private final Handler mHandler; + private final SharedLog mLog; + private final IOffload mIOffload; + @OffloadHardwareInterface.OffloadHalVersion + private final int mOffloadVersion; + + private TetheringOffloadCallback mTetheringOffloadCallback; + + public OffloadHalAidlImpl(int version, @NonNull IOffload offload, @NonNull Handler handler, + @NonNull SharedLog log) { + mOffloadVersion = version; + mIOffload = offload; + mHandler = handler; + mLog = log.forSubComponent(TAG); + } + + /** + * Initialize the Tetheroffload HAL. Provides bound netlink file descriptors for use in the + * management process. + */ + public boolean initOffload(@NonNull NativeHandle handle1, @NonNull NativeHandle handle2, + @NonNull OffloadHalCallback callback) { + final String methodStr = String.format("initOffload(%d, %d, %s)", + handle1.getFileDescriptor().getInt$(), handle2.getFileDescriptor().getInt$(), + (callback == null) ? "null" + : "0x" + Integer.toHexString(System.identityHashCode(callback))); + mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, callback, mLog); + try { + mIOffload.initOffload( + ParcelFileDescriptor.adoptFd(handle1.getFileDescriptor().getInt$()), + ParcelFileDescriptor.adoptFd(handle2.getFileDescriptor().getInt$()), + mTetheringOffloadCallback); + } catch (Exception e) { + logAndIgnoreException(e, methodStr); + return false; + } + mLog.i(methodStr); + return true; + } + + /** Stop the Tetheroffload HAL. */ + public boolean stopOffload() { + final String methodStr = "stopOffload()"; + try { + mIOffload.stopOffload(); + } catch (Exception e) { + logAndIgnoreException(e, methodStr); + return false; + } + + mTetheringOffloadCallback = null; + mLog.i(methodStr); + return true; + } + + /** Get HAL interface version number. */ + public int getVersion() { + return mOffloadVersion; + } + + /** Get Tx/Rx usage from last query. */ + public OffloadHardwareInterface.ForwardedStats getForwardedStats(@NonNull String upstream) { + ForwardedStats stats = new ForwardedStats(); + final String methodStr = String.format("getForwardedStats(%s)", upstream); + try { + stats = mIOffload.getForwardedStats(upstream); + } catch (Exception e) { + logAndIgnoreException(e, methodStr); + } + mLog.i(methodStr); + return new OffloadHardwareInterface.ForwardedStats(stats.rxBytes, stats.txBytes); + } + + /** Set local prefixes to offload management process. */ + public boolean setLocalPrefixes(@NonNull ArrayList<String> localPrefixes) { + final String methodStr = String.format("setLocalPrefixes([%s])", + String.join(",", localPrefixes)); + try { + mIOffload.setLocalPrefixes(localPrefixes.toArray(new String[localPrefixes.size()])); + } catch (Exception e) { + logAndIgnoreException(e, methodStr); + return false; + } + mLog.i(methodStr); + return true; + } + + /** + * Set data limit value to offload management process. + * Method setDataLimit is deprecated in AIDL, so call setDataWarningAndLimit instead, + * with warningBytes set to its MAX_VALUE. + */ + public boolean setDataLimit(@NonNull String iface, long limit) { + final long warning = Long.MAX_VALUE; + final String methodStr = String.format("setDataLimit(%s, %d)", iface, limit); + try { + mIOffload.setDataWarningAndLimit(iface, warning, limit); + } catch (Exception e) { + logAndIgnoreException(e, methodStr); + return false; + } + mLog.i(methodStr); + return true; + } + + /** Set data warning and limit value to offload management process. */ + public boolean setDataWarningAndLimit(@NonNull String iface, long warning, long limit) { + final String methodStr = + String.format("setDataWarningAndLimit(%s, %d, %d)", iface, warning, limit); + try { + mIOffload.setDataWarningAndLimit(iface, warning, limit); + } catch (Exception e) { + logAndIgnoreException(e, methodStr); + return false; + } + mLog.i(methodStr); + return true; + } + + /** Set upstream parameters to offload management process. */ + public boolean setUpstreamParameters(@NonNull String iface, @NonNull String v4addr, + @NonNull String v4gateway, @NonNull ArrayList<String> v6gws) { + final String methodStr = String.format("setUpstreamParameters(%s, %s, %s, [%s])", + iface, v4addr, v4gateway, String.join(",", v6gws)); + try { + mIOffload.setUpstreamParameters(iface, v4addr, v4gateway, + v6gws.toArray(new String[v6gws.size()])); + } catch (Exception e) { + logAndIgnoreException(e, methodStr); + return false; + } + mLog.i(methodStr); + return true; + } + + /** Add downstream prefix to offload management process. */ + public boolean addDownstream(@NonNull String ifname, @NonNull String prefix) { + final String methodStr = String.format("addDownstream(%s, %s)", ifname, prefix); + try { + mIOffload.addDownstream(ifname, prefix); + } catch (Exception e) { + logAndIgnoreException(e, methodStr); + return false; + } + mLog.i(methodStr); + return true; + } + + /** Remove downstream prefix from offload management process. */ + public boolean removeDownstream(@NonNull String ifname, @NonNull String prefix) { + final String methodStr = String.format("removeDownstream(%s, %s)", ifname, prefix); + try { + mIOffload.removeDownstream(ifname, prefix); + } catch (Exception e) { + logAndIgnoreException(e, methodStr); + return false; + } + mLog.i(methodStr); + return true; + } + + /** + * Get {@link IOffloadHal} object from the AIDL service. + * + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + * @param log Log to be used by the repository. + */ + public static IOffloadHal getIOffloadHal(Handler handler, SharedLog log) { + // Tetheroffload AIDL interface is only supported after U. + if (!SdkLevel.isAtLeastU() || !ServiceManager.isDeclared(HAL_INSTANCE_NAME)) return null; + + IOffload offload = IOffload.Stub.asInterface( + ServiceManager.waitForDeclaredService(HAL_INSTANCE_NAME)); + if (offload == null) return null; + + return new OffloadHalAidlImpl(OFFLOAD_HAL_VERSION_AIDL, offload, handler, log); + } + + private void logAndIgnoreException(Exception e, final String methodStr) { + mLog.e(methodStr + " failed with " + e.getClass().getSimpleName() + ": ", e); + } + + private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub { + public final Handler handler; + public final OffloadHalCallback callback; + public final SharedLog log; + + TetheringOffloadCallback( + Handler h, OffloadHalCallback cb, SharedLog sharedLog) { + handler = h; + callback = cb; + log = sharedLog; + } + + private void handleOnEvent(int event) { + switch (event) { + case OffloadCallbackEvent.OFFLOAD_STARTED: + callback.onStarted(); + break; + case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR: + callback.onStoppedError(); + break; + case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED: + callback.onStoppedUnsupported(); + break; + case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE: + callback.onSupportAvailable(); + break; + case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED: + callback.onStoppedLimitReached(); + break; + case OffloadCallbackEvent.OFFLOAD_WARNING_REACHED: + callback.onWarningReached(); + break; + default: + log.e("Unsupported OffloadCallbackEvent: " + event); + } + } + + @Override + public void onEvent(int event) { + handler.post(() -> { + handleOnEvent(event); + }); + } + + @Override + public void updateTimeout(NatTimeoutUpdate params) { + handler.post(() -> { + callback.onNatTimeoutUpdate( + networkProtocolToOsConstant(params.proto), + params.src.addr, params.src.port, + params.dst.addr, params.dst.port); + }); + } + + @Override + public String getInterfaceHash() { + return ITetheringOffloadCallback.HASH; + } + + @Override + public int getInterfaceVersion() { + return ITetheringOffloadCallback.VERSION; + } + } + + private static int networkProtocolToOsConstant(int proto) { + switch (proto) { + case NetworkProtocol.TCP: return OsConstants.IPPROTO_TCP; + case NetworkProtocol.UDP: return OsConstants.IPPROTO_UDP; + default: + // The caller checks this value and will log an error. Just make + // sure it won't collide with valid OsConstants.IPPROTO_* values. + return -Math.abs(proto); + } + } +}
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java b/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java new file mode 100644 index 0000000..e0a9878 --- /dev/null +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java
@@ -0,0 +1,439 @@ +/* + * 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.networkstack.tethering; + +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE; +import static com.android.networkstack.tethering.OffloadHardwareInterface.halVerToString; +import static com.android.networkstack.tethering.util.TetheringUtils.uint16; + +import android.annotation.NonNull; +import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; +import android.hardware.tetheroffload.control.V1_0.IOffloadControl; +import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; +import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; +import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; +import android.hardware.tetheroffload.control.V1_1.ITetheringOffloadCallback; +import android.os.Handler; +import android.os.NativeHandle; +import android.os.RemoteException; +import android.system.OsConstants; +import android.util.Log; + +import com.android.net.module.util.SharedLog; +import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; +import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback; + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +/** + * The implementation of IOffloadHal which based on HIDL interfaces + */ +public class OffloadHalHidlImpl implements IOffloadHal { + private static final String TAG = OffloadHalHidlImpl.class.getSimpleName(); + private static final String YIELDS = " -> "; + + private final Handler mHandler; + private final SharedLog mLog; + private final IOffloadConfig mIOffloadConfig; + private final IOffloadControl mIOffloadControl; + @OffloadHardwareInterface.OffloadHalVersion + private final int mOffloadControlVersion; + + private OffloadHalCallback mOffloadHalCallback; + private TetheringOffloadCallback mTetheringOffloadCallback; + + public OffloadHalHidlImpl(int version, @NonNull IOffloadConfig config, + @NonNull IOffloadControl control, @NonNull Handler handler, @NonNull SharedLog log) { + mOffloadControlVersion = version; + mIOffloadConfig = config; + mIOffloadControl = control; + mHandler = handler; + mLog = log.forSubComponent(TAG); + } + + /** + * Initialize the Tetheroffload HAL. Provides bound netlink file descriptors for use in the + * management process. + */ + public boolean initOffload(@NonNull NativeHandle handle1, @NonNull NativeHandle handle2, + @NonNull OffloadHalCallback callback) { + final String logmsg = String.format("initOffload(%d, %d, %s)", + handle1.getFileDescriptor().getInt$(), handle2.getFileDescriptor().getInt$(), + (callback == null) ? "null" + : "0x" + Integer.toHexString(System.identityHashCode(callback))); + + mOffloadHalCallback = callback; + mTetheringOffloadCallback = new TetheringOffloadCallback( + mHandler, mOffloadHalCallback, mLog, mOffloadControlVersion); + final CbResults results = new CbResults(); + try { + mIOffloadConfig.setHandles(handle1, handle2, + (boolean success, String errMsg) -> { + results.mSuccess = success; + results.mErrMsg = errMsg; + }); + mIOffloadControl.initOffload( + mTetheringOffloadCallback, + (boolean success, String errMsg) -> { + results.mSuccess = success; + results.mErrMsg = errMsg; + }); + } catch (RemoteException e) { + record(logmsg, e); + return false; + } + + record(logmsg, results); + return results.mSuccess; + } + + /** Stop the Tetheroffload HAL. */ + public boolean stopOffload() { + try { + mIOffloadControl.stopOffload( + (boolean success, String errMsg) -> { + if (!success) mLog.e("stopOffload failed: " + errMsg); + }); + } catch (RemoteException e) { + mLog.e("failed to stopOffload: " + e); + } + mOffloadHalCallback = null; + mTetheringOffloadCallback = null; + mLog.log("stopOffload()"); + return true; + } + + /** Get HAL interface version number. */ + public int getVersion() { + return mOffloadControlVersion; + } + + /** Get Tx/Rx usage from last query. */ + public ForwardedStats getForwardedStats(@NonNull String upstream) { + final String logmsg = String.format("getForwardedStats(%s)", upstream); + + final ForwardedStats stats = new ForwardedStats(); + try { + mIOffloadControl.getForwardedStats( + upstream, + (long rxBytes, long txBytes) -> { + stats.rxBytes = (rxBytes > 0) ? rxBytes : 0; + stats.txBytes = (txBytes > 0) ? txBytes : 0; + }); + } catch (RemoteException e) { + record(logmsg, e); + return stats; + } + + return stats; + } + + /** Set local prefixes to offload management process. */ + public boolean setLocalPrefixes(@NonNull ArrayList<String> localPrefixes) { + final String logmsg = String.format("setLocalPrefixes([%s])", + String.join(",", localPrefixes)); + + final CbResults results = new CbResults(); + try { + mIOffloadControl.setLocalPrefixes(localPrefixes, + (boolean success, String errMsg) -> { + results.mSuccess = success; + results.mErrMsg = errMsg; + }); + } catch (RemoteException e) { + record(logmsg, e); + return false; + } + + record(logmsg, results); + return results.mSuccess; + } + + /** Set data limit value to offload management process. */ + public boolean setDataLimit(@NonNull String iface, long limit) { + + final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit); + + final CbResults results = new CbResults(); + try { + mIOffloadControl.setDataLimit( + iface, limit, + (boolean success, String errMsg) -> { + results.mSuccess = success; + results.mErrMsg = errMsg; + }); + } catch (RemoteException e) { + record(logmsg, e); + return false; + } + + record(logmsg, results); + return results.mSuccess; + } + + /** Set data warning and limit value to offload management process. */ + public boolean setDataWarningAndLimit(@NonNull String iface, long warning, long limit) { + if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_HIDL_1_1) { + throw new UnsupportedOperationException( + "setDataWarningAndLimit is not supported below HAL V1.1"); + } + final String logmsg = + String.format("setDataWarningAndLimit(%s, %d, %d)", iface, warning, limit); + + final CbResults results = new CbResults(); + try { + ((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mIOffloadControl) + .setDataWarningAndLimit( + iface, warning, limit, + (boolean success, String errMsg) -> { + results.mSuccess = success; + results.mErrMsg = errMsg; + }); + } catch (RemoteException e) { + record(logmsg, e); + return false; + } + + record(logmsg, results); + return results.mSuccess; + } + + /** Set upstream parameters to offload management process. */ + public boolean setUpstreamParameters(@NonNull String iface, @NonNull String v4addr, + @NonNull String v4gateway, @NonNull ArrayList<String> v6gws) { + final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])", + iface, v4addr, v4gateway, String.join(",", v6gws)); + + final CbResults results = new CbResults(); + try { + mIOffloadControl.setUpstreamParameters( + iface, v4addr, v4gateway, v6gws, + (boolean success, String errMsg) -> { + results.mSuccess = success; + results.mErrMsg = errMsg; + }); + } catch (RemoteException e) { + record(logmsg, e); + return false; + } + + record(logmsg, results); + return results.mSuccess; + } + + /** Add downstream prefix to offload management process. */ + public boolean addDownstream(@NonNull String ifname, @NonNull String prefix) { + final String logmsg = String.format("addDownstream(%s, %s)", ifname, prefix); + + final CbResults results = new CbResults(); + try { + mIOffloadControl.addDownstream(ifname, prefix, + (boolean success, String errMsg) -> { + results.mSuccess = success; + results.mErrMsg = errMsg; + }); + } catch (RemoteException e) { + record(logmsg, e); + return false; + } + + record(logmsg, results); + return results.mSuccess; + } + + /** Remove downstream prefix from offload management process. */ + public boolean removeDownstream(@NonNull String ifname, @NonNull String prefix) { + final String logmsg = String.format("removeDownstream(%s, %s)", ifname, prefix); + + final CbResults results = new CbResults(); + try { + mIOffloadControl.removeDownstream(ifname, prefix, + (boolean success, String errMsg) -> { + results.mSuccess = success; + results.mErrMsg = errMsg; + }); + } catch (RemoteException e) { + record(logmsg, e); + return false; + } + + record(logmsg, results); + return results.mSuccess; + } + + /** + * Get {@link IOffloadHal} object from the HIDL service. + * + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + * @param log Log to be used by the repository. + */ + public static IOffloadHal getIOffloadHal(Handler handler, SharedLog log) { + IOffloadConfig config = null; + try { + config = IOffloadConfig.getService(true /*retry*/); + } catch (RemoteException e) { + log.e("getIOffloadConfig error " + e); + return null; + } catch (NoSuchElementException e) { + log.i("getIOffloadConfig Tether Offload HAL not present/implemented"); + return null; + } + + IOffloadControl control = null; + int version = OFFLOAD_HAL_VERSION_NONE; + try { + control = android.hardware.tetheroffload.control + .V1_1.IOffloadControl.getService(true /*retry*/); + version = OFFLOAD_HAL_VERSION_HIDL_1_1; + } catch (NoSuchElementException e) { + // Unsupported by device. + } catch (RemoteException e) { + log.e("Unable to get offload control " + OFFLOAD_HAL_VERSION_HIDL_1_1); + } + if (control == null) { + try { + control = IOffloadControl.getService(true /*retry*/); + version = OFFLOAD_HAL_VERSION_HIDL_1_0; + } catch (NoSuchElementException e) { + // Unsupported by device. + } catch (RemoteException e) { + log.e("Unable to get offload control " + OFFLOAD_HAL_VERSION_HIDL_1_0); + } + } + + if (config == null || control == null) return null; + + return new OffloadHalHidlImpl(version, config, control, handler, log); + } + + private void record(String msg, Throwable t) { + mLog.e(msg + YIELDS + "exception: " + t); + } + + private void record(String msg, CbResults results) { + final String logmsg = msg + YIELDS + results; + if (!results.mSuccess) { + mLog.e(logmsg); + } else { + mLog.log(logmsg); + } + } + + private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub { + public final Handler handler; + public final OffloadHalCallback callback; + public final SharedLog log; + private final int mOffloadControlVersion; + + TetheringOffloadCallback( + Handler h, OffloadHalCallback cb, SharedLog sharedLog, int offloadControlVersion) { + handler = h; + callback = cb; + log = sharedLog; + this.mOffloadControlVersion = offloadControlVersion; + } + + private void handleOnEvent(int event) { + switch (event) { + case OffloadCallbackEvent.OFFLOAD_STARTED: + callback.onStarted(); + break; + case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR: + callback.onStoppedError(); + break; + case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED: + callback.onStoppedUnsupported(); + break; + case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE: + callback.onSupportAvailable(); + break; + case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED: + callback.onStoppedLimitReached(); + break; + case android.hardware.tetheroffload.control + .V1_1.OffloadCallbackEvent.OFFLOAD_WARNING_REACHED: + callback.onWarningReached(); + break; + default: + log.e("Unsupported OffloadCallbackEvent: " + event); + } + } + + @Override + public void onEvent(int event) { + // The implementation should never call onEvent()) if the event is already reported + // through newer callback. + if (mOffloadControlVersion > OFFLOAD_HAL_VERSION_HIDL_1_0) { + Log.wtf(TAG, "onEvent(" + event + ") fired on HAL " + + halVerToString(mOffloadControlVersion)); + } + handler.post(() -> { + handleOnEvent(event); + }); + } + + @Override + public void onEvent_1_1(int event) { + if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_HIDL_1_1) { + Log.wtf(TAG, "onEvent_1_1(" + event + ") fired on HAL " + + halVerToString(mOffloadControlVersion)); + return; + } + handler.post(() -> { + handleOnEvent(event); + }); + } + + @Override + public void updateTimeout(NatTimeoutUpdate params) { + handler.post(() -> { + callback.onNatTimeoutUpdate( + networkProtocolToOsConstant(params.proto), + params.src.addr, uint16(params.src.port), + params.dst.addr, uint16(params.dst.port)); + }); + } + } + + private static int networkProtocolToOsConstant(int proto) { + switch (proto) { + case NetworkProtocol.TCP: return OsConstants.IPPROTO_TCP; + case NetworkProtocol.UDP: return OsConstants.IPPROTO_UDP; + default: + // The caller checks this value and will log an error. Just make + // sure it won't collide with valid OsConstants.IPPROTO_* values. + return -Math.abs(proto); + } + } + + private static class CbResults { + boolean mSuccess; + String mErrMsg; + + @Override + public String toString() { + if (mSuccess) { + return "ok"; + } else { + return "fail: " + mErrMsg; + } + } + } +}
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index 846abcb..de15c5b 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
@@ -18,29 +18,19 @@ import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; -import static com.android.networkstack.tethering.util.TetheringUtils.uint16; import android.annotation.IntDef; import android.annotation.NonNull; -import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; -import android.hardware.tetheroffload.control.V1_0.IOffloadControl; -import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; -import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; -import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; -import android.hardware.tetheroffload.control.V1_1.ITetheringOffloadCallback; import android.net.util.SocketUtils; import android.os.Handler; import android.os.NativeHandle; -import android.os.RemoteException; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; -import android.util.Log; -import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.SharedLog; -import com.android.net.module.util.netlink.NetlinkSocket; +import com.android.net.module.util.netlink.NetlinkUtils; import com.android.net.module.util.netlink.StructNfGenMsg; import com.android.net.module.util.netlink.StructNlMsgHdr; @@ -54,8 +44,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.NoSuchElementException; - /** * Capture tethering dependencies, for injection. @@ -86,43 +74,43 @@ private final Handler mHandler; private final SharedLog mLog; private final Dependencies mDeps; - private IOffloadControl mOffloadControl; + private IOffloadHal mIOffload; // TODO: Use major-minor version control to prevent from defining new constants. static final int OFFLOAD_HAL_VERSION_NONE = 0; - static final int OFFLOAD_HAL_VERSION_1_0 = 1; - static final int OFFLOAD_HAL_VERSION_1_1 = 2; + static final int OFFLOAD_HAL_VERSION_HIDL_1_0 = 1; + static final int OFFLOAD_HAL_VERSION_HIDL_1_1 = 2; + static final int OFFLOAD_HAL_VERSION_AIDL = 3; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "OFFLOAD_HAL_VERSION_", value = { OFFLOAD_HAL_VERSION_NONE, - OFFLOAD_HAL_VERSION_1_0, - OFFLOAD_HAL_VERSION_1_1 + OFFLOAD_HAL_VERSION_HIDL_1_0, + OFFLOAD_HAL_VERSION_HIDL_1_1, + OFFLOAD_HAL_VERSION_AIDL, }) public @interface OffloadHalVersion {} - @OffloadHalVersion - private int mOffloadControlVersion = OFFLOAD_HAL_VERSION_NONE; @NonNull static String halVerToString(int version) { switch(version) { - case OFFLOAD_HAL_VERSION_1_0: - return "1.0"; - case OFFLOAD_HAL_VERSION_1_1: - return "1.1"; + case OFFLOAD_HAL_VERSION_HIDL_1_0: + return "HIDL 1.0"; + case OFFLOAD_HAL_VERSION_HIDL_1_1: + return "HIDL 1.1"; + case OFFLOAD_HAL_VERSION_AIDL: + return "AIDL"; case OFFLOAD_HAL_VERSION_NONE: return "None"; default: throw new IllegalArgumentException("Unsupported version int " + version); } - } - private TetheringOffloadCallback mTetheringOffloadCallback; - private ControlCallback mControlCallback; + private OffloadHalCallback mOffloadHalCallback; /** The callback to notify status of offload management process. */ - public static class ControlCallback { + public static class OffloadHalCallback { /** Offload started. */ public void onStarted() {} /** @@ -179,7 +167,7 @@ } public OffloadHardwareInterface(Handler h, SharedLog log) { - this(h, log, new Dependencies(log)); + this(h, log, new Dependencies(h, log)); } OffloadHardwareInterface(Handler h, SharedLog log, Dependencies deps) { @@ -190,51 +178,27 @@ /** Capture OffloadHardwareInterface dependencies, for injection. */ static class Dependencies { + private final Handler mHandler; private final SharedLog mLog; - Dependencies(SharedLog log) { + Dependencies(Handler handler, SharedLog log) { + mHandler = handler; mLog = log; } - public IOffloadConfig getOffloadConfig() { - try { - return IOffloadConfig.getService(true /*retry*/); - } catch (RemoteException | NoSuchElementException e) { - mLog.e("getIOffloadConfig error " + e); - return null; - } - } - - @NonNull - public Pair<IOffloadControl, Integer> getOffloadControl() { - IOffloadControl hal = null; - int version = OFFLOAD_HAL_VERSION_NONE; - try { - hal = android.hardware.tetheroffload.control - .V1_1.IOffloadControl.getService(true /*retry*/); - version = OFFLOAD_HAL_VERSION_1_1; - } catch (NoSuchElementException e) { - // Unsupported by device. - } catch (RemoteException e) { - mLog.e("Unable to get offload control " + OFFLOAD_HAL_VERSION_1_1); - } + public IOffloadHal getOffload() { + // Prefer AIDL implementation if its service is declared. + IOffloadHal hal = OffloadHalAidlImpl.getIOffloadHal(mHandler, mLog); if (hal == null) { - try { - hal = IOffloadControl.getService(true /*retry*/); - version = OFFLOAD_HAL_VERSION_1_0; - } catch (NoSuchElementException e) { - // Unsupported by device. - } catch (RemoteException e) { - mLog.e("Unable to get offload control " + OFFLOAD_HAL_VERSION_1_0); - } + hal = OffloadHalHidlImpl.getIOffloadHal(mHandler, mLog); } - return new Pair<IOffloadControl, Integer>(hal, version); + return hal; } public NativeHandle createConntrackSocket(final int groups) { final FileDescriptor fd; try { - fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER); + fd = NetlinkUtils.netlinkSocketForProto(OsConstants.NETLINK_NETFILTER); } catch (ErrnoException e) { mLog.e("Unable to create conntrack socket " + e); return null; @@ -273,56 +237,6 @@ return DEFAULT_TETHER_OFFLOAD_DISABLED; } - /** - * Offload management process need to know conntrack rules to support NAT, but it may not have - * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and - * share them with offload management process. - */ - public boolean initOffloadConfig() { - final IOffloadConfig offloadConfig = mDeps.getOffloadConfig(); - if (offloadConfig == null) { - mLog.e("Could not find IOffloadConfig service"); - return false; - } - // Per the IConfigOffload definition: - // - // h1 provides a file descriptor bound to the following netlink groups - // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY). - // - // h2 provides a file descriptor bound to the following netlink groups - // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). - final NativeHandle h1 = mDeps.createConntrackSocket( - NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); - if (h1 == null) return false; - - requestSocketDump(h1); - - final NativeHandle h2 = mDeps.createConntrackSocket( - NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY); - if (h2 == null) { - closeFdInNativeHandle(h1); - return false; - } - - final CbResults results = new CbResults(); - try { - offloadConfig.setHandles(h1, h2, - (boolean success, String errMsg) -> { - results.mSuccess = success; - results.mErrMsg = errMsg; - }); - } catch (RemoteException e) { - record("initOffloadConfig, setHandles fail", e); - return false; - } - // Explicitly close FDs. - closeFdInNativeHandle(h1); - closeFdInNativeHandle(h2); - - record("initOffloadConfig, setHandles results:", results); - return results.mSuccess; - } - @VisibleForTesting void sendIpv4NfGenMsg(@NonNull NativeHandle handle, short type, short flags) { final int length = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; @@ -342,7 +256,7 @@ nfh.pack(byteBuffer); try { - NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length, + NetlinkUtils.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length, NETLINK_MESSAGE_TIMEOUT_MS); } catch (ErrnoException | InterruptedIOException e) { mLog.e("Unable to send netfilter message, error: " + e); @@ -355,165 +269,107 @@ (short) (NLM_F_REQUEST | NLM_F_DUMP)); } - private void closeFdInNativeHandle(final NativeHandle h) { - try { - h.close(); - } catch (IOException | IllegalStateException e) { - // IllegalStateException means fd is already closed, do nothing here. - // Also nothing we can do if IOException. + private void maybeCloseFdInNativeHandles(final NativeHandle... handles) { + for (NativeHandle h : handles) { + if (h == null) continue; + try { + h.close(); + } catch (IOException | IllegalStateException e) { + // IllegalStateException means fd is already closed, do nothing here. + // Also nothing we can do if IOException. + } } } + private int initWithHandles(NativeHandle h1, NativeHandle h2) { + if (h1 == null || h2 == null) { + mLog.e("Failed to create socket."); + return OFFLOAD_HAL_VERSION_NONE; + } + + requestSocketDump(h1); + if (!mIOffload.initOffload(h1, h2, mOffloadHalCallback)) { + mIOffload.stopOffload(); + mLog.e("Failed to initialize offload."); + return OFFLOAD_HAL_VERSION_NONE; + } + + return mIOffload.getVersion(); + } + /** * Initialize the tethering offload HAL. * * @return one of {@code OFFLOAD_HAL_VERSION_*} represents the HAL version, or * {@link #OFFLOAD_HAL_VERSION_NONE} if failed. */ - public int initOffloadControl(ControlCallback controlCb) { - mControlCallback = controlCb; - - if (mOffloadControl == null) { - final Pair<IOffloadControl, Integer> halAndVersion = mDeps.getOffloadControl(); - mOffloadControl = halAndVersion.first; - mOffloadControlVersion = halAndVersion.second; - if (mOffloadControl == null) { - mLog.e("tethering IOffloadControl.getService() returned null"); + public int initOffload(OffloadHalCallback offloadCb) { + if (mIOffload == null) { + mIOffload = mDeps.getOffload(); + if (mIOffload == null) { + mLog.i("No tethering offload HAL service found."); return OFFLOAD_HAL_VERSION_NONE; } - mLog.i("tethering offload control version " - + halVerToString(mOffloadControlVersion) + " is supported."); + mLog.i("Tethering offload version " + + halVerToString(mIOffload.getVersion()) + " is supported."); } - final String logmsg = String.format("initOffloadControl(%s)", - (controlCb == null) ? "null" - : "0x" + Integer.toHexString(System.identityHashCode(controlCb))); + // Per the IOffload definition: + // + // h1 provides a file descriptor bound to the following netlink groups + // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY). + // + // h2 provides a file descriptor bound to the following netlink groups + // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). + final NativeHandle h1 = mDeps.createConntrackSocket( + NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); + final NativeHandle h2 = mDeps.createConntrackSocket( + NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY); - mTetheringOffloadCallback = new TetheringOffloadCallback( - mHandler, mControlCallback, mLog, mOffloadControlVersion); - final CbResults results = new CbResults(); - try { - mOffloadControl.initOffload( - mTetheringOffloadCallback, - (boolean success, String errMsg) -> { - results.mSuccess = success; - results.mErrMsg = errMsg; - }); - } catch (RemoteException e) { - record(logmsg, e); - return OFFLOAD_HAL_VERSION_NONE; + mOffloadHalCallback = offloadCb; + final int version = initWithHandles(h1, h2); + + // Explicitly close FDs for HIDL. AIDL will pass the original FDs to the service, + // they shouldn't be closed here. + if (version < OFFLOAD_HAL_VERSION_AIDL) { + maybeCloseFdInNativeHandles(h1, h2); } - - record(logmsg, results); - return results.mSuccess ? mOffloadControlVersion : OFFLOAD_HAL_VERSION_NONE; + return version; } - /** Stop IOffloadControl. */ - public void stopOffloadControl() { - if (mOffloadControl != null) { - try { - mOffloadControl.stopOffload( - (boolean success, String errMsg) -> { - if (!success) mLog.e("stopOffload failed: " + errMsg); - }); - } catch (RemoteException e) { - mLog.e("failed to stopOffload: " + e); + /** Stop the tethering offload HAL. */ + public void stopOffload() { + if (mIOffload != null) { + if (!mIOffload.stopOffload()) { + mLog.e("Failed to stop offload."); } } - mOffloadControl = null; - mTetheringOffloadCallback = null; - mControlCallback = null; - mLog.log("stopOffloadControl()"); + mIOffload = null; + mOffloadHalCallback = null; } /** Get Tx/Rx usage from last query. */ public ForwardedStats getForwardedStats(String upstream) { - final String logmsg = String.format("getForwardedStats(%s)", upstream); - - final ForwardedStats stats = new ForwardedStats(); - try { - mOffloadControl.getForwardedStats( - upstream, - (long rxBytes, long txBytes) -> { - stats.rxBytes = (rxBytes > 0) ? rxBytes : 0; - stats.txBytes = (txBytes > 0) ? txBytes : 0; - }); - } catch (RemoteException e) { - record(logmsg, e); - return stats; - } - - return stats; + return mIOffload.getForwardedStats(upstream); } /** Set local prefixes to offload management process. */ public boolean setLocalPrefixes(ArrayList<String> localPrefixes) { - final String logmsg = String.format("setLocalPrefixes([%s])", - String.join(",", localPrefixes)); - - final CbResults results = new CbResults(); - try { - mOffloadControl.setLocalPrefixes(localPrefixes, - (boolean success, String errMsg) -> { - results.mSuccess = success; - results.mErrMsg = errMsg; - }); - } catch (RemoteException e) { - record(logmsg, e); - return false; - } - - record(logmsg, results); - return results.mSuccess; + return mIOffload.setLocalPrefixes(localPrefixes); } /** Set data limit value to offload management process. */ public boolean setDataLimit(String iface, long limit) { - - final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit); - - final CbResults results = new CbResults(); - try { - mOffloadControl.setDataLimit( - iface, limit, - (boolean success, String errMsg) -> { - results.mSuccess = success; - results.mErrMsg = errMsg; - }); - } catch (RemoteException e) { - record(logmsg, e); - return false; - } - - record(logmsg, results); - return results.mSuccess; + return mIOffload.setDataLimit(iface, limit); } /** Set data warning and limit value to offload management process. */ public boolean setDataWarningAndLimit(String iface, long warning, long limit) { - if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_1_1) { - throw new IllegalArgumentException( + if (mIOffload.getVersion() < OFFLOAD_HAL_VERSION_HIDL_1_1) { + throw new UnsupportedOperationException( "setDataWarningAndLimit is not supported below HAL V1.1"); } - final String logmsg = - String.format("setDataWarningAndLimit(%s, %d, %d)", iface, warning, limit); - - final CbResults results = new CbResults(); - try { - ((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mOffloadControl) - .setDataWarningAndLimit( - iface, warning, limit, - (boolean success, String errMsg) -> { - results.mSuccess = success; - results.mErrMsg = errMsg; - }); - } catch (RemoteException e) { - record(logmsg, e); - return false; - } - - record(logmsg, results); - return results.mSuccess; + return mIOffload.setDataWarningAndLimit(iface, warning, limit); } /** Set upstream parameters to offload management process. */ @@ -523,178 +379,16 @@ v4addr = (v4addr != null) ? v4addr : NO_IPV4_ADDRESS; v4gateway = (v4gateway != null) ? v4gateway : NO_IPV4_GATEWAY; v6gws = (v6gws != null) ? v6gws : new ArrayList<>(); - - final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])", - iface, v4addr, v4gateway, String.join(",", v6gws)); - - final CbResults results = new CbResults(); - try { - mOffloadControl.setUpstreamParameters( - iface, v4addr, v4gateway, v6gws, - (boolean success, String errMsg) -> { - results.mSuccess = success; - results.mErrMsg = errMsg; - }); - } catch (RemoteException e) { - record(logmsg, e); - return false; - } - - record(logmsg, results); - return results.mSuccess; + return mIOffload.setUpstreamParameters(iface, v4addr, v4gateway, v6gws); } /** Add downstream prefix to offload management process. */ - public boolean addDownstreamPrefix(String ifname, String prefix) { - final String logmsg = String.format("addDownstreamPrefix(%s, %s)", ifname, prefix); - - final CbResults results = new CbResults(); - try { - mOffloadControl.addDownstream(ifname, prefix, - (boolean success, String errMsg) -> { - results.mSuccess = success; - results.mErrMsg = errMsg; - }); - } catch (RemoteException e) { - record(logmsg, e); - return false; - } - - record(logmsg, results); - return results.mSuccess; + public boolean addDownstream(String ifname, String prefix) { + return mIOffload.addDownstream(ifname, prefix); } /** Remove downstream prefix from offload management process. */ - public boolean removeDownstreamPrefix(String ifname, String prefix) { - final String logmsg = String.format("removeDownstreamPrefix(%s, %s)", ifname, prefix); - - final CbResults results = new CbResults(); - try { - mOffloadControl.removeDownstream(ifname, prefix, - (boolean success, String errMsg) -> { - results.mSuccess = success; - results.mErrMsg = errMsg; - }); - } catch (RemoteException e) { - record(logmsg, e); - return false; - } - - record(logmsg, results); - return results.mSuccess; - } - - private void record(String msg, Throwable t) { - mLog.e(msg + YIELDS + "exception: " + t); - } - - private void record(String msg, CbResults results) { - final String logmsg = msg + YIELDS + results; - if (!results.mSuccess) { - mLog.e(logmsg); - } else { - mLog.log(logmsg); - } - } - - private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub { - public final Handler handler; - public final ControlCallback controlCb; - public final SharedLog log; - private final int mOffloadControlVersion; - - TetheringOffloadCallback( - Handler h, ControlCallback cb, SharedLog sharedLog, int offloadControlVersion) { - handler = h; - controlCb = cb; - log = sharedLog; - this.mOffloadControlVersion = offloadControlVersion; - } - - private void handleOnEvent(int event) { - switch (event) { - case OffloadCallbackEvent.OFFLOAD_STARTED: - controlCb.onStarted(); - break; - case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR: - controlCb.onStoppedError(); - break; - case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED: - controlCb.onStoppedUnsupported(); - break; - case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE: - controlCb.onSupportAvailable(); - break; - case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED: - controlCb.onStoppedLimitReached(); - break; - case android.hardware.tetheroffload.control - .V1_1.OffloadCallbackEvent.OFFLOAD_WARNING_REACHED: - controlCb.onWarningReached(); - break; - default: - log.e("Unsupported OffloadCallbackEvent: " + event); - } - } - - @Override - public void onEvent(int event) { - // The implementation should never call onEvent()) if the event is already reported - // through newer callback. - if (mOffloadControlVersion > OFFLOAD_HAL_VERSION_1_0) { - Log.wtf(TAG, "onEvent(" + event + ") fired on HAL " - + halVerToString(mOffloadControlVersion)); - } - handler.post(() -> { - handleOnEvent(event); - }); - } - - @Override - public void onEvent_1_1(int event) { - if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_1_1) { - Log.wtf(TAG, "onEvent_1_1(" + event + ") fired on HAL " - + halVerToString(mOffloadControlVersion)); - return; - } - handler.post(() -> { - handleOnEvent(event); - }); - } - - @Override - public void updateTimeout(NatTimeoutUpdate params) { - handler.post(() -> { - controlCb.onNatTimeoutUpdate( - networkProtocolToOsConstant(params.proto), - params.src.addr, uint16(params.src.port), - params.dst.addr, uint16(params.dst.port)); - }); - } - } - - private static int networkProtocolToOsConstant(int proto) { - switch (proto) { - case NetworkProtocol.TCP: return OsConstants.IPPROTO_TCP; - case NetworkProtocol.UDP: return OsConstants.IPPROTO_UDP; - default: - // The caller checks this value and will log an error. Just make - // sure it won't collide with valid OsContants.IPPROTO_* values. - return -Math.abs(proto); - } - } - - private static class CbResults { - boolean mSuccess; - String mErrMsg; - - @Override - public String toString() { - if (mSuccess) { - return "ok"; - } else { - return "fail: " + mErrMsg; - } - } + public boolean removeDownstream(String ifname, String prefix) { + return mIOffload.removeDownstream(ifname, prefix); } }
diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index 41a10ae..6c0ca82 100644 --- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -16,6 +16,8 @@ package com.android.networkstack.tethering; import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_WIFI_P2P; @@ -34,7 +36,6 @@ import android.net.ip.IpServer; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.SparseArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -77,7 +78,7 @@ private final ConnectivityManager mConnectivityMgr; private final TetheringConfiguration mConfig; // keyed by downstream type(TetheringManager.TETHERING_*). - private final SparseArray<LinkAddress> mCachedAddresses; + private final ArrayMap<AddressKey, LinkAddress> mCachedAddresses; public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { mDownstreams = new ArraySet<>(); @@ -85,10 +86,12 @@ mConnectivityMgr = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE); mConfig = config; - mCachedAddresses = new SparseArray<>(); + mCachedAddresses = new ArrayMap<AddressKey, LinkAddress>(); // Reserved static addresses for bluetooth and wifi p2p. - mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS)); - mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS)); + mCachedAddresses.put(new AddressKey(TETHERING_BLUETOOTH, CONNECTIVITY_SCOPE_GLOBAL), + new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS)); + mCachedAddresses.put(new AddressKey(TETHERING_WIFI_P2P, CONNECTIVITY_SCOPE_LOCAL), + new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS)); mTetheringPrefixes = new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16"), new IpPrefix("172.16.0.0/12"), new IpPrefix("10.0.0.0/8"))); @@ -166,16 +169,18 @@ * returns null if there is no available address. */ @Nullable - public LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { + public LinkAddress requestDownstreamAddress(final IpServer ipServer, final int scope, + boolean useLastAddress) { if (mConfig.shouldEnableWifiP2pDedicatedIp() && ipServer.interfaceType() == TETHERING_WIFI_P2P) { return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS); } + final AddressKey addrKey = new AddressKey(ipServer.interfaceType(), scope); // This ensures that tethering isn't started on 2 different interfaces with the same type. // Once tethering could support multiple interface with the same type, // TetheringSoftApCallback would need to handle it among others. - final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType()); + final LinkAddress cachedAddress = mCachedAddresses.get(addrKey); if (useLastAddress && cachedAddress != null && !isConflictWithUpstream(asIpPrefix(cachedAddress))) { mDownstreams.add(ipServer); @@ -186,7 +191,7 @@ final LinkAddress newAddress = chooseDownstreamAddress(prefixRange); if (newAddress != null) { mDownstreams.add(ipServer); - mCachedAddresses.put(ipServer.interfaceType(), newAddress); + mCachedAddresses.put(addrKey, newAddress); return newAddress; } } @@ -384,6 +389,34 @@ return asIpPrefix(address); } + private static class AddressKey { + private final int mTetheringType; + private final int mScope; + + private AddressKey(int type, int scope) { + mTetheringType = type; + mScope = scope; + } + + @Override + public int hashCode() { + return (mTetheringType << 16) + mScope; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof AddressKey)) return false; + final AddressKey other = (AddressKey) obj; + + return mTetheringType == other.mTetheringType && mScope == other.mScope; + } + + @Override + public String toString() { + return "AddressKey(" + mTetheringType + ", " + mScope + ")"; + } + } + void dump(final IndentingPrintWriter pw) { pw.println("mTetheringPrefixes:"); pw.increaseIndent();
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index f0dd030..e5f644e 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -58,6 +58,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.IFACE_IP_MODE_UNSPECIFIED; +import static android.net.wifi.WifiManager.SoftApCallback; import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -88,7 +89,6 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; -import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.TetherStatesParcel; import android.net.TetheredClient; @@ -146,6 +146,7 @@ import com.android.networkstack.tethering.util.PrefixUtils; import com.android.networkstack.tethering.util.TetheringUtils; import com.android.networkstack.tethering.util.VersionedBroadcastListener; +import com.android.networkstack.tethering.wear.WearableConnectionManager; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -257,6 +258,7 @@ private final BpfCoordinator mBpfCoordinator; private final PrivateAddressCoordinator mPrivateAddressCoordinator; private final TetheringMetrics mTetheringMetrics; + private final WearableConnectionManager mWearableConnectionManager; private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID; private volatile TetheringConfiguration mConfig; @@ -393,6 +395,12 @@ } }); + if (SdkLevel.isAtLeastT() && mConfig.isWearTetheringEnabled()) { + mWearableConnectionManager = mDeps.getWearableConnectionManager(mContext); + } else { + mWearableConnectionManager = null; + } + startStateMachineUpdaters(); } @@ -472,15 +480,15 @@ mStateReceiver, noUpstreamFilter, PERMISSION_MAINLINE_NETWORK_STACK, mHandler); final WifiManager wifiManager = getWifiManager(); - TetheringSoftApCallback softApCallback = new TetheringSoftApCallback(); if (wifiManager != null) { - wifiManager.registerSoftApCallback(mExecutor, softApCallback); - } - if (SdkLevel.isAtLeastT() && wifiManager != null) { - // Although WifiManager#registerLocalOnlyHotspotSoftApCallback document that it need - // NEARBY_WIFI_DEVICES permission, but actually a caller who have NETWORK_STACK - // or MAINLINE_NETWORK_STACK permission would also able to use this API. - wifiManager.registerLocalOnlyHotspotSoftApCallback(mExecutor, softApCallback); + wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback()); + if (SdkLevel.isAtLeastT()) { + // Although WifiManager#registerLocalOnlyHotspotSoftApCallback document that it need + // NEARBY_WIFI_DEVICES permission, but actually a caller who have NETWORK_STACK + // or MAINLINE_NETWORK_STACK permission can also use this API. + wifiManager.registerLocalOnlyHotspotSoftApCallback(mExecutor, + new LocalOnlyHotspotCallback()); + } } startTrackDefaultNetwork(); @@ -566,26 +574,17 @@ } } - private class TetheringSoftApCallback implements WifiManager.SoftApCallback { - // TODO: Remove onStateChanged override when this method has default on - // WifiManager#SoftApCallback interface. - // Wifi listener for state change of the soft AP - @Override - public void onStateChanged(final int state, final int failureReason) { - // Nothing - } - - // Called by wifi when the number of soft AP clients changed. - // Currently multiple softAp would not behave well in PrivateAddressCoordinator - // (where it gets the address from cache), it ensure tethering only support one ipServer for - // TETHERING_WIFI. Once tethering support multiple softAp enabled simultaneously, - // onConnectedClientsChanged should also be updated to support tracking different softAp's - // clients individually. - // TODO: Add wtf log and have check to reject request duplicated type with different - // interface. + private class TetheringSoftApCallback implements SoftApCallback { @Override public void onConnectedClientsChanged(final List<WifiClient> clients) { - updateConnectedClients(clients); + updateConnectedClients(clients, null); + } + } + + private class LocalOnlyHotspotCallback implements SoftApCallback { + @Override + public void onConnectedClientsChanged(final List<WifiClient> clients) { + updateConnectedClients(null, clients); } } @@ -1195,6 +1194,9 @@ } private void handleConnectivityAction(Intent intent) { + // CONNECTIVITY_ACTION is not handled since U+ device. + if (SdkLevel.isAtLeastU()) return; + final NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO); if (networkInfo == null @@ -1845,9 +1847,13 @@ final Network newUpstream = (ns != null) ? ns.network : null; if (mTetherUpstream != newUpstream) { mTetherUpstream = newUpstream; - mUpstreamNetworkMonitor.setCurrentUpstream(mTetherUpstream); - reportUpstreamChanged(ns); + reportUpstreamChanged(mTetherUpstream); + // Need to notify capabilities change after upstream network changed because new + // network's capabilities should be checked every time. + mNotificationUpdater.onUpstreamCapabilitiesChanged( + (ns != null) ? ns.networkCapabilities : null); } + mTetheringMetrics.maybeUpdateUpstreamType(ns); } protected void setUpstreamNetwork(UpstreamNetworkState ns) { @@ -1954,7 +1960,7 @@ mIPv6TetheringCoordinator.removeActiveDownstream(who); mOffload.excludeDownstreamInterface(who.interfaceName()); mForwardedDownstreams.remove(who); - updateConnectedClients(null /* wifiClients */); + maybeDhcpLeasesChanged(); // If this is a Wi-Fi interface, tell WifiManager of any errors // or the inactive serving state. @@ -2026,6 +2032,11 @@ // broadcasts that result in being passed a // TetherMainSM.CMD_UPSTREAM_CHANGED. handleNewUpstreamNetworkState(null); + + if (SdkLevel.isAtLeastU()) { + // Need to try DUN immediately if Wi-Fi goes down. + chooseUpstreamType(true); + } break; default: mLog.e("Unknown arg1 value: " + arg1); @@ -2069,8 +2080,10 @@ if (mTetherUpstream != null) { mTetherUpstream = null; reportUpstreamChanged(null); + mNotificationUpdater.onUpstreamCapabilitiesChanged(null); } mBpfCoordinator.stopPolling(); + mTetheringMetrics.cleanup(); } private boolean updateUpstreamWanted() { @@ -2399,6 +2412,9 @@ /** Unregister tethering event callback */ void unregisterTetheringEventCallback(ITetheringEventCallback callback) { + if (callback == null) { + throw new NullPointerException(); + } mHandler.post(() -> { mTetheringEventCallbacks.unregister(callback); }); @@ -2420,10 +2436,8 @@ } } - private void reportUpstreamChanged(UpstreamNetworkState ns) { + private void reportUpstreamChanged(final Network network) { final int length = mTetheringEventCallbacks.beginBroadcast(); - final Network network = (ns != null) ? ns.network : null; - final NetworkCapabilities capabilities = (ns != null) ? ns.networkCapabilities : null; try { for (int i = 0; i < length; i++) { try { @@ -2435,9 +2449,6 @@ } finally { mTetheringEventCallbacks.finishBroadcast(); } - // Need to notify capabilities change after upstream network changed because new network's - // capabilities should be checked every time. - mNotificationUpdater.onUpstreamCapabilitiesChanged(capabilities); } private void reportConfigurationChanged(TetheringConfigurationParcel config) { @@ -2638,6 +2649,13 @@ mPrivateAddressCoordinator.dump(pw); pw.decreaseIndent(); + if (mWearableConnectionManager != null) { + pw.println("WearableConnectionManager:"); + pw.increaseIndent(); + mWearableConnectionManager.dump(pw); + pw.decreaseIndent(); + } + pw.println("Log:"); pw.increaseIndent(); if (CollectionUtils.contains(args, "--short")) { @@ -2684,9 +2702,15 @@ if (e != null) throw e; } - private void updateConnectedClients(final List<WifiClient> wifiClients) { + private void maybeDhcpLeasesChanged() { + // null means wifi clients did not change. + updateConnectedClients(null, null); + } + + private void updateConnectedClients(final List<WifiClient> wifiClients, + final List<WifiClient> localOnlyClients) { if (mConnectedClientsTracker.updateConnectedClients(mTetherMainSM.getAllDownstreams(), - wifiClients)) { + wifiClients, localOnlyClients)) { reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients()); } } @@ -2705,7 +2729,7 @@ @Override public void dhcpLeasesChanged() { - updateConnectedClients(null /* wifiClients */); + maybeDhcpLeasesChanged(); } @Override
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 903de9d..b0aa668 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -39,6 +39,8 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; +import androidx.annotation.NonNull; + import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.DeviceConfigUtils; @@ -123,6 +125,13 @@ */ public static final String TETHER_FORCE_USB_FUNCTIONS = "tether_force_usb_functions"; + + /** + * Experiment flag to enable TETHERING_WEAR. + */ + public static final String TETHER_ENABLE_WEAR_TETHERING = + "tether_enable_wear_tethering"; + /** * Default value that used to periodic polls tether offload stats from tethering offload HAL * to make the data warnings work. @@ -151,6 +160,8 @@ public final int activeDataSubId; + private final Dependencies mDeps; + private final boolean mEnableLegacyDhcpServer; private final int mOffloadPollInterval; // TODO: Add to TetheringConfigurationParcel if required. @@ -158,10 +169,36 @@ private final boolean mEnableWifiP2pDedicatedIp; private final int mP2pLeasesSubnetPrefixLength; + private final boolean mEnableWearTethering; + private final int mUsbTetheringFunction; protected final ContentResolver mContentResolver; - public TetheringConfiguration(Context ctx, SharedLog log, int id) { + /** + * A class wrapping dependencies of {@link TetheringConfiguration}, useful for testing. + */ + @VisibleForTesting + public static class Dependencies { + boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, + @NonNull String name, @NonNull String moduleName, boolean defaultEnabled) { + return DeviceConfigUtils.isFeatureEnabled(context, namespace, name, + moduleName, defaultEnabled); + } + + boolean getDeviceConfigBoolean(@NonNull String namespace, @NonNull String name, + boolean defaultValue) { + return DeviceConfig.getBoolean(namespace, name, defaultValue); + } + } + + public TetheringConfiguration(@NonNull Context ctx, @NonNull SharedLog log, int id) { + this(ctx, log, id, new Dependencies()); + } + + @VisibleForTesting + public TetheringConfiguration(@NonNull Context ctx, @NonNull SharedLog log, int id, + @NonNull Dependencies deps) { + mDeps = deps; final SharedLog configLog = log.forSubComponent("config"); activeDataSubId = id; @@ -234,6 +271,8 @@ mP2pLeasesSubnetPrefixLength = getP2pLeasesSubnetPrefixLengthFromRes(res, configLog); + mEnableWearTethering = shouldEnableWearTethering(ctx); + configLog.log(toString()); } @@ -317,6 +356,11 @@ return mP2pLeasesSubnetPrefixLength; } + /** Returns true if wearable device tethering is enabled. */ + public boolean isWearTetheringEnabled() { + return mEnableWearTethering; + } + /** Does the dumping.*/ public void dump(PrintWriter pw) { pw.print("activeDataSubId: "); @@ -362,6 +406,9 @@ pw.print("p2pLeasesSubnetPrefixLength: "); pw.println(mP2pLeasesSubnetPrefixLength); + pw.print("enableWearTethering: "); + pw.println(mEnableWearTethering); + pw.print("mUsbTetheringFunction: "); pw.println(isUsingNcm() ? "NCM" : "RNDIS"); } @@ -387,6 +434,7 @@ isCarrierConfigAffirmsEntitlementCheckRequired)); sj.add(String.format("enableBpfOffload:%s", mEnableBpfOffload)); sj.add(String.format("enableLegacyDhcpServer:%s", mEnableLegacyDhcpServer)); + sj.add(String.format("enableWearTethering:%s", mEnableWearTethering)); return String.format("TetheringConfiguration{%s}", sj.toString()); } @@ -557,18 +605,13 @@ TETHER_ENABLE_LEGACY_DHCP_SERVER, false /** defaultValue */); } - private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) { - // Due to the limitation of static mock for testing, using #getDeviceConfigProperty instead - // of DeviceConfig#getBoolean. If using #getBoolean here, the test can't know that the - // returned boolean value comes from device config or default value (because of null - // property string). See the test case testBpfOffload{*} in TetheringConfigurationTest.java. - final String value = getDeviceConfigProperty(name); - return value != null ? Boolean.parseBoolean(value) : defaultValue; + private boolean shouldEnableWearTethering(Context context) { + return SdkLevel.isAtLeastT() + && isTetheringFeatureEnabled(context, TETHER_ENABLE_WEAR_TETHERING); } - @VisibleForTesting - protected String getDeviceConfigProperty(String name) { - return DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, name); + private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) { + return mDeps.getDeviceConfigBoolean(NAMESPACE_CONNECTIVITY, name, defaultValue); } /** @@ -585,10 +628,9 @@ return isFeatureEnabled(ctx, NAMESPACE_TETHERING, featureVersionFlag); } - @VisibleForTesting - protected boolean isFeatureEnabled(Context ctx, String namespace, String featureVersionFlag) { - return DeviceConfigUtils.isFeatureEnabled(ctx, namespace, featureVersionFlag, - TETHERING_MODULE_NAME, false /* defaultEnabled */); + private boolean isFeatureEnabled(Context ctx, String namespace, String featureVersionFlag) { + return mDeps.isFeatureEnabled(ctx, namespace, featureVersionFlag, TETHERING_MODULE_NAME, + false /* defaultEnabled */); } private Resources getResources(Context ctx, int subId) {
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index 611d1cf..741a5c5 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
@@ -22,6 +22,7 @@ import android.content.Context; import android.net.INetd; import android.net.ip.IpServer; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -29,12 +30,14 @@ import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import com.android.internal.util.StateMachine; import com.android.net.module.util.SharedLog; import com.android.networkstack.apishim.BluetoothPanShimImpl; import com.android.networkstack.apishim.common.BluetoothPanShim; import com.android.networkstack.tethering.metrics.TetheringMetrics; +import com.android.networkstack.tethering.wear.WearableConnectionManager; import java.util.ArrayList; @@ -171,4 +174,12 @@ public TetheringMetrics getTetheringMetrics() { return new TetheringMetrics(); } + + /** + * Returns the implementation of WearableConnectionManager. + */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public WearableConnectionManager getWearableConnectionManager(Context ctx) { + return new WearableConnectionManager(ctx); + } }
diff --git a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java index 16c031b..ac2aa7b 100644 --- a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java +++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
@@ -133,8 +133,6 @@ private boolean mIsDefaultCellularUpstream; // The current system default network (not really used yet). private Network mDefaultInternetNetwork; - // The current upstream network used for tethering. - private Network mTetheringUpstreamNetwork; private boolean mPreferTestNetworks; public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) { @@ -191,7 +189,6 @@ releaseCallback(mListenAllCallback); mListenAllCallback = null; - mTetheringUpstreamNetwork = null; mNetworkMap.clear(); } @@ -342,11 +339,6 @@ return findFirstDunNetwork(mNetworkMap.values()); } - /** Tell UpstreamNetworkMonitor which network is the current upstream of tethering. */ - public void setCurrentUpstream(Network upstream) { - mTetheringUpstreamNetwork = upstream; - } - /** Return local prefixes. */ public Set<IpPrefix> getLocalPrefixes() { return (Set<IpPrefix>) mLocalPrefixes.clone();
diff --git a/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java b/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java index ffcea4e..814afcd 100644 --- a/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java +++ b/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java
@@ -16,6 +16,12 @@ package com.android.networkstack.tethering.metrics; +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; +import static android.net.NetworkCapabilities.TRANSPORT_LOWPAN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_NCM; @@ -39,6 +45,8 @@ import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED; import static android.net.TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; +import android.annotation.Nullable; +import android.net.NetworkCapabilities; import android.stats.connectivity.DownstreamType; import android.stats.connectivity.ErrorCode; import android.stats.connectivity.UpstreamType; @@ -49,6 +57,11 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import com.android.networkstack.tethering.UpstreamNetworkState; + +import java.util.ArrayList; +import java.util.Arrays; + /** * Collection of utilities for tethering metrics. * @@ -66,21 +79,58 @@ private static final String SYSTEMUI_PKG_NAME = "com.android.systemui"; private static final String GMS_PKG_NAME = "com.google.android.gms"; private final SparseArray<NetworkTetheringReported.Builder> mBuilderMap = new SparseArray<>(); + private final SparseArray<Long> mDownstreamStartTime = new SparseArray<Long>(); + private final ArrayList<RecordUpstreamEvent> mUpstreamEventList = new ArrayList<>(); + private UpstreamType mCurrentUpstream = null; + private Long mCurrentUpStreamStartTime = 0L; - /** Update Tethering stats about caller's package name and downstream type. */ - public void createBuilder(final int downstreamType, final String callerPkg) { - NetworkTetheringReported.Builder statsBuilder = - NetworkTetheringReported.newBuilder(); - statsBuilder.setDownstreamType(downstreamTypeToEnum(downstreamType)) - .setUserType(userTypeToEnum(callerPkg)) - .setUpstreamType(UpstreamType.UT_UNKNOWN) - .setErrorCode(ErrorCode.EC_NO_ERROR) - .setUpstreamEvents(UpstreamEvents.newBuilder()) - .setDurationMillis(0); - mBuilderMap.put(downstreamType, statsBuilder); + + /** + * Return the current system time in milliseconds. + * @return the current system time in milliseconds. + */ + public long timeNow() { + return System.currentTimeMillis(); } - /** Update error code of given downstreamType. */ + private static class RecordUpstreamEvent { + public final long mStartTime; + public final long mStopTime; + public final UpstreamType mUpstreamType; + + RecordUpstreamEvent(final long startTime, final long stopTime, + final UpstreamType upstream) { + mStartTime = startTime; + mStopTime = stopTime; + mUpstreamType = upstream; + } + } + + /** + * Creates a |NetworkTetheringReported.Builder| object to update the tethering stats for the + * specified downstream type and caller's package name. Initializes the upstream events, error + * code, and duration to default values. Sets the start time for the downstream type in the + * |mDownstreamStartTime| map. + * @param downstreamType The type of downstream connection (e.g. Wifi, USB, Bluetooth). + * @param callerPkg The package name of the caller. + */ + public void createBuilder(final int downstreamType, final String callerPkg) { + NetworkTetheringReported.Builder statsBuilder = NetworkTetheringReported.newBuilder() + .setDownstreamType(downstreamTypeToEnum(downstreamType)) + .setUserType(userTypeToEnum(callerPkg)) + .setUpstreamType(UpstreamType.UT_UNKNOWN) + .setErrorCode(ErrorCode.EC_NO_ERROR) + .setUpstreamEvents(UpstreamEvents.newBuilder()) + .setDurationMillis(0); + mBuilderMap.put(downstreamType, statsBuilder); + mDownstreamStartTime.put(downstreamType, timeNow()); + } + + /** + * Update the error code of the given downstream type in the Tethering stats. + * @param downstreamType The downstream type whose error code to update. + * @param errCode The error code to set. + */ public void updateErrorCode(final int downstreamType, final int errCode) { NetworkTetheringReported.Builder statsBuilder = mBuilderMap.get(downstreamType); if (statsBuilder == null) { @@ -90,38 +140,150 @@ statsBuilder.setErrorCode(errorCodeToEnum(errCode)); } - /** Remove Tethering stats. - * If Tethering stats is ready to write then write it before removing. + /** + * Update the list of upstream types and their duration whenever the current upstream type + * changes. + * @param ns The UpstreamNetworkState object representing the current upstream network state. + */ + public void maybeUpdateUpstreamType(@Nullable final UpstreamNetworkState ns) { + UpstreamType upstream = transportTypeToUpstreamTypeEnum(ns); + if (upstream.equals(mCurrentUpstream)) return; + + final long newTime = timeNow(); + if (mCurrentUpstream != null) { + mUpstreamEventList.add(new RecordUpstreamEvent(mCurrentUpStreamStartTime, newTime, + mCurrentUpstream)); + } + mCurrentUpstream = upstream; + mCurrentUpStreamStartTime = newTime; + } + + /** + * Updates the upstream events builder with a new upstream event. + * @param upstreamEventsBuilder the builder for the upstream events list + * @param start the start time of the upstream event + * @param stop the stop time of the upstream event + * @param upstream the type of upstream type (e.g. Wifi, Cellular, Bluetooth, ...) + */ + private void addUpstreamEvent(final UpstreamEvents.Builder upstreamEventsBuilder, + final long start, final long stop, @Nullable final UpstreamType upstream, + final long txBytes, final long rxBytes) { + final UpstreamEvent.Builder upstreamEventBuilder = UpstreamEvent.newBuilder() + .setUpstreamType(upstream == null ? UpstreamType.UT_NO_NETWORK : upstream) + .setDurationMillis(stop - start) + .setTxBytes(txBytes) + .setRxBytes(rxBytes); + upstreamEventsBuilder.addUpstreamEvent(upstreamEventBuilder); + } + + /** + * Updates the |NetworkTetheringReported.Builder| with relevant upstream events associated with + * the downstream event identified by the given downstream start time. + * + * This method iterates through the list of upstream events and adds any relevant events to a + * |UpstreamEvents.Builder|. Upstream events are considered relevant if their stop time is + * greater than or equal to the given downstream start time. The method also adds the last + * upstream event that occurred up until the current time. + * + * The resulting |UpstreamEvents.Builder| is then added to the + * |NetworkTetheringReported.Builder|, along with the duration of the downstream event + * (i.e., stop time minus downstream start time). + * + * @param statsBuilder the builder for the NetworkTetheringReported message + * @param downstreamStartTime the start time of the downstream event to find relevant upstream + * events for + */ + private void noteDownstreamStopped(final NetworkTetheringReported.Builder statsBuilder, + final long downstreamStartTime) { + UpstreamEvents.Builder upstreamEventsBuilder = UpstreamEvents.newBuilder(); + + for (RecordUpstreamEvent event : mUpstreamEventList) { + if (downstreamStartTime > event.mStopTime) continue; + + final long startTime = Math.max(downstreamStartTime, event.mStartTime); + // Handle completed upstream events. + addUpstreamEvent(upstreamEventsBuilder, startTime, event.mStopTime, + event.mUpstreamType, 0L /* txBytes */, 0L /* rxBytes */); + } + final long startTime = Math.max(downstreamStartTime, mCurrentUpStreamStartTime); + final long stopTime = timeNow(); + // Handle the last upstream event. + addUpstreamEvent(upstreamEventsBuilder, startTime, stopTime, mCurrentUpstream, + 0L /* txBytes */, 0L /* rxBytes */); + statsBuilder.setUpstreamEvents(upstreamEventsBuilder); + statsBuilder.setDurationMillis(stopTime - downstreamStartTime); + } + + /** + * Removes tethering statistics for the given downstream type. If there are any stats to write + * for the downstream event associated with the type, they are written before removing the + * statistics. + * + * If the given downstream type does not exist in the map, an error message is logged and the + * method returns without doing anything. + * + * @param downstreamType the type of downstream event to remove statistics for */ public void sendReport(final int downstreamType) { - final NetworkTetheringReported.Builder statsBuilder = - mBuilderMap.get(downstreamType); + final NetworkTetheringReported.Builder statsBuilder = mBuilderMap.get(downstreamType); if (statsBuilder == null) { Log.e(TAG, "Given downstreamType does not exist, this is a bug!"); return; } + + noteDownstreamStopped(statsBuilder, mDownstreamStartTime.get(downstreamType)); write(statsBuilder.build()); + mBuilderMap.remove(downstreamType); + mDownstreamStartTime.remove(downstreamType); } - /** Collect Tethering stats and write metrics data to statsd pipeline. */ + /** + * Collects tethering statistics and writes them to the statsd pipeline. This method takes in a + * NetworkTetheringReported object, extracts its fields and uses them to write statistics data + * to the statsd pipeline. + * + * @param reported a NetworkTetheringReported object containing statistics to write + */ @VisibleForTesting public void write(@NonNull final NetworkTetheringReported reported) { - TetheringStatsLog.write(TetheringStatsLog.NETWORK_TETHERING_REPORTED, + final byte[] upstreamEvents = reported.getUpstreamEvents().toByteArray(); + + TetheringStatsLog.write( + TetheringStatsLog.NETWORK_TETHERING_REPORTED, reported.getErrorCode().getNumber(), reported.getDownstreamType().getNumber(), reported.getUpstreamType().getNumber(), reported.getUserType().getNumber(), - null, 0); + upstreamEvents, + reported.getDurationMillis()); if (DBG) { - Log.d(TAG, "Write errorCode: " + reported.getErrorCode().getNumber() - + ", downstreamType: " + reported.getDownstreamType().getNumber() - + ", upstreamType: " + reported.getUpstreamType().getNumber() - + ", userType: " + reported.getUserType().getNumber()); + Log.d( + TAG, + "Write errorCode: " + + reported.getErrorCode().getNumber() + + ", downstreamType: " + + reported.getDownstreamType().getNumber() + + ", upstreamType: " + + reported.getUpstreamType().getNumber() + + ", userType: " + + reported.getUserType().getNumber() + + ", upstreamTypes: " + + Arrays.toString(upstreamEvents) + + ", durationMillis: " + + reported.getDurationMillis()); } } - /** Map {@link TetheringType} to {@link DownstreamType} */ + /** + * Cleans up the variables related to upstream events when tethering is turned off. + */ + public void cleanup() { + mUpstreamEventList.clear(); + mCurrentUpstream = null; + mCurrentUpStreamStartTime = 0L; + } + private DownstreamType downstreamTypeToEnum(final int ifaceType) { switch(ifaceType) { case TETHERING_WIFI: @@ -141,7 +303,6 @@ } } - /** Map {@link StartTetheringError} to {@link ErrorCode} */ private ErrorCode errorCodeToEnum(final int lastError) { switch(lastError) { case TETHER_ERROR_NO_ERROR: @@ -181,7 +342,6 @@ } } - /** Map callerPkg to {@link UserType} */ private UserType userTypeToEnum(final String callerPkg) { if (callerPkg.equals(SETTINGS_PKG_NAME)) { return UserType.USER_SETTINGS; @@ -193,4 +353,25 @@ return UserType.USER_UNKNOWN; } } + + private UpstreamType transportTypeToUpstreamTypeEnum(final UpstreamNetworkState ns) { + final NetworkCapabilities nc = (ns != null) ? ns.networkCapabilities : null; + if (nc == null) return UpstreamType.UT_NO_NETWORK; + + final int typeCount = nc.getTransportTypes().length; + // It's possible for a VCN network to be mapped to UT_UNKNOWN, as it may consist of both + // Wi-Fi and cellular transport. + // TODO: It's necessary to define a new upstream type for VCN, which can be identified by + // NET_CAPABILITY_NOT_VCN_MANAGED. + if (typeCount > 1) return UpstreamType.UT_UNKNOWN; + + if (nc.hasTransport(TRANSPORT_CELLULAR)) return UpstreamType.UT_CELLULAR; + if (nc.hasTransport(TRANSPORT_WIFI)) return UpstreamType.UT_WIFI; + if (nc.hasTransport(TRANSPORT_BLUETOOTH)) return UpstreamType.UT_BLUETOOTH; + if (nc.hasTransport(TRANSPORT_ETHERNET)) return UpstreamType.UT_ETHERNET; + if (nc.hasTransport(TRANSPORT_WIFI_AWARE)) return UpstreamType.UT_WIFI_AWARE; + if (nc.hasTransport(TRANSPORT_LOWPAN)) return UpstreamType.UT_LOWPAN; + + return UpstreamType.UT_UNKNOWN; + } }
diff --git a/Tethering/src/com/android/networkstack/tethering/metrics/stats.proto b/Tethering/src/com/android/networkstack/tethering/metrics/stats.proto index 27f2126..b276389 100644 --- a/Tethering/src/com/android/networkstack/tethering/metrics/stats.proto +++ b/Tethering/src/com/android/networkstack/tethering/metrics/stats.proto
@@ -21,13 +21,21 @@ import "frameworks/proto_logging/stats/enums/stats/connectivity/tethering.proto"; -// Logs each upstream for a successful switch over +/** + * Represents an event that logs information about a successful switch to an upstream network. + */ message UpstreamEvent { - // Transport type of upstream network + // Indicates the transport type of network. optional .android.stats.connectivity.UpstreamType upstream_type = 1; - // A time period that an upstream continued + // The duration of network usage. optional int64 duration_millis = 2; + + // The amount of data received from tethered clients. + optional int64 tx_bytes = 3; + + // The amount of data received from remote. + optional int64 rx_bytes = 4; } message UpstreamEvents {
diff --git a/Tethering/src/com/android/networkstack/tethering/wear/CompanionDeviceManagerProxy.java b/Tethering/src/com/android/networkstack/tethering/wear/CompanionDeviceManagerProxy.java new file mode 100644 index 0000000..e94febb --- /dev/null +++ b/Tethering/src/com/android/networkstack/tethering/wear/CompanionDeviceManagerProxy.java
@@ -0,0 +1,55 @@ +/* + * 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.networkstack.tethering.wear; + +import android.companion.AssociationInfo; +import android.companion.CompanionDeviceManager; +import android.content.Context; +import android.net.connectivity.TiramisuConnectivityInternalApiUtil; +import android.net.wear.ICompanionDeviceManagerProxy; +import android.os.Build; +import android.os.RemoteException; + +import androidx.annotation.RequiresApi; + +import java.util.List; + +/** + * A proxy for {@link android.companion.CompanionDeviceManager}, allowing Tethering to call it with + * a different set of permissions. + * @hide + */ +public class CompanionDeviceManagerProxy { + private final ICompanionDeviceManagerProxy mService; + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public CompanionDeviceManagerProxy(Context context) { + mService = ICompanionDeviceManagerProxy.Stub.asInterface( + TiramisuConnectivityInternalApiUtil.getCompanionDeviceManagerProxyService(context)); + } + + /** + * @see CompanionDeviceManager#getAllAssociations() + */ + public List<AssociationInfo> getAllAssociations() { + try { + return mService.getAllAssociations(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +}
diff --git a/Tethering/src/com/android/networkstack/tethering/wear/WearableConnectionManager.java b/Tethering/src/com/android/networkstack/tethering/wear/WearableConnectionManager.java new file mode 100644 index 0000000..a1b535a --- /dev/null +++ b/Tethering/src/com/android/networkstack/tethering/wear/WearableConnectionManager.java
@@ -0,0 +1,36 @@ +/* + * 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.networkstack.tethering.wear; + +import android.content.Context; +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import com.android.internal.util.IndentingPrintWriter; + +/** + * Manages Bluetooth connections from Wearable devices. + */ +public class WearableConnectionManager { + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public WearableConnectionManager(Context context) { + } + + public void dump(IndentingPrintWriter pw) { + } +}
diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp index 11e3dc0..5e08aba 100644 --- a/Tethering/tests/integration/Android.bp +++ b/Tethering/tests/integration/Android.bp
@@ -21,8 +21,7 @@ name: "TetheringIntegrationTestsDefaults", defaults: ["framework-connectivity-test-defaults"], srcs: [ - "src/**/*.java", - "src/**/*.kt", + "base/**/*.java", ], min_sdk_version: "30", static_libs: [ @@ -47,6 +46,16 @@ ], } +android_library { + name: "TetheringIntegrationTestsBaseLib", + target_sdk_version: "current", + platform_apis: true, + defaults: ["TetheringIntegrationTestsDefaults"], + visibility: [ + "//packages/modules/Connectivity/Tethering/tests/mts", + ] +} + // Library including tethering integration tests targeting the latest stable SDK. // Use with NetworkStackJarJarRules. android_library { @@ -54,6 +63,9 @@ target_sdk_version: "33", platform_apis: true, defaults: ["TetheringIntegrationTestsDefaults"], + srcs: [ + "src/**/*.java", + ], visibility: [ "//packages/modules/Connectivity/tests/cts/tethering", "//packages/modules/Connectivity/tests:__subpackages__", @@ -68,12 +80,16 @@ target_sdk_version: "current", platform_apis: true, defaults: ["TetheringIntegrationTestsDefaults"], + srcs: [ + "src/**/*.java", + ], visibility: [ "//packages/modules/Connectivity/tests/cts/tethering", "//packages/modules/Connectivity/Tethering/tests/mts", ] } +// TODO: remove because TetheringIntegrationTests has been covered by ConnectivityCoverageTests. android_test { name: "TetheringIntegrationTests", platform_apis: true, @@ -81,6 +97,9 @@ test_suites: [ "device-tests", ], + srcs: [ + "src/**/*.java", + ], compile_multilib: "both", jarjar_rules: ":NetworkStackJarJarRules", }
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java similarity index 97% rename from Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java rename to Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java index 7685981..007bf23 100644 --- a/Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java +++ b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
@@ -72,6 +72,8 @@ import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.PacketBuilder; +import com.android.net.module.util.Struct; +import com.android.net.module.util.structs.Ipv6Header; import com.android.testutils.HandlerUtils; import com.android.testutils.TapPacketReader; import com.android.testutils.TestNetworkTracker; @@ -213,6 +215,13 @@ } } + protected void stopEthernetTethering(final MyTetheringEventCallback callback) { + runAsShell(TETHER_PRIVILEGED, () -> { + mTm.stopTethering(TETHERING_ETHERNET); + maybeUnregisterTetheringEventCallback(callback); + }); + } + protected void cleanUp() throws Exception { setPreferTestNetworks(false); @@ -251,6 +260,7 @@ if (mRunTests) cleanUp(); } finally { mHandlerThread.quitSafely(); + mHandlerThread.join(); mUiAutomation.dropShellPermissionIdentity(); } } @@ -1013,6 +1023,18 @@ return new TetheringTester(mDownstreamReader, mUpstreamReader); } + @NonNull + protected Inet6Address getClatIpv6Address(TetheringTester tester, TetheredDevice tethered) + throws Exception { + // Send an IPv4 UDP packet from client and check that a CLAT translated IPv6 UDP packet can + // be found on upstream interface. Get CLAT IPv6 address from the CLAT translated IPv6 UDP + // packet. + byte[] expectedPacket = probeV4TetheringConnectivity(tester, tethered, true /* is4To6 */); + + // Above has guaranteed that the found packet is an IPv6 packet without ether header. + return Struct.parse(Ipv6Header.class, ByteBuffer.wrap(expectedPacket)).srcIp; + } + protected <T> List<T> toList(T... array) { return Arrays.asList(array); }
diff --git a/Tethering/tests/integration/src/android/net/TetheringTester.java b/Tethering/tests/integration/base/android/net/TetheringTester.java similarity index 98% rename from Tethering/tests/integration/src/android/net/TetheringTester.java rename to Tethering/tests/integration/base/android/net/TetheringTester.java index ae39b24..1c0803e 100644 --- a/Tethering/tests/integration/src/android/net/TetheringTester.java +++ b/Tethering/tests/integration/base/android/net/TetheringTester.java
@@ -628,7 +628,7 @@ return false; } - private void sendUploadPacket(ByteBuffer packet) throws Exception { + public void sendUploadPacket(ByteBuffer packet) throws Exception { mDownstreamReader.sendResponse(packet); } @@ -680,4 +680,12 @@ return verifyPacketNotNull("Download fail", getDownloadPacket(filter)); } + + // Send DHCPDISCOVER to DHCP server to see if DHCP server is still alive to handle + // the upcoming DHCP packets. This method should be only used when we know the DHCP + // server has been created successfully before. + public boolean testDhcpServerAlive(final MacAddress mac) throws Exception { + sendDhcpDiscover(mac.toByteArray()); + return getNextDhcpPacket() != null; + } }
diff --git a/Tethering/tests/integration/src/android/net/CtsEthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java similarity index 77% rename from Tethering/tests/integration/src/android/net/CtsEthernetTetheringTest.java rename to Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index aea6728..4ee5c42 100644 --- a/Tethering/tests/integration/src/android/net/CtsEthernetTetheringTest.java +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -16,7 +16,6 @@ package android.net; -import static android.Manifest.permission.DUMP; import static android.net.InetAddresses.parseNumericAddress; import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; import static android.net.TetheringManager.TETHERING_ETHERNET; @@ -26,7 +25,6 @@ import static android.system.OsConstants.ICMP_ECHO; import static android.system.OsConstants.ICMP_ECHOREPLY; import static android.system.OsConstants.IPPROTO_ICMP; -import static android.system.OsConstants.IPPROTO_UDP; import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA; import static com.android.net.module.util.HexDump.dumpHexString; @@ -39,48 +37,34 @@ import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET; import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN; import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET; -import static com.android.testutils.DeviceInfoUtils.KVersion; -import static com.android.testutils.TestPermissionUtil.runAsShell; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; -import android.content.Context; import android.net.TetheringManager.TetheringRequest; import android.net.TetheringTester.TetheredDevice; import android.os.Build; import android.os.SystemClock; import android.os.SystemProperties; -import android.os.VintfRuntimeInfo; import android.util.Log; -import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.BpfDump; import com.android.net.module.util.Ipv6Utils; import com.android.net.module.util.Struct; -import com.android.net.module.util.bpf.Tether4Key; -import com.android.net.module.util.bpf.Tether4Value; -import com.android.net.module.util.bpf.TetherStatsKey; -import com.android.net.module.util.bpf.TetherStatsValue; import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Icmpv4Header; import com.android.net.module.util.structs.Ipv4Header; -import com.android.net.module.util.structs.Ipv6Header; import com.android.net.module.util.structs.UdpHeader; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; -import com.android.testutils.DeviceInfoUtils; -import com.android.testutils.DumpTestUtils; import com.android.testutils.TapPacketReader; import org.junit.Rule; @@ -96,9 +80,7 @@ import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Random; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -106,34 +88,13 @@ @RunWith(AndroidJUnit4.class) @MediumTest -public class CtsEthernetTetheringTest extends EthernetTetheringTestBase { +public class EthernetTetheringTest extends EthernetTetheringTestBase { @Rule public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); - private static final String TAG = CtsEthernetTetheringTest.class.getSimpleName(); - - private static final int DUMP_POLLING_MAX_RETRY = 100; - private static final int DUMP_POLLING_INTERVAL_MS = 50; - // Kernel treats a confirmed UDP connection which active after two seconds as stream mode. - // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5. - private static final int UDP_STREAM_TS_MS = 2000; - // Give slack time for waiting UDP stream mode because handling conntrack event in user space - // may not in precise time. Used to reduce the flaky rate. - private static final int UDP_STREAM_SLACK_MS = 500; - // Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes. - private static final int RX_UDP_PACKET_SIZE = 30; - private static final int RX_UDP_PACKET_COUNT = 456; - // Per TX UDP packet size: ethhdr (14) + iphdr (20) + udphdr (8) + payload (2) = 44 bytes. - private static final int TX_UDP_PACKET_SIZE = 44; - private static final int TX_UDP_PACKET_COUNT = 123; + private static final String TAG = EthernetTetheringTest.class.getSimpleName(); private static final short DNS_PORT = 53; - - private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap"; - private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats"; - private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4"; - private static final String LINE_DELIMITER = "\\n"; - private static final short ICMPECHO_CODE = 0x0; private static final short ICMPECHO_ID = 0x0; private static final short ICMPECHO_SEQ = 0x0; @@ -403,7 +364,7 @@ // Enable Ethernet tethering and check that it starts. tetheringEventCallback = enableEthernetTethering(iface, null /* any upstream */); } finally { - maybeUnregisterTetheringEventCallback(tetheringEventCallback); + stopEthernetTethering(tetheringEventCallback); } // There is nothing more we can do on a physical interface without connecting an actual // client, which is not possible in this test. @@ -529,7 +490,7 @@ // remote ip public ip private ip // 8.8.8.8:443 <Upstream ip>:9876 <TetheredDevice ip>:9876 // - private void runUdp4Test(boolean verifyBpf) throws Exception { + private void runUdp4Test() throws Exception { final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS)); final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */); @@ -549,123 +510,6 @@ final InetAddress clientIp = tethered.ipv4Addr; sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */); sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */); - - if (verifyBpf) { - // Send second UDP packet in original direction. - // The BPF coordinator only offloads the ASSURED conntrack entry. The "request + reply" - // packets can make status IPS_SEEN_REPLY to be set. Need one more packet to make - // conntrack status IPS_ASSURED_BIT to be set. Note the third packet needs to delay - // 2 seconds because kernel monitors a UDP connection which still alive after 2 seconds - // and apply ASSURED flag. - // See kernel upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5 and - // nf_conntrack_udp_packet in net/netfilter/nf_conntrack_proto_udp.c - Thread.sleep(UDP_STREAM_TS_MS); - sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */); - - // Give a slack time for handling conntrack event in user space. - Thread.sleep(UDP_STREAM_SLACK_MS); - - // [1] Verify IPv4 upstream rule map. - final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump( - Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4); - assertNotNull(upstreamMap); - assertEquals(1, upstreamMap.size()); - - final Map.Entry<Tether4Key, Tether4Value> rule = - upstreamMap.entrySet().iterator().next(); - - final Tether4Key upstream4Key = rule.getKey(); - assertEquals(IPPROTO_UDP, upstream4Key.l4proto); - assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), upstream4Key.src4)); - assertEquals(LOCAL_PORT, upstream4Key.srcPort); - assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), upstream4Key.dst4)); - assertEquals(REMOTE_PORT, upstream4Key.dstPort); - - final Tether4Value upstream4Value = rule.getValue(); - assertTrue(Arrays.equals(tetheringUpstreamIp.getAddress(), - InetAddress.getByAddress(upstream4Value.src46).getAddress())); - assertEquals(LOCAL_PORT, upstream4Value.srcPort); - assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), - InetAddress.getByAddress(upstream4Value.dst46).getAddress())); - assertEquals(REMOTE_PORT, upstream4Value.dstPort); - - // [2] Verify stats map. - // Transmit packets on both direction for verifying stats. Because we only care the - // packet count in stats test, we just reuse the existing packets to increaes - // the packet count on both direction. - - // Send packets on original direction. - for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) { - sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, - false /* is4To6 */); - } - - // Send packets on reply direction. - for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) { - sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */); - } - - // Dump stats map to verify. - final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump( - TetherStatsKey.class, TetherStatsValue.class, DUMPSYS_RAWMAP_ARG_STATS); - assertNotNull(statsMap); - assertEquals(1, statsMap.size()); - - final Map.Entry<TetherStatsKey, TetherStatsValue> stats = - statsMap.entrySet().iterator().next(); - - // TODO: verify the upstream index in TetherStatsKey. - - final TetherStatsValue statsValue = stats.getValue(); - assertEquals(RX_UDP_PACKET_COUNT, statsValue.rxPackets); - assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE, statsValue.rxBytes); - assertEquals(0, statsValue.rxErrors); - assertEquals(TX_UDP_PACKET_COUNT, statsValue.txPackets); - assertEquals(TX_UDP_PACKET_COUNT * TX_UDP_PACKET_SIZE, statsValue.txBytes); - assertEquals(0, statsValue.txErrors); - } - } - - private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) { - final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion); - return current.isInRange(new KVersion(4, 14, 222), new KVersion(4, 19, 0)) - || current.isInRange(new KVersion(4, 19, 176), new KVersion(5, 4, 0)) - || current.isAtLeast(new KVersion(5, 4, 98)); - } - - @Test - public void testIsUdpOffloadSupportedByKernel() throws Exception { - assertFalse(isUdpOffloadSupportedByKernel("4.14.221")); - assertTrue(isUdpOffloadSupportedByKernel("4.14.222")); - assertTrue(isUdpOffloadSupportedByKernel("4.16.0")); - assertTrue(isUdpOffloadSupportedByKernel("4.18.0")); - assertFalse(isUdpOffloadSupportedByKernel("4.19.0")); - - assertFalse(isUdpOffloadSupportedByKernel("4.19.175")); - assertTrue(isUdpOffloadSupportedByKernel("4.19.176")); - assertTrue(isUdpOffloadSupportedByKernel("5.2.0")); - assertTrue(isUdpOffloadSupportedByKernel("5.3.0")); - assertFalse(isUdpOffloadSupportedByKernel("5.4.0")); - - assertFalse(isUdpOffloadSupportedByKernel("5.4.97")); - assertTrue(isUdpOffloadSupportedByKernel("5.4.98")); - assertTrue(isUdpOffloadSupportedByKernel("5.10.0")); - } - - private static void assumeKernelSupportBpfOffloadUdpV4() { - final String kernelVersion = VintfRuntimeInfo.getKernelVersion(); - assumeTrue("Kernel version " + kernelVersion + " doesn't support IPv4 UDP BPF offload", - isUdpOffloadSupportedByKernel(kernelVersion)); - } - - @Test - public void testKernelSupportBpfOffloadUdpV4() throws Exception { - assumeKernelSupportBpfOffloadUdpV4(); - } - - @Test - public void testTetherConfigBpfOffloadEnabled() throws Exception { - assumeTrue(isTetherConfigBpfOffloadEnabled()); } /** @@ -674,85 +518,7 @@ */ @Test public void testTetherUdpV4() throws Exception { - runUdp4Test(false /* verifyBpf */); - } - - /** - * BPF offload IPv4 UDP tethering test. Verify that UDP tethered packets are offloaded by BPF. - * Minimum test requirement: - * 1. S+ device. - * 2. Tethering config enables tethering BPF offload. - * 3. Kernel supports IPv4 UDP BPF offload. See #isUdpOffloadSupportedByKernel. - * - * TODO: consider enabling the test even tethering config disables BPF offload. See b/238288883 - */ - @Test - @IgnoreUpTo(Build.VERSION_CODES.R) - public void testTetherUdpV4_VerifyBpf() throws Exception { - assumeTrue("Tethering config disabled BPF offload", isTetherConfigBpfOffloadEnabled()); - assumeKernelSupportBpfOffloadUdpV4(); - - runUdp4Test(true /* verifyBpf */); - } - - @NonNull - private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap( - Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg) - throws Exception { - final String[] args = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG, mapArg}; - final String rawMapStr = runAsShell(DUMP, () -> - DumpTestUtils.dumpService(Context.TETHERING_SERVICE, args)); - final HashMap<K, V> map = new HashMap<>(); - - for (final String line : rawMapStr.split(LINE_DELIMITER)) { - final Pair<K, V> rule = - BpfDump.fromBase64EncodedString(keyClass, valueClass, line.trim()); - map.put(rule.first, rule.second); - } - return map; - } - - @Nullable - private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump( - Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg) - throws Exception { - for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) { - final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, mapArg); - if (!map.isEmpty()) return map; - - Thread.sleep(DUMP_POLLING_INTERVAL_MS); - } - - fail("Cannot get rules after " + DUMP_POLLING_MAX_RETRY * DUMP_POLLING_INTERVAL_MS + "ms"); - return null; - } - - private boolean isTetherConfigBpfOffloadEnabled() throws Exception { - final String dumpStr = runAsShell(DUMP, () -> - DumpTestUtils.dumpService(Context.TETHERING_SERVICE, "--short")); - - // BPF offload tether config can be overridden by "config_tether_enable_bpf_offload" in - // packages/modules/Connectivity/Tethering/res/values/config.xml. OEM may disable config by - // RRO to override the enabled default value. Get the tethering config via dumpsys. - // $ dumpsys tethering - // mIsBpfEnabled: true - boolean enabled = dumpStr.contains("mIsBpfEnabled: true"); - if (!enabled) { - Log.d(TAG, "BPF offload tether config not enabled: " + dumpStr); - } - return enabled; - } - - @NonNull - private Inet6Address getClatIpv6Address(TetheringTester tester, TetheredDevice tethered) - throws Exception { - // Send an IPv4 UDP packet from client and check that a CLAT translated IPv6 UDP packet can - // be found on upstream interface. Get CLAT IPv6 address from the CLAT translated IPv6 UDP - // packet. - byte[] expectedPacket = probeV4TetheringConnectivity(tester, tethered, true /* is4To6 */); - - // Above has guaranteed that the found packet is an IPv6 packet without ether header. - return Struct.parse(Ipv6Header.class, ByteBuffer.wrap(expectedPacket)).srcIp; + runUdp4Test(); } // Test network topology: @@ -1073,4 +839,41 @@ REMOTE_NAT64_ADDR /* downloadSrcIp */, clatIp6 /* downloadDstIp */, tester, true /* isClat */); } + + private static final byte[] ZeroLengthDhcpPacket = new byte[] { + // scapy.Ether( + // dst="ff:ff:ff:ff:ff:ff") + // scapy.IP( + // dst="255.255.255.255") + // scapy.UDP(sport=68, dport=67) + /* Ethernet Header */ + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xe0, (byte) 0x4f, (byte) 0x43, (byte) 0xe6, (byte) 0xfb, (byte) 0xd2, + (byte) 0x08, (byte) 0x00, + /* Ip header */ + (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x1c, (byte) 0x00, (byte) 0x01, + (byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x11, (byte) 0xb6, (byte) 0x58, + (byte) 0x64, (byte) 0x4f, (byte) 0x60, (byte) 0x29, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, + /* UDP header */ + (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43, + (byte) 0x00, (byte) 0x08, (byte) 0x3a, (byte) 0xdf + }; + + @Test + public void testTetherZeroLengthDhcpPacket() throws Exception { + final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR), + toList(TEST_IP4_DNS)); + tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */); + + // Send a zero-length DHCP packet to upstream DHCP server. + final ByteBuffer packet = ByteBuffer.wrap(ZeroLengthDhcpPacket); + tester.sendUploadPacket(packet); + + // Send DHCPDISCOVER packet from another downstream tethered device to verify that + // upstream DHCP server doesn't close the listening socket and stop reading, then we + // can still receive the next DHCP packet from server. + final MacAddress macAddress = MacAddress.fromString("11:22:33:44:55:66"); + assertTrue(tester.testDhcpServerAlive(macAddress)); + } }
diff --git a/Tethering/tests/mts/Android.bp b/Tethering/tests/mts/Android.bp index ae36499..4f4b03c 100644 --- a/Tethering/tests/mts/Android.bp +++ b/Tethering/tests/mts/Android.bp
@@ -33,6 +33,7 @@ ], static_libs: [ + "TetheringIntegrationTestsBaseLib", "androidx.test.rules", // mockito-target-extended-minus-junit4 used in this lib have dependency with // jni_libs libdexmakerjvmtiagent and libstaticjvmtiagent.
diff --git a/Tethering/tests/mts/AndroidManifest.xml b/Tethering/tests/mts/AndroidManifest.xml index 6d2abca..42f2da9 100644 --- a/Tethering/tests/mts/AndroidManifest.xml +++ b/Tethering/tests/mts/AndroidManifest.xml
@@ -27,8 +27,6 @@ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.tethering.mts" android:label="MTS tests of android.tethering"> - <meta-data android:name="listener" - android:value="com.android.cts.runner.CtsTestRunListener" /> </instrumentation> </manifest>
diff --git a/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java b/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java new file mode 100644 index 0000000..c2bc812 --- /dev/null +++ b/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java
@@ -0,0 +1,304 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.Manifest.permission.DUMP; +import static android.system.OsConstants.IPPROTO_UDP; + +import static com.android.testutils.DeviceInfoUtils.KVersion; +import static com.android.testutils.TestPermissionUtil.runAsShell; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.net.TetheringTester.TetheredDevice; +import android.os.Build; +import android.os.VintfRuntimeInfo; +import android.util.Log; +import android.util.Pair; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.BpfDump; +import com.android.net.module.util.Struct; +import com.android.net.module.util.bpf.Tether4Key; +import com.android.net.module.util.bpf.Tether4Value; +import com.android.net.module.util.bpf.TetherStatsKey; +import com.android.net.module.util.bpf.TetherStatsValue; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DeviceInfoUtils; +import com.android.testutils.DumpTestUtils; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +@RunWith(AndroidJUnit4.class) +@MediumTest +public class MtsEthernetTetheringTest extends EthernetTetheringTestBase { + @Rule + public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); + + private static final String TAG = MtsEthernetTetheringTest.class.getSimpleName(); + + private static final int DUMP_POLLING_MAX_RETRY = 100; + private static final int DUMP_POLLING_INTERVAL_MS = 50; + // Kernel treats a confirmed UDP connection which active after two seconds as stream mode. + // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5. + private static final int UDP_STREAM_TS_MS = 2000; + // Give slack time for waiting UDP stream mode because handling conntrack event in user space + // may not in precise time. Used to reduce the flaky rate. + private static final int UDP_STREAM_SLACK_MS = 500; + // Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes. + private static final int RX_UDP_PACKET_SIZE = 30; + private static final int RX_UDP_PACKET_COUNT = 456; + // Per TX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes. + private static final int TX_UDP_PACKET_SIZE = 30; + private static final int TX_UDP_PACKET_COUNT = 123; + + private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap"; + private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats"; + private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4"; + private static final String LINE_DELIMITER = "\\n"; + + private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) { + final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion); + return current.isInRange(new KVersion(4, 14, 222), new KVersion(4, 19, 0)) + || current.isInRange(new KVersion(4, 19, 176), new KVersion(5, 4, 0)) + || current.isAtLeast(new KVersion(5, 4, 98)); + } + + @Test + public void testIsUdpOffloadSupportedByKernel() throws Exception { + assertFalse(isUdpOffloadSupportedByKernel("4.14.221")); + assertTrue(isUdpOffloadSupportedByKernel("4.14.222")); + assertTrue(isUdpOffloadSupportedByKernel("4.16.0")); + assertTrue(isUdpOffloadSupportedByKernel("4.18.0")); + assertFalse(isUdpOffloadSupportedByKernel("4.19.0")); + + assertFalse(isUdpOffloadSupportedByKernel("4.19.175")); + assertTrue(isUdpOffloadSupportedByKernel("4.19.176")); + assertTrue(isUdpOffloadSupportedByKernel("5.2.0")); + assertTrue(isUdpOffloadSupportedByKernel("5.3.0")); + assertFalse(isUdpOffloadSupportedByKernel("5.4.0")); + + assertFalse(isUdpOffloadSupportedByKernel("5.4.97")); + assertTrue(isUdpOffloadSupportedByKernel("5.4.98")); + assertTrue(isUdpOffloadSupportedByKernel("5.10.0")); + } + + private static void assumeKernelSupportBpfOffloadUdpV4() { + final String kernelVersion = VintfRuntimeInfo.getKernelVersion(); + assumeTrue("Kernel version " + kernelVersion + " doesn't support IPv4 UDP BPF offload", + isUdpOffloadSupportedByKernel(kernelVersion)); + } + + @Test + public void testKernelSupportBpfOffloadUdpV4() throws Exception { + assumeKernelSupportBpfOffloadUdpV4(); + } + + private boolean isTetherConfigBpfOffloadEnabled() throws Exception { + final String dumpStr = runAsShell(DUMP, () -> + DumpTestUtils.dumpService(Context.TETHERING_SERVICE, "--short")); + + // BPF offload tether config can be overridden by "config_tether_enable_bpf_offload" in + // packages/modules/Connectivity/Tethering/res/values/config.xml. OEM may disable config by + // RRO to override the enabled default value. Get the tethering config via dumpsys. + // $ dumpsys tethering + // mIsBpfEnabled: true + boolean enabled = dumpStr.contains("mIsBpfEnabled: true"); + if (!enabled) { + Log.d(TAG, "BPF offload tether config not enabled: " + dumpStr); + } + return enabled; + } + + @Test + public void testTetherConfigBpfOffloadEnabled() throws Exception { + assumeTrue(isTetherConfigBpfOffloadEnabled()); + } + + @NonNull + private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap( + Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg) + throws Exception { + final String[] args = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG, mapArg}; + final String rawMapStr = runAsShell(DUMP, () -> + DumpTestUtils.dumpService(Context.TETHERING_SERVICE, args)); + final HashMap<K, V> map = new HashMap<>(); + + for (final String line : rawMapStr.split(LINE_DELIMITER)) { + final Pair<K, V> rule = + BpfDump.fromBase64EncodedString(keyClass, valueClass, line.trim()); + map.put(rule.first, rule.second); + } + return map; + } + + @Nullable + private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump( + Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg) + throws Exception { + for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) { + final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, mapArg); + if (!map.isEmpty()) return map; + + Thread.sleep(DUMP_POLLING_INTERVAL_MS); + } + + fail("Cannot get rules after " + DUMP_POLLING_MAX_RETRY * DUMP_POLLING_INTERVAL_MS + "ms"); + return null; + } + + // Test network topology: + // + // public network (rawip) private network + // | UE | + // +------------+ V +------------+------------+ V +------------+ + // | Sever +---------+ Upstream | Downstream +---------+ Client | + // +------------+ +------------+------------+ +------------+ + // remote ip public ip private ip + // 8.8.8.8:443 <Upstream ip>:9876 <TetheredDevice ip>:9876 + // + private void runUdp4Test() throws Exception { + final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR), + toList(TEST_IP4_DNS)); + final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */); + + // TODO: remove the connectivity verification for upstream connected notification race. + // Because async upstream connected notification can't guarantee the tethering routing is + // ready to use. Need to test tethering connectivity before testing. + // For short term plan, consider using IPv6 RA to get MAC address because the prefix comes + // from upstream. That can guarantee that the routing is ready. Long term plan is that + // refactors upstream connected notification from async to sync. + probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */); + + final MacAddress srcMac = tethered.macAddr; + final MacAddress dstMac = tethered.routerMacAddr; + final InetAddress remoteIp = REMOTE_IP4_ADDR; + final InetAddress tetheringUpstreamIp = TEST_IP4_ADDR.getAddress(); + final InetAddress clientIp = tethered.ipv4Addr; + sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */); + sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */); + + // Send second UDP packet in original direction. + // The BPF coordinator only offloads the ASSURED conntrack entry. The "request + reply" + // packets can make status IPS_SEEN_REPLY to be set. Need one more packet to make + // conntrack status IPS_ASSURED_BIT to be set. Note the third packet needs to delay + // 2 seconds because kernel monitors a UDP connection which still alive after 2 seconds + // and apply ASSURED flag. + // See kernel upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5 and + // nf_conntrack_udp_packet in net/netfilter/nf_conntrack_proto_udp.c + Thread.sleep(UDP_STREAM_TS_MS); + sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */); + + // Give a slack time for handling conntrack event in user space. + Thread.sleep(UDP_STREAM_SLACK_MS); + + // [1] Verify IPv4 upstream rule map. + final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump( + Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4); + assertNotNull(upstreamMap); + assertEquals(1, upstreamMap.size()); + + final Map.Entry<Tether4Key, Tether4Value> rule = + upstreamMap.entrySet().iterator().next(); + + final Tether4Key upstream4Key = rule.getKey(); + assertEquals(IPPROTO_UDP, upstream4Key.l4proto); + assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), upstream4Key.src4)); + assertEquals(LOCAL_PORT, upstream4Key.srcPort); + assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), upstream4Key.dst4)); + assertEquals(REMOTE_PORT, upstream4Key.dstPort); + + final Tether4Value upstream4Value = rule.getValue(); + assertTrue(Arrays.equals(tetheringUpstreamIp.getAddress(), + InetAddress.getByAddress(upstream4Value.src46).getAddress())); + assertEquals(LOCAL_PORT, upstream4Value.srcPort); + assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), + InetAddress.getByAddress(upstream4Value.dst46).getAddress())); + assertEquals(REMOTE_PORT, upstream4Value.dstPort); + + // [2] Verify stats map. + // Transmit packets on both direction for verifying stats. Because we only care the + // packet count in stats test, we just reuse the existing packets to increaes + // the packet count on both direction. + + // Send packets on original direction. + for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) { + sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, + false /* is4To6 */); + } + + // Send packets on reply direction. + for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) { + sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */); + } + + // Dump stats map to verify. + final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump( + TetherStatsKey.class, TetherStatsValue.class, DUMPSYS_RAWMAP_ARG_STATS); + assertNotNull(statsMap); + assertEquals(1, statsMap.size()); + + final Map.Entry<TetherStatsKey, TetherStatsValue> stats = + statsMap.entrySet().iterator().next(); + + // TODO: verify the upstream index in TetherStatsKey. + + final TetherStatsValue statsValue = stats.getValue(); + assertEquals(RX_UDP_PACKET_COUNT, statsValue.rxPackets); + assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE, statsValue.rxBytes); + assertEquals(0, statsValue.rxErrors); + assertEquals(TX_UDP_PACKET_COUNT, statsValue.txPackets); + assertEquals(TX_UDP_PACKET_COUNT * TX_UDP_PACKET_SIZE, statsValue.txBytes); + assertEquals(0, statsValue.txErrors); + } + + /** + * BPF offload IPv4 UDP tethering test. Verify that UDP tethered packets are offloaded by BPF. + * Minimum test requirement: + * 1. S+ device. + * 2. Tethering config enables tethering BPF offload. + * 3. Kernel supports IPv4 UDP BPF offload. See #isUdpOffloadSupportedByKernel. + * + * TODO: consider enabling the test even tethering config disables BPF offload. See b/238288883 + */ + @Test + @IgnoreUpTo(Build.VERSION_CODES.R) + public void testTetherBpfOffloadUdpV4() throws Exception { + assumeTrue("Tethering config disabled BPF offload", isTetherConfigBpfOffloadEnabled()); + assumeKernelSupportBpfOffloadUdpV4(); + + runUdp4Test(); + } +}
diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java index 23fb60c..81d4fbe 100644 --- a/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java +++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java
@@ -20,7 +20,7 @@ import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.NETLINK_NETFILTER; -import static com.android.net.module.util.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE; +import static com.android.net.module.util.netlink.NetlinkUtils.DEFAULT_RECV_BUFSIZE; import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_NEW; import static com.android.networkstack.tethering.OffloadHardwareInterface.NFNL_SUBSYS_CTNETLINK; import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_DESTROY; @@ -41,7 +41,7 @@ import com.android.net.module.util.SharedLog; import com.android.net.module.util.netlink.ConntrackMessage; import com.android.net.module.util.netlink.NetlinkMessage; -import com.android.net.module.util.netlink.NetlinkSocket; +import com.android.net.module.util.netlink.NetlinkUtils; import com.android.net.module.util.netlink.StructNlMsgHdr; import org.junit.Before; @@ -80,7 +80,7 @@ // Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads. if (Looper.myLooper() == null) Looper.prepare(); - mDeps = new OffloadHardwareInterface.Dependencies(mLog); + mDeps = new OffloadHardwareInterface.Dependencies(mHandler, mLog); mOffloadHw = new OffloadHardwareInterface(mHandler, mLog, mDeps); } @@ -90,7 +90,7 @@ // Loop until the socket is found (and return) or recvMessage throws an exception. while (true) { - final ByteBuffer buffer = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT); + final ByteBuffer buffer = NetlinkUtils.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT); // Parse all the netlink messages in the dump. // NetlinkMessage#parse returns null if the message is truncated or invalid. @@ -106,6 +106,7 @@ ConntrackMessage.Tuple tuple = ctmsg.tupleOrig; if (nlmsghdr.nlmsg_type == (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_NEW) + && tuple != null && tuple.protoNum == IPPROTO_TCP && tuple.srcIp.equals(local.getAddress()) && tuple.dstIp.equals(remote.getAddress())
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index f0d9057..46e50ef 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -19,6 +19,8 @@ import static android.net.INetd.IF_STATE_DOWN; import static android.net.INetd.IF_STATE_UP; import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; @@ -48,6 +50,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; @@ -271,8 +274,8 @@ dispatchTetherConnectionChanged(upstreamIface, lp, 0); } reset(mNetd, mCallback, mAddressCoordinator, mBpfCoordinator); - when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( - mTestAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(), + anyBoolean())).thenReturn(mTestAddress); } @SuppressWarnings("DoNotCall") // Ignore warning for synchronous to call to Thread.run() @@ -293,8 +296,8 @@ @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); - when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( - mTestAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(), + anyBoolean())).thenReturn(mTestAddress); when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(DEFAULT_USING_BPF_OFFLOAD); when(mTetherConfig.useLegacyDhcpServer()).thenReturn(false /* default value */); @@ -428,7 +431,8 @@ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); if (isAtLeastT()) { - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), + eq(CONNECTIVITY_SCOPE_GLOBAL), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); } @@ -477,7 +481,8 @@ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), + eq(CONNECTIVITY_SCOPE_GLOBAL), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); @@ -498,7 +503,8 @@ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), + eq(CONNECTIVITY_SCOPE_LOCAL), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); @@ -766,7 +772,8 @@ final ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class); InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), + eq(CONNECTIVITY_SCOPE_LOCAL), eq(true)); inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); // One for ipv4 route, one for ipv6 link local route. inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), @@ -779,12 +786,13 @@ // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals // onNewPrefixRequest callback. final LinkAddress newAddress = new LinkAddress("192.168.100.125/24"); - when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( - newAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(), + anyBoolean())).thenReturn(newAddress); eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24")); mLooper.dispatchAll(); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(false)); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), + eq(CONNECTIVITY_SCOPE_LOCAL), eq(false)); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); verifyNoMoreInteractions(mCallback);
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 53984a8..4f32f3c 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -16,6 +16,8 @@ package com.android.networkstack.tethering; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.METERED_NO; import static android.net.NetworkStats.ROAMING_NO; @@ -32,6 +34,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.staticMockMarker; +import static com.android.net.module.util.NetworkStackConstants.IPV4_MIN_MTU; import static com.android.net.module.util.ip.ConntrackMonitor.ConntrackEvent; import static com.android.net.module.util.netlink.ConntrackMessage.DYING_MASK; import static com.android.net.module.util.netlink.ConntrackMessage.ESTABLISHED_MASK; @@ -41,6 +44,7 @@ import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_DELETE; import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_NEW; import static com.android.networkstack.tethering.BpfCoordinator.CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS; +import static com.android.networkstack.tethering.BpfCoordinator.INVALID_MTU; import static com.android.networkstack.tethering.BpfCoordinator.NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED; import static com.android.networkstack.tethering.BpfCoordinator.NF_CONNTRACK_UDP_TIMEOUT_STREAM; import static com.android.networkstack.tethering.BpfCoordinator.NON_OFFLOADED_UPSTREAM_IPV4_TCP_PORTS; @@ -75,6 +79,7 @@ import android.app.usage.NetworkStatsManager; import android.net.INetd; import android.net.InetAddresses; +import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; @@ -87,6 +92,7 @@ import android.os.Build; import android.os.Handler; import android.os.test.TestLooper; +import android.util.SparseArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -109,7 +115,7 @@ import com.android.net.module.util.ip.ConntrackMonitor.ConntrackEventConsumer; import com.android.net.module.util.netlink.ConntrackMessage; import com.android.net.module.util.netlink.NetlinkConstants; -import com.android.net.module.util.netlink.NetlinkSocket; +import com.android.net.module.util.netlink.NetlinkUtils; import com.android.networkstack.tethering.BpfCoordinator.BpfConntrackEventConsumer; import com.android.networkstack.tethering.BpfCoordinator.ClientInfo; import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule; @@ -154,11 +160,13 @@ private static final int INVALID_IFINDEX = 0; private static final int UPSTREAM_IFINDEX = 1001; - private static final int UPSTREAM_IFINDEX2 = 1002; - private static final int DOWNSTREAM_IFINDEX = 1003; - private static final int DOWNSTREAM_IFINDEX2 = 1004; + private static final int UPSTREAM_XLAT_IFINDEX = 1002; + private static final int UPSTREAM_IFINDEX2 = 1003; + private static final int DOWNSTREAM_IFINDEX = 2001; + private static final int DOWNSTREAM_IFINDEX2 = 2002; private static final String UPSTREAM_IFACE = "rmnet0"; + private static final String UPSTREAM_XLAT_IFACE = "v4-rmnet0"; private static final String UPSTREAM_IFACE2 = "wlan0"; private static final MacAddress DOWNSTREAM_MAC = MacAddress.fromString("12:34:56:78:90:ab"); @@ -181,6 +189,10 @@ private static final Inet4Address PRIVATE_ADDR2 = (Inet4Address) InetAddresses.parseNumericAddress("192.168.90.12"); + private static final Inet4Address XLAT_LOCAL_IPV4ADDR = + (Inet4Address) InetAddresses.parseNumericAddress("192.0.0.46"); + private static final IpPrefix NAT64_IP_PREFIX = new IpPrefix("64:ff9b::/96"); + // Generally, public port and private port are the same in the NAT conntrack message. // TODO: consider using different private port and public port for testing. private static final short REMOTE_PORT = (short) 443; @@ -192,6 +204,10 @@ private static final InterfaceParams UPSTREAM_IFACE_PARAMS = new InterfaceParams( UPSTREAM_IFACE, UPSTREAM_IFINDEX, null /* macAddr, rawip */, NetworkStackConstants.ETHER_MTU); + private static final InterfaceParams UPSTREAM_XLAT_IFACE_PARAMS = new InterfaceParams( + UPSTREAM_XLAT_IFACE, UPSTREAM_XLAT_IFINDEX, null /* macAddr, rawip */, + NetworkStackConstants.ETHER_MTU - 28 + /* mtu delta from external/android-clat/clatd.c */); private static final InterfaceParams UPSTREAM_IFACE_PARAMS2 = new InterfaceParams( UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.fromString("44:55:66:00:00:0c"), NetworkStackConstants.ETHER_MTU); @@ -283,6 +299,11 @@ private int mDstPort = REMOTE_PORT; private long mLastUsed = 0; + public Builder setPmtu(short pmtu) { + mPmtu = pmtu; + return this; + } + public Tether4Value build() { return new Tether4Value(mOif, mEthDstMac, mEthSrcMac, mEthProto, mPmtu, mSrc46, mDst46, mSrcPort, mDstPort, mLastUsed); @@ -303,6 +324,11 @@ private int mDstPort = PRIVATE_PORT; private long mLastUsed = 0; + public Builder setPmtu(short pmtu) { + mPmtu = pmtu; + return this; + } + public Tether4Value build() { return new Tether4Value(mOif, mEthDstMac, mEthSrcMac, mEthProto, mPmtu, mSrc46, mDst46, mSrcPort, mDstPort, mLastUsed); @@ -375,6 +401,7 @@ private HashMap<IpServer, HashMap<Inet4Address, ClientInfo>> mTetherClients; private long mElapsedRealtimeNanos = 0; + private int mMtu = NetworkStackConstants.ETHER_MTU; private final ArgumentCaptor<ArrayList> mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class); private final TestLooper mTestLooper = new TestLooper(); @@ -430,6 +457,10 @@ return mElapsedRealtimeNanos; } + public int getNetworkInterfaceMtu(@NonNull String iface) { + return mMtu; + } + @Nullable public IBpfMap<Tether4Key, Tether4Value> getBpfDownstream4Map() { return mBpfDownstream4Map; @@ -1518,6 +1549,7 @@ final LinkProperties lp = new LinkProperties(); lp.setInterfaceName(upstreamInfo.interfaceParams.name); lp.addLinkAddress(new LinkAddress(upstreamInfo.address, 32 /* prefix length */)); + lp.setMtu(mMtu); final NetworkCapabilities capabilities = new NetworkCapabilities() .addTransportType(upstreamInfo.transportType); coordinator.updateUpstreamNetworkState(new UpstreamNetworkState(lp, capabilities, @@ -1697,9 +1729,9 @@ final long validTime = (CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS - 1) * 1_000_000L; final long expiredTime = (CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS + 1) * 1_000_000L; - // Static mocking for NetlinkSocket. + // Static mocking for NetlinkUtils. MockitoSession mockSession = ExtendedMockito.mockitoSession() - .mockStatic(NetlinkSocket.class) + .mockStatic(NetlinkUtils.class) .startMocking(); try { final BpfCoordinator coordinator = makeBpfCoordinator(); @@ -1711,8 +1743,8 @@ setElapsedRealtimeNanos(expiredTime); mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS); waitForIdle(); - ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkSocket.class)); - ExtendedMockito.clearInvocations(staticMockMarker(NetlinkSocket.class)); + ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkUtils.class)); + ExtendedMockito.clearInvocations(staticMockMarker(NetlinkUtils.class)); // [2] Refresh conntrack timeout. setElapsedRealtimeNanos(validTime); @@ -1724,19 +1756,19 @@ final byte[] expectedNetlinkUdp = ConntrackMessage.newIPv4TimeoutUpdateRequest( IPPROTO_UDP, PRIVATE_ADDR, (int) PRIVATE_PORT, REMOTE_ADDR, (int) REMOTE_PORT, NF_CONNTRACK_UDP_TIMEOUT_STREAM); - ExtendedMockito.verify(() -> NetlinkSocket.sendOneShotKernelMessage( + ExtendedMockito.verify(() -> NetlinkUtils.sendOneShotKernelMessage( eq(NETLINK_NETFILTER), eq(expectedNetlinkTcp))); - ExtendedMockito.verify(() -> NetlinkSocket.sendOneShotKernelMessage( + ExtendedMockito.verify(() -> NetlinkUtils.sendOneShotKernelMessage( eq(NETLINK_NETFILTER), eq(expectedNetlinkUdp))); - ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkSocket.class)); - ExtendedMockito.clearInvocations(staticMockMarker(NetlinkSocket.class)); + ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkUtils.class)); + ExtendedMockito.clearInvocations(staticMockMarker(NetlinkUtils.class)); // [3] Don't refresh conntrack timeout if polling stopped. coordinator.stopPolling(); mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS); waitForIdle(); - ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkSocket.class)); - ExtendedMockito.clearInvocations(staticMockMarker(NetlinkSocket.class)); + ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkUtils.class)); + ExtendedMockito.clearInvocations(staticMockMarker(NetlinkUtils.class)); } finally { mockSession.finishMocking(); } @@ -2108,7 +2140,7 @@ @Test public void testIpv6ForwardingRuleToString() throws Exception { final Ipv6ForwardingRule rule = buildTestForwardingRule(UPSTREAM_IFINDEX, NEIGH_A, MAC_A); - assertEquals("upstreamIfindex: 1001, downstreamIfindex: 1003, address: 2001:db8::1, " + assertEquals("upstreamIfindex: 1001, downstreamIfindex: 2001, address: 2001:db8::1, " + "srcMac: 12:34:56:78:90:ab, dstMac: 00:00:00:00:00:0a", rule.toString()); } @@ -2195,4 +2227,238 @@ verifyDump(coordinator); } + + private void verifyAddTetherOffloadRule4Mtu(final int ifaceMtu, final boolean isKernelMtu, + final int expectedMtu) throws Exception { + // BpfCoordinator#updateUpstreamNetworkState geta mtu from LinkProperties. If not found, + // try to get from kernel. + if (isKernelMtu) { + // LinkProperties mtu is invalid and kernel mtu is valid. + mMtu = INVALID_MTU; + doReturn(ifaceMtu).when(mDeps).getNetworkInterfaceMtu(any()); + } else { + // LinkProperties mtu is valid and kernel mtu is invalid. + mMtu = ifaceMtu; + doReturn(INVALID_MTU).when(mDeps).getNetworkInterfaceMtu(any()); + } + + final BpfCoordinator coordinator = makeBpfCoordinator(); + initBpfCoordinatorForRule4(coordinator); + + final Tether4Key expectedUpstream4KeyTcp = new TestUpstream4Key.Builder() + .setProto(IPPROTO_TCP) + .build(); + final Tether4Key expectedDownstream4KeyTcp = new TestDownstream4Key.Builder() + .setProto(IPPROTO_TCP) + .build(); + final Tether4Value expectedUpstream4ValueTcp = new TestUpstream4Value.Builder() + .setPmtu((short) expectedMtu) + .build(); + final Tether4Value expectedDownstream4ValueTcp = new TestDownstream4Value.Builder() + .setPmtu((short) expectedMtu) + .build(); + + mConsumer.accept(new TestConntrackEvent.Builder() + .setMsgType(IPCTNL_MSG_CT_NEW) + .setProto(IPPROTO_TCP) + .build()); + verify(mBpfUpstream4Map) + .insertEntry(eq(expectedUpstream4KeyTcp), eq(expectedUpstream4ValueTcp)); + verify(mBpfDownstream4Map) + .insertEntry(eq(expectedDownstream4KeyTcp), eq(expectedDownstream4ValueTcp)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.R) + public void testAddTetherOffloadRule4LowMtuFromLinkProperties() throws Exception { + verifyAddTetherOffloadRule4Mtu( + IPV4_MIN_MTU, false /* isKernelMtu */, IPV4_MIN_MTU /* expectedMtu */); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.R) + public void testAddTetherOffloadRule4LowMtuFromKernel() throws Exception { + verifyAddTetherOffloadRule4Mtu( + IPV4_MIN_MTU, true /* isKernelMtu */, IPV4_MIN_MTU /* expectedMtu */); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.R) + public void testAddTetherOffloadRule4LessThanIpv4MinMtu() throws Exception { + verifyAddTetherOffloadRule4Mtu( + IPV4_MIN_MTU - 1, false /* isKernelMtu */, IPV4_MIN_MTU /* expectedMtu */); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.R) + public void testAddTetherOffloadRule4InvalidMtu() throws Exception { + verifyAddTetherOffloadRule4Mtu(INVALID_MTU, false /* isKernelMtu */, + NetworkStackConstants.ETHER_MTU /* expectedMtu */); + } + + private static LinkProperties buildUpstreamLinkProperties(final String interfaceName, + boolean withIPv4, boolean withIPv6, boolean with464xlat) { + final LinkProperties prop = new LinkProperties(); + prop.setInterfaceName(interfaceName); + + if (withIPv4) { + // Assign the address no matter what the interface is. It is okay for now because + // only single upstream is available. + // TODO: consider to assign address by interface once we need to test two or more + // BPF supported upstreams or multi upstreams are supported. + prop.addLinkAddress(new LinkAddress(PUBLIC_ADDR, 24)); + } + + if (withIPv6) { + // TODO: make this to be constant. Currently, no test who uses this function cares what + // the upstream IPv6 address is. + prop.addLinkAddress(new LinkAddress("2001:db8::5175:15ca/64")); + } + + if (with464xlat) { + final String clatInterface = "v4-" + interfaceName; + final LinkProperties stackedLink = new LinkProperties(); + stackedLink.setInterfaceName(clatInterface); + stackedLink.addLinkAddress(new LinkAddress(XLAT_LOCAL_IPV4ADDR, 24)); + prop.addStackedLink(stackedLink); + prop.setNat64Prefix(NAT64_IP_PREFIX); + } + + return prop; + } + + private void verifyIpv4Upstream( + @NonNull final HashMap<Inet4Address, Integer> ipv4UpstreamIndices, + @NonNull final SparseArray<String> interfaceNames) { + assertEquals(1, ipv4UpstreamIndices.size()); + Integer upstreamIndex = ipv4UpstreamIndices.get(PUBLIC_ADDR); + assertNotNull(upstreamIndex); + assertEquals(UPSTREAM_IFINDEX, upstreamIndex.intValue()); + assertEquals(1, interfaceNames.size()); + assertTrue(interfaceNames.contains(UPSTREAM_IFINDEX)); + } + + private void verifyUpdateUpstreamNetworkState() + throws Exception { + final BpfCoordinator coordinator = makeBpfCoordinator(); + final HashMap<Inet4Address, Integer> ipv4UpstreamIndices = + coordinator.getIpv4UpstreamIndicesForTesting(); + assertTrue(ipv4UpstreamIndices.isEmpty()); + final SparseArray<String> interfaceNames = + coordinator.getInterfaceNamesForTesting(); + assertEquals(0, interfaceNames.size()); + + // Verify the following are added or removed after upstream changes. + // - BpfCoordinator#mIpv4UpstreamIndices (for building IPv4 offload rules) + // - BpfCoordinator#mInterfaceNames (for updating limit) + // + // +-------+-------+-----------------------+ + // | Test | Up | Protocol | + // | Case# | stream+-------+-------+-------+ + // | | | IPv4 | IPv6 | Xlat | + // +-------+-------+-------+-------+-------+ + // | 1 | Cell | O | | | + // +-------+-------+-------+-------+-------+ + // | 2 | Cell | | O | | + // +-------+-------+-------+-------+-------+ + // | 3 | Cell | O | O | | + // +-------+-------+-------+-------+-------+ + // | 4 | - | | | | + // +-------+-------+-------+-------+-------+ + // | | Cell | O | | | + // | +-------+-------+-------+-------+ + // | 5 | Cell | | O | O | <-- doesn't support offload (xlat) + // | +-------+-------+-------+-------+ + // | | Cell | O | | | + // +-------+-------+-------+-------+-------+ + // | 6 | Wifi | O | O | | <-- doesn't support offload (ether ip) + // +-------+-------+-------+-------+-------+ + + // [1] Mobile IPv4 only + coordinator.addUpstreamNameToLookupTable(UPSTREAM_IFINDEX, UPSTREAM_IFACE); + doReturn(UPSTREAM_IFACE_PARAMS).when(mDeps).getInterfaceParams(UPSTREAM_IFACE); + final UpstreamNetworkState mobileIPv4UpstreamState = new UpstreamNetworkState( + buildUpstreamLinkProperties(UPSTREAM_IFACE, + true /* IPv4 */, false /* IPv6 */, false /* 464xlat */), + new NetworkCapabilities().addTransportType(TRANSPORT_CELLULAR), + new Network(TEST_NET_ID)); + coordinator.updateUpstreamNetworkState(mobileIPv4UpstreamState); + verifyIpv4Upstream(ipv4UpstreamIndices, interfaceNames); + + // [2] Mobile IPv6 only + final UpstreamNetworkState mobileIPv6UpstreamState = new UpstreamNetworkState( + buildUpstreamLinkProperties(UPSTREAM_IFACE, + false /* IPv4 */, true /* IPv6 */, false /* 464xlat */), + new NetworkCapabilities().addTransportType(TRANSPORT_CELLULAR), + new Network(TEST_NET_ID)); + coordinator.updateUpstreamNetworkState(mobileIPv6UpstreamState); + assertTrue(ipv4UpstreamIndices.isEmpty()); + assertEquals(1, interfaceNames.size()); + assertTrue(interfaceNames.contains(UPSTREAM_IFINDEX)); + + // [3] Mobile IPv4 and IPv6 + final UpstreamNetworkState mobileDualStackUpstreamState = new UpstreamNetworkState( + buildUpstreamLinkProperties(UPSTREAM_IFACE, + true /* IPv4 */, true /* IPv6 */, false /* 464xlat */), + new NetworkCapabilities().addTransportType(TRANSPORT_CELLULAR), + new Network(TEST_NET_ID)); + coordinator.updateUpstreamNetworkState(mobileDualStackUpstreamState); + verifyIpv4Upstream(ipv4UpstreamIndices, interfaceNames); + + // [4] Lost upstream + coordinator.updateUpstreamNetworkState(null); + assertTrue(ipv4UpstreamIndices.isEmpty()); + assertEquals(1, interfaceNames.size()); + assertTrue(interfaceNames.contains(UPSTREAM_IFINDEX)); + + // [5] verify xlat interface + // Expect that xlat interface information isn't added to mapping. + doReturn(UPSTREAM_XLAT_IFACE_PARAMS).when(mDeps).getInterfaceParams( + UPSTREAM_XLAT_IFACE); + final UpstreamNetworkState mobile464xlatUpstreamState = new UpstreamNetworkState( + buildUpstreamLinkProperties(UPSTREAM_IFACE, + false /* IPv4 */, true /* IPv6 */, true /* 464xlat */), + new NetworkCapabilities().addTransportType(TRANSPORT_CELLULAR), + new Network(TEST_NET_ID)); + + // Need to add a valid IPv4 upstream to verify that xlat interface doesn't support. + // Mobile IPv4 only + coordinator.updateUpstreamNetworkState(mobileIPv4UpstreamState); + verifyIpv4Upstream(ipv4UpstreamIndices, interfaceNames); + + // Mobile IPv6 and xlat + // IpServer doesn't add xlat interface mapping via #addUpstreamNameToLookupTable on + // S and T devices. + coordinator.updateUpstreamNetworkState(mobile464xlatUpstreamState); + // Upstream IPv4 address mapping is removed because xlat interface is not supported. + assertTrue(ipv4UpstreamIndices.isEmpty()); + assertEquals(1, interfaceNames.size()); + assertTrue(interfaceNames.contains(UPSTREAM_IFINDEX)); + + // Need to add a valid IPv4 upstream to verify that wifi interface doesn't support. + // Mobile IPv4 only + coordinator.updateUpstreamNetworkState(mobileIPv4UpstreamState); + verifyIpv4Upstream(ipv4UpstreamIndices, interfaceNames); + + // [6] Wifi IPv4 and IPv6 + // Expect that upstream index map is cleared because ether ip is not supported. + coordinator.addUpstreamNameToLookupTable(UPSTREAM_IFINDEX2, UPSTREAM_IFACE2); + doReturn(UPSTREAM_IFACE_PARAMS2).when(mDeps).getInterfaceParams(UPSTREAM_IFACE2); + final UpstreamNetworkState wifiDualStackUpstreamState = new UpstreamNetworkState( + buildUpstreamLinkProperties(UPSTREAM_IFACE2, + true /* IPv4 */, true /* IPv6 */, false /* 464xlat */), + new NetworkCapabilities().addTransportType(TRANSPORT_WIFI), + new Network(TEST_NET_ID2)); + coordinator.updateUpstreamNetworkState(wifiDualStackUpstreamState); + assertTrue(ipv4UpstreamIndices.isEmpty()); + assertEquals(2, interfaceNames.size()); + assertTrue(interfaceNames.contains(UPSTREAM_IFINDEX)); + assertTrue(interfaceNames.contains(UPSTREAM_IFINDEX2)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.R) + public void testUpdateUpstreamNetworkState() throws Exception { + verifyUpdateUpstreamNetworkState(); + } }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt index d915354..2dd9f91 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt
@@ -24,19 +24,25 @@ import android.net.TetheringManager.TETHERING_WIFI import android.net.ip.IpServer import android.net.wifi.WifiClient +import android.os.Build import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue @RunWith(AndroidJUnit4::class) @SmallTest class ConnectedClientsTrackerTest { + @get:Rule + val ignoreRule = DevSdkIgnoreRule() private val server1 = mock(IpServer::class.java) private val server2 = mock(IpServer::class.java) @@ -70,55 +76,122 @@ @Test fun testUpdateConnectedClients() { + doReturn(IpServer.STATE_TETHERED).`when`(server1).servingMode() + doReturn(IpServer.STATE_TETHERED).`when`(server2).servingMode() + runUpdateConnectedClientsTest(isGlobal = true) + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2) + fun testUpdateConnectedClients_LocalOnly() { + doReturn(IpServer.STATE_LOCAL_ONLY).`when`(server1).servingMode() + doReturn(IpServer.STATE_LOCAL_ONLY).`when`(server2).servingMode() + runUpdateConnectedClientsTest(isGlobal = false) + } + + fun runUpdateConnectedClientsTest(isGlobal: Boolean) { doReturn(emptyList<TetheredClient>()).`when`(server1).allLeases doReturn(emptyList<TetheredClient>()).`when`(server2).allLeases val tracker = ConnectedClientsTracker(clock) - assertFalse(tracker.updateConnectedClients(servers, null)) + assertFalse(tracker.updateConnectedClients(servers, null, null)) // Obtain a lease for client 1 doReturn(listOf(client1)).`when`(server1).allLeases - assertSameClients(listOf(client1), assertNewClients(tracker, servers, listOf(wifiClient1))) + if (isGlobal) { + assertSameClients(listOf(client1), assertNewClients(tracker, servers, + wifiClients = listOf(wifiClient1))) + } else { + assertSameClients(listOf(client1), assertNewClients(tracker, servers, + localOnlyClients = listOf(wifiClient1))) + } // Client 2 L2-connected, no lease yet val client2WithoutAddr = TetheredClient(client2Addr, emptyList(), TETHERING_WIFI) - assertSameClients(listOf(client1, client2WithoutAddr), - assertNewClients(tracker, servers, listOf(wifiClient1, wifiClient2))) + if (isGlobal) { + assertSameClients(listOf(client1, client2WithoutAddr), assertNewClients( + tracker, servers, wifiClients = listOf(wifiClient1, wifiClient2))) + } else { + assertSameClients(listOf(client1, client2WithoutAddr), assertNewClients( + tracker, servers, localOnlyClients = listOf(wifiClient1, wifiClient2))) + } // Client 2 lease obtained doReturn(listOf(client1, client2)).`when`(server1).allLeases - assertSameClients(listOf(client1, client2), assertNewClients(tracker, servers, null)) + assertSameClients(listOf(client1, client2), assertNewClients(tracker, servers)) // Client 3 lease obtained doReturn(listOf(client3)).`when`(server2).allLeases - assertSameClients(listOf(client1, client2, client3), - assertNewClients(tracker, servers, null)) + assertSameClients(listOf(client1, client2, client3), assertNewClients(tracker, servers)) - // Client 2 L2-disconnected - assertSameClients(listOf(client1, client3), - assertNewClients(tracker, servers, listOf(wifiClient1))) - - // Client 1 L2-disconnected - assertSameClients(listOf(client3), assertNewClients(tracker, servers, emptyList())) - - // Client 1 comes back - assertSameClients(listOf(client1, client3), - assertNewClients(tracker, servers, listOf(wifiClient1))) + if (isGlobal) { + // Client 2 L2-disconnected + assertSameClients(listOf(client1, client3), + assertNewClients(tracker, servers, wifiClients = listOf(wifiClient1))) + // Client 1 L2-disconnected + assertSameClients(listOf(client3), assertNewClients(tracker, servers, + wifiClients = emptyList())) + // Client 1 comes back + assertSameClients(listOf(client1, client3), + assertNewClients(tracker, servers, wifiClients = listOf(wifiClient1))) + } else { + // Client 2 L2-disconnected + assertSameClients(listOf(client1, client3), + assertNewClients(tracker, servers, localOnlyClients = listOf(wifiClient1))) + // Client 1 L2-disconnected + assertSameClients(listOf(client3), + assertNewClients(tracker, servers, localOnlyClients = emptyList())) + // Client 1 comes back + assertSameClients(listOf(client1, client3), + assertNewClients(tracker, servers, localOnlyClients = listOf(wifiClient1))) + } // Leases lost, client 1 still L2-connected doReturn(emptyList<TetheredClient>()).`when`(server1).allLeases doReturn(emptyList<TetheredClient>()).`when`(server2).allLeases assertSameClients(listOf(TetheredClient(client1Addr, emptyList(), TETHERING_WIFI)), - assertNewClients(tracker, servers, null)) + assertNewClients(tracker, servers)) + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2) + fun testLocalOnlyAndTetheredHotspotClients() { + val tracker = ConnectedClientsTracker(clock) + doReturn(IpServer.STATE_LOCAL_ONLY).`when`(server1).servingMode() + doReturn(IpServer.STATE_TETHERED).`when`(server2).servingMode() + + // Client 1 connected to server1 (LOHS) + doReturn(listOf(client1)).`when`(server1).allLeases + doReturn(emptyList<TetheredClient>()).`when`(server2).allLeases + assertSameClients(listOf(client1), assertNewClients(tracker, servers, + localOnlyClients = listOf(wifiClient1))) + + // Client 2 connected to server2 (wifi Tethering) + doReturn(listOf(client2)).`when`(server2).allLeases + assertSameClients(listOf(client1, client2), assertNewClients(tracker, servers, + listOf(wifiClient2), listOf(wifiClient1))) + + // Client 2 L2-disconnected but lease doesn't expired yet + assertSameClients(listOf(client1), assertNewClients(tracker, servers, + wifiClients = emptyList())) + + // Client 1 lease lost but still L2-connected + doReturn(emptyList<TetheredClient>()).`when`(server1).allLeases + val client1WithoutAddr = TetheredClient(client1Addr, emptyList(), TETHERING_WIFI) + assertSameClients(listOf(client1WithoutAddr), assertNewClients(tracker, servers)) + + // Client 1 L2-disconnected + assertSameClients(emptyList(), assertNewClients(tracker, servers, + localOnlyClients = emptyList())) } @Test fun testUpdateConnectedClients_LeaseExpiration() { + doReturn(IpServer.STATE_TETHERED).`when`(server1).servingMode() + doReturn(IpServer.STATE_TETHERED).`when`(server2).servingMode() val tracker = ConnectedClientsTracker(clock) doReturn(listOf(client1, client2)).`when`(server1).allLeases doReturn(listOf(client3)).`when`(server2).allLeases assertSameClients(listOf(client1, client2, client3), assertNewClients( - tracker, servers, listOf(wifiClient1, wifiClient2))) + tracker, servers, wifiClients = listOf(wifiClient1, wifiClient2))) clock.time += 20 // Client 3 has no remaining lease: removed @@ -131,15 +204,16 @@ // Only the "t + 30" address is left, the "t + 10" address expired listOf(client2Exp30AddrInfo), TETHERING_WIFI)) - assertSameClients(expectedClients, assertNewClients(tracker, servers, null)) + assertSameClients(expectedClients, assertNewClients(tracker, servers)) } private fun assertNewClients( tracker: ConnectedClientsTracker, ipServers: Iterable<IpServer>, - wifiClients: List<WifiClient>? + wifiClients: List<WifiClient>? = null, + localOnlyClients: List<WifiClient>? = null ): List<TetheredClient> { - assertTrue(tracker.updateConnectedClients(ipServers, wifiClients)) + assertTrue(tracker.updateConnectedClients(ipServers, wifiClients, localOnlyClients)) return tracker.lastTetheredClients }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java index e4263db..c2e1617 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
@@ -213,7 +213,8 @@ } @Override - PendingIntent createRecheckAlarmIntent() { + PendingIntent createRecheckAlarmIntent(final String pkgName) { + assertEquals(TEST_PACKAGE_NAME, pkgName); return mAlarmIntent; } }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java index 0d686ed..9e287a0 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java
@@ -19,22 +19,26 @@ import android.content.Context; import android.content.res.Resources; +import androidx.annotation.NonNull; + import com.android.net.module.util.SharedLog; /** FakeTetheringConfiguration is used to override static method for testing. */ public class FakeTetheringConfiguration extends TetheringConfiguration { FakeTetheringConfiguration(Context ctx, SharedLog log, int id) { - super(ctx, log, id); - } + super(ctx, log, id, new Dependencies() { + @Override + boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, + @NonNull String name, @NonNull String moduleName, boolean defaultEnabled) { + return defaultEnabled; + } - @Override - protected String getDeviceConfigProperty(final String name) { - return null; - } - - @Override - protected boolean isFeatureEnabled(Context ctx, String namespace, String featureVersionFlag) { - return false; + @Override + boolean getDeviceConfigBoolean(@NonNull String namespace, @NonNull String name, + boolean defaultValue) { + return defaultValue; + } + }); } @Override
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java index faca1c8..36c15a7 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
@@ -31,8 +31,8 @@ import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE; import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID; import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; -import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0; -import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_1; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1; import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; import static com.android.testutils.MiscAsserts.assertContainsAll; import static com.android.testutils.MiscAsserts.assertThrows; @@ -79,6 +79,7 @@ import com.android.internal.util.test.FakeSettingsProvider; import com.android.net.module.util.SharedLog; +import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.TestableNetworkStatsProviderCbBinder; @@ -125,8 +126,8 @@ private OffloadController.OffloadTetheringStatsProvider mTetherStatsProvider; private final ArgumentCaptor<ArrayList> mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class); - private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor = - ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class); + private final ArgumentCaptor<OffloadHalCallback> mOffloadHalCallbackCaptor = + ArgumentCaptor.forClass(OffloadHalCallback.class); private MockContentResolver mContentResolver; private final TestLooper mTestLooper = new TestLooper(); private OffloadController.Dependencies mDeps = new OffloadController.Dependencies() { @@ -151,10 +152,9 @@ FakeSettingsProvider.clearSettingsProvider(); } - private void setupFunctioningHardwareInterface(int controlVersion) { - when(mHardware.initOffloadConfig()).thenReturn(true); - when(mHardware.initOffloadControl(mControlCallbackCaptor.capture())) - .thenReturn(controlVersion); + private void setupFunctioningHardwareInterface(int offloadHalVersion) { + when(mHardware.initOffload(mOffloadHalCallbackCaptor.capture())) + .thenReturn(offloadHalVersion); when(mHardware.setUpstreamParameters(anyString(), any(), any(), any())).thenReturn(true); when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats()); when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); @@ -192,9 +192,9 @@ @Test public void testStartStop() throws Exception { stopOffloadController( - startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/)); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/)); stopOffloadController( - startOffloadController(OFFLOAD_HAL_VERSION_1_1, true /*expectStart*/)); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_1, true /*expectStart*/)); } @NonNull @@ -206,9 +206,8 @@ final InOrder inOrder = inOrder(mHardware); inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled(); - inOrder.verify(mHardware, times(expectStart ? 1 : 0)).initOffloadConfig(); - inOrder.verify(mHardware, times(expectStart ? 1 : 0)).initOffloadControl( - any(OffloadHardwareInterface.ControlCallback.class)); + inOrder.verify(mHardware, times(expectStart ? 1 : 0)).initOffload( + any(OffloadHalCallback.class)); inOrder.verifyNoMoreInteractions(); // Clear counters only instead of whole mock to preserve the mocking setup. clearInvocations(mHardware); @@ -218,7 +217,7 @@ private void stopOffloadController(final OffloadController offload) throws Exception { final InOrder inOrder = inOrder(mHardware); offload.stop(); - inOrder.verify(mHardware, times(1)).stopOffloadControl(); + inOrder.verify(mHardware, times(1)).stopOffload(); inOrder.verifyNoMoreInteractions(); reset(mHardware); } @@ -228,7 +227,7 @@ when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1); assertThrows(SettingNotFoundException.class, () -> Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED)); - startOffloadController(OFFLOAD_HAL_VERSION_1_0, false /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, false /*expectStart*/); } @Test @@ -236,26 +235,26 @@ when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0); assertThrows(SettingNotFoundException.class, () -> Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED)); - startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); } @Test public void testSettingsAllowsStart() throws Exception { Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0); - startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); } @Test public void testSettingsDisablesStart() throws Exception { Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1); - startOffloadController(OFFLOAD_HAL_VERSION_1_0, false /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, false /*expectStart*/); } @Test public void testSetUpstreamLinkPropertiesWorking() throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); // In reality, the UpstreamNetworkMonitor would have passed down to us // a covering set of local prefixes representing a minimum essential @@ -426,7 +425,7 @@ public void testGetForwardedStats() throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); final String ethernetIface = "eth1"; final String mobileIface = "rmnet_data0"; @@ -521,11 +520,11 @@ // Verify the OffloadController is called by R framework, where the framework doesn't send // warning. // R only uses HAL 1.0. - checkSetDataWarningAndLimit(false, OFFLOAD_HAL_VERSION_1_0); + checkSetDataWarningAndLimit(false, OFFLOAD_HAL_VERSION_HIDL_1_0); // Verify the OffloadController is called by S+ framework, where the framework sends // warning along with limit. - checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_1_0); - checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_1_1); + checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_HIDL_1_0); + checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_HIDL_1_1); } private void checkSetDataWarningAndLimit(boolean isProviderSetWarning, int controlVersion) @@ -550,7 +549,7 @@ when(mHardware.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(true); offload.setUpstreamLinkProperties(lp); // Applying an interface sends the initial quota to the hardware. - if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) { + if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { inOrder.verify(mHardware).setDataWarningAndLimit(ethernetIface, Long.MAX_VALUE, Long.MAX_VALUE); } else { @@ -576,7 +575,7 @@ mTetherStatsProvider.onSetLimit(ethernetIface, ethernetLimit); } waitForIdle(); - if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) { + if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { inOrder.verify(mHardware).setDataWarningAndLimit(ethernetIface, Long.MAX_VALUE, ethernetLimit); } else { @@ -591,7 +590,7 @@ mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); } waitForIdle(); - if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) { + if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { inOrder.verify(mHardware, never()).setDataWarningAndLimit(anyString(), anyLong(), anyLong()); } else { @@ -603,7 +602,7 @@ lp.setInterfaceName(mobileIface); offload.setUpstreamLinkProperties(lp); waitForIdle(); - if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) { + if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { inOrder.verify(mHardware).setDataWarningAndLimit(mobileIface, isProviderSetWarning ? mobileWarning : Long.MAX_VALUE, mobileLimit); @@ -620,7 +619,7 @@ mTetherStatsProvider.onSetLimit(mobileIface, NetworkStatsProvider.QUOTA_UNLIMITED); } waitForIdle(); - if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) { + if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { inOrder.verify(mHardware).setDataWarningAndLimit(mobileIface, Long.MAX_VALUE, Long.MAX_VALUE); } else { @@ -655,15 +654,15 @@ } waitForIdle(); inOrder.verify(mHardware).getForwardedStats(ethernetIface); - inOrder.verify(mHardware).stopOffloadControl(); + inOrder.verify(mHardware).stopOffload(); } @Test public void testDataWarningAndLimitCallback_LimitReached() throws Exception { enableOffload(); - startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); - final OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); + final OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue(); callback.onStoppedLimitReached(); mTetherStatsProviderCb.expectNotifyStatsUpdated(); @@ -679,8 +678,8 @@ @Test @IgnoreUpTo(Build.VERSION_CODES.R) // HAL 1.1 is only supported from S public void testDataWarningAndLimitCallback_WarningReached() throws Exception { - startOffloadController(OFFLOAD_HAL_VERSION_1_1, true /*expectStart*/); - final OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_1, true /*expectStart*/); + final OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue(); callback.onWarningReached(); mTetherStatsProviderCb.expectNotifyStatsUpdated(); @@ -695,7 +694,7 @@ public void testAddRemoveDownstreams() throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); final InOrder inOrder = inOrder(mHardware); // Tethering makes several calls to setLocalPrefixes() before add/remove @@ -710,14 +709,14 @@ usbLinkProperties.addRoute( new RouteInfo(new IpPrefix(USB_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); - inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, USB_PREFIX); + inOrder.verify(mHardware, times(1)).addDownstream(RNDIS0, USB_PREFIX); inOrder.verifyNoMoreInteractions(); // [2] Routes for IPv6 link-local prefixes should never be added. usbLinkProperties.addRoute( new RouteInfo(new IpPrefix(IPV6_LINKLOCAL), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); - inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString()); + inOrder.verify(mHardware, never()).addDownstream(eq(RNDIS0), anyString()); inOrder.verifyNoMoreInteractions(); // [3] Add an IPv6 prefix for good measure. Only new offload-able @@ -726,14 +725,14 @@ usbLinkProperties.addRoute( new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); - inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX); + inOrder.verify(mHardware, times(1)).addDownstream(RNDIS0, IPV6_DOC_PREFIX); inOrder.verifyNoMoreInteractions(); // [4] Adding addresses doesn't affect notifyDownstreamLinkProperties(). // The address is passed in by a separate setLocalPrefixes() invocation. usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::2/64")); offload.notifyDownstreamLinkProperties(usbLinkProperties); - inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString()); + inOrder.verify(mHardware, never()).addDownstream(eq(RNDIS0), anyString()); // [5] Differences in local routes are converted into addDownstream() // and removeDownstream() invocations accordingly. @@ -742,8 +741,8 @@ usbLinkProperties.addRoute( new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); - inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX); - inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX); + inOrder.verify(mHardware, times(1)).removeDownstream(RNDIS0, IPV6_DOC_PREFIX); + inOrder.verify(mHardware, times(1)).addDownstream(RNDIS0, IPV6_DISCARD_PREFIX); inOrder.verifyNoMoreInteractions(); // [6] Removing a downstream interface which was never added causes no @@ -753,8 +752,8 @@ // [7] Removing an active downstream removes all remaining prefixes. offload.removeDownstreamInterface(RNDIS0); - inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, USB_PREFIX); - inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX); + inOrder.verify(mHardware, times(1)).removeDownstream(RNDIS0, USB_PREFIX); + inOrder.verify(mHardware, times(1)).removeDownstream(RNDIS0, IPV6_DISCARD_PREFIX); inOrder.verifyNoMoreInteractions(); } @@ -762,7 +761,7 @@ public void testControlCallbackOnStoppedUnsupportedFetchesAllStats() throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); // Pretend to set a few different upstreams (only the interface name // matters for this test; we're ignoring IP and route information). @@ -776,7 +775,7 @@ // that happen with setUpstreamParameters(). clearInvocations(mHardware); - OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); + OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue(); callback.onStoppedUnsupported(); // Verify forwarded stats behaviour. @@ -793,7 +792,7 @@ throws Exception { enableOffload(); final OffloadController offload = - startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); // Pretend to set a few different upstreams (only the interface name // matters for this test; we're ignoring IP and route information). @@ -840,7 +839,7 @@ // that happen with setUpstreamParameters(). clearInvocations(mHardware); - OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); + OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue(); callback.onSupportAvailable(); // Verify forwarded stats behaviour. @@ -859,8 +858,8 @@ // into OffloadController proper. After this, also check for: // "192.168.43.1/32", "2001:2::1/128", "2001:2::2/128" "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"); - verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "192.168.43.0/24"); - verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "2001:2::/64"); + verify(mHardware, times(1)).addDownstream(WLAN0, "192.168.43.0/24"); + verify(mHardware, times(1)).addDownstream(WLAN0, "2001:2::/64"); verify(mHardware, times(1)).setUpstreamParameters(eq(RMNET0), any(), any(), any()); verify(mHardware, times(1)).setDataLimit(eq(RMNET0), anyLong()); verifyNoMoreInteractions(mHardware); @@ -871,7 +870,7 @@ enableOffload(); setOffloadPollInterval(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); final OffloadController offload = - startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); + startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); // Initialize with fake eth upstream. final String ethernetIface = "eth1"; @@ -925,7 +924,7 @@ offload.setUpstreamLinkProperties(makeEthernetLinkProperties()); mTetherStatsProvider.onSetAlert(0); waitForIdle(); - if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) { + if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { mTetherStatsProviderCb.assertNoCallback(); } else { mTetherStatsProviderCb.expectNotifyAlertReached(); @@ -935,7 +934,7 @@ @Test public void testSoftwarePollingUsed() throws Exception { - checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_1_0); - checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_1_1); + checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_HIDL_1_0); + checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_HIDL_1_1); } }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHalAidlImplTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHalAidlImplTest.java new file mode 100644 index 0000000..c9ce64f --- /dev/null +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHalAidlImplTest.java
@@ -0,0 +1,390 @@ +/* + * 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.networkstack.tethering; + +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_AIDL; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.hardware.tetheroffload.ForwardedStats; +import android.hardware.tetheroffload.IOffload; +import android.hardware.tetheroffload.IPv4AddrPortPair; +import android.hardware.tetheroffload.ITetheringOffloadCallback; +import android.hardware.tetheroffload.NatTimeoutUpdate; +import android.hardware.tetheroffload.NetworkProtocol; +import android.hardware.tetheroffload.OffloadCallbackEvent; +import android.os.Handler; +import android.os.NativeHandle; +import android.os.ParcelFileDescriptor; +import android.os.ServiceSpecificException; +import android.os.test.TestLooper; +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.SharedLog; +import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.mockito.MockitoAnnotations; + +import java.io.FileDescriptor; +import java.util.ArrayList; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public final class OffloadHalAidlImplTest { + private static final String RMNET0 = "test_rmnet_data0"; + + private final SharedLog mLog = new SharedLog("test"); + private final TestLooper mTestLooper = new TestLooper(); + + private IOffload mIOffloadMock; + private OffloadHalAidlImpl mIOffloadHal; + private ITetheringOffloadCallback mTetheringOffloadCallback; + private OffloadHalCallback mOffloadHalCallback; + + private void initAndValidateOffloadHal(boolean initSuccess) + throws Exception { + final FileDescriptor fd1 = new FileDescriptor(); + final FileDescriptor fd2 = new FileDescriptor(); + final NativeHandle handle1 = new NativeHandle(fd1, true); + final NativeHandle handle2 = new NativeHandle(fd2, true); + final ArgumentCaptor<ParcelFileDescriptor> fdCaptor1 = + ArgumentCaptor.forClass(ParcelFileDescriptor.class); + final ArgumentCaptor<ParcelFileDescriptor> fdCaptor2 = + ArgumentCaptor.forClass(ParcelFileDescriptor.class); + final ArgumentCaptor<ITetheringOffloadCallback> offloadCallbackCaptor = + ArgumentCaptor.forClass(ITetheringOffloadCallback.class); + if (initSuccess) { + doNothing().when(mIOffloadMock).initOffload(any(), any(), any()); + } else { + doThrow(new IllegalStateException()).when(mIOffloadMock).initOffload(any(), any(), + any()); + } + assertEquals(mIOffloadHal.initOffload(handle1, handle2, mOffloadHalCallback), + initSuccess); + verify(mIOffloadMock).initOffload(fdCaptor1.capture(), fdCaptor2.capture(), + offloadCallbackCaptor.capture()); + assertEquals(fdCaptor1.getValue().getFd(), fd1.getInt$()); + assertEquals(fdCaptor2.getValue().getFd(), fd2.getInt$()); + mTetheringOffloadCallback = offloadCallbackCaptor.getValue(); + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mIOffloadMock = mock(IOffload.class); + mIOffloadHal = new OffloadHalAidlImpl(OFFLOAD_HAL_VERSION_AIDL, mIOffloadMock, + new Handler(mTestLooper.getLooper()), mLog); + mOffloadHalCallback = spy(new OffloadHalCallback()); + } + + @Test + public void testInitOffloadSuccess() throws Exception { + initAndValidateOffloadHal(true /* initSuccess */); + } + + @Test + public void testInitOffloadFailure() throws Exception { + initAndValidateOffloadHal(false /* initSuccess */); + } + + @Test + public void testStopOffloadSuccess() throws Exception { + initAndValidateOffloadHal(true); + doNothing().when(mIOffloadMock).stopOffload(); + assertTrue(mIOffloadHal.stopOffload()); + verify(mIOffloadMock).stopOffload(); + } + + @Test + public void testStopOffloadFailure() throws Exception { + initAndValidateOffloadHal(true); + doThrow(new IllegalStateException()).when(mIOffloadMock).stopOffload(); + assertFalse(mIOffloadHal.stopOffload()); + } + + private void doTestGetForwardedStats(boolean expectSuccess) throws Exception { + initAndValidateOffloadHal(true); + final ForwardedStats returnStats = new ForwardedStats(); + if (expectSuccess) { + returnStats.rxBytes = 12345; + returnStats.txBytes = 67890; + when(mIOffloadMock.getForwardedStats(anyString())).thenReturn(returnStats); + } else { + when(mIOffloadMock.getForwardedStats(anyString())) + .thenThrow(new ServiceSpecificException(IOffload.ERROR_CODE_UNUSED)); + } + final OffloadHardwareInterface.ForwardedStats stats = + mIOffloadHal.getForwardedStats(RMNET0); + verify(mIOffloadMock).getForwardedStats(eq(RMNET0)); + assertNotNull(stats); + assertEquals(stats.rxBytes, returnStats.rxBytes); + assertEquals(stats.txBytes, returnStats.txBytes); + } + + @Test + public void testGetForwardedStatsSuccess() throws Exception { + doTestGetForwardedStats(true); + } + + @Test + public void testGetForwardedStatsFailure() throws Exception { + doTestGetForwardedStats(false); + } + + private void doTestSetLocalPrefixes(boolean expectSuccess) throws Exception { + initAndValidateOffloadHal(true); + final ArrayList<String> localPrefixes = new ArrayList<>(); + localPrefixes.add("127.0.0.0/8"); + localPrefixes.add("fe80::/64"); + final String[] localPrefixesArray = + localPrefixes.toArray(new String[localPrefixes.size()]); + if (expectSuccess) { + doNothing().when(mIOffloadMock).setLocalPrefixes(any()); + } else { + doThrow(new IllegalArgumentException()).when(mIOffloadMock).setLocalPrefixes(any()); + } + assertEquals(expectSuccess, mIOffloadHal.setLocalPrefixes(localPrefixes)); + verify(mIOffloadMock).setLocalPrefixes(eq(localPrefixesArray)); + } + + @Test + public void testSetLocalPrefixesSuccess() throws Exception { + doTestSetLocalPrefixes(true); + } + + @Test + public void testSetLocalPrefixesFailure() throws Exception { + doTestSetLocalPrefixes(false); + } + + private void doTestSetDataLimit(boolean expectSuccess) throws Exception { + initAndValidateOffloadHal(true); + final long limit = 12345; + if (expectSuccess) { + doNothing().when(mIOffloadMock).setDataWarningAndLimit(anyString(), anyLong(), + anyLong()); + } else { + doThrow(new IllegalArgumentException()) + .when(mIOffloadMock).setDataWarningAndLimit(anyString(), anyLong(), anyLong()); + } + assertEquals(expectSuccess, mIOffloadHal.setDataLimit(RMNET0, limit)); + verify(mIOffloadMock).setDataWarningAndLimit(eq(RMNET0), eq(Long.MAX_VALUE), eq(limit)); + } + + @Test + public void testSetDataLimitSuccess() throws Exception { + doTestSetDataLimit(true); + } + + @Test + public void testSetDataLimitFailure() throws Exception { + doTestSetDataLimit(false); + } + + private void doTestSetDataWarningAndLimit(boolean expectSuccess) throws Exception { + initAndValidateOffloadHal(true); + final long warning = 12345; + final long limit = 67890; + if (expectSuccess) { + doNothing().when(mIOffloadMock).setDataWarningAndLimit(anyString(), anyLong(), + anyLong()); + } else { + doThrow(new IllegalArgumentException()) + .when(mIOffloadMock).setDataWarningAndLimit(anyString(), anyLong(), anyLong()); + } + assertEquals(expectSuccess, mIOffloadHal.setDataWarningAndLimit(RMNET0, warning, limit)); + verify(mIOffloadMock).setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit)); + } + + @Test + public void testSetDataWarningAndLimitSuccess() throws Exception { + doTestSetDataWarningAndLimit(true); + } + + @Test + public void testSetDataWarningAndLimitFailure() throws Exception { + doTestSetDataWarningAndLimit(false); + } + + private void doTestSetUpstreamParameters(boolean expectSuccess) throws Exception { + initAndValidateOffloadHal(true); + final String v4addr = "192.168.10.1"; + final String v4gateway = "192.168.10.255"; + final ArrayList<String> v6gws = new ArrayList<>(0); + v6gws.add("2001:db8::1"); + String[] v6gwsArray = v6gws.toArray(new String[v6gws.size()]); + if (expectSuccess) { + doNothing().when(mIOffloadMock).setUpstreamParameters(anyString(), anyString(), + anyString(), any()); + } else { + doThrow(new IllegalArgumentException()).when(mIOffloadMock).setUpstreamParameters( + anyString(), anyString(), anyString(), any()); + } + assertEquals(expectSuccess, mIOffloadHal.setUpstreamParameters(RMNET0, v4addr, v4gateway, + v6gws)); + verify(mIOffloadMock).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway), + eq(v6gwsArray)); + } + + @Test + public void testSetUpstreamParametersSuccess() throws Exception { + doTestSetUpstreamParameters(true); + } + + @Test + public void testSetUpstreamParametersFailure() throws Exception { + doTestSetUpstreamParameters(false); + } + + private void doTestAddDownstream(boolean expectSuccess) throws Exception { + initAndValidateOffloadHal(true); + final String ifName = "wlan1"; + final String prefix = "192.168.43.0/24"; + if (expectSuccess) { + doNothing().when(mIOffloadMock).addDownstream(anyString(), anyString()); + } else { + doThrow(new IllegalStateException()).when(mIOffloadMock).addDownstream(anyString(), + anyString()); + } + assertEquals(expectSuccess, mIOffloadHal.addDownstream(ifName, prefix)); + verify(mIOffloadMock).addDownstream(eq(ifName), eq(prefix)); + } + + @Test + public void testAddDownstreamSuccess() throws Exception { + doTestAddDownstream(true); + } + + @Test + public void testAddDownstreamFailure() throws Exception { + doTestAddDownstream(false); + } + + private void doTestRemoveDownstream(boolean expectSuccess) throws Exception { + initAndValidateOffloadHal(true); + final String ifName = "wlan1"; + final String prefix = "192.168.43.0/24"; + if (expectSuccess) { + doNothing().when(mIOffloadMock).removeDownstream(anyString(), anyString()); + } else { + doThrow(new IllegalArgumentException()).when(mIOffloadMock).removeDownstream( + anyString(), anyString()); + } + assertEquals(expectSuccess, mIOffloadHal.removeDownstream(ifName, prefix)); + verify(mIOffloadMock).removeDownstream(eq(ifName), eq(prefix)); + } + + @Test + public void testRemoveDownstreamSuccess() throws Exception { + doTestRemoveDownstream(true); + } + + @Test + public void testRemoveDownstreamFailure() throws Exception { + doTestRemoveDownstream(false); + } + + @Test + public void testTetheringOffloadCallback() throws Exception { + initAndValidateOffloadHal(true); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED); + mTestLooper.dispatchAll(); + final InOrder inOrder = inOrder(mOffloadHalCallback); + inOrder.verify(mOffloadHalCallback).onStarted(); + inOrder.verifyNoMoreInteractions(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR); + mTestLooper.dispatchAll(); + inOrder.verify(mOffloadHalCallback).onStoppedError(); + inOrder.verifyNoMoreInteractions(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED); + mTestLooper.dispatchAll(); + inOrder.verify(mOffloadHalCallback).onStoppedUnsupported(); + inOrder.verifyNoMoreInteractions(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE); + mTestLooper.dispatchAll(); + inOrder.verify(mOffloadHalCallback).onSupportAvailable(); + inOrder.verifyNoMoreInteractions(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED); + mTestLooper.dispatchAll(); + inOrder.verify(mOffloadHalCallback).onStoppedLimitReached(); + inOrder.verifyNoMoreInteractions(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_WARNING_REACHED); + mTestLooper.dispatchAll(); + inOrder.verify(mOffloadHalCallback).onWarningReached(); + inOrder.verifyNoMoreInteractions(); + + final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP); + mTetheringOffloadCallback.updateTimeout(tcpParams); + mTestLooper.dispatchAll(); + inOrder.verify(mOffloadHalCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP), + eq(tcpParams.src.addr), + eq(tcpParams.src.port), + eq(tcpParams.dst.addr), + eq(tcpParams.dst.port)); + inOrder.verifyNoMoreInteractions(); + + final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP); + mTetheringOffloadCallback.updateTimeout(udpParams); + mTestLooper.dispatchAll(); + inOrder.verify(mOffloadHalCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP), + eq(udpParams.src.addr), + eq(udpParams.src.port), + eq(udpParams.dst.addr), + eq(udpParams.dst.port)); + inOrder.verifyNoMoreInteractions(); + } + + private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) { + final NatTimeoutUpdate params = new NatTimeoutUpdate(); + params.proto = proto; + params.src = new IPv4AddrPortPair(); + params.dst = new IPv4AddrPortPair(); + params.src.addr = "192.168.43.200"; + params.src.port = 100; + params.dst.addr = "172.50.46.169"; + params.dst.port = 150; + return params; + } +}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHalHidlImplTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHalHidlImplTest.java new file mode 100644 index 0000000..6fdab5a --- /dev/null +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHalHidlImplTest.java
@@ -0,0 +1,359 @@ +/* + * 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.networkstack.tethering; + +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1; +import static com.android.networkstack.tethering.util.TetheringUtils.uint16; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; +import android.hardware.tetheroffload.control.V1_0.IOffloadControl; +import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; +import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; +import android.hardware.tetheroffload.control.V1_1.ITetheringOffloadCallback; +import android.hardware.tetheroffload.control.V1_1.OffloadCallbackEvent; +import android.os.Handler; +import android.os.NativeHandle; +import android.os.test.TestLooper; +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.SharedLog; +import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; +import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.mockito.MockitoAnnotations; + +import java.io.FileDescriptor; +import java.util.ArrayList; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public final class OffloadHalHidlImplTest { + private static final String RMNET0 = "test_rmnet_data0"; + + private final SharedLog mLog = new SharedLog("test"); + private final TestLooper mTestLooper = new TestLooper(); + + private OffloadHalHidlImpl mIOffloadHal; + private IOffloadConfig mIOffloadConfigMock; + private IOffloadControl mIOffloadControlMock; + private ITetheringOffloadCallback mTetheringOffloadCallback; + private OffloadHalCallback mOffloadHalCallback; + + private void createAndInitOffloadHal(int version) throws Exception { + final FileDescriptor fd1 = new FileDescriptor(); + final FileDescriptor fd2 = new FileDescriptor(); + final NativeHandle handle1 = new NativeHandle(fd1, true); + final NativeHandle handle2 = new NativeHandle(fd2, true); + mIOffloadConfigMock = mock(IOffloadConfig.class); + switch (version) { + case OFFLOAD_HAL_VERSION_HIDL_1_0: + mIOffloadControlMock = mock(IOffloadControl.class); + break; + case OFFLOAD_HAL_VERSION_HIDL_1_1: + mIOffloadControlMock = mock( + android.hardware.tetheroffload.control.V1_1.IOffloadControl.class); + break; + default: + fail("Nonexistent HAL version"); + return; + } + mIOffloadHal = new OffloadHalHidlImpl(version, mIOffloadConfigMock, + mIOffloadControlMock, new Handler(mTestLooper.getLooper()), mLog); + mIOffloadHal.initOffload(handle1, handle2, mOffloadHalCallback); + + final ArgumentCaptor<NativeHandle> nativeHandleCaptor1 = + ArgumentCaptor.forClass(NativeHandle.class); + final ArgumentCaptor<NativeHandle> nativeHandleCaptor2 = + ArgumentCaptor.forClass(NativeHandle.class); + final ArgumentCaptor<ITetheringOffloadCallback> offloadCallbackCaptor = + ArgumentCaptor.forClass(ITetheringOffloadCallback.class); + verify(mIOffloadConfigMock).setHandles(nativeHandleCaptor1.capture(), + nativeHandleCaptor2.capture(), any()); + verify(mIOffloadControlMock).initOffload(offloadCallbackCaptor.capture(), any()); + assertEquals(nativeHandleCaptor1.getValue().getFileDescriptor().getInt$(), + handle1.getFileDescriptor().getInt$()); + assertEquals(nativeHandleCaptor2.getValue().getFileDescriptor().getInt$(), + handle2.getFileDescriptor().getInt$()); + mTetheringOffloadCallback = offloadCallbackCaptor.getValue(); + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mOffloadHalCallback = spy(new OffloadHalCallback()); + } + + @Test + public void testGetForwardedStats() throws Exception { + createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0); + final long rxBytes = 12345; + final long txBytes = 67890; + doAnswer(invocation -> { + ((IOffloadControl.getForwardedStatsCallback) invocation.getArgument(1)) + .onValues(rxBytes, txBytes); + return null; + }).when(mIOffloadControlMock).getForwardedStats(eq(RMNET0), any()); + final ForwardedStats stats = mIOffloadHal.getForwardedStats(RMNET0); + verify(mIOffloadControlMock).getForwardedStats(eq(RMNET0), any()); + assertNotNull(stats); + assertEquals(rxBytes, stats.rxBytes); + assertEquals(txBytes, stats.txBytes); + } + + private void doTestSetLocalPrefixes(boolean expectSuccess) throws Exception { + createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0); + final ArrayList<String> localPrefixes = new ArrayList<>(); + localPrefixes.add("127.0.0.0/8"); + localPrefixes.add("fe80::/64"); + doAnswer(invocation -> { + ((IOffloadControl.setLocalPrefixesCallback) invocation.getArgument(1)) + .onValues(expectSuccess, ""); + return null; + }).when(mIOffloadControlMock).setLocalPrefixes(eq(localPrefixes), any()); + assertEquals(expectSuccess, mIOffloadHal.setLocalPrefixes(localPrefixes)); + verify(mIOffloadControlMock).setLocalPrefixes(eq(localPrefixes), any()); + } + + @Test + public void testSetLocalPrefixesSuccess() throws Exception { + doTestSetLocalPrefixes(true); + } + + @Test + public void testSetLocalPrefixesFailure() throws Exception { + doTestSetLocalPrefixes(false); + } + + private void doTestSetDataLimit(boolean expectSuccess) throws Exception { + createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0); + final long limit = 12345; + doAnswer(invocation -> { + ((IOffloadControl.setDataLimitCallback) invocation.getArgument(2)) + .onValues(expectSuccess, ""); + return null; + }).when(mIOffloadControlMock).setDataLimit(eq(RMNET0), eq(limit), any()); + assertEquals(expectSuccess, mIOffloadHal.setDataLimit(RMNET0, limit)); + verify(mIOffloadControlMock).setDataLimit(eq(RMNET0), eq(limit), any()); + } + + @Test + public void testSetDataLimitSuccess() throws Exception { + doTestSetDataLimit(true); + } + + @Test + public void testSetDataLimitFailure() throws Exception { + doTestSetDataLimit(false); + } + + private void doTestSetDataWarningAndLimit(boolean expectSuccess) throws Exception { + createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_1); + final long warning = 12345; + final long limit = 67890; + doAnswer(invocation -> { + ((android.hardware.tetheroffload.control.V1_1.IOffloadControl + .setDataWarningAndLimitCallback) invocation.getArgument(3)) + .onValues(expectSuccess, ""); + return null; + }).when((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mIOffloadControlMock) + .setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit), any()); + assertEquals(expectSuccess, mIOffloadHal.setDataWarningAndLimit(RMNET0, warning, limit)); + verify((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mIOffloadControlMock) + .setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit), any()); + } + + @Test + public void testSetDataWarningAndLimitSuccess() throws Exception { + doTestSetDataWarningAndLimit(true); + } + + @Test + public void testSetDataWarningAndLimitFailure() throws Exception { + // Verify that V1.0 control HAL would reject the function call with exception. + createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0); + final long warning = 12345; + final long limit = 67890; + assertThrows(UnsupportedOperationException.class, + () -> mIOffloadHal.setDataWarningAndLimit(RMNET0, warning, limit)); + + doTestSetDataWarningAndLimit(false); + } + + private void doTestSetUpstreamParameters(boolean expectSuccess) throws Exception { + createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0); + final String v4addr = "192.168.10.1"; + final String v4gateway = "192.168.10.255"; + final ArrayList<String> v6gws = new ArrayList<>(0); + v6gws.add("2001:db8::1"); + doAnswer(invocation -> { + ((IOffloadControl.setUpstreamParametersCallback) invocation.getArgument(4)) + .onValues(expectSuccess, ""); + return null; + }).when(mIOffloadControlMock).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway), + eq(v6gws), any()); + assertEquals(expectSuccess, mIOffloadHal.setUpstreamParameters(RMNET0, v4addr, v4gateway, + v6gws)); + verify(mIOffloadControlMock).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway), + eq(v6gws), any()); + } + + @Test + public void testSetUpstreamParametersSuccess() throws Exception { + doTestSetUpstreamParameters(true); + } + + @Test + public void testSetUpstreamParametersFailure() throws Exception { + doTestSetUpstreamParameters(false); + } + + private void doTestAddDownstream(boolean expectSuccess) throws Exception { + createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0); + final String ifName = "wlan1"; + final String prefix = "192.168.43.0/24"; + doAnswer(invocation -> { + ((IOffloadControl.addDownstreamCallback) invocation.getArgument(2)) + .onValues(expectSuccess, ""); + return null; + }).when(mIOffloadControlMock).addDownstream(eq(ifName), eq(prefix), any()); + assertEquals(expectSuccess, mIOffloadHal.addDownstream(ifName, prefix)); + verify(mIOffloadControlMock).addDownstream(eq(ifName), eq(prefix), any()); + } + + @Test + public void testAddDownstreamSuccess() throws Exception { + doTestAddDownstream(true); + } + + @Test + public void testAddDownstreamFailure() throws Exception { + doTestAddDownstream(false); + } + + private void doTestRemoveDownstream(boolean expectSuccess) throws Exception { + createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0); + final String ifName = "wlan1"; + final String prefix = "192.168.43.0/24"; + doAnswer(invocation -> { + ((IOffloadControl.removeDownstreamCallback) invocation.getArgument(2)) + .onValues(expectSuccess, ""); + return null; + }).when(mIOffloadControlMock).removeDownstream(eq(ifName), eq(prefix), any()); + assertEquals(expectSuccess, mIOffloadHal.removeDownstream(ifName, prefix)); + verify(mIOffloadControlMock).removeDownstream(eq(ifName), eq(prefix), any()); + } + + @Test + public void testRemoveDownstreamSuccess() throws Exception { + doTestRemoveDownstream(true); + } + + @Test + public void testRemoveDownstreamFailure() throws Exception { + doTestRemoveDownstream(false); + } + + @Test + public void testTetheringOffloadCallback() throws Exception { + createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_0); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED); + mTestLooper.dispatchAll(); + verify(mOffloadHalCallback).onStarted(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR); + mTestLooper.dispatchAll(); + verify(mOffloadHalCallback).onStoppedError(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED); + mTestLooper.dispatchAll(); + verify(mOffloadHalCallback).onStoppedUnsupported(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE); + mTestLooper.dispatchAll(); + verify(mOffloadHalCallback).onSupportAvailable(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED); + mTestLooper.dispatchAll(); + verify(mOffloadHalCallback).onStoppedLimitReached(); + + final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP); + mTetheringOffloadCallback.updateTimeout(tcpParams); + mTestLooper.dispatchAll(); + verify(mOffloadHalCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP), + eq(tcpParams.src.addr), + eq(uint16(tcpParams.src.port)), + eq(tcpParams.dst.addr), + eq(uint16(tcpParams.dst.port))); + + final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP); + mTetheringOffloadCallback.updateTimeout(udpParams); + mTestLooper.dispatchAll(); + verify(mOffloadHalCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP), + eq(udpParams.src.addr), + eq(uint16(udpParams.src.port)), + eq(udpParams.dst.addr), + eq(uint16(udpParams.dst.port))); + reset(mOffloadHalCallback); + + createAndInitOffloadHal(OFFLOAD_HAL_VERSION_HIDL_1_1); + + // Verify the interface will process the events that comes from V1.1 HAL. + mTetheringOffloadCallback.onEvent_1_1(OffloadCallbackEvent.OFFLOAD_STARTED); + mTestLooper.dispatchAll(); + final InOrder inOrder = inOrder(mOffloadHalCallback); + inOrder.verify(mOffloadHalCallback).onStarted(); + inOrder.verifyNoMoreInteractions(); + + mTetheringOffloadCallback.onEvent_1_1(OffloadCallbackEvent.OFFLOAD_WARNING_REACHED); + mTestLooper.dispatchAll(); + inOrder.verify(mOffloadHalCallback).onWarningReached(); + inOrder.verifyNoMoreInteractions(); + } + + private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) { + final NatTimeoutUpdate params = new NatTimeoutUpdate(); + params.proto = proto; + params.src.addr = "192.168.43.200"; + params.src.port = 100; + params.dst.addr = "172.50.46.169"; + params.dst.port = 150; + return params; + } +}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java index 36b439b..b1f875b 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
@@ -20,36 +20,29 @@ import static android.system.OsConstants.AF_UNIX; import static android.system.OsConstants.SOCK_STREAM; -import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0; -import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_1; -import static com.android.networkstack.tethering.util.TetheringUtils.uint16; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_AIDL; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; -import android.hardware.tetheroffload.control.V1_0.IOffloadControl; -import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; -import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; -import android.hardware.tetheroffload.control.V1_1.ITetheringOffloadCallback; -import android.hardware.tetheroffload.control.V1_1.OffloadCallbackEvent; import android.os.Handler; import android.os.NativeHandle; import android.os.test.TestLooper; import android.system.ErrnoException; import android.system.Os; -import android.system.OsConstants; -import android.util.Pair; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -57,12 +50,13 @@ import com.android.net.module.util.SharedLog; import com.android.net.module.util.netlink.StructNfGenMsg; import com.android.net.module.util.netlink.StructNlMsgHdr; +import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; +import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -79,11 +73,9 @@ private final TestLooper mTestLooper = new TestLooper(); private OffloadHardwareInterface mOffloadHw; - private ITetheringOffloadCallback mTetheringOffloadCallback; - private OffloadHardwareInterface.ControlCallback mControlCallback; + private OffloadHalCallback mOffloadHalCallback; - @Mock private IOffloadConfig mIOffloadConfig; - private IOffloadControl mIOffloadControl; + @Mock private IOffloadHal mIOffload; @Mock private NativeHandle mNativeHandle; // Random values to test Netlink message. @@ -91,32 +83,16 @@ private static final short TEST_FLAGS = 263; class MyDependencies extends OffloadHardwareInterface.Dependencies { - private final int mMockControlVersion; - MyDependencies(SharedLog log, final int mockControlVersion) { - super(log); - mMockControlVersion = mockControlVersion; + private final int mMockOffloadHalVersion; + MyDependencies(Handler handler, SharedLog log, final int mockOffloadHalVersion) { + super(handler, log); + mMockOffloadHalVersion = mockOffloadHalVersion; + when(mIOffload.getVersion()).thenReturn(mMockOffloadHalVersion); } @Override - public IOffloadConfig getOffloadConfig() { - return mIOffloadConfig; - } - - @Override - public Pair<IOffloadControl, Integer> getOffloadControl() { - switch (mMockControlVersion) { - case OFFLOAD_HAL_VERSION_1_0: - mIOffloadControl = mock(IOffloadControl.class); - break; - case OFFLOAD_HAL_VERSION_1_1: - mIOffloadControl = - mock(android.hardware.tetheroffload.control.V1_1.IOffloadControl.class); - break; - default: - throw new IllegalArgumentException("Invalid offload control version " - + mMockControlVersion); - } - return new Pair<IOffloadControl, Integer>(mIOffloadControl, mMockControlVersion); + public IOffloadHal getOffload() { + return mMockOffloadHalVersion == OFFLOAD_HAL_VERSION_NONE ? null : mIOffload; } @Override @@ -128,156 +104,140 @@ @Before public void setUp() { MockitoAnnotations.initMocks(this); - mControlCallback = spy(new OffloadHardwareInterface.ControlCallback()); + mOffloadHalCallback = new OffloadHalCallback(); + when(mIOffload.initOffload(any(NativeHandle.class), any(NativeHandle.class), + any(OffloadHalCallback.class))).thenReturn(true); } - private void startOffloadHardwareInterface(int controlVersion) throws Exception { + private void startOffloadHardwareInterface(int offloadHalVersion) + throws Exception { final SharedLog log = new SharedLog("test"); - mOffloadHw = new OffloadHardwareInterface(new Handler(mTestLooper.getLooper()), log, - new MyDependencies(log, controlVersion)); - mOffloadHw.initOffloadConfig(); - mOffloadHw.initOffloadControl(mControlCallback); - final ArgumentCaptor<ITetheringOffloadCallback> mOffloadCallbackCaptor = - ArgumentCaptor.forClass(ITetheringOffloadCallback.class); - verify(mIOffloadControl).initOffload(mOffloadCallbackCaptor.capture(), any()); - mTetheringOffloadCallback = mOffloadCallbackCaptor.getValue(); + final Handler handler = new Handler(mTestLooper.getLooper()); + final int num = offloadHalVersion != OFFLOAD_HAL_VERSION_NONE ? 1 : 0; + mOffloadHw = new OffloadHardwareInterface(handler, log, + new MyDependencies(handler, log, offloadHalVersion)); + assertEquals(offloadHalVersion, mOffloadHw.initOffload(mOffloadHalCallback)); + verify(mIOffload, times(num)).initOffload(any(NativeHandle.class), any(NativeHandle.class), + eq(mOffloadHalCallback)); + } + + @Test + public void testInitFailureWithNoHal() throws Exception { + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_NONE); + } + + @Test + public void testInitSuccessWithAidl() throws Exception { + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_AIDL); + } + + @Test + public void testInitSuccessWithHidl_1_0() throws Exception { + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0); + } + + @Test + public void testInitSuccessWithHidl_1_1() throws Exception { + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_1); } @Test public void testGetForwardedStats() throws Exception { - startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); - final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0); - verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any()); - assertNotNull(stats); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0); + ForwardedStats stats = new ForwardedStats(12345, 56780); + when(mIOffload.getForwardedStats(anyString())).thenReturn(stats); + assertEquals(mOffloadHw.getForwardedStats(RMNET0), stats); + verify(mIOffload).getForwardedStats(eq(RMNET0)); } @Test public void testSetLocalPrefixes() throws Exception { - startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0); final ArrayList<String> localPrefixes = new ArrayList<>(); localPrefixes.add("127.0.0.0/8"); localPrefixes.add("fe80::/64"); - mOffloadHw.setLocalPrefixes(localPrefixes); - verify(mIOffloadControl).setLocalPrefixes(eq(localPrefixes), any()); + when(mIOffload.setLocalPrefixes(any())).thenReturn(true); + assertTrue(mOffloadHw.setLocalPrefixes(localPrefixes)); + verify(mIOffload).setLocalPrefixes(eq(localPrefixes)); + when(mIOffload.setLocalPrefixes(any())).thenReturn(false); + assertFalse(mOffloadHw.setLocalPrefixes(localPrefixes)); } @Test public void testSetDataLimit() throws Exception { - startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0); final long limit = 12345; - mOffloadHw.setDataLimit(RMNET0, limit); - verify(mIOffloadControl).setDataLimit(eq(RMNET0), eq(limit), any()); + when(mIOffload.setDataLimit(anyString(), anyLong())).thenReturn(true); + assertTrue(mOffloadHw.setDataLimit(RMNET0, limit)); + verify(mIOffload).setDataLimit(eq(RMNET0), eq(limit)); + when(mIOffload.setDataLimit(anyString(), anyLong())).thenReturn(false); + assertFalse(mOffloadHw.setDataLimit(RMNET0, limit)); + } + + @Test + public void testSetDataWarningAndLimitFailureWithHidl_1_0() throws Exception { + // Verify V1.0 control HAL would reject the function call with exception. + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0); + final long warning = 12345; + final long limit = 67890; + assertThrows(UnsupportedOperationException.class, + () -> mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit)); } @Test public void testSetDataWarningAndLimit() throws Exception { - // Verify V1.0 control HAL would reject the function call with exception. - startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); + // Verify V1.1 control HAL could receive this function call. + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_1); final long warning = 12345; final long limit = 67890; - assertThrows(IllegalArgumentException.class, - () -> mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit)); - reset(mIOffloadControl); - - // Verify V1.1 control HAL could receive this function call. - startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_1); - mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit); - verify((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mIOffloadControl) - .setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit), any()); + when(mIOffload.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(true); + assertTrue(mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit)); + verify(mIOffload).setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit)); + when(mIOffload.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(false); + assertFalse(mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit)); } @Test public void testSetUpstreamParameters() throws Exception { - startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0); final String v4addr = "192.168.10.1"; final String v4gateway = "192.168.10.255"; final ArrayList<String> v6gws = new ArrayList<>(0); v6gws.add("2001:db8::1"); - mOffloadHw.setUpstreamParameters(RMNET0, v4addr, v4gateway, v6gws); - verify(mIOffloadControl).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway), - eq(v6gws), any()); + when(mIOffload.setUpstreamParameters(anyString(), anyString(), anyString(), any())) + .thenReturn(true); + assertTrue(mOffloadHw.setUpstreamParameters(RMNET0, v4addr, v4gateway, v6gws)); + verify(mIOffload).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway), eq(v6gws)); final ArgumentCaptor<ArrayList<String>> mArrayListCaptor = ArgumentCaptor.forClass(ArrayList.class); - mOffloadHw.setUpstreamParameters(null, null, null, null); - verify(mIOffloadControl).setUpstreamParameters(eq(""), eq(""), eq(""), - mArrayListCaptor.capture(), any()); + when(mIOffload.setUpstreamParameters(anyString(), anyString(), anyString(), any())) + .thenReturn(false); + assertFalse(mOffloadHw.setUpstreamParameters(null, null, null, null)); + verify(mIOffload).setUpstreamParameters(eq(""), eq(""), eq(""), mArrayListCaptor.capture()); assertEquals(mArrayListCaptor.getValue().size(), 0); } @Test - public void testUpdateDownstreamPrefix() throws Exception { - startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); + public void testUpdateDownstream() throws Exception { + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0); final String ifName = "wlan1"; final String prefix = "192.168.43.0/24"; - mOffloadHw.addDownstreamPrefix(ifName, prefix); - verify(mIOffloadControl).addDownstream(eq(ifName), eq(prefix), any()); - - mOffloadHw.removeDownstreamPrefix(ifName, prefix); - verify(mIOffloadControl).removeDownstream(eq(ifName), eq(prefix), any()); - } - - @Test - public void testTetheringOffloadCallback() throws Exception { - startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); - - mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED); - mTestLooper.dispatchAll(); - verify(mControlCallback).onStarted(); - - mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR); - mTestLooper.dispatchAll(); - verify(mControlCallback).onStoppedError(); - - mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED); - mTestLooper.dispatchAll(); - verify(mControlCallback).onStoppedUnsupported(); - - mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE); - mTestLooper.dispatchAll(); - verify(mControlCallback).onSupportAvailable(); - - mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED); - mTestLooper.dispatchAll(); - verify(mControlCallback).onStoppedLimitReached(); - - final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP); - mTetheringOffloadCallback.updateTimeout(tcpParams); - mTestLooper.dispatchAll(); - verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP), - eq(tcpParams.src.addr), - eq(uint16(tcpParams.src.port)), - eq(tcpParams.dst.addr), - eq(uint16(tcpParams.dst.port))); - - final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP); - mTetheringOffloadCallback.updateTimeout(udpParams); - mTestLooper.dispatchAll(); - verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP), - eq(udpParams.src.addr), - eq(uint16(udpParams.src.port)), - eq(udpParams.dst.addr), - eq(uint16(udpParams.dst.port))); - reset(mControlCallback); - - startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_1); - - // Verify the interface will process the events that comes from V1.1 HAL. - mTetheringOffloadCallback.onEvent_1_1(OffloadCallbackEvent.OFFLOAD_STARTED); - mTestLooper.dispatchAll(); - final InOrder inOrder = inOrder(mControlCallback); - inOrder.verify(mControlCallback).onStarted(); - inOrder.verifyNoMoreInteractions(); - - mTetheringOffloadCallback.onEvent_1_1(OffloadCallbackEvent.OFFLOAD_WARNING_REACHED); - mTestLooper.dispatchAll(); - inOrder.verify(mControlCallback).onWarningReached(); - inOrder.verifyNoMoreInteractions(); + when(mIOffload.addDownstream(anyString(), anyString())).thenReturn(true); + assertTrue(mOffloadHw.addDownstream(ifName, prefix)); + verify(mIOffload).addDownstream(eq(ifName), eq(prefix)); + when(mIOffload.addDownstream(anyString(), anyString())).thenReturn(false); + assertFalse(mOffloadHw.addDownstream(ifName, prefix)); + when(mIOffload.removeDownstream(anyString(), anyString())).thenReturn(true); + assertTrue(mOffloadHw.removeDownstream(ifName, prefix)); + verify(mIOffload).removeDownstream(eq(ifName), eq(prefix)); + when(mIOffload.removeDownstream(anyString(), anyString())).thenReturn(false); + assertFalse(mOffloadHw.removeDownstream(ifName, prefix)); } @Test public void testSendIpv4NfGenMsg() throws Exception { - startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0); FileDescriptor writeSocket = new FileDescriptor(); FileDescriptor readSocket = new FileDescriptor(); try { @@ -308,14 +268,4 @@ assertEquals(0 /* error */, buffer.getShort()); // res_id assertEquals(expectedLen, buffer.position()); } - - private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) { - final NatTimeoutUpdate params = new NatTimeoutUpdate(); - params.proto = proto; - params.src.addr = "192.168.43.200"; - params.src.port = 100; - params.dst.addr = "172.50.46.169"; - params.dst.port = 150; - return params; - } }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 55d9852..91b092a 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -19,6 +19,8 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL; +import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; @@ -61,6 +63,7 @@ private static final String TEST_IFNAME = "test0"; @Mock private IpServer mHotspotIpServer; + @Mock private IpServer mLocalHotspotIpServer; @Mock private IpServer mUsbIpServer; @Mock private IpServer mEthernetIpServer; @Mock private IpServer mWifiP2pIpServer; @@ -90,6 +93,7 @@ when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB); when(mEthernetIpServer.interfaceType()).thenReturn(TETHERING_ETHERNET); when(mHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI); + when(mLocalHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI); when(mWifiP2pIpServer.interfaceType()).thenReturn(TETHERING_WIFI_P2P); } @@ -104,9 +108,10 @@ mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig)); } - private LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { + private LinkAddress requestDownstreamAddress(final IpServer ipServer, int scope, + boolean useLastAddress) { final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - ipServer, useLastAddress); + ipServer, scope, useLastAddress); when(ipServer.getAddress()).thenReturn(address); return address; } @@ -115,19 +120,19 @@ public void testRequestDownstreamAddressWithoutUsingLastAddress() throws Exception { final IpPrefix bluetoothPrefix = asIpPrefix(mBluetoothAddress); final LinkAddress address = requestDownstreamAddress(mHotspotIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(address); assertNotEquals(hotspotPrefix, bluetoothPrefix); final LinkAddress newAddress = requestDownstreamAddress(mHotspotIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix testDupRequest = asIpPrefix(newAddress); assertNotEquals(hotspotPrefix, testDupRequest); assertNotEquals(bluetoothPrefix, testDupRequest); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix usbPrefix = asIpPrefix(usbAddress); assertNotEquals(usbPrefix, bluetoothPrefix); assertNotEquals(usbPrefix, hotspotPrefix); @@ -139,25 +144,28 @@ int fakeSubAddr = 0x2b00; // 43.0. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); LinkAddress actualAddress = requestDownstreamAddress(mHotspotIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.43.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2d01; // 45.1. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); - actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); + actualAddress = requestDownstreamAddress(mHotspotIpServer, + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.45.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2eff; // 46.255. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); - actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); + actualAddress = requestDownstreamAddress(mHotspotIpServer, + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.46.254/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2f05; // 47.5. when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); - actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); + actualAddress = requestDownstreamAddress(mHotspotIpServer, + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); } @@ -168,7 +176,7 @@ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mBluetoothAddress.getAddress().getAddress())); final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddress); assertNotEquals(asIpPrefix(mBluetoothAddress), hotspotPrefix); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); @@ -177,7 +185,7 @@ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(hotspotAddress.getAddress().getAddress())); final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix usbPrefix = asIpPrefix(usbAddress); assertNotEquals(asIpPrefix(mBluetoothAddress), usbPrefix); assertNotEquals(hotspotPrefix, usbPrefix); @@ -187,7 +195,7 @@ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress())); final LinkAddress etherAddress = requestDownstreamAddress(mEthernetIpServer, - false /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */); final IpPrefix etherPrefix = asIpPrefix(etherAddress); assertNotEquals(asIpPrefix(mLegacyWifiP2pAddress), etherPrefix); assertNotEquals(asIpPrefix(mBluetoothAddress), etherPrefix); @@ -200,11 +208,11 @@ final int fakeHotspotSubAddr = 0x2b05; // 43.5 when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress); final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.45.5/24"), usbAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); @@ -214,10 +222,10 @@ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); final LinkAddress newHotspotAddress = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals(hotspotAddress, newHotspotAddress); final LinkAddress newUsbAddress = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals(usbAddress, newUsbAddress); final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, @@ -257,7 +265,7 @@ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); // - Enable hotspot with prefix 192.168.43.0/24 final LinkAddress hotspotAddr = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddr); assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); // - test mobile network with null NetworkCapabilities. Ideally this should not happen @@ -311,21 +319,21 @@ // - Restart hotspot again and its prefix is different previous. mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); final LinkAddress hotspotAddr2 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); final IpPrefix hotspotPrefix2 = asIpPrefix(hotspotAddr2); assertNotEquals(hotspotPrefix, hotspotPrefix2); mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); // - Usb tethering can be enabled and its prefix is different with conflict one. final LinkAddress usbAddr = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); final IpPrefix usbPrefix = asIpPrefix(usbAddr); assertNotEquals(predefinedPrefix, usbPrefix); assertNotEquals(hotspotPrefix2, usbPrefix); // - Disable wifi upstream, then wifi's prefix can be selected again. mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); final LinkAddress ethAddr = requestDownstreamAddress(mEthernetIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); final IpPrefix ethPrefix = asIpPrefix(ethAddr); assertEquals(predefinedPrefix, ethPrefix); } @@ -335,7 +343,7 @@ final int randomAddress = 0x8605; // 134.5 when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); final LinkAddress addr0 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.134.5. assertEquals("Wrong prefix: ", new LinkAddress("192.168.134.5/24"), addr0); final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, @@ -345,7 +353,7 @@ // Check whether return address is next prefix of 192.168.134.0/24. final LinkAddress addr1 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.135.5/24"), addr1); final UpstreamNetworkState wifiUpstream2 = buildUpstreamNetworkState(mWifiNetwork, new LinkAddress("192.168.149.16/19"), null, @@ -355,7 +363,7 @@ // The conflict range is 128 ~ 159, so the address is 192.168.160.5/24. final LinkAddress addr2 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.160.5/24"), addr2); final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, new LinkAddress("192.168.129.53/18"), null, @@ -370,7 +378,7 @@ // The conflict range are 128 ~ 159 and 159 ~ 191, so the address is 192.168.192.5/24. final LinkAddress addr3 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.192.5/24"), addr3); final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, new LinkAddress("192.168.188.133/17"), null, @@ -380,7 +388,7 @@ // Conflict range: 128 ~ 255. The next available address is 192.168.0.5 because // 192.168.134/24 ~ 192.168.255.255/24 is not available. final LinkAddress addr4 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.0.5/24"), addr4); final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, new LinkAddress("192.168.3.59/21"), null, @@ -389,7 +397,7 @@ // Conflict ranges: 128 ~ 255 and 0 ~ 7, so the address is 192.168.8.5/24. final LinkAddress addr5 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr5); final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, new LinkAddress("192.168.68.43/21"), null, @@ -399,7 +407,7 @@ // Update an upstream that does *not* conflict, check whether return the same address // 192.168.5/24. final LinkAddress addr6 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr6); final UpstreamNetworkState mobileUpstream6 = buildUpstreamNetworkState(mMobileNetwork6, new LinkAddress("192.168.10.97/21"), null, @@ -408,7 +416,7 @@ // Conflict ranges: 0 ~ 15 and 128 ~ 255, so the address is 192.168.16.5/24. final LinkAddress addr7 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.16.5/24"), addr7); final UpstreamNetworkState mobileUpstream7 = buildUpstreamNetworkState(mMobileNetwork6, new LinkAddress("192.168.0.0/17"), null, @@ -417,7 +425,7 @@ // Choose prefix from next range(172.16.0.0/12) when no available prefix in 192.168.0.0/16. final LinkAddress addr8 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.134.5/24"), addr8); } @@ -426,7 +434,7 @@ final int randomAddress = 0x1f2b2a; // 31.43.42 when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); final LinkAddress classC1 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.43.42. assertEquals("Wrong prefix: ", new LinkAddress("192.168.43.42/24"), classC1); final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, @@ -437,7 +445,7 @@ // Check whether return address is next address of prefix 192.168.128.0/17. final LinkAddress classC2 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("192.168.128.42/24"), classC2); final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, new LinkAddress("192.1.2.3/8"), null, @@ -447,7 +455,7 @@ // Check whether return address is under prefix 172.16.0.0/12. final LinkAddress classB1 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.31.43.42/24"), classB1); final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2, new LinkAddress("172.28.123.100/14"), null, @@ -458,12 +466,12 @@ // 172.28.0.0 ~ 172.31.255.255 is not available. // Check whether return address is next address of prefix 172.16.0.0/14. final LinkAddress classB2 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.0.42/24"), classB2); // Check whether new downstream is next address of address 172.16.0.42/24. final LinkAddress classB3 = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.1.42/24"), classB3); final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, new LinkAddress("172.16.0.1/24"), null, @@ -474,7 +482,7 @@ // Check whether return address is next address of prefix 172.16.1.42/24. final LinkAddress classB4 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.16.2.42/24"), classB4); final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, new LinkAddress("172.16.0.1/13"), null, @@ -485,11 +493,11 @@ // Check whether return address is next address of prefix 172.16.0.1/13. final LinkAddress classB5 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.24.0.42/24"), classB5); // Check whether return address is next address of prefix 172.24.0.42/24. final LinkAddress classB6 = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("172.24.1.42/24"), classB6); final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, new LinkAddress("172.24.0.1/12"), null, @@ -500,11 +508,11 @@ // Check whether return address is prefix 10.0.0.0/8 + subAddress 0.31.43.42. final LinkAddress classA1 = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("10.31.43.42/24"), classA1); // Check whether new downstream is next address of address 10.31.43.42/24. final LinkAddress classA2 = requestDownstreamAddress(mUsbIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); assertEquals("Wrong prefix: ", new LinkAddress("10.31.44.42/24"), classA2); } @@ -524,7 +532,7 @@ private void assertReseveredWifiP2pPrefix() throws Exception { LinkAddress address = requestDownstreamAddress(mHotspotIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); final IpPrefix hotspotPrefix = asIpPrefix(address); final IpPrefix legacyWifiP2pPrefix = asIpPrefix(mLegacyWifiP2pAddress); assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix); @@ -544,8 +552,23 @@ // If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address. LinkAddress address = requestDownstreamAddress(mWifiP2pIpServer, - true /* useLastAddress */); + CONNECTIVITY_SCOPE_LOCAL, true /* useLastAddress */); assertEquals(mLegacyWifiP2pAddress, address); mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer); } + + @Test + public void testEnableSapAndLohsConcurrently() throws Exception { + // 0x2b05 -> 43.5, 0x8605 -> 134.5 + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(0x2b05, 0x8605); + + final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer, + CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */); + assertEquals("Wrong hotspot prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress); + + final LinkAddress localHotspotAddress = requestDownstreamAddress(mLocalHotspotIpServer, + CONNECTIVITY_SCOPE_LOCAL, true /* useLastAddress */); + assertEquals("Wrong local hotspot prefix: ", new LinkAddress("192.168.134.5/24"), + localHotspotAddress); + } }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index f662c02..3382af8 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -21,14 +21,13 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.telephony.CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL; import static android.telephony.CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.networkstack.apishim.ConstantsShim.KEY_CARRIER_SUPPORTS_TETHERING_BOOL; +import static com.android.networkstack.tethering.TetheringConfiguration.OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD; +import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER; import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_FORCE_USB_FUNCTIONS; import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_NCM_FUNCTION; import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_RNDIS_FUNCTION; @@ -39,6 +38,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; import android.content.Context; @@ -49,12 +49,13 @@ import android.content.res.Resources; import android.os.Build; import android.os.PersistableBundle; -import android.provider.DeviceConfig; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.TelephonyManager; import android.test.mock.MockContentResolver; +import android.util.ArrayMap; +import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -73,8 +74,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoSession; -import org.mockito.quality.Strictness; +import org.mockito.MockitoAnnotations; import java.util.Arrays; import java.util.Iterator; @@ -102,13 +102,13 @@ @Mock private ModuleInfo mMi; private Context mMockContext; private boolean mHasTelephonyManager; - private MockitoSession mMockingSession; private MockContentResolver mContentResolver; private final PersistableBundle mCarrierConfig = new PersistableBundle(); + private final MockDependencies mDeps = new MockDependencies(); private class MockTetheringConfiguration extends TetheringConfiguration { MockTetheringConfiguration(Context ctx, SharedLog log, int id) { - super(ctx, log, id); + super(ctx, log, id, mDeps); } @Override @@ -151,19 +151,43 @@ } } + private static class MockDependencies extends TetheringConfiguration.Dependencies { + private ArrayMap<String, Boolean> mMockFlags = new ArrayMap<>(); + + @Override + boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, + @NonNull String name, @NonNull String moduleName, boolean defaultEnabled) { + return isMockFlagEnabled(name, defaultEnabled); + } + + @Override + boolean getDeviceConfigBoolean(@NonNull String namespace, @NonNull String name, + boolean defaultValue) { + // Flags should use isFeatureEnabled instead of getBoolean; see comments in + // DeviceConfigUtils. getBoolean should only be used for the two legacy flags below. + assertTrue(OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD.equals(name) + || TETHER_ENABLE_LEGACY_DHCP_SERVER.equals(name)); + + // Use the same mocking strategy as isFeatureEnabled for testing + return isMockFlagEnabled(name, defaultValue); + } + + private boolean isMockFlagEnabled(@NonNull String name, boolean defaultEnabled) { + final Boolean flag = mMockFlags.getOrDefault(name, defaultEnabled); + // Value in the map can also be null + if (flag != null) return flag; + return defaultEnabled; + } + + void setFeatureEnabled(@NonNull String flag, Boolean enabled) { + mMockFlags.put(flag, enabled); + } + } + @Before public void setUp() throws Exception { - // TODO: use a dependencies class instead of mock statics. - mMockingSession = mockitoSession() - .initMocks(this) - .mockStatic(DeviceConfig.class) - .strictness(Strictness.WARN) - .startMocking(); - DeviceConfigUtils.resetPackageVersionCacheForTest(); - doReturn(null).when( - () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); - setTetherForceUpstreamAutomaticFlagVersion(null); + MockitoAnnotations.initMocks(this); + setTetherForceUpstreamAutomaticFlagEnabled(null); final PackageInfo pi = new PackageInfo(); pi.setLongVersionCode(TEST_PACKAGE_VERSION); @@ -202,7 +226,6 @@ @After public void tearDown() throws Exception { - mMockingSession.finishMocking(); DeviceConfigUtils.resetPackageVersionCacheForTest(); // Call {@link #clearSettingsProvider()} before and after using FakeSettingsProvider. FakeSettingsProvider.clearSettingsProvider(); @@ -211,7 +234,7 @@ private TetheringConfiguration getTetheringConfiguration(int... legacyTetherUpstreamTypes) { when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn( legacyTetherUpstreamTypes); - return new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + return new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); } @Test @@ -297,7 +320,7 @@ when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); @@ -320,7 +343,7 @@ when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); @@ -338,7 +361,7 @@ when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_WIFI, upstreamIterator.next().intValue()); @@ -350,27 +373,26 @@ } private void initializeBpfOffloadConfiguration( - final boolean fromRes, final String fromDevConfig) { + final boolean fromRes, final Boolean fromDevConfig) { when(mResources.getBoolean(R.bool.config_tether_enable_bpf_offload)).thenReturn(fromRes); - doReturn(fromDevConfig).when( - () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD))); + mDeps.setFeatureEnabled( + TetheringConfiguration.OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD, fromDevConfig); } @Test public void testBpfOffloadEnabledByResource() { initializeBpfOffloadConfiguration(true, null /* unset */); final TetheringConfiguration enableByRes = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertTrue(enableByRes.isBpfOffloadEnabled()); } @Test public void testBpfOffloadEnabledByDeviceConfigOverride() { for (boolean res : new boolean[]{true, false}) { - initializeBpfOffloadConfiguration(res, "true"); + initializeBpfOffloadConfiguration(res, true); final TetheringConfiguration enableByDevConOverride = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertTrue(enableByDevConOverride.isBpfOffloadEnabled()); } } @@ -379,16 +401,16 @@ public void testBpfOffloadDisabledByResource() { initializeBpfOffloadConfiguration(false, null /* unset */); final TetheringConfiguration disableByRes = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertFalse(disableByRes.isBpfOffloadEnabled()); } @Test public void testBpfOffloadDisabledByDeviceConfigOverride() { for (boolean res : new boolean[]{true, false}) { - initializeBpfOffloadConfiguration(res, "false"); + initializeBpfOffloadConfiguration(res, false); final TetheringConfiguration disableByDevConOverride = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertFalse(disableByDevConOverride.isBpfOffloadEnabled()); } } @@ -397,22 +419,18 @@ public void testNewDhcpServerDisabled() { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( true); - doReturn("false").when( - () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); + mDeps.setFeatureEnabled(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER, false); final TetheringConfiguration enableByRes = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertTrue(enableByRes.useLegacyDhcpServer()); when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); - doReturn("true").when( - () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); + mDeps.setFeatureEnabled(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER, true); final TetheringConfiguration enableByDevConfig = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertTrue(enableByDevConfig.useLegacyDhcpServer()); } @@ -420,12 +438,10 @@ public void testNewDhcpServerEnabled() { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); - doReturn("false").when( - () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); + mDeps.setFeatureEnabled(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER, false); final TetheringConfiguration cfg = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertFalse(cfg.useLegacyDhcpServer()); } @@ -433,7 +449,7 @@ @Test public void testOffloadIntervalByResource() { final TetheringConfiguration intervalByDefault = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertEquals(TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, intervalByDefault.getOffloadPollInterval()); @@ -442,7 +458,7 @@ when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn( override); final TetheringConfiguration overrideByRes = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertEquals(override, overrideByRes.getOffloadPollInterval()); } } @@ -451,7 +467,7 @@ public void testGetResourcesBySubId() { setUpResourceForSubId(); final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertTrue(cfg.provisioningApp.length == 0); final int anyValidSubId = 1; final MockTetheringConfiguration mockCfg = @@ -493,7 +509,7 @@ mockService(Context.CARRIER_CONFIG_SERVICE, CarrierConfigManager.class, null); final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertTrue(cfg.isCarrierSupportTethering); assertTrue(cfg.isCarrierConfigAffirmsEntitlementCheckRequired); @@ -506,7 +522,7 @@ CarrierConfigManager.class, mCarrierConfigManager); when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(null); final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertTrue(cfg.isCarrierSupportTethering); assertTrue(cfg.isCarrierConfigAffirmsEntitlementCheckRequired); @@ -521,7 +537,7 @@ mCarrierConfig.putBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, false); when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mCarrierConfig); final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); if (SdkLevel.isAtLeastT()) { assertFalse(cfg.isCarrierSupportTethering); @@ -535,13 +551,13 @@ @Test public void testEnableLegacyWifiP2PAddress() throws Exception { final TetheringConfiguration defaultCfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertFalse(defaultCfg.shouldEnableWifiP2pDedicatedIp()); when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip)) .thenReturn(true); final TetheringConfiguration testCfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertTrue(testCfg.shouldEnableWifiP2pDedicatedIp()); } @@ -576,16 +592,13 @@ public void testChooseUpstreamAutomatically_FlagOverride() throws Exception { when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) .thenReturn(false); - setTetherForceUpstreamAutomaticFlagVersion(TEST_PACKAGE_VERSION - 1); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mMockContext, NAMESPACE_CONNECTIVITY, - TetheringConfiguration.TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION, APEX_NAME, false)); - + setTetherForceUpstreamAutomaticFlagEnabled(true); assertChooseUpstreamAutomaticallyIs(true); - setTetherForceUpstreamAutomaticFlagVersion(0L); + setTetherForceUpstreamAutomaticFlagEnabled(null); assertChooseUpstreamAutomaticallyIs(false); - setTetherForceUpstreamAutomaticFlagVersion(Long.MAX_VALUE); + setTetherForceUpstreamAutomaticFlagEnabled(false); assertChooseUpstreamAutomaticallyIs(false); } @@ -593,7 +606,7 @@ public void testChooseUpstreamAutomatically_FlagOverrideOnSAndT() throws Exception { when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) .thenReturn(false); - setTetherForceUpstreamAutomaticFlagVersion(TEST_PACKAGE_VERSION - 1); + setTetherForceUpstreamAutomaticFlagEnabled(true); assertChooseUpstreamAutomaticallyIs(false); } @@ -604,28 +617,24 @@ // TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION is. when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) .thenReturn(false); - setTetherForceUpstreamAutomaticFlagVersion(TEST_PACKAGE_VERSION - 1); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mMockContext, NAMESPACE_CONNECTIVITY, - TetheringConfiguration.TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION, APEX_NAME, false)); - + setTetherForceUpstreamAutomaticFlagEnabled(true); assertChooseUpstreamAutomaticallyIs(true); - setTetherForceUpstreamAutomaticFlagVersion(0L); + setTetherForceUpstreamAutomaticFlagEnabled(null); assertChooseUpstreamAutomaticallyIs(true); - setTetherForceUpstreamAutomaticFlagVersion(Long.MAX_VALUE); + setTetherForceUpstreamAutomaticFlagEnabled(false); assertChooseUpstreamAutomaticallyIs(true); } - private void setTetherForceUpstreamAutomaticFlagVersion(Long version) { - doReturn(version == null ? null : Long.toString(version)).when( - () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION))); + private void setTetherForceUpstreamAutomaticFlagEnabled(Boolean enabled) { + mDeps.setFeatureEnabled( + TetheringConfiguration.TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION, enabled); } private void assertChooseUpstreamAutomaticallyIs(boolean value) { - assertEquals(value, new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID) - .chooseUpstreamAutomatically); + assertEquals(value, new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps).chooseUpstreamAutomatically); } @Test @@ -654,7 +663,7 @@ private void assertIsUsingNcm(boolean expected) { final TetheringConfiguration cfg = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertEquals(expected, cfg.isUsingNcm()); } @@ -704,7 +713,7 @@ private void assertUsbAndNcmRegexs(final String[] usbRegexs, final String[] ncmRegexs) { final TetheringConfiguration cfg = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertArrayEquals(usbRegexs, cfg.tetherableUsbRegexs); assertArrayEquals(ncmRegexs, cfg.tetherableNcmRegexs); } @@ -716,28 +725,28 @@ final int defaultSubnetPrefixLength = 0; final TetheringConfiguration defaultCfg = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertEquals(defaultSubnetPrefixLength, defaultCfg.getP2pLeasesSubnetPrefixLength()); final int prefixLengthTooSmall = -1; when(mResources.getInteger(R.integer.config_p2p_leases_subnet_prefix_length)).thenReturn( prefixLengthTooSmall); final TetheringConfiguration tooSmallCfg = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertEquals(defaultSubnetPrefixLength, tooSmallCfg.getP2pLeasesSubnetPrefixLength()); final int prefixLengthTooLarge = 31; when(mResources.getInteger(R.integer.config_p2p_leases_subnet_prefix_length)).thenReturn( prefixLengthTooLarge); final TetheringConfiguration tooLargeCfg = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertEquals(defaultSubnetPrefixLength, tooLargeCfg.getP2pLeasesSubnetPrefixLength()); final int p2pLeasesSubnetPrefixLength = 27; when(mResources.getInteger(R.integer.config_p2p_leases_subnet_prefix_length)).thenReturn( p2pLeasesSubnetPrefixLength); final TetheringConfiguration p2pCfg = - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID, mDeps); assertEquals(p2pLeasesSubnetPrefixLength, p2pCfg.getP2pLeasesSubnetPrefixLength()); } }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index 75c819b..ac3d713 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
@@ -156,6 +156,7 @@ @After fun tearDown() { fakeTetheringThread.quitSafely() + fakeTetheringThread.join() } private fun verifyActivityPendingIntent(intent: Intent, flags: Int) {
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java index 38f1e9c..da81bda 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -666,7 +666,7 @@ // Calling System.gc() or System.runFinalization() doesn't guarantee GCs or finalizers // are executed synchronously. The finalizer is called after GC on a separate thread. - final int attempts = 100; + final int attempts = 600; final long waitIntervalMs = 50; for (int i = 0; i < attempts; i++) { forceGc();
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index a8d886b..bd8b325 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -29,6 +29,7 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; @@ -67,7 +68,7 @@ import static com.android.modules.utils.build.SdkLevel.isAtLeastT; import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; -import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0; +import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0; import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE; import static com.android.networkstack.tethering.TestConnectivityManager.BROADCAST_FIRST; import static com.android.networkstack.tethering.TestConnectivityManager.CALLBACKS_FIRST; @@ -82,6 +83,8 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; @@ -179,6 +182,7 @@ import android.util.ArraySet; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -258,6 +262,8 @@ private static final int DHCPSERVER_START_TIMEOUT_MS = 1000; + private static final Network[] NULL_NETWORK = new Network[] {null}; + @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; @Mock private NetworkStatsManager mStatsManager; @@ -300,6 +306,7 @@ private MockContentResolver mContentResolver; private BroadcastReceiver mBroadcastReceiver; private Tethering mTethering; + private TestTetheringEventCallback mTetheringEventCallback; private PhoneStateListener mPhoneStateListener; private InterfaceConfigurationParcel mInterfaceConfiguration; private TetheringConfiguration mConfig; @@ -642,8 +649,7 @@ mInterfaceConfiguration.flags = new String[0]; when(mRouterAdvertisementDaemon.start()) .thenReturn(true); - initOffloadConfiguration(true /* offloadConfig */, OFFLOAD_HAL_VERSION_1_0, - 0 /* defaultDisabled */); + initOffloadConfiguration(OFFLOAD_HAL_VERSION_HIDL_1_0, 0 /* defaultDisabled */); when(mOffloadHardwareInterface.getForwardedStats(any())).thenReturn(mForwardedStats); mServiceContext = new TestContext(mContext); @@ -667,6 +673,7 @@ verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any()); verify(mNetd).registerUnsolicitedEventListener(any()); verifyDefaultNetworkRequestFiled(); + mTetheringEventCallback = registerTetheringEventCallback(); final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor = ArgumentCaptor.forClass(PhoneStateListener.class); @@ -742,6 +749,16 @@ return request; } + @NonNull + private TestTetheringEventCallback registerTetheringEventCallback() { + TestTetheringEventCallback callback = new TestTetheringEventCallback(); + mTethering.registerTetheringEventCallback(callback); + mLooper.dispatchAll(); + // Pull the first event which is filed immediately after the callback registration. + callback.expectUpstreamChanged(NULL_NETWORK); + return callback; + } + @After public void tearDown() { mServiceContext.unregisterReceiver(mBroadcastReceiver); @@ -921,9 +938,9 @@ // tetherMatchingInterfaces() which starts by fetching all interfaces). verify(mNetd, times(1)).interfaceGetList(); - // UpstreamNetworkMonitor should receive selected upstream + // Event callback should receive selected upstream verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream(); - verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network); + mTetheringEventCallback.expectUpstreamChanged(upstreamState.network); } @Test @@ -1178,7 +1195,7 @@ verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream(); verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any()); - verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network); + mTetheringEventCallback.expectUpstreamChanged(upstreamState.network); } private void verifyDisableTryCellWhenTetheringStop(InOrder inOrder) { @@ -1203,14 +1220,14 @@ mobile.fakeConnect(); mCm.makeDefaultNetwork(mobile, BROADCAST_FIRST); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(mobile.networkId); + mTetheringEventCallback.expectUpstreamChanged(mobile.networkId); // Switch upstream to wifi. wifi.fakeConnect(); mCm.makeDefaultNetwork(wifi, BROADCAST_FIRST); mLooper.dispatchAll(); inOrder.verify(mUpstreamNetworkMonitor).setTryCell(false); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(wifi.networkId); + mTetheringEventCallback.expectUpstreamChanged(wifi.networkId); } private void verifyAutomaticUpstreamSelection(boolean configAutomatic) throws Exception { @@ -1227,30 +1244,30 @@ // Switch upstreams a few times. mCm.makeDefaultNetwork(mobile, BROADCAST_FIRST, doDispatchAll); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(mobile.networkId); + mTetheringEventCallback.expectUpstreamChanged(mobile.networkId); mCm.makeDefaultNetwork(wifi, BROADCAST_FIRST, doDispatchAll); mLooper.dispatchAll(); inOrder.verify(mUpstreamNetworkMonitor).setTryCell(false); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(wifi.networkId); + mTetheringEventCallback.expectUpstreamChanged(wifi.networkId); mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(mobile.networkId); + mTetheringEventCallback.expectUpstreamChanged(mobile.networkId); mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST); mLooper.dispatchAll(); inOrder.verify(mUpstreamNetworkMonitor).setTryCell(false); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(wifi.networkId); + mTetheringEventCallback.expectUpstreamChanged(wifi.networkId); mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST, doDispatchAll); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(mobile.networkId); + mTetheringEventCallback.expectUpstreamChanged(mobile.networkId); // Wifi disconnecting should not have any affect since it's not the current upstream. wifi.fakeDisconnect(); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor, never()).setCurrentUpstream(any()); + mTetheringEventCallback.assertNoUpstreamChangeCallback(); // Lose and regain upstream. assertTrue(mUpstreamNetworkMonitor.getCurrentPreferredUpstream().linkProperties @@ -1260,13 +1277,13 @@ mobile.fakeDisconnect(); mLooper.dispatchAll(); inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(null); + mTetheringEventCallback.expectUpstreamChanged(NULL_NETWORK); mobile = new TestNetworkAgent(mCm, buildMobile464xlatUpstreamState()); mobile.fakeConnect(); mCm.makeDefaultNetwork(mobile, BROADCAST_FIRST, doDispatchAll); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(mobile.networkId); + mTetheringEventCallback.expectUpstreamChanged(mobile.networkId); // Check the IP addresses to ensure that the upstream is indeed not the same as the previous // mobile upstream, even though the netId is (unrealistically) the same. @@ -1278,13 +1295,13 @@ mobile.fakeDisconnect(); mLooper.dispatchAll(); inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(null); + mTetheringEventCallback.expectUpstreamChanged(NULL_NETWORK); mobile = new TestNetworkAgent(mCm, buildMobileDualStackUpstreamState()); mobile.fakeConnect(); mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST, doDispatchAll); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(mobile.networkId); + mTetheringEventCallback.expectUpstreamChanged(mobile.networkId); assertTrue(mUpstreamNetworkMonitor.getCurrentPreferredUpstream().linkProperties .hasIPv4Address()); @@ -1325,18 +1342,143 @@ mLooper.dispatchAll(); mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST, null); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(mobile.networkId); + mTetheringEventCallback.expectUpstreamChanged(mobile.networkId); wifi.fakeConnect(); mLooper.dispatchAll(); mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST, null); mLooper.dispatchAll(); inOrder.verify(mUpstreamNetworkMonitor).setTryCell(false); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(wifi.networkId); + mTetheringEventCallback.expectUpstreamChanged(wifi.networkId); verifyDisableTryCellWhenTetheringStop(inOrder); } + private void verifyWifiUpstreamAndUnregisterDunCallback(@NonNull final InOrder inOrder, + @NonNull final TestNetworkAgent wifi, @NonNull final NetworkCallback currentDunCallack) + throws Exception { + assertNotNull(currentDunCallack); + + inOrder.verify(mUpstreamNetworkMonitor).setTryCell(false); + inOrder.verify(mCm).unregisterNetworkCallback(eq(currentDunCallack)); + mTetheringEventCallback.expectUpstreamChanged(wifi.networkId); + mTetheringEventCallback.assertNoUpstreamChangeCallback(); + } + + @Nullable + private NetworkCallback verifyDunUpstream(@NonNull final InOrder inOrder, + @NonNull final TestNetworkAgent dun, final boolean needToRequestNetwork) + throws Exception { + inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true); + ArgumentCaptor<NetworkCallback> captor = ArgumentCaptor.forClass(NetworkCallback.class); + NetworkCallback dunNetworkCallback = null; + if (needToRequestNetwork) { + inOrder.verify(mCm).requestNetwork(any(), eq(0), eq(TYPE_MOBILE_DUN), any(), + captor.capture()); + dunNetworkCallback = captor.getValue(); + } + mTetheringEventCallback.expectUpstreamChanged(NULL_NETWORK); + final Runnable doDispatchAll = () -> mLooper.dispatchAll(); + dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll); + mLooper.dispatchAll(); + mTetheringEventCallback.expectUpstreamChanged(dun.networkId); + + if (needToRequestNetwork) { + assertNotNull(dunNetworkCallback); + } else { + assertNull(dunNetworkCallback); + } + + return dunNetworkCallback; + } + + // Overall test coverage: + // - verifyChooseDunUpstreamByAutomaticMode: common, test#1, test#2 + // - testChooseDunUpstreamByAutomaticMode_defaultNetworkWifi: test#3, test#4 + // - testChooseDunUpstreamByAutomaticMode_loseDefaultNetworkWifi: test#5 + // - testChooseDunUpstreamByAutomaticMode_defaultNetworkCell: test#5, test#7 + // - testChooseDunUpstreamByAutomaticMode_loseAndRegainDun: test#8 + // - testChooseDunUpstreamByAutomaticMode_switchDefaultFromWifiToCell: test#9, test#10 + // + // Overall test cases: + // +-------+-------+-------+-------+-------+ + // | Test | WiFi | Cellu | Dun | Expec | + // | Case | | alr | | ted | + // | # | | | | Upstr | + // | | | | | eam | + // +-------+-------+-------+-------+-------+ + // | - | | | | - | --+ + // +-------+-------+-------+-------+-------+ | + // | - | | V | | - | | + // +-------+-------+-------+-------+-------+ | + // | - | | V | O | Dun | +-- chooseDunUpstreamTestCommon + // +-------+-------+-------+-------+-------+ | + // | - | V | O | O | WiFi | | + // +-------+-------+-------+-------+-------+ | + // | - | V | O | | WiFi | --+ + // +-------+-------+-------+-------+-------+ + // | | O | V | | - | + // | 1 +-------+-------+-------+-------+ + // | | O | V | O | Dun | + // +-------+-------+-------+-------+-------+ + // | | O | V | | - | + // | 2 +-------+-------+-------+-------+ + // | | O | V | O | Dun | + // +-------+-------+-------+-------+-------+ + // | 3 | V | O | | WiFi | + // +-------+-------+-------+-------+-------+ + // | 4 | V | | | WiFi | + // +-------+-------+-------+-------+-------+ + // | 5 | | | O | Dun | + // +-------+-------+-------+-------+-------+ + // | 6 | | V | O | Dun | + // +-------+-------+-------+-------+-------+ + // | 7 | | | O | Dun | + // +-------+-------+-------+-------+-------+ + // | | | | | - | + // | 8 +-------+-------+-------+-------+ + // | | | | O | Dun | + // +-------+-------+-------+-------+-------+ + // | | V | | O | WiFi | + // | 9 +-------+-------+-------+-------+ + // | | V | | | WiFi | + // +-------+-------+-------+-------+-------+ + // | | O | V | | - | + // | 10 +-------+-------+-------+-------+ + // | | O | V | O | Dun | + // +-------+-------+-------+-------+-------+ + // + // Annotation: + // 1. "V" means that the given network is connected and it is default network. + // 2. "O" means that the given network is connected and it is not default network. + // + + // Test case: + // +-------+-------+-------+-------+-------+ + // | Test | WiFi | Cellu | Dun | Expec | + // | Case | | alr | | ted | + // | # | | | | Upstr | + // | | | | | eam | + // +-------+-------+-------+-------+-------+ + // | - | | | | - | --+ + // +-------+-------+-------+-------+-------+ | + // | - | | V | | - | | + // +-------+-------+-------+-------+-------+ | + // | - | | V | O | Dun | +-- chooseDunUpstreamTestCommon + // +-------+-------+-------+-------+-------+ | + // | - | V | O | O | WiFi | | + // +-------+-------+-------+-------+-------+ | + // | - | V | O | | WiFi | --+ + // +-------+-------+-------+-------+-------+ + // | | O | V | | - | + // | 1 +-------+-------+-------+-------+ + // | | O | V | O | Dun | + // +-------+-------+-------+-------+-------+ + // | | O | V | | - | + // | 2 +-------+-------+-------+-------+ + // | | O | V | O | Dun | + // +-------+-------+-------+-------+-------+ + // private void verifyChooseDunUpstreamByAutomaticMode(boolean configAutomatic) throws Exception { // Enable automatic upstream selection. TestNetworkAgent mobile = new TestNetworkAgent(mCm, buildMobileDualStackUpstreamState()); @@ -1345,28 +1487,22 @@ InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor); chooseDunUpstreamTestCommon(configAutomatic, inOrder, mobile, wifi, dun); - // When default network switch to mobile and wifi is connected (may have low signal), + // [1] When default network switch to mobile and wifi is connected (may have low signal), // automatic mode would request dun again and choose it as upstream. mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true); - ArgumentCaptor<NetworkCallback> captor = ArgumentCaptor.forClass(NetworkCallback.class); - inOrder.verify(mCm).requestNetwork(any(), eq(0), eq(TYPE_MOBILE_DUN), any(), any()); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(null); - final Runnable doDispatchAll = () -> mLooper.dispatchAll(); - dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll); - mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(dun.networkId); + verifyDunUpstream(inOrder, dun, true /* needToRequestNetwork */); - // Lose and regain upstream again. + // [2] Lose and regain upstream again. + final Runnable doDispatchAll = () -> mLooper.dispatchAll(); dun.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll); mLooper.dispatchAll(); inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(null); + mTetheringEventCallback.expectUpstreamChanged(NULL_NETWORK); inOrder.verify(mCm, never()).unregisterNetworkCallback(any(NetworkCallback.class)); dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(dun.networkId); + mTetheringEventCallback.expectUpstreamChanged(dun.networkId); verifyDisableTryCellWhenTetheringStop(inOrder); } @@ -1376,12 +1512,245 @@ verifyChooseDunUpstreamByAutomaticMode(true /* configAutomatic */); } + // testChooseDunUpstreamByAutomaticMode_* doesn't verify configAutomatic:false because no + // matter |configAutomatic| set to true or false, the result always be automatic mode. We + // just need one test to make sure this behavior. Don't need to test this configuration + // in all tests. @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) public void testChooseDunUpstreamByAutomaticModeWithConfigDisabled() throws Exception { verifyChooseDunUpstreamByAutomaticMode(false /* configAutomatic */); } + // Test case: + // +-------+-------+-------+-------+-------+ + // | Test | WiFi | Cellu | Dun | Expec | + // | Case | | alr | | ted | + // | # | | | | Upstr | + // | | | | | eam | + // +-------+-------+-------+-------+-------+ + // | - | O | V | O | Dun | + // +-------+-------+-------+-------+-------+ + // | 3 | V | O | | WiFi | + // +-------+-------+-------+-------+-------+ + // | 4 | V | | | WiFi | + // +-------+-------+-------+-------+-------+ + // + // See verifyChooseDunUpstreamByAutomaticMode for the annotation. + // + @Test + public void testChooseDunUpstreamByAutomaticMode_defaultNetworkWifi() throws Exception { + TestNetworkAgent mobile = new TestNetworkAgent(mCm, buildMobileDualStackUpstreamState()); + TestNetworkAgent wifi = new TestNetworkAgent(mCm, buildWifiUpstreamState()); + TestNetworkAgent dun = new TestNetworkAgent(mCm, buildDunUpstreamState()); + final InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor); + final NetworkCallback dunNetworkCallback1 = setupDunUpstreamTest( + true /* configAutomatic */, inOrder); + + // When wifi connected, unregister dun request and choose wifi as upstream. + wifi.fakeConnect(); + mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST); + mLooper.dispatchAll(); + verifyWifiUpstreamAndUnregisterDunCallback(inOrder, wifi, dunNetworkCallback1); + + // When default network switch to mobile and wifi is connected (may have low signal), + // automatic mode would request dun again and choose it as upstream. + mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST); + mLooper.dispatchAll(); + final NetworkCallback dunNetworkCallback2 = verifyDunUpstream(inOrder, dun, + true /* needToRequestNetwork */); + + // [3] When default network switch to wifi and mobile is still connected, + // unregister dun request and choose wifi as upstream. + mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST); + mLooper.dispatchAll(); + verifyWifiUpstreamAndUnregisterDunCallback(inOrder, wifi, dunNetworkCallback2); + + // [4] When mobile is disconnected, keep wifi as upstream. + final Runnable doDispatchAll = () -> mLooper.dispatchAll(); + mobile.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll); + mLooper.dispatchAll(); + mTetheringEventCallback.assertNoUpstreamChangeCallback(); + + verifyDisableTryCellWhenTetheringStop(inOrder); + } + + // Test case: + // +-------+-------+-------+-------+-------+ + // | Test | WiFi | Cellu | Dun | Expec | + // | Case | | alr | | ted | + // | # | | | | Upstr | + // | | | | | eam | + // +-------+-------+-------+-------+-------+ + // | - | V | | | WiFi | + // +-------+-------+-------+-------+-------+ + // | 5 | | | O | Dun | + // +-------+-------+-------+-------+-------+ + // + // See verifyChooseDunUpstreamByAutomaticMode for the annotation. + // + @Test + public void testChooseDunUpstreamByAutomaticMode_loseDefaultNetworkWifi() throws Exception { + TestNetworkAgent wifi = new TestNetworkAgent(mCm, buildWifiUpstreamState()); + TestNetworkAgent dun = new TestNetworkAgent(mCm, buildDunUpstreamState()); + final InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor); + final NetworkCallback dunNetworkCallback = setupDunUpstreamTest( + true /* configAutomatic */, inOrder); + + // When wifi connected, unregister dun request and choose wifi as upstream. + wifi.fakeConnect(); + mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST); + mLooper.dispatchAll(); + verifyWifiUpstreamAndUnregisterDunCallback(inOrder, wifi, dunNetworkCallback); + + // [5] When wifi is disconnected, automatic mode would request dun again and choose it + // as upstream. + final Runnable doDispatchAll = () -> mLooper.dispatchAll(); + mCm.makeDefaultNetwork(null, CALLBACKS_FIRST, doDispatchAll); + wifi.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll); + mLooper.dispatchAll(); + verifyDunUpstream(inOrder, dun, true /* needToRequestNetwork */); + + verifyDisableTryCellWhenTetheringStop(inOrder); + } + + // Test case: + // +-------+-------+-------+-------+-------+ + // | Test | WiFi | Cellu | Dun | Expec | + // | Case | | alr | | ted | + // | # | | | | Upstr | + // | | | | | eam | + // +-------+-------+-------+-------+-------+ + // | - | | | O | Dun | + // +-------+-------+-------+-------+-------+ + // | 6 | | V | O | Dun | + // +-------+-------+-------+-------+-------+ + // | 7 | | | O | Dun | + // +-------+-------+-------+-------+-------+ + // + // See verifyChooseDunUpstreamByAutomaticMode for the annotation. + // + @Test + public void testChooseDunUpstreamByAutomaticMode_defaultNetworkCell() throws Exception { + TestNetworkAgent mobile = new TestNetworkAgent(mCm, buildMobileDualStackUpstreamState()); + TestNetworkAgent dun = new TestNetworkAgent(mCm, buildDunUpstreamState()); + final InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor); + setupDunUpstreamTest(true /* configAutomatic */, inOrder); + + // Pretend dun connected and expect choose dun as upstream. + final Runnable doDispatchAll = () -> mLooper.dispatchAll(); + dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll); + mLooper.dispatchAll(); + mTetheringEventCallback.expectUpstreamChanged(dun.networkId); + + // [6] When mobile is connected and default network switch to mobile, keep dun as upstream. + mobile.fakeConnect(); + mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST); + mLooper.dispatchAll(); + mTetheringEventCallback.assertNoUpstreamChangeCallback(); + + // [7] When mobile is disconnected, keep dun as upstream. + mCm.makeDefaultNetwork(null, CALLBACKS_FIRST, doDispatchAll); + mobile.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll); + mLooper.dispatchAll(); + mTetheringEventCallback.assertNoUpstreamChangeCallback(); + + verifyDisableTryCellWhenTetheringStop(inOrder); + } + + // Test case: + // +-------+-------+-------+-------+-------+ + // | Test | WiFi | Cellu | Dun | Expec | + // | Case | | alr | | ted | + // | # | | | | Upstr | + // | | | | | eam | + // +-------+-------+-------+-------+-------+ + // | - | | | O | Dun | + // +-------+-------+-------+-------+-------+ + // | | | | | - | + // | 8 +-------+-------+-------+-------+ + // | | | | O | Dun | + // +-------+-------+-------+-------+-------+ + // + // See verifyChooseDunUpstreamByAutomaticMode for the annotation. + // + @Test + public void testChooseDunUpstreamByAutomaticMode_loseAndRegainDun() throws Exception { + TestNetworkAgent dun = new TestNetworkAgent(mCm, buildDunUpstreamState()); + final InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor); + setupDunUpstreamTest(true /* configAutomatic */, inOrder); + + // Pretend dun connected and expect choose dun as upstream. + final Runnable doDispatchAll = () -> mLooper.dispatchAll(); + dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll); + mLooper.dispatchAll(); + mTetheringEventCallback.expectUpstreamChanged(dun.networkId); + + // [8] Lose and regain upstream again. + dun.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll); + mLooper.dispatchAll(); + verifyDunUpstream(inOrder, dun, false /* needToRequestNetwork */); + + verifyDisableTryCellWhenTetheringStop(inOrder); + } + + // Test case: + // +-------+-------+-------+-------+-------+ + // | Test | WiFi | Cellu | Dun | Expec | + // | Case | | alr | | ted | + // | # | | | | Upstr | + // | | | | | eam | + // +-------+-------+-------+-------+-------+ + // | - | | | O | Dun | + // +-------+-------+-------+-------+-------+ + // | | V | | O | WiFi | + // | 9 +-------+-------+-------+-------+ + // | | V | | | WiFi | + // +-------+-------+-------+-------+-------+ + // | | O | V | | - | + // | 10 +-------+-------+-------+-------+ + // | | O | V | O | Dun | + // +-------+-------+-------+-------+-------+ + // + // See verifyChooseDunUpstreamByAutomaticMode for the annotation. + // + @Test + public void testChooseDunUpstreamByAutomaticMode_switchDefaultFromWifiToCell() + throws Exception { + TestNetworkAgent mobile = new TestNetworkAgent(mCm, buildMobileDualStackUpstreamState()); + TestNetworkAgent wifi = new TestNetworkAgent(mCm, buildWifiUpstreamState()); + TestNetworkAgent dun = new TestNetworkAgent(mCm, buildDunUpstreamState()); + final InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor); + final NetworkCallback dunNetworkCallback = setupDunUpstreamTest( + true /* configAutomatic */, inOrder); + + // Pretend dun connected and expect choose dun as upstream. + final Runnable doDispatchAll = () -> mLooper.dispatchAll(); + dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll); + mLooper.dispatchAll(); + mTetheringEventCallback.expectUpstreamChanged(dun.networkId); + + // [9] When wifi is connected and default network switch to wifi, unregister dun request + // and choose wifi as upstream. When dun is disconnected, keep wifi as upstream. + wifi.fakeConnect(); + mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST); + mLooper.dispatchAll(); + verifyWifiUpstreamAndUnregisterDunCallback(inOrder, wifi, dunNetworkCallback); + dun.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll); + mLooper.dispatchAll(); + mTetheringEventCallback.assertNoUpstreamChangeCallback(); + + // [10] When mobile and mobile are connected and default network switch to mobile + // (may have low signal), automatic mode would request dun again and choose it as + // upstream. + mobile.fakeConnect(); + mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST); + mLooper.dispatchAll(); + verifyDunUpstream(inOrder, dun, true /* needToRequestNetwork */); + + verifyDisableTryCellWhenTetheringStop(inOrder); + } + @Test @IgnoreAfter(Build.VERSION_CODES.TIRAMISU) public void testChooseDunUpstreamByLegacyMode() throws Exception { @@ -1397,7 +1766,7 @@ mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST); mLooper.dispatchAll(); inOrder.verify(mUpstreamNetworkMonitor).setTryCell(false); - inOrder.verify(mUpstreamNetworkMonitor, never()).setCurrentUpstream(any()); + mTetheringEventCallback.assertNoUpstreamChangeCallback(); // BUG: when wifi disconnect, the dun request would not be filed again because wifi is // no longer be default network which do not have CONNECTIVIY_ACTION broadcast. wifi.fakeDisconnect(); @@ -1425,8 +1794,7 @@ verifyDisableTryCellWhenTetheringStop(inOrder); } - private void chooseDunUpstreamTestCommon(final boolean automatic, InOrder inOrder, - TestNetworkAgent mobile, TestNetworkAgent wifi, TestNetworkAgent dun) throws Exception { + private NetworkCallback setupDunUpstreamTest(final boolean automatic, InOrder inOrder) { when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(automatic); when(mTelephonyManager.isTetheringApnRequired()).thenReturn(true); sendConfigurationChanged(); @@ -1439,31 +1807,36 @@ inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true); ArgumentCaptor<NetworkCallback> captor = ArgumentCaptor.forClass(NetworkCallback.class); inOrder.verify(mCm).requestNetwork(any(), eq(0), eq(TYPE_MOBILE_DUN), any(), - captor.capture()); - final NetworkCallback dunNetworkCallback1 = captor.getValue(); + captor.capture() /* DUN network callback */); - // Pretend cellular connected and expect the upstream to be set. + return captor.getValue(); + } + + private void chooseDunUpstreamTestCommon(final boolean automatic, InOrder inOrder, + TestNetworkAgent mobile, TestNetworkAgent wifi, TestNetworkAgent dun) + throws Exception { + final NetworkCallback dunNetworkCallback = setupDunUpstreamTest(automatic, inOrder); + + // Pretend cellular connected and expect the upstream to be not set. mobile.fakeConnect(); mCm.makeDefaultNetwork(mobile, BROADCAST_FIRST); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor, never()).setCurrentUpstream(mobile.networkId); + mTetheringEventCallback.assertNoUpstreamChangeCallback(); // Pretend dun connected and expect choose dun as upstream. final Runnable doDispatchAll = () -> mLooper.dispatchAll(); dun.fakeConnect(BROADCAST_FIRST, doDispatchAll); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(dun.networkId); + mTetheringEventCallback.expectUpstreamChanged(dun.networkId); // When wifi connected, unregister dun request and choose wifi as upstream. wifi.fakeConnect(); mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor).setTryCell(false); - inOrder.verify(mCm).unregisterNetworkCallback(eq(dunNetworkCallback1)); - inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(wifi.networkId); + verifyWifiUpstreamAndUnregisterDunCallback(inOrder, wifi, dunNetworkCallback); dun.fakeDisconnect(BROADCAST_FIRST, doDispatchAll); mLooper.dispatchAll(); - inOrder.verify(mUpstreamNetworkMonitor, never()).setCurrentUpstream(any()); + mTetheringEventCallback.assertNoUpstreamChangeCallback(); } private void runNcmTethering() { @@ -1627,6 +2000,7 @@ verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR); + verify(mTetheringMetrics, times(0)).maybeUpdateUpstreamType(any()); verify(mTetheringMetrics, times(2)).updateErrorCode(eq(TETHERING_WIFI), eq(TETHER_ERROR_INTERNAL_ERROR)); verify(mTetheringMetrics, times(2)).sendReport(eq(TETHERING_WIFI)); @@ -1767,7 +2141,7 @@ new ArrayList<Network>(Arrays.asList(networks)); for (Network upstream : expectedUpstreams) { // throws OOB if no expectations - assertEquals(mActualUpstreams.remove(0), upstream); + assertEquals(upstream, mActualUpstreams.remove(0)); } assertNoUpstreamChangeCallback(); } @@ -1782,14 +2156,14 @@ for (TetheringConfigurationParcel config : expectedTetherConfig) { // throws OOB if no expectations final TetheringConfigurationParcel actualConfig = mTetheringConfigs.remove(0); - assertTetherConfigParcelEqual(actualConfig, config); + assertTetherConfigParcelEqual(config, actualConfig); } assertNoConfigChangeCallback(); } public void expectOffloadStatusChanged(final int expectedStatus) { assertOffloadStatusChangedCallback(); - assertEquals(mOffloadStatus.remove(0), new Integer(expectedStatus)); + assertEquals(Integer.valueOf(expectedStatus), mOffloadStatus.remove(0)); } public TetherStatesParcel pollTetherStatesChanged() { @@ -1880,12 +2254,12 @@ private void assertTetherConfigParcelEqual(@NonNull TetheringConfigurationParcel actual, @NonNull TetheringConfigurationParcel expect) { - assertArrayEquals(actual.tetherableUsbRegexs, expect.tetherableUsbRegexs); - assertArrayEquals(actual.tetherableWifiRegexs, expect.tetherableWifiRegexs); - assertArrayEquals(actual.tetherableBluetoothRegexs, expect.tetherableBluetoothRegexs); - assertArrayEquals(actual.legacyDhcpRanges, expect.legacyDhcpRanges); - assertArrayEquals(actual.provisioningApp, expect.provisioningApp); - assertEquals(actual.provisioningAppNoUi, expect.provisioningAppNoUi); + assertArrayEquals(expect.tetherableUsbRegexs, actual.tetherableUsbRegexs); + assertArrayEquals(expect.tetherableWifiRegexs, actual.tetherableWifiRegexs); + assertArrayEquals(expect.tetherableBluetoothRegexs, actual.tetherableBluetoothRegexs); + assertArrayEquals(expect.legacyDhcpRanges, actual.legacyDhcpRanges); + assertArrayEquals(expect.provisioningApp, actual.provisioningApp); + assertEquals(expect.provisioningAppNoUi, actual.provisioningAppNoUi); } } @@ -1910,7 +2284,7 @@ mTethering.registerTetheringEventCallback(callback); mLooper.dispatchAll(); callback.expectTetheredClientChanged(Collections.emptyList()); - callback.expectUpstreamChanged(new Network[] {null}); + callback.expectUpstreamChanged(NULL_NETWORK); callback.expectConfigurationChanged( mTethering.getTetheringConfiguration().toStableParcelable()); TetherStatesParcel tetherState = callback.pollTetherStatesChanged(); @@ -1958,7 +2332,7 @@ tetherState = callback2.pollTetherStatesChanged(); assertArrayEquals(tetherState.availableList, new TetheringInterface[] {wifiIface}); mLooper.dispatchAll(); - callback2.expectUpstreamChanged(new Network[] {null}); + callback2.expectUpstreamChanged(NULL_NETWORK); callback2.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); callback.assertNoCallback(); } @@ -1971,25 +2345,15 @@ mLooper.dispatchAll(); callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - // 1. Offload fail if no OffloadConfig. - initOffloadConfiguration(false /* offloadConfig */, OFFLOAD_HAL_VERSION_1_0, - 0 /* defaultDisabled */); + // 1. Offload fail if no IOffloadHal. + initOffloadConfiguration(OFFLOAD_HAL_VERSION_NONE, 0 /* defaultDisabled */); runUsbTethering(upstreamState); callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED); runStopUSBTethering(); callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); reset(mUsbManager, mIPv6TetheringCoordinator); - // 2. Offload fail if no OffloadControl. - initOffloadConfiguration(true /* offloadConfig */, OFFLOAD_HAL_VERSION_NONE, - 0 /* defaultDisabled */); - runUsbTethering(upstreamState); - callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED); - runStopUSBTethering(); - callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - reset(mUsbManager, mIPv6TetheringCoordinator); - // 3. Offload fail if disabled by settings. - initOffloadConfiguration(true /* offloadConfig */, OFFLOAD_HAL_VERSION_1_0, - 1 /* defaultDisabled */); + // 2. Offload fail if disabled by settings. + initOffloadConfiguration(OFFLOAD_HAL_VERSION_HIDL_1_0, 1 /* defaultDisabled */); runUsbTethering(upstreamState); callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED); runStopUSBTethering(); @@ -2004,11 +2368,10 @@ verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); } - private void initOffloadConfiguration(final boolean offloadConfig, - @OffloadHardwareInterface.OffloadHalVersion final int offloadControlVersion, + private void initOffloadConfiguration( + @OffloadHardwareInterface.OffloadHalVersion final int offloadHalVersion, final int defaultDisabled) { - when(mOffloadHardwareInterface.initOffloadConfig()).thenReturn(offloadConfig); - when(mOffloadHardwareInterface.initOffloadControl(any())).thenReturn(offloadControlVersion); + when(mOffloadHardwareInterface.initOffload(any())).thenReturn(offloadHalVersion); when(mOffloadHardwareInterface.getDefaultTetherOffloadDisabled()).thenReturn( defaultDisabled); } @@ -2305,27 +2668,67 @@ public void testUpstreamNetworkChanged() { final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM) mTetheringDependencies.mUpstreamNetworkMonitorSM; + final InOrder inOrder = inOrder(mNotificationUpdater); + + // Gain upstream. final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); initTetheringUpstream(upstreamState); stateMachine.chooseUpstreamType(true); + mTetheringEventCallback.expectUpstreamChanged(upstreamState.network); + inOrder.verify(mNotificationUpdater) + .onUpstreamCapabilitiesChanged(upstreamState.networkCapabilities); - verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(eq(upstreamState.network)); - verify(mNotificationUpdater, times(1)).onUpstreamCapabilitiesChanged(any()); + // Set the upstream with the same network ID but different object and the same capability. + final UpstreamNetworkState upstreamState2 = buildMobileIPv4UpstreamState(); + initTetheringUpstream(upstreamState2); + stateMachine.chooseUpstreamType(true); + // Bug: duplicated upstream change event. + mTetheringEventCallback.expectUpstreamChanged(upstreamState2.network); + inOrder.verify(mNotificationUpdater) + .onUpstreamCapabilitiesChanged(upstreamState2.networkCapabilities); + + // Set the upstream with the same network ID but different object and different capability. + final UpstreamNetworkState upstreamState3 = buildMobileIPv4UpstreamState(); + assertFalse(upstreamState3.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)); + upstreamState3.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED); + initTetheringUpstream(upstreamState3); + stateMachine.chooseUpstreamType(true); + // Bug: duplicated upstream change event. + mTetheringEventCallback.expectUpstreamChanged(upstreamState3.network); + inOrder.verify(mNotificationUpdater) + .onUpstreamCapabilitiesChanged(upstreamState3.networkCapabilities); + + // Lose upstream. + initTetheringUpstream(null); + stateMachine.chooseUpstreamType(true); + mTetheringEventCallback.expectUpstreamChanged(NULL_NETWORK); + inOrder.verify(mNotificationUpdater).onUpstreamCapabilitiesChanged(null); } @Test public void testUpstreamCapabilitiesChanged() { final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM) mTetheringDependencies.mUpstreamNetworkMonitorSM; + final InOrder inOrder = inOrder(mNotificationUpdater); final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); initTetheringUpstream(upstreamState); + stateMachine.chooseUpstreamType(true); + inOrder.verify(mNotificationUpdater) + .onUpstreamCapabilitiesChanged(upstreamState.networkCapabilities); stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState); - // Should have two onUpstreamCapabilitiesChanged(). - // One is called by reportUpstreamChanged(). One is called by EVENT_ON_CAPABILITIES. - verify(mNotificationUpdater, times(2)).onUpstreamCapabilitiesChanged(any()); - reset(mNotificationUpdater); + inOrder.verify(mNotificationUpdater) + .onUpstreamCapabilitiesChanged(upstreamState.networkCapabilities); + + // Verify that onUpstreamCapabilitiesChanged is called if current upstream network + // capabilities changed. + // Expect that capability is changed with new capability VALIDATED. + assertFalse(upstreamState.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)); + upstreamState.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED); + stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState); + inOrder.verify(mNotificationUpdater) + .onUpstreamCapabilitiesChanged(upstreamState.networkCapabilities); // Verify that onUpstreamCapabilitiesChanged won't be called if not current upstream network // capabilities changed. @@ -2333,7 +2736,28 @@ upstreamState.linkProperties, upstreamState.networkCapabilities, new Network(WIFI_NETID)); stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState2); - verify(mNotificationUpdater, never()).onUpstreamCapabilitiesChanged(any()); + inOrder.verify(mNotificationUpdater, never()).onUpstreamCapabilitiesChanged(any()); + } + + @Test + public void testUpstreamCapabilitiesChanged_startStopTethering() throws Exception { + final TestNetworkAgent wifi = new TestNetworkAgent(mCm, buildWifiUpstreamState()); + + // Start USB tethering with no current upstream. + prepareUsbTethering(); + sendUsbBroadcast(true, true, TETHER_USB_RNDIS_FUNCTION); + + // Pretend wifi connected and expect the upstream to be set. + wifi.fakeConnect(); + mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST); + mLooper.dispatchAll(); + verify(mNotificationUpdater).onUpstreamCapabilitiesChanged( + wifi.networkCapabilities); + + // Stop tethering. + // Expect that TetherModeAliveState#exit sends capabilities change notification to null. + runStopUSBTethering(); + verify(mNotificationUpdater).onUpstreamCapabilitiesChanged(null); } @Test @@ -2564,9 +2988,9 @@ final MacAddress testMac1 = MacAddress.fromString("11:11:11:11:11:11"); final DhcpLeaseParcelable p2pLease = createDhcpLeaseParcelable("clientId1", testMac1, "192.168.50.24", 24, Long.MAX_VALUE, "test1"); - final List<TetheredClient> p2pClients = notifyDhcpLeasesChanged(TETHERING_WIFI_P2P, + final List<TetheredClient> connectedClients = notifyDhcpLeasesChanged(TETHERING_WIFI_P2P, eventCallbacks, p2pLease); - callback.expectTetheredClientChanged(p2pClients); + callback.expectTetheredClientChanged(connectedClients); reset(mDhcpServer); // Run wifi tethering. @@ -2575,21 +2999,11 @@ verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS)).startWithCallbacks( any(), dhcpEventCbsCaptor.capture()); eventCallbacks = dhcpEventCbsCaptor.getValue(); - // Update mac address from softAp callback before getting dhcp lease. final MacAddress testMac2 = MacAddress.fromString("22:22:22:22:22:22"); - final TetheredClient noAddrClient = notifyConnectedWifiClientsChanged(testMac2, - false /* isLocalOnly */); - final List<TetheredClient> p2pAndNoAddrClients = new ArrayList<>(p2pClients); - p2pAndNoAddrClients.add(noAddrClient); - callback.expectTetheredClientChanged(p2pAndNoAddrClients); - - // Update dhcp lease for wifi tethering. final DhcpLeaseParcelable wifiLease = createDhcpLeaseParcelable("clientId2", testMac2, "192.168.43.24", 24, Long.MAX_VALUE, "test2"); - final List<TetheredClient> p2pAndWifiClients = new ArrayList<>(p2pClients); - p2pAndWifiClients.addAll(notifyDhcpLeasesChanged(TETHERING_WIFI, - eventCallbacks, wifiLease)); - callback.expectTetheredClientChanged(p2pAndWifiClients); + verifyHotspotClientUpdate(false /* isLocalOnly */, testMac2, wifiLease, connectedClients, + eventCallbacks, callback); // Test onStarted callback that register second callback when tethering is running. TestTetheringEventCallback callback2 = new TestTetheringEventCallback(); @@ -2597,7 +3011,7 @@ mTethering.registerTetheringEventCallback(callback2); mLooper.dispatchAll(); }); - callback2.expectTetheredClientChanged(p2pAndWifiClients); + callback2.expectTetheredClientChanged(connectedClients); } @Test @@ -2619,26 +3033,34 @@ verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS)).startWithCallbacks( any(), dhcpEventCbsCaptor.capture()); final IDhcpEventCallbacks eventCallbacks = dhcpEventCbsCaptor.getValue(); - // Update mac address from softAp callback before getting dhcp lease. - final MacAddress testMac = MacAddress.fromString("22:22:22:22:22:22"); - final TetheredClient noAddrClient = notifyConnectedWifiClientsChanged(testMac, - true /* isLocalOnly */); - final List<TetheredClient> noAddrLocalOnlyClients = new ArrayList<>(); - noAddrLocalOnlyClients.add(noAddrClient); - callback.expectTetheredClientChanged(noAddrLocalOnlyClients); - // Update dhcp lease for local only hotspot. + final List<TetheredClient> connectedClients = new ArrayList<>(); + final MacAddress testMac = MacAddress.fromString("22:22:22:22:22:22"); final DhcpLeaseParcelable wifiLease = createDhcpLeaseParcelable("clientId", testMac, "192.168.43.24", 24, Long.MAX_VALUE, "test"); - final List<TetheredClient> localOnlyClients = notifyDhcpLeasesChanged(TETHERING_WIFI, - eventCallbacks, wifiLease); - callback.expectTetheredClientChanged(localOnlyClients); + verifyHotspotClientUpdate(true /* isLocalOnly */, testMac, wifiLease, connectedClients, + eventCallbacks, callback); // Client disconnect from local only hotspot. mLocalOnlyHotspotCallback.onConnectedClientsChanged(Collections.emptyList()); callback.expectTetheredClientChanged(Collections.emptyList()); } + private void verifyHotspotClientUpdate(final boolean isLocalOnly, final MacAddress testMac, + final DhcpLeaseParcelable dhcpLease, final List<TetheredClient> currentClients, + final IDhcpEventCallbacks dhcpCallback, final TestTetheringEventCallback callback) + throws Exception { + // Update mac address from softAp callback before getting dhcp lease. + final TetheredClient noAddrClient = notifyConnectedWifiClientsChanged(testMac, isLocalOnly); + final List<TetheredClient> withNoAddrClients = new ArrayList<>(currentClients); + withNoAddrClients.add(noAddrClient); + callback.expectTetheredClientChanged(withNoAddrClients); + + // Update dhcp lease for hotspot. + currentClients.addAll(notifyDhcpLeasesChanged(TETHERING_WIFI, dhcpCallback, dhcpLease)); + callback.expectTetheredClientChanged(currentClients); + } + private TetheredClient notifyConnectedWifiClientsChanged(final MacAddress mac, boolean isLocalOnly) throws Exception { final ArrayList<WifiClient> wifiClients = new ArrayList<>(); @@ -2942,6 +3364,7 @@ verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( any(), any()); verify(mTetheringMetrics).createBuilder(eq(TETHERING_NCM), anyString()); + verify(mTetheringMetrics, times(1)).maybeUpdateUpstreamType(any()); // Change the USB tethering function to NCM. Because the USB tethering function was set to // RNDIS (the default), tethering is stopped. @@ -2958,6 +3381,7 @@ mLooper.dispatchAll(); ncmResult.assertHasResult(); verify(mTetheringMetrics, times(2)).createBuilder(eq(TETHERING_NCM), anyString()); + verify(mTetheringMetrics, times(1)).maybeUpdateUpstreamType(any()); verify(mTetheringMetrics).updateErrorCode(eq(TETHERING_NCM), eq(TETHER_ERROR_SERVICE_UNAVAIL)); verify(mTetheringMetrics, times(2)).sendReport(eq(TETHERING_NCM));
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java index 9b9507b..e756bd3 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java
@@ -49,6 +49,7 @@ import android.net.LinkProperties; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -62,9 +63,12 @@ import com.android.net.module.util.SharedLog; import com.android.networkstack.tethering.TestConnectivityManager.NetworkRequestInfo; import com.android.networkstack.tethering.TestConnectivityManager.TestNetworkAgent; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -92,6 +96,8 @@ private static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities.Builder() .addTransportType(TRANSPORT_WIFI).addCapability(NET_CAPABILITY_INTERNET).build(); + @Rule public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); + @Mock private Context mContext; @Mock private EntitlementManager mEntitleMgr; @Mock private IConnectivityManager mCS; @@ -301,6 +307,7 @@ } @Test + @IgnoreAfter(Build.VERSION_CODES.TIRAMISU) public void testSelectPreferredUpstreamType() throws Exception { final Collection<Integer> preferredTypes = new ArrayList<>(); preferredTypes.add(TYPE_WIFI); @@ -556,6 +563,7 @@ } @Test + @IgnoreAfter(Build.VERSION_CODES.TIRAMISU) public void testSelectMobileWhenMobileIsNotDefault() { final Collection<Integer> preferredTypes = new ArrayList<>(); // Mobile has higher pirority than wifi.
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/metrics/TetheringMetricsTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/metrics/TetheringMetricsTest.java index 7fdde97..e2c924c 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/metrics/TetheringMetricsTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/metrics/TetheringMetricsTest.java
@@ -16,6 +16,12 @@ package com.android.networkstack.tethering.metrics; +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; +import static android.net.NetworkCapabilities.TRANSPORT_LOWPAN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_NCM; @@ -44,15 +50,17 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import android.net.NetworkCapabilities; import android.stats.connectivity.DownstreamType; import android.stats.connectivity.ErrorCode; import android.stats.connectivity.UpstreamType; import android.stats.connectivity.UserType; -import android.util.Pair; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.networkstack.tethering.UpstreamNetworkState; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -65,138 +73,310 @@ private static final String SETTINGS_PKG = "com.android.settings"; private static final String SYSTEMUI_PKG = "com.android.systemui"; private static final String GMS_PKG = "com.google.android.gms"; - private TetheringMetrics mTetheringMetrics; + private static final long TEST_START_TIME = 1670395936033L; + private static final long SECOND_IN_MILLIS = 1_000L; + private TetheringMetrics mTetheringMetrics; private final NetworkTetheringReported.Builder mStatsBuilder = NetworkTetheringReported.newBuilder(); + private long mElapsedRealtime; + private class MockTetheringMetrics extends TetheringMetrics { @Override - public void write(final NetworkTetheringReported reported) { } + public void write(final NetworkTetheringReported reported) {} + @Override + public long timeNow() { + return currentTimeMillis(); + } + } + + private long currentTimeMillis() { + return TEST_START_TIME + mElapsedRealtime; + } + + private void incrementCurrentTime(final long duration) { + mElapsedRealtime += duration; + mTetheringMetrics.timeNow(); + } + + private long getElapsedRealtime() { + return mElapsedRealtime; + } + + private void clearElapsedRealtime() { + mElapsedRealtime = 0; } @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mTetheringMetrics = spy(new MockTetheringMetrics()); + mElapsedRealtime = 0L; } - private void verifyReport(DownstreamType downstream, ErrorCode error, UserType user) + private void verifyReport(final DownstreamType downstream, final ErrorCode error, + final UserType user, final UpstreamEvents.Builder upstreamEvents, final long duration) throws Exception { final NetworkTetheringReported expectedReport = mStatsBuilder.setDownstreamType(downstream) .setUserType(user) .setUpstreamType(UpstreamType.UT_UNKNOWN) .setErrorCode(error) - .setUpstreamEvents(UpstreamEvents.newBuilder()) - .setDurationMillis(0) + .setUpstreamEvents(upstreamEvents) + .setDurationMillis(duration) .build(); verify(mTetheringMetrics).write(expectedReport); } - private void updateErrorAndSendReport(int downstream, int error) { + private void updateErrorAndSendReport(final int downstream, final int error) { mTetheringMetrics.updateErrorCode(downstream, error); mTetheringMetrics.sendReport(downstream); } - private void runDownstreamTypesTest(final Pair<Integer, DownstreamType>... testPairs) - throws Exception { - for (Pair<Integer, DownstreamType> testPair : testPairs) { - final int type = testPair.first; - final DownstreamType expectedResult = testPair.second; - - mTetheringMetrics.createBuilder(type, TEST_CALLER_PKG); - updateErrorAndSendReport(type, TETHER_ERROR_NO_ERROR); - verifyReport(expectedResult, ErrorCode.EC_NO_ERROR, UserType.USER_UNKNOWN); - reset(mTetheringMetrics); + private static NetworkCapabilities buildUpstreamCapabilities(final int[] transports) { + final NetworkCapabilities nc = new NetworkCapabilities(); + for (int type: transports) { + nc.addTransportType(type); } + return nc; + } + + private static UpstreamNetworkState buildUpstreamState(final int... transports) { + return new UpstreamNetworkState( + null, + buildUpstreamCapabilities(transports), + null); + } + + private void addUpstreamEvent(UpstreamEvents.Builder upstreamEvents, + final UpstreamType expectedResult, final long duration, final long txBytes, + final long rxBytes) { + UpstreamEvent.Builder upstreamEvent = UpstreamEvent.newBuilder() + .setUpstreamType(expectedResult) + .setDurationMillis(duration) + .setTxBytes(txBytes) + .setRxBytes(rxBytes); + upstreamEvents.addUpstreamEvent(upstreamEvent); + } + + private void runDownstreamTypesTest(final int type, final DownstreamType expectedResult) + throws Exception { + mTetheringMetrics.createBuilder(type, TEST_CALLER_PKG); + final long duration = 2 * SECOND_IN_MILLIS; + incrementCurrentTime(duration); + UpstreamEvents.Builder upstreamEvents = UpstreamEvents.newBuilder(); + // Set UpstreamType as NO_NETWORK because the upstream type has not been changed. + addUpstreamEvent(upstreamEvents, UpstreamType.UT_NO_NETWORK, duration, 0L, 0L); + updateErrorAndSendReport(type, TETHER_ERROR_NO_ERROR); + + verifyReport(expectedResult, ErrorCode.EC_NO_ERROR, UserType.USER_UNKNOWN, + upstreamEvents, getElapsedRealtime()); + reset(mTetheringMetrics); + clearElapsedRealtime(); + mTetheringMetrics.cleanup(); } @Test public void testDownstreamTypes() throws Exception { - runDownstreamTypesTest(new Pair<>(TETHERING_WIFI, DownstreamType.DS_TETHERING_WIFI), - new Pair<>(TETHERING_WIFI_P2P, DownstreamType.DS_TETHERING_WIFI_P2P), - new Pair<>(TETHERING_BLUETOOTH, DownstreamType.DS_TETHERING_BLUETOOTH), - new Pair<>(TETHERING_USB, DownstreamType.DS_TETHERING_USB), - new Pair<>(TETHERING_NCM, DownstreamType.DS_TETHERING_NCM), - new Pair<>(TETHERING_ETHERNET, DownstreamType.DS_TETHERING_ETHERNET)); + runDownstreamTypesTest(TETHERING_WIFI, DownstreamType.DS_TETHERING_WIFI); + runDownstreamTypesTest(TETHERING_WIFI_P2P, DownstreamType.DS_TETHERING_WIFI_P2P); + runDownstreamTypesTest(TETHERING_BLUETOOTH, DownstreamType.DS_TETHERING_BLUETOOTH); + runDownstreamTypesTest(TETHERING_USB, DownstreamType.DS_TETHERING_USB); + runDownstreamTypesTest(TETHERING_NCM, DownstreamType.DS_TETHERING_NCM); + runDownstreamTypesTest(TETHERING_ETHERNET, DownstreamType.DS_TETHERING_ETHERNET); } - private void runErrorCodesTest(final Pair<Integer, ErrorCode>... testPairs) + private void runErrorCodesTest(final int errorCode, final ErrorCode expectedResult) throws Exception { - for (Pair<Integer, ErrorCode> testPair : testPairs) { - final int errorCode = testPair.first; - final ErrorCode expectedResult = testPair.second; + mTetheringMetrics.createBuilder(TETHERING_WIFI, TEST_CALLER_PKG); + mTetheringMetrics.maybeUpdateUpstreamType(buildUpstreamState(TRANSPORT_WIFI)); + final long duration = 2 * SECOND_IN_MILLIS; + incrementCurrentTime(duration); + updateErrorAndSendReport(TETHERING_WIFI, errorCode); - mTetheringMetrics.createBuilder(TETHERING_WIFI, TEST_CALLER_PKG); - updateErrorAndSendReport(TETHERING_WIFI, errorCode); - verifyReport(DownstreamType.DS_TETHERING_WIFI, expectedResult, UserType.USER_UNKNOWN); - reset(mTetheringMetrics); - } + UpstreamEvents.Builder upstreamEvents = UpstreamEvents.newBuilder(); + addUpstreamEvent(upstreamEvents, UpstreamType.UT_WIFI, duration, 0L, 0L); + verifyReport(DownstreamType.DS_TETHERING_WIFI, expectedResult, UserType.USER_UNKNOWN, + upstreamEvents, getElapsedRealtime()); + reset(mTetheringMetrics); + clearElapsedRealtime(); + mTetheringMetrics.cleanup(); } @Test public void testErrorCodes() throws Exception { - runErrorCodesTest(new Pair<>(TETHER_ERROR_NO_ERROR, ErrorCode.EC_NO_ERROR), - new Pair<>(TETHER_ERROR_UNKNOWN_IFACE, ErrorCode.EC_UNKNOWN_IFACE), - new Pair<>(TETHER_ERROR_SERVICE_UNAVAIL, ErrorCode.EC_SERVICE_UNAVAIL), - new Pair<>(TETHER_ERROR_UNSUPPORTED, ErrorCode.EC_UNSUPPORTED), - new Pair<>(TETHER_ERROR_UNAVAIL_IFACE, ErrorCode.EC_UNAVAIL_IFACE), - new Pair<>(TETHER_ERROR_INTERNAL_ERROR, ErrorCode.EC_INTERNAL_ERROR), - new Pair<>(TETHER_ERROR_TETHER_IFACE_ERROR, ErrorCode.EC_TETHER_IFACE_ERROR), - new Pair<>(TETHER_ERROR_UNTETHER_IFACE_ERROR, ErrorCode.EC_UNTETHER_IFACE_ERROR), - new Pair<>(TETHER_ERROR_ENABLE_FORWARDING_ERROR, - ErrorCode.EC_ENABLE_FORWARDING_ERROR), - new Pair<>(TETHER_ERROR_DISABLE_FORWARDING_ERROR, - ErrorCode.EC_DISABLE_FORWARDING_ERROR), - new Pair<>(TETHER_ERROR_IFACE_CFG_ERROR, ErrorCode.EC_IFACE_CFG_ERROR), - new Pair<>(TETHER_ERROR_PROVISIONING_FAILED, ErrorCode.EC_PROVISIONING_FAILED), - new Pair<>(TETHER_ERROR_DHCPSERVER_ERROR, ErrorCode.EC_DHCPSERVER_ERROR), - new Pair<>(TETHER_ERROR_ENTITLEMENT_UNKNOWN, ErrorCode.EC_ENTITLEMENT_UNKNOWN), - new Pair<>(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, - ErrorCode.EC_NO_CHANGE_TETHERING_PERMISSION), - new Pair<>(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION, - ErrorCode.EC_NO_ACCESS_TETHERING_PERMISSION), - new Pair<>(TETHER_ERROR_UNKNOWN_TYPE, ErrorCode.EC_UNKNOWN_TYPE)); + runErrorCodesTest(TETHER_ERROR_NO_ERROR, ErrorCode.EC_NO_ERROR); + runErrorCodesTest(TETHER_ERROR_UNKNOWN_IFACE, ErrorCode.EC_UNKNOWN_IFACE); + runErrorCodesTest(TETHER_ERROR_SERVICE_UNAVAIL, ErrorCode.EC_SERVICE_UNAVAIL); + runErrorCodesTest(TETHER_ERROR_UNSUPPORTED, ErrorCode.EC_UNSUPPORTED); + runErrorCodesTest(TETHER_ERROR_UNAVAIL_IFACE, ErrorCode.EC_UNAVAIL_IFACE); + runErrorCodesTest(TETHER_ERROR_INTERNAL_ERROR, ErrorCode.EC_INTERNAL_ERROR); + runErrorCodesTest(TETHER_ERROR_TETHER_IFACE_ERROR, ErrorCode.EC_TETHER_IFACE_ERROR); + runErrorCodesTest(TETHER_ERROR_UNTETHER_IFACE_ERROR, ErrorCode.EC_UNTETHER_IFACE_ERROR); + runErrorCodesTest(TETHER_ERROR_ENABLE_FORWARDING_ERROR, + ErrorCode.EC_ENABLE_FORWARDING_ERROR); + runErrorCodesTest(TETHER_ERROR_DISABLE_FORWARDING_ERROR, + ErrorCode.EC_DISABLE_FORWARDING_ERROR); + runErrorCodesTest(TETHER_ERROR_IFACE_CFG_ERROR, ErrorCode.EC_IFACE_CFG_ERROR); + runErrorCodesTest(TETHER_ERROR_PROVISIONING_FAILED, ErrorCode.EC_PROVISIONING_FAILED); + runErrorCodesTest(TETHER_ERROR_DHCPSERVER_ERROR, ErrorCode.EC_DHCPSERVER_ERROR); + runErrorCodesTest(TETHER_ERROR_ENTITLEMENT_UNKNOWN, ErrorCode.EC_ENTITLEMENT_UNKNOWN); + runErrorCodesTest(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, + ErrorCode.EC_NO_CHANGE_TETHERING_PERMISSION); + runErrorCodesTest(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION, + ErrorCode.EC_NO_ACCESS_TETHERING_PERMISSION); + runErrorCodesTest(TETHER_ERROR_UNKNOWN_TYPE, ErrorCode.EC_UNKNOWN_TYPE); } - private void runUserTypesTest(final Pair<String, UserType>... testPairs) + private void runUserTypesTest(final String callerPkg, final UserType expectedResult) throws Exception { - for (Pair<String, UserType> testPair : testPairs) { - final String callerPkg = testPair.first; - final UserType expectedResult = testPair.second; + mTetheringMetrics.createBuilder(TETHERING_WIFI, callerPkg); + final long duration = 1 * SECOND_IN_MILLIS; + incrementCurrentTime(duration); + updateErrorAndSendReport(TETHERING_WIFI, TETHER_ERROR_NO_ERROR); - mTetheringMetrics.createBuilder(TETHERING_WIFI, callerPkg); - updateErrorAndSendReport(TETHERING_WIFI, TETHER_ERROR_NO_ERROR); - verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_NO_ERROR, expectedResult); - reset(mTetheringMetrics); - } + UpstreamEvents.Builder upstreamEvents = UpstreamEvents.newBuilder(); + // Set UpstreamType as NO_NETWORK because the upstream type has not been changed. + addUpstreamEvent(upstreamEvents, UpstreamType.UT_NO_NETWORK, duration, 0L, 0L); + verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_NO_ERROR, expectedResult, + upstreamEvents, getElapsedRealtime()); + reset(mTetheringMetrics); + clearElapsedRealtime(); + mTetheringMetrics.cleanup(); } @Test public void testUserTypes() throws Exception { - runUserTypesTest(new Pair<>(TEST_CALLER_PKG, UserType.USER_UNKNOWN), - new Pair<>(SETTINGS_PKG, UserType.USER_SETTINGS), - new Pair<>(SYSTEMUI_PKG, UserType.USER_SYSTEMUI), - new Pair<>(GMS_PKG, UserType.USER_GMS)); + runUserTypesTest(TEST_CALLER_PKG, UserType.USER_UNKNOWN); + runUserTypesTest(SETTINGS_PKG, UserType.USER_SETTINGS); + runUserTypesTest(SYSTEMUI_PKG, UserType.USER_SYSTEMUI); + runUserTypesTest(GMS_PKG, UserType.USER_GMS); + } + + private void runUpstreamTypesTest(final UpstreamNetworkState ns, + final UpstreamType expectedResult) throws Exception { + mTetheringMetrics.createBuilder(TETHERING_WIFI, TEST_CALLER_PKG); + mTetheringMetrics.maybeUpdateUpstreamType(ns); + final long duration = 2 * SECOND_IN_MILLIS; + incrementCurrentTime(duration); + updateErrorAndSendReport(TETHERING_WIFI, TETHER_ERROR_NO_ERROR); + + UpstreamEvents.Builder upstreamEvents = UpstreamEvents.newBuilder(); + addUpstreamEvent(upstreamEvents, expectedResult, duration, 0L, 0L); + verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_NO_ERROR, + UserType.USER_UNKNOWN, upstreamEvents, getElapsedRealtime()); + reset(mTetheringMetrics); + clearElapsedRealtime(); + mTetheringMetrics.cleanup(); + } + + @Test + public void testUpstreamTypes() throws Exception { + runUpstreamTypesTest(null , UpstreamType.UT_NO_NETWORK); + runUpstreamTypesTest(buildUpstreamState(TRANSPORT_CELLULAR), UpstreamType.UT_CELLULAR); + runUpstreamTypesTest(buildUpstreamState(TRANSPORT_WIFI), UpstreamType.UT_WIFI); + runUpstreamTypesTest(buildUpstreamState(TRANSPORT_BLUETOOTH), UpstreamType.UT_BLUETOOTH); + runUpstreamTypesTest(buildUpstreamState(TRANSPORT_ETHERNET), UpstreamType.UT_ETHERNET); + runUpstreamTypesTest(buildUpstreamState(TRANSPORT_WIFI_AWARE), UpstreamType.UT_WIFI_AWARE); + runUpstreamTypesTest(buildUpstreamState(TRANSPORT_LOWPAN), UpstreamType.UT_LOWPAN); + runUpstreamTypesTest(buildUpstreamState(TRANSPORT_CELLULAR, TRANSPORT_WIFI, + TRANSPORT_BLUETOOTH), UpstreamType.UT_UNKNOWN); } @Test public void testMultiBuildersCreatedBeforeSendReport() throws Exception { mTetheringMetrics.createBuilder(TETHERING_WIFI, SETTINGS_PKG); + final long wifiTetheringStartTime = currentTimeMillis(); + incrementCurrentTime(1 * SECOND_IN_MILLIS); mTetheringMetrics.createBuilder(TETHERING_USB, SYSTEMUI_PKG); + final long usbTetheringStartTime = currentTimeMillis(); + incrementCurrentTime(2 * SECOND_IN_MILLIS); mTetheringMetrics.createBuilder(TETHERING_BLUETOOTH, GMS_PKG); - + final long bluetoothTetheringStartTime = currentTimeMillis(); + incrementCurrentTime(3 * SECOND_IN_MILLIS); updateErrorAndSendReport(TETHERING_WIFI, TETHER_ERROR_DHCPSERVER_ERROR); + + UpstreamEvents.Builder wifiTetheringUpstreamEvents = UpstreamEvents.newBuilder(); + addUpstreamEvent(wifiTetheringUpstreamEvents, UpstreamType.UT_NO_NETWORK, + currentTimeMillis() - wifiTetheringStartTime, 0L, 0L); verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_DHCPSERVER_ERROR, - UserType.USER_SETTINGS); - + UserType.USER_SETTINGS, wifiTetheringUpstreamEvents, + currentTimeMillis() - wifiTetheringStartTime); + incrementCurrentTime(1 * SECOND_IN_MILLIS); updateErrorAndSendReport(TETHERING_USB, TETHER_ERROR_ENABLE_FORWARDING_ERROR); - verifyReport(DownstreamType.DS_TETHERING_USB, ErrorCode.EC_ENABLE_FORWARDING_ERROR, - UserType.USER_SYSTEMUI); + UpstreamEvents.Builder usbTetheringUpstreamEvents = UpstreamEvents.newBuilder(); + addUpstreamEvent(usbTetheringUpstreamEvents, UpstreamType.UT_NO_NETWORK, + currentTimeMillis() - usbTetheringStartTime, 0L, 0L); + + verifyReport(DownstreamType.DS_TETHERING_USB, ErrorCode.EC_ENABLE_FORWARDING_ERROR, + UserType.USER_SYSTEMUI, usbTetheringUpstreamEvents, + currentTimeMillis() - usbTetheringStartTime); + incrementCurrentTime(1 * SECOND_IN_MILLIS); updateErrorAndSendReport(TETHERING_BLUETOOTH, TETHER_ERROR_TETHER_IFACE_ERROR); + + UpstreamEvents.Builder bluetoothTetheringUpstreamEvents = UpstreamEvents.newBuilder(); + addUpstreamEvent(bluetoothTetheringUpstreamEvents, UpstreamType.UT_NO_NETWORK, + currentTimeMillis() - bluetoothTetheringStartTime, 0L, 0L); verifyReport(DownstreamType.DS_TETHERING_BLUETOOTH, ErrorCode.EC_TETHER_IFACE_ERROR, - UserType.USER_GMS); + UserType.USER_GMS, bluetoothTetheringUpstreamEvents, + currentTimeMillis() - bluetoothTetheringStartTime); + } + + @Test + public void testUpstreamsWithMultipleDownstreams() throws Exception { + mTetheringMetrics.createBuilder(TETHERING_WIFI, SETTINGS_PKG); + final long wifiTetheringStartTime = currentTimeMillis(); + incrementCurrentTime(1 * SECOND_IN_MILLIS); + mTetheringMetrics.maybeUpdateUpstreamType(buildUpstreamState(TRANSPORT_WIFI)); + final long wifiUpstreamStartTime = currentTimeMillis(); + incrementCurrentTime(5 * SECOND_IN_MILLIS); + mTetheringMetrics.createBuilder(TETHERING_USB, SYSTEMUI_PKG); + final long usbTetheringStartTime = currentTimeMillis(); + incrementCurrentTime(5 * SECOND_IN_MILLIS); + updateErrorAndSendReport(TETHERING_USB, TETHER_ERROR_NO_ERROR); + + UpstreamEvents.Builder usbTetheringUpstreamEvents = UpstreamEvents.newBuilder(); + addUpstreamEvent(usbTetheringUpstreamEvents, UpstreamType.UT_WIFI, + currentTimeMillis() - usbTetheringStartTime, 0L, 0L); + verifyReport(DownstreamType.DS_TETHERING_USB, ErrorCode.EC_NO_ERROR, + UserType.USER_SYSTEMUI, usbTetheringUpstreamEvents, + currentTimeMillis() - usbTetheringStartTime); + incrementCurrentTime(7 * SECOND_IN_MILLIS); + updateErrorAndSendReport(TETHERING_WIFI, TETHER_ERROR_NO_ERROR); + + UpstreamEvents.Builder wifiTetheringUpstreamEvents = UpstreamEvents.newBuilder(); + addUpstreamEvent(wifiTetheringUpstreamEvents, UpstreamType.UT_WIFI, + currentTimeMillis() - wifiUpstreamStartTime, 0L, 0L); + verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_NO_ERROR, + UserType.USER_SETTINGS, wifiTetheringUpstreamEvents, + currentTimeMillis() - wifiTetheringStartTime); + } + + @Test + public void testSwitchingMultiUpstreams() throws Exception { + mTetheringMetrics.createBuilder(TETHERING_WIFI, SETTINGS_PKG); + final long wifiTetheringStartTime = currentTimeMillis(); + incrementCurrentTime(1 * SECOND_IN_MILLIS); + mTetheringMetrics.maybeUpdateUpstreamType(buildUpstreamState(TRANSPORT_WIFI)); + final long wifiDuration = 5 * SECOND_IN_MILLIS; + incrementCurrentTime(wifiDuration); + mTetheringMetrics.maybeUpdateUpstreamType(buildUpstreamState(TRANSPORT_BLUETOOTH)); + final long bluetoothDuration = 15 * SECOND_IN_MILLIS; + incrementCurrentTime(bluetoothDuration); + mTetheringMetrics.maybeUpdateUpstreamType(buildUpstreamState(TRANSPORT_CELLULAR)); + final long celltoothDuration = 20 * SECOND_IN_MILLIS; + incrementCurrentTime(celltoothDuration); + updateErrorAndSendReport(TETHERING_WIFI, TETHER_ERROR_NO_ERROR); + + UpstreamEvents.Builder upstreamEvents = UpstreamEvents.newBuilder(); + addUpstreamEvent(upstreamEvents, UpstreamType.UT_WIFI, wifiDuration, 0L, 0L); + addUpstreamEvent(upstreamEvents, UpstreamType.UT_BLUETOOTH, bluetoothDuration, 0L, 0L); + addUpstreamEvent(upstreamEvents, UpstreamType.UT_CELLULAR, celltoothDuration, 0L, 0L); + + verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_NO_ERROR, + UserType.USER_SETTINGS, upstreamEvents, + currentTimeMillis() - wifiTetheringStartTime); } }
diff --git a/bpf_progs/Android.bp b/bpf_progs/Android.bp index 8eb9cfd..b3f8ed6 100644 --- a/bpf_progs/Android.bp +++ b/bpf_progs/Android.bp
@@ -54,7 +54,6 @@ "//packages/modules/Connectivity/tests/native/utilities", "//packages/modules/Connectivity/service-t/native/libs/libnetworkstats", "//packages/modules/Connectivity/tests/unit/jni", - "//system/netd/tests", ], } @@ -104,18 +103,6 @@ } bpf { - name: "offload@inprocess.o", - srcs: ["offload@inprocess.c"], - btf: true, - cflags: [ - "-Wall", - "-Werror", - "-DBTF", - "-DINPROCESS", - ], -} - -bpf { name: "test.o", srcs: ["test.c"], cflags: [ @@ -136,18 +123,6 @@ } bpf { - name: "test@inprocess.o", - srcs: ["test@inprocess.c"], - btf: true, - cflags: [ - "-Wall", - "-Werror", - "-DBTF", - "-DINPROCESS", - ], -} - -bpf { name: "clatd.o", srcs: ["clatd.c"], btf: true,
diff --git a/bpf_progs/block.c b/bpf_progs/block.c index f2a3e62..3797a38 100644 --- a/bpf_progs/block.c +++ b/bpf_progs/block.c
@@ -19,8 +19,8 @@ #include <netinet/in.h> #include <stdint.h> -// The resulting .o needs to load on the Android T beta 3 bpfloader -#define BPFLOADER_MIN_VER BPFLOADER_T_BETA3_VERSION +// The resulting .o needs to load on the Android T bpfloader +#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION #include "bpf_helpers.h"
diff --git a/bpf_progs/bpf_net_helpers.h b/bpf_progs/bpf_net_helpers.h index c39269e..ed33cc9 100644 --- a/bpf_progs/bpf_net_helpers.h +++ b/bpf_progs/bpf_net_helpers.h
@@ -21,6 +21,18 @@ #include <stdbool.h> #include <stdint.h> +// bionic kernel uapi linux/udp.h header is munged... +#define __kernel_udphdr udphdr +#include <linux/udp.h> + +// Offsets from beginning of L4 (TCP/UDP) header +#define TCP_OFFSET(field) offsetof(struct tcphdr, field) +#define UDP_OFFSET(field) offsetof(struct udphdr, field) + +// Offsets from beginning of L3 (IPv4/IPv6) header +#define IP4_OFFSET(field) offsetof(struct iphdr, field) +#define IP6_OFFSET(field) offsetof(struct ipv6hdr, field) + // this returns 0 iff skb->sk is NULL static uint64_t (*bpf_get_socket_cookie)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_cookie; @@ -74,3 +86,30 @@ if (len > skb->len) len = skb->len; if (skb->data_end - skb->data < len) bpf_skb_pull_data(skb, len); } + +// constants for passing in to 'bool egress' +static const bool INGRESS = false; +static const bool EGRESS = true; + +// constants for passing in to 'bool downstream' +static const bool UPSTREAM = false; +static const bool DOWNSTREAM = true; + +// constants for passing in to 'bool is_ethernet' +static const bool RAWIP = false; +static const bool ETHER = true; + +// constants for passing in to 'bool updatetime' +static const bool NO_UPDATETIME = false; +static const bool UPDATETIME = true; + +// constants for passing in to ignore_on_eng / ignore_on_user / ignore_on_userdebug +// define's instead of static const due to tm-mainline-prod compiler static_assert limitations +#define LOAD_ON_ENG false +#define LOAD_ON_USER false +#define LOAD_ON_USERDEBUG false +#define IGNORE_ON_ENG true +#define IGNORE_ON_USER true +#define IGNORE_ON_USERDEBUG true + +#define KVER_4_14 KVER(4, 14, 0)
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c index 14cddf6..85ba58e 100644 --- a/bpf_progs/clatd.c +++ b/bpf_progs/clatd.c
@@ -30,8 +30,8 @@ #define __kernel_udphdr udphdr #include <linux/udp.h> -// The resulting .o needs to load on the Android T beta 3 bpfloader -#define BPFLOADER_MIN_VER BPFLOADER_T_BETA3_VERSION +// The resulting .o needs to load on the Android T bpfloader +#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION #include "bpf_helpers.h" #include "bpf_net_helpers.h" @@ -54,7 +54,9 @@ DEFINE_BPF_MAP_GRW(clat_ingress6_map, HASH, ClatIngress6Key, ClatIngress6Value, 16, AID_SYSTEM) -static inline __always_inline int nat64(struct __sk_buff* skb, bool is_ethernet) { +static inline __always_inline int nat64(struct __sk_buff* skb, + const bool is_ethernet, + const unsigned kver) { // Require ethernet dst mac address to be our unicast address. if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_PIPE; @@ -83,6 +85,12 @@ if (ip6->version != 6) return TC_ACT_PIPE; // Maximum IPv6 payload length that can be translated to IPv4 + // Note: technically this check is too strict for an IPv6 fragment, + // which by virtue of stripping the extra 8 byte fragment extension header, + // could thus be 8 bytes larger and still fit in an ipv4 packet post + // translation. However... who ever heard of receiving ~64KB frags... + // fragments are kind of by definition smaller than ingress device mtu, + // and thus, on the internet, very very unlikely to exceed 1500 bytes. if (ntohs(ip6->payload_len) > 0xFFFF - sizeof(struct iphdr)) return TC_ACT_PIPE; ClatIngress6Key k = { @@ -106,6 +114,9 @@ __u16 tot_len = ntohs(ip6->payload_len) + sizeof(struct iphdr); // cannot overflow, see above if (proto == IPPROTO_FRAGMENT) { + // Fragment handling requires bpf_skb_adjust_room which is 4.14+ + if (kver < KVER_4_14) return TC_ACT_PIPE; + // 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; @@ -208,7 +219,20 @@ // return -ENOTSUPP; bpf_csum_update(skb, sum6); - if (frag_off != htons(IP_DF)) { + // Technically 'kver < KVER_4_14' already implies 'frag_off == htons(IP_DF)' due to logic above, + // thus the initial 'kver >= KVER_4_14' check here is entirely superfluous. + // + // However, we *need* the compiler (when compiling the program for 4.9) to entirely + // optimize out the call to bpf_skb_adjust_room() bpf helper: it's not enough for it to emit + // an unreachable call to it, it must *not* emit it at all (otherwise the 4.9 kernel's + // bpf verifier will refuse to load a program with an unknown bpf helper call) + // + // This is easiest to achieve by being very explicit in the if clause, + // better safe than sorry... + // + // Note: we currently have no TreeHugger coverage for 4.9-T devices (there are no such + // Pixel or cuttlefish devices), so likely you won't notice for months if this breaks... + if (kver >= KVER_4_14 && 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)) @@ -243,14 +267,24 @@ return TC_ACT_PIPE; } -DEFINE_BPF_PROG("schedcls/ingress6/clat_ether", AID_ROOT, AID_SYSTEM, sched_cls_ingress6_clat_ether) +DEFINE_BPF_PROG_KVER("schedcls/ingress6/clat_ether$4_14", AID_ROOT, AID_SYSTEM, sched_cls_ingress6_clat_ether_4_14, KVER_4_14) (struct __sk_buff* skb) { - return nat64(skb, true); + return nat64(skb, ETHER, KVER_4_14); } -DEFINE_BPF_PROG("schedcls/ingress6/clat_rawip", AID_ROOT, AID_SYSTEM, sched_cls_ingress6_clat_rawip) +DEFINE_BPF_PROG_KVER_RANGE("schedcls/ingress6/clat_ether$4_9", AID_ROOT, AID_SYSTEM, sched_cls_ingress6_clat_ether_4_9, KVER_NONE, KVER_4_14) (struct __sk_buff* skb) { - return nat64(skb, false); + return nat64(skb, ETHER, KVER_NONE); +} + +DEFINE_BPF_PROG_KVER("schedcls/ingress6/clat_rawip$4_14", AID_ROOT, AID_SYSTEM, sched_cls_ingress6_clat_rawip_4_14, KVER_4_14) +(struct __sk_buff* skb) { + return nat64(skb, RAWIP, KVER_4_14); +} + +DEFINE_BPF_PROG_KVER_RANGE("schedcls/ingress6/clat_rawip$4_9", AID_ROOT, AID_SYSTEM, sched_cls_ingress6_clat_rawip_4_9, KVER_NONE, KVER_4_14) +(struct __sk_buff* skb) { + return nat64(skb, RAWIP, KVER_NONE); } DEFINE_BPF_MAP_GRW(clat_egress4_map, HASH, ClatEgress4Key, ClatEgress4Value, 16, AID_SYSTEM)
diff --git a/bpf_progs/dscpPolicy.c b/bpf_progs/dscpPolicy.c index 72f63c6..262b65b 100644 --- a/bpf_progs/dscpPolicy.c +++ b/bpf_progs/dscpPolicy.c
@@ -27,8 +27,8 @@ #include <stdint.h> #include <string.h> -// The resulting .o needs to load on the Android T beta 3 bpfloader -#define BPFLOADER_MIN_VER BPFLOADER_T_BETA3_VERSION +// The resulting .o needs to load on the Android T bpfloader +#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION #include "bpf_helpers.h" #include "dscpPolicy.h"
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c index 8e99b8d..245ad7a 100644 --- a/bpf_progs/netd.c +++ b/bpf_progs/netd.c
@@ -14,8 +14,8 @@ * limitations under the License. */ -// The resulting .o needs to load on the Android T Beta 3 bpfloader -#define BPFLOADER_MIN_VER BPFLOADER_T_BETA3_VERSION +// The resulting .o needs to load on the Android T bpfloader +#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION #include <bpf_helpers.h> #include <linux/bpf.h> @@ -31,7 +31,7 @@ #include <stdbool.h> #include <stdint.h> #include "bpf_net_helpers.h" -#include "bpf_shared.h" +#include "netd.h" // This is defined for cgroup bpf filter only. static const int DROP = 0; @@ -42,12 +42,9 @@ static const int BPF_NOMATCH = 0; static const int BPF_MATCH = 1; -// Used for 'bool egress' -static const bool INGRESS = false; -static const bool EGRESS = true; - -#define IP_PROTO_OFF offsetof(struct iphdr, protocol) -#define IPV6_PROTO_OFF offsetof(struct ipv6hdr, nexthdr) +// Used for 'bool enable_tracing' +static const bool TRACE_ON = true; +static const bool TRACE_OFF = false; // offsetof(struct iphdr, ihl) -- but that's a bitfield #define IPPROTO_IHL_OFF 0 @@ -60,14 +57,18 @@ #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) \ - DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \ - AID_ROOT, AID_NET_BW_ACCT, 0060, "fs_bpf_net_shared", "", false) +#define DEFINE_BPF_MAP_NO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ + DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \ + AID_ROOT, AID_NET_BW_ACCT, 0060, "fs_bpf_net_shared", "", false, \ + BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG, \ + LOAD_ON_USER, LOAD_ON_USERDEBUG) // For maps netd only needs read only access to -#define DEFINE_BPF_MAP_RO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ - DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \ - AID_ROOT, AID_NET_BW_ACCT, 0460, "fs_bpf_netd_readonly", "", false) +#define DEFINE_BPF_MAP_RO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ + DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \ + AID_ROOT, AID_NET_BW_ACCT, 0460, "fs_bpf_netd_readonly", "", false, \ + BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG, \ + LOAD_ON_USER, LOAD_ON_USERDEBUG) // For maps netd needs to be able to read and write #define DEFINE_BPF_MAP_RW_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ @@ -95,6 +96,19 @@ /* never actually used from ebpf */ DEFINE_BPF_MAP_NO_NETD(iface_index_name_map, HASH, uint32_t, IfaceValue, IFACE_INDEX_NAME_MAP_SIZE) +// A single-element configuration array, packet tracing is enabled when 'true'. +DEFINE_BPF_MAP_EXT(packet_trace_enabled_map, ARRAY, uint32_t, bool, 1, + AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", false, + BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG, + IGNORE_ON_USER, LOAD_ON_USERDEBUG) + +// A ring buffer on which packet information is pushed. This map will only be loaded +// on eng and userdebug devices. User devices won't load this to save memory. +DEFINE_BPF_RINGBUF_EXT(packet_trace_ringbuf, PacketTrace, PACKET_TRACE_BUF_SIZE, + AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", false, + BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG, + IGNORE_ON_USER, LOAD_ON_USERDEBUG); + // iptables xt_bpf programs need to be usable by both netd and netutils_wrappers // selinux contexts, because even non-xt_bpf iptables mutations are implemented as // a full table dump, followed by an update in userspace, and then a reload into the kernel, @@ -109,8 +123,9 @@ // (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_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, minKV, maxKV) \ - DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \ - minKV, maxKV, false, "fs_bpf_netd_readonly", "") + DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \ + minKV, maxKV, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, false, \ + "fs_bpf_netd_readonly", "", false, false, false) #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) @@ -120,8 +135,9 @@ // programs that only need to be usable by the system server #define DEFINE_SYS_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \ - DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \ - KVER_NONE, KVER_INF, false, "fs_bpf_net_shared", "") + DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, KVER_NONE, KVER_INF, \ + BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, false, "fs_bpf_net_shared", \ + "", false, false, false) static __always_inline int is_system_uid(uint32_t uid) { // MIN_SYSTEM_UID is AID_ROOT == 0, so uint32_t is *always* >= 0 @@ -156,36 +172,38 @@ * Especially since the number of packets is important for any future clat offload correction. * (which adjusts upward by 20 bytes per packet to account for ipv4 -> ipv6 header conversion) */ -#define DEFINE_UPDATE_STATS(the_stats_map, TypeOfKey) \ - static __always_inline inline void update_##the_stats_map(struct __sk_buff* skb, \ - bool egress, TypeOfKey* key) { \ - StatsValue* value = bpf_##the_stats_map##_lookup_elem(key); \ - if (!value) { \ - StatsValue newValue = {}; \ - bpf_##the_stats_map##_update_elem(key, &newValue, BPF_NOEXIST); \ - value = bpf_##the_stats_map##_lookup_elem(key); \ - } \ - if (value) { \ - const int mtu = 1500; \ - uint64_t packets = 1; \ - uint64_t bytes = skb->len; \ - if (bytes > mtu) { \ - bool is_ipv6 = (skb->protocol == htons(ETH_P_IPV6)); \ - int ip_overhead = (is_ipv6 ? sizeof(struct ipv6hdr) : sizeof(struct iphdr)); \ - int tcp_overhead = ip_overhead + sizeof(struct tcphdr) + 12; \ - int mss = mtu - tcp_overhead; \ - uint64_t payload = bytes - tcp_overhead; \ - packets = (payload + mss - 1) / mss; \ - bytes = tcp_overhead * packets + payload; \ - } \ - if (egress) { \ - __sync_fetch_and_add(&value->txPackets, packets); \ - __sync_fetch_and_add(&value->txBytes, bytes); \ - } else { \ - __sync_fetch_and_add(&value->rxPackets, packets); \ - __sync_fetch_and_add(&value->rxBytes, bytes); \ - } \ - } \ +#define DEFINE_UPDATE_STATS(the_stats_map, TypeOfKey) \ + static __always_inline inline void update_##the_stats_map(const struct __sk_buff* const skb, \ + const TypeOfKey* const key, \ + const bool egress, \ + const unsigned kver) { \ + StatsValue* value = bpf_##the_stats_map##_lookup_elem(key); \ + if (!value) { \ + StatsValue newValue = {}; \ + bpf_##the_stats_map##_update_elem(key, &newValue, BPF_NOEXIST); \ + value = bpf_##the_stats_map##_lookup_elem(key); \ + } \ + if (value) { \ + const int mtu = 1500; \ + uint64_t packets = 1; \ + uint64_t bytes = skb->len; \ + if (bytes > mtu) { \ + bool is_ipv6 = (skb->protocol == htons(ETH_P_IPV6)); \ + int ip_overhead = (is_ipv6 ? sizeof(struct ipv6hdr) : sizeof(struct iphdr)); \ + int tcp_overhead = ip_overhead + sizeof(struct tcphdr) + 12; \ + int mss = mtu - tcp_overhead; \ + uint64_t payload = bytes - tcp_overhead; \ + packets = (payload + mss - 1) / mss; \ + bytes = tcp_overhead * packets + payload; \ + } \ + if (egress) { \ + __sync_fetch_and_add(&value->txPackets, packets); \ + __sync_fetch_and_add(&value->txBytes, bytes); \ + } else { \ + __sync_fetch_and_add(&value->rxPackets, packets); \ + __sync_fetch_and_add(&value->rxBytes, bytes); \ + } \ + } \ } DEFINE_UPDATE_STATS(app_uid_stats_map, uint32_t) @@ -194,19 +212,99 @@ DEFINE_UPDATE_STATS(stats_map_B, StatsKey) // 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 int bpf_skb_load_bytes_net(const struct __sk_buff* const skb, + const int L3_off, + void* const to, + const int len, + const unsigned kver) { + // 'kver' (here and throughout) is the compile time guaranteed minimum kernel version, + // ie. we're building (a version of) the bpf program for kver (or newer!) kernels. + // + // 4.19+ kernels support the 'bpf_skb_load_bytes_relative()' bpf helper function, + // so we can use it. On pre-4.19 kernels we cannot use the relative load helper, + // and thus will simply get things wrong if there's any L2 (ethernet) header in the skb. + // + // Luckily, for cellular traffic, there likely isn't any, as cell is usually 'rawip'. + // + // However, this does mean that wifi (and ethernet) on 4.14 is basically a lost cause: + // we'll be making decisions based on the *wrong* bytes (fetched from the wrong offset), + // because the 'L3_off' passed to bpf_skb_load_bytes() should be increased by l2_header_size, + // which for ethernet is 14 and not 0 like it is for rawip. + // + // For similar reasons this will fail with non-offloaded VLAN tags on < 4.19 kernels, + // since those extend the ethernet header from 14 to 18 bytes. + return kver >= KVER(4, 19, 0) + ? bpf_skb_load_bytes_relative(skb, L3_off, to, len, BPF_HDR_START_NET) + : bpf_skb_load_bytes(skb, L3_off, to, len); } -static __always_inline inline bool skip_owner_match(struct __sk_buff* skb, bool is_4_19) { +static __always_inline inline void do_packet_tracing( + const struct __sk_buff* const skb, const bool egress, const uint32_t uid, + const uint32_t tag, const bool enable_tracing, const unsigned kver) { + if (!enable_tracing) return; + if (kver < KVER(5, 8, 0)) return; + + uint32_t mapKey = 0; + bool* traceConfig = bpf_packet_trace_enabled_map_lookup_elem(&mapKey); + if (traceConfig == NULL) return; + if (*traceConfig == false) return; + + PacketTrace* pkt = bpf_packet_trace_ringbuf_reserve(); + if (pkt == NULL) return; + + // Errors from bpf_skb_load_bytes_net are ignored to favor returning something + // over returning nothing. In the event of an error, the kernel will fill in + // zero for the destination memory. Do not change the default '= 0' below. + + uint8_t proto = 0; + uint8_t L4_off = 0; + uint8_t ipVersion = 0; + if (skb->protocol == htons(ETH_P_IP)) { + (void)bpf_skb_load_bytes_net(skb, IP4_OFFSET(protocol), &proto, sizeof(proto), kver); + (void)bpf_skb_load_bytes_net(skb, IPPROTO_IHL_OFF, &L4_off, sizeof(L4_off), kver); + L4_off = (L4_off & 0x0F) * 4; // IHL calculation. + ipVersion = 4; + } else if (skb->protocol == htons(ETH_P_IPV6)) { + (void)bpf_skb_load_bytes_net(skb, IP6_OFFSET(nexthdr), &proto, sizeof(proto), kver); + L4_off = sizeof(struct ipv6hdr); + ipVersion = 6; + } + + uint8_t flags = 0; + __be16 sport = 0, dport = 0; + if (proto == IPPROTO_TCP && L4_off >= 20) { + (void)bpf_skb_load_bytes_net(skb, L4_off + TCP_FLAG32_OFF + 1, &flags, sizeof(flags), kver); + (void)bpf_skb_load_bytes_net(skb, L4_off + TCP_OFFSET(source), &sport, sizeof(sport), kver); + (void)bpf_skb_load_bytes_net(skb, L4_off + TCP_OFFSET(dest), &dport, sizeof(dport), kver); + } else if (proto == IPPROTO_UDP && L4_off >= 20) { + (void)bpf_skb_load_bytes_net(skb, L4_off + UDP_OFFSET(source), &sport, sizeof(sport), kver); + (void)bpf_skb_load_bytes_net(skb, L4_off + UDP_OFFSET(dest), &dport, sizeof(dport), kver); + } + + pkt->timestampNs = bpf_ktime_get_boot_ns(); + pkt->ifindex = skb->ifindex; + pkt->length = skb->len; + + pkt->uid = uid; + pkt->tag = tag; + pkt->sport = sport; + pkt->dport = dport; + + pkt->egress = egress; + pkt->ipProto = proto; + pkt->tcpFlags = flags; + pkt->ipVersion = ipVersion; + + bpf_packet_trace_ringbuf_submit(pkt); +} + +static __always_inline inline bool skip_owner_match(struct __sk_buff* skb, bool egress, + const unsigned kver) { uint32_t flag = 0; if (skb->protocol == htons(ETH_P_IP)) { 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, IP_PROTO_OFF, &proto, sizeof(proto), is_4_19); + (void)bpf_skb_load_bytes_net(skb, IP4_OFFSET(protocol), &proto, sizeof(proto), kver); if (proto == IPPROTO_ESP) return true; if (proto != IPPROTO_TCP) return false; // handles read failure above uint8_t ihl; @@ -215,23 +313,24 @@ // (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); + (void)bpf_skb_load_bytes_net(skb, IPPROTO_IHL_OFF, &ihl, sizeof(ihl), kver); // 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); + &flag, sizeof(flag), kver); } 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); + (void)bpf_skb_load_bytes_net(skb, IP6_OFFSET(nexthdr), &proto, sizeof(proto), kver); if (proto == IPPROTO_ESP) return true; if (proto != IPPROTO_TCP) return false; // handles read failure above // 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); + &flag, sizeof(flag), kver); } else { return false; } - return flag & TCP_FLAG_RST; // false on read failure + // Always allow RST's, and additionally allow ingress FINs + return flag & (TCP_FLAG_RST | (egress ? 0 : TCP_FLAG_FIN)); // false on read failure } static __always_inline inline BpfConfig getConfig(uint32_t configKey) { @@ -250,11 +349,11 @@ #define DROP_IF_UNSET (DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH | LOW_POWER_STANDBY_MATCH) static __always_inline inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid, - bool egress, bool is_4_19) { - if (skip_owner_match(skb, is_4_19)) return PASS; - + bool egress, const unsigned kver) { if (is_system_uid(uid)) return PASS; + if (skip_owner_match(skb, egress, kver)) return PASS; + BpfConfig enabledRules = getConfig(UID_RULES_CONFIGURATION_KEY); UidOwnerValue* uidEntry = bpf_uid_owner_map_lookup_elem(&uid); @@ -284,17 +383,21 @@ return PASS; } -static __always_inline inline void update_stats_with_config(struct __sk_buff* skb, bool egress, - StatsKey* key, uint32_t selectedMap) { +static __always_inline inline void update_stats_with_config(const uint32_t selectedMap, + const struct __sk_buff* const skb, + const StatsKey* const key, + const bool egress, + const unsigned kver) { if (selectedMap == SELECT_MAP_A) { - update_stats_map_A(skb, egress, key); - } else if (selectedMap == SELECT_MAP_B) { - update_stats_map_B(skb, egress, key); + update_stats_map_A(skb, key, egress, kver); + } else { + update_stats_map_B(skb, key, egress, kver); } } static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, bool egress, - bool is_4_19) { + const bool enable_tracing, + const unsigned kver) { 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); @@ -309,17 +412,10 @@ // Always allow and never count clat traffic. Only the IPv4 traffic on the stacked // interface is accounted for and subject to usage restrictions. - // TODO: remove sock_uid check once Nat464Xlat javaland adds the socket tag AID_CLAT for clat. - if (sock_uid == AID_CLAT || uid == AID_CLAT) { - return PASS; - } + // CLAT IPv6 TX sockets are *always* tagged with CLAT uid, see tagSocketAsClat() + if (uid == AID_CLAT) return PASS; - int match = bpf_owner_match(skb, sock_uid, egress, is_4_19); - if (egress && (match == DROP)) { - // If an outbound packet is going to be dropped, we do not count that - // traffic. - return match; - } + int match = bpf_owner_match(skb, sock_uid, egress, kver); // Workaround for secureVPN with VpnIsolation enabled, refer to b/159994981 for details. // Keep TAG_SYSTEM_DNS in sync with DnsResolver/include/netd_resolv/resolv.h @@ -332,6 +428,9 @@ if (match == DROP_UNLESS_DNS) match = DROP; } + // If an outbound packet is going to be dropped, we do not count that traffic. + if (egress && (match == DROP)) return DROP; + StatsKey key = {.uid = uid, .tag = tag, .counterSet = 0, .ifaceIndex = skb->ifindex}; uint8_t* counterSet = bpf_uid_counterset_map_lookup_elem(&uid); @@ -340,47 +439,59 @@ uint32_t mapSettingKey = CURRENT_STATS_MAP_CONFIGURATION_KEY; uint32_t* selectedMap = bpf_configuration_map_lookup_elem(&mapSettingKey); - // Use asm("%0 &= 1" : "+r"(match)) before return match, - // to help kernel's bpf verifier, so that it can be 100% certain - // that the returned value is always BPF_NOMATCH(0) or BPF_MATCH(1). - if (!selectedMap) { - asm("%0 &= 1" : "+r"(match)); - return match; - } + if (!selectedMap) return PASS; // cannot happen, needed to keep bpf verifier happy - if (key.tag) { - update_stats_with_config(skb, egress, &key, *selectedMap); - key.tag = 0; - } + do_packet_tracing(skb, egress, uid, tag, enable_tracing, kver); + update_stats_with_config(*selectedMap, skb, &key, egress, kver); + update_app_uid_stats_map(skb, &uid, egress, kver); - update_stats_with_config(skb, egress, &key, *selectedMap); - update_app_uid_stats_map(skb, egress, &uid); + // We've already handled DROP_UNLESS_DNS up above, thus when we reach here the only + // possible values of match are DROP(0) or PASS(1), however we need to use + // "match &= 1" before 'return match' to help the kernel's bpf verifier, + // so that it can be 100% certain that the returned value is always 0 or 1. + // We use assembly so that it cannot be optimized out by a too smart compiler. asm("%0 &= 1" : "+r"(match)); return match; } +DEFINE_BPF_PROG_EXT("cgroupskb/ingress/stats$trace", AID_ROOT, AID_SYSTEM, + bpf_cgroup_ingress_trace, KVER(5, 8, 0), KVER_INF, + BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, false, + "fs_bpf_netd_readonly", "", false, true, false) +(struct __sk_buff* skb) { + return bpf_traffic_account(skb, INGRESS, TRACE_ON, KVER(5, 8, 0)); +} + 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, INGRESS, /* is_4_19 */ true); + return bpf_traffic_account(skb, INGRESS, TRACE_OFF, KVER(4, 19, 0)); } 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, INGRESS, /* is_4_19 */ false); + return bpf_traffic_account(skb, INGRESS, TRACE_OFF, KVER_NONE); +} + +DEFINE_BPF_PROG_EXT("cgroupskb/egress/stats$trace", AID_ROOT, AID_SYSTEM, + bpf_cgroup_egress_trace, KVER(5, 8, 0), KVER_INF, + BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, false, + "fs_bpf_netd_readonly", "", false, true, false) +(struct __sk_buff* skb) { + return bpf_traffic_account(skb, EGRESS, TRACE_ON, KVER(5, 8, 0)); } 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, EGRESS, /* is_4_19 */ true); + return bpf_traffic_account(skb, EGRESS, TRACE_OFF, KVER(4, 19, 0)); } 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, EGRESS, /* is_4_19 */ false); + return bpf_traffic_account(skb, EGRESS, TRACE_OFF, KVER_NONE); } // WARNING: Android T's non-updatable netd depends on the name of this program. @@ -389,9 +500,8 @@ // Clat daemon does not generate new traffic, all its traffic is accounted for already // on the v4-* interfaces (except for the 20 (or 28) extra bytes of IPv6 vs IPv4 overhead, // but that can be corrected for later when merging v4-foo stats into interface foo's). - // TODO: remove sock_uid check once Nat464Xlat javaland adds the socket tag AID_CLAT for clat. + // CLAT sockets are created by system server and tagged as uid CLAT, see tagSocketAsClat() uint32_t sock_uid = bpf_get_socket_uid(skb); - if (sock_uid == AID_CLAT) return BPF_NOMATCH; if (sock_uid == AID_SYSTEM) { uint64_t cookie = bpf_get_socket_cookie(skb); UidTagValue* utag = bpf_cookie_tag_map_lookup_elem(&cookie); @@ -399,7 +509,7 @@ } uint32_t key = skb->ifindex; - update_iface_stats_map(skb, EGRESS, &key); + update_iface_stats_map(skb, &key, EGRESS, KVER_NONE); return BPF_MATCH; } @@ -412,7 +522,7 @@ // Keep that in mind when moving this out of iptables xt_bpf and into tc ingress (or xdp). uint32_t key = skb->ifindex; - update_iface_stats_map(skb, INGRESS, &key); + update_iface_stats_map(skb, &key, INGRESS, KVER_NONE); return BPF_MATCH; } @@ -422,7 +532,7 @@ if (is_received_skb(skb)) { // Account for ingress traffic before tc drops it. uint32_t key = skb->ifindex; - update_iface_stats_map(skb, INGRESS, &key); + update_iface_stats_map(skb, &key, INGRESS, KVER_NONE); } return TC_ACT_UNSPEC; }
diff --git a/bpf_progs/bpf_shared.h b/bpf_progs/netd.h similarity index 92% rename from bpf_progs/bpf_shared.h rename to bpf_progs/netd.h index cc88680..be604f9 100644 --- a/bpf_progs/bpf_shared.h +++ b/bpf_progs/netd.h
@@ -69,6 +69,24 @@ uint64_t tcpTxPackets; } Stats; +typedef struct { + uint64_t timestampNs; + uint32_t ifindex; + uint32_t length; + + uint32_t uid; + uint32_t tag; + + __be16 sport; + __be16 dport; + + bool egress; + uint8_t ipProto; + uint8_t tcpFlags; + uint8_t ipVersion; // 4=IPv4, 6=IPv6, 0=unknown +} PacketTrace; +STRUCT_SIZE(PacketTrace, 8+4+4 + 4+4 + 2+2 + 1+1+1+1); + // Since we cannot garbage collect the stats map since device boot, we need to make these maps as // large as possible. The maximum size of number of map entries we can have is depend on the rlimit // of MEM_LOCK granted to netd. The memory space needed by each map can be calculated by the @@ -87,7 +105,8 @@ // dozable_uid_map: key: 4 bytes, value: 1 bytes, cost: 145216 bytes = 145Kbytes // standby_uid_map: key: 4 bytes, value: 1 bytes, cost: 145216 bytes = 145Kbytes // powersave_uid_map: key: 4 bytes, value: 1 bytes, cost: 145216 bytes = 145Kbytes -// total: 4930Kbytes +// packet_trace_ringbuf:key: 0 bytes, value: 24 bytes, cost: 32768 bytes = 32Kbytes +// total: 4962Kbytes // It takes maximum 4.9MB kernel memory space if all maps are full, which requires any devices // running this module to have a memlock rlimit to be larger then 5MB. In the old qtaguid module, // we don't have a total limit for data entries but only have limitation of tags each uid can have. @@ -102,6 +121,7 @@ static const int IFACE_STATS_MAP_SIZE = 1000; static const int CONFIGURATION_MAP_SIZE = 2; static const int UID_OWNER_MAP_SIZE = 4000; +static const int PACKET_TRACE_BUF_SIZE = 32 * 1024; #ifdef __cplusplus @@ -145,6 +165,8 @@ #define CONFIGURATION_MAP_PATH BPF_NETD_PATH "map_netd_configuration_map" #define UID_OWNER_MAP_PATH BPF_NETD_PATH "map_netd_uid_owner_map" #define UID_PERMISSION_MAP_PATH BPF_NETD_PATH "map_netd_uid_permission_map" +#define PACKET_TRACE_RINGBUF_PATH BPF_NETD_PATH "map_netd_packet_trace_ringbuf" +#define PACKET_TRACE_ENABLED_MAP_PATH BPF_NETD_PATH "map_netd_packet_trace_enabled_map" #endif // __cplusplus
diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c index a8612df..80d1a41 100644 --- a/bpf_progs/offload.c +++ b/bpf_progs/offload.c
@@ -38,13 +38,7 @@ // Warning: values other than AID_ROOT don't work for map uid on BpfLoader < v0.21 #define TETHERING_UID AID_ROOT -#ifdef INPROCESS -#define DEFAULT_BPF_MAP_SELINUX_CONTEXT "fs_bpf_net_shared" -#define DEFAULT_BPF_PROG_SELINUX_CONTEXT "fs_bpf_net_shared" -#define TETHERING_GID AID_SYSTEM -#else #define TETHERING_GID AID_NETWORK_STACK -#endif #include "bpf_helpers.h" #include "bpf_net_helpers.h" @@ -131,7 +125,7 @@ TETHERING_GID) static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool is_ethernet, - const bool downstream) { + const bool downstream, const unsigned kver) { // Must be meta-ethernet IPv6 frame if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_PIPE; @@ -232,13 +226,13 @@ // This would require a much newer kernel with newer ebpf accessors. // (This is also blindly assuming 12 bytes of tcp timestamp option in tcp header) uint64_t packets = 1; - uint64_t bytes = skb->len; - if (bytes > v->pmtu) { - const int tcp_overhead = sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 12; - const int mss = v->pmtu - tcp_overhead; - const uint64_t payload = bytes - tcp_overhead; + uint64_t L3_bytes = skb->len - l2_header_size; + if (L3_bytes > v->pmtu) { + const int tcp6_overhead = sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 12; + const int mss = v->pmtu - tcp6_overhead; + const uint64_t payload = L3_bytes - tcp6_overhead; packets = (payload + mss - 1) / mss; - bytes = tcp_overhead * packets + payload; + L3_bytes = tcp6_overhead * packets + payload; } // Are we past the limit? If so, then abort... @@ -247,7 +241,7 @@ // a packet we let the core stack deal with things. // (The core stack needs to handle limits correctly anyway, // since we don't offload all traffic in both directions) - if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) TC_PUNT(LIMIT_REACHED); + if (stat_v->rxBytes + stat_v->txBytes + L3_bytes > *limit_v) TC_PUNT(LIMIT_REACHED); if (!is_ethernet) { // Try to inject an ethernet header, and simply return if we fail. @@ -287,7 +281,7 @@ bpf_csum_update(skb, 0xFFFF - ntohs(old_hl) + ntohs(new_hl)); __sync_fetch_and_add(downstream ? &stat_v->rxPackets : &stat_v->txPackets, packets); - __sync_fetch_and_add(downstream ? &stat_v->rxBytes : &stat_v->txBytes, bytes); + __sync_fetch_and_add(downstream ? &stat_v->rxBytes : &stat_v->txBytes, L3_bytes); // Overwrite any mac header with the new one // For a rawip tx interface it will simply be a bunch of zeroes and later stripped. @@ -305,13 +299,13 @@ DEFINE_BPF_PROG("schedcls/tether_downstream6_ether", TETHERING_UID, TETHERING_GID, sched_cls_tether_downstream6_ether) (struct __sk_buff* skb) { - return do_forward6(skb, /* is_ethernet */ true, /* downstream */ true); + return do_forward6(skb, ETHER, DOWNSTREAM, KVER_NONE); } DEFINE_BPF_PROG("schedcls/tether_upstream6_ether", TETHERING_UID, TETHERING_GID, sched_cls_tether_upstream6_ether) (struct __sk_buff* skb) { - return do_forward6(skb, /* is_ethernet */ true, /* downstream */ false); + return do_forward6(skb, ETHER, UPSTREAM, KVER_NONE); } // Note: section names must be unique to prevent programs from appending to each other, @@ -331,13 +325,13 @@ DEFINE_BPF_PROG_KVER("schedcls/tether_downstream6_rawip$4_14", TETHERING_UID, TETHERING_GID, sched_cls_tether_downstream6_rawip_4_14, KVER(4, 14, 0)) (struct __sk_buff* skb) { - return do_forward6(skb, /* is_ethernet */ false, /* downstream */ true); + return do_forward6(skb, RAWIP, DOWNSTREAM, KVER(4, 14, 0)); } DEFINE_BPF_PROG_KVER("schedcls/tether_upstream6_rawip$4_14", TETHERING_UID, TETHERING_GID, sched_cls_tether_upstream6_rawip_4_14, KVER(4, 14, 0)) (struct __sk_buff* skb) { - return do_forward6(skb, /* is_ethernet */ false, /* downstream */ false); + return do_forward6(skb, RAWIP, UPSTREAM, KVER(4, 14, 0)); } // and define no-op stubs for pre-4.14 kernels. @@ -362,7 +356,8 @@ static inline __always_inline int do_forward4_bottom(struct __sk_buff* skb, const int l2_header_size, void* data, const void* data_end, struct ethhdr* eth, struct iphdr* ip, const bool is_ethernet, - const bool downstream, const bool updatetime, const bool is_tcp) { + const bool downstream, const bool updatetime, const bool is_tcp, + const unsigned kver) { struct tcphdr* tcph = is_tcp ? (void*)(ip + 1) : NULL; struct udphdr* udph = is_tcp ? NULL : (void*)(ip + 1); @@ -449,13 +444,13 @@ // This would require a much newer kernel with newer ebpf accessors. // (This is also blindly assuming 12 bytes of tcp timestamp option in tcp header) uint64_t packets = 1; - uint64_t bytes = skb->len; - if (bytes > v->pmtu) { - const int tcp_overhead = sizeof(struct iphdr) + sizeof(struct tcphdr) + 12; - const int mss = v->pmtu - tcp_overhead; - const uint64_t payload = bytes - tcp_overhead; + uint64_t L3_bytes = skb->len - l2_header_size; + if (L3_bytes > v->pmtu) { + const int tcp4_overhead = sizeof(struct iphdr) + sizeof(struct tcphdr) + 12; + const int mss = v->pmtu - tcp4_overhead; + const uint64_t payload = L3_bytes - tcp4_overhead; packets = (payload + mss - 1) / mss; - bytes = tcp_overhead * packets + payload; + L3_bytes = tcp4_overhead * packets + payload; } // Are we past the limit? If so, then abort... @@ -464,7 +459,7 @@ // a packet we let the core stack deal with things. // (The core stack needs to handle limits correctly anyway, // since we don't offload all traffic in both directions) - if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) TC_PUNT(LIMIT_REACHED); + if (stat_v->rxBytes + stat_v->txBytes + L3_bytes > *limit_v) TC_PUNT(LIMIT_REACHED); if (!is_ethernet) { // Try to inject an ethernet header, and simply return if we fail. @@ -540,7 +535,7 @@ if (updatetime) v->last_used = bpf_ktime_get_boot_ns(); __sync_fetch_and_add(downstream ? &stat_v->rxPackets : &stat_v->txPackets, packets); - __sync_fetch_and_add(downstream ? &stat_v->rxBytes : &stat_v->txBytes, bytes); + __sync_fetch_and_add(downstream ? &stat_v->rxBytes : &stat_v->txBytes, L3_bytes); // Redirect to forwarded interface. // @@ -552,7 +547,7 @@ } static inline __always_inline int do_forward4(struct __sk_buff* skb, const bool is_ethernet, - const bool downstream, const bool updatetime) { + const bool downstream, const bool updatetime, const unsigned kver) { // Require ethernet dst mac address to be our unicast address. if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_PIPE; @@ -640,10 +635,10 @@ // if the underlying requisite kernel support (bpf_ktime_get_boot_ns) was backported. if (is_tcp) { return do_forward4_bottom(skb, l2_header_size, data, data_end, eth, ip, - is_ethernet, downstream, updatetime, /* is_tcp */ true); + is_ethernet, downstream, updatetime, /* is_tcp */ true, kver); } else { return do_forward4_bottom(skb, l2_header_size, data, data_end, eth, ip, - is_ethernet, downstream, updatetime, /* is_tcp */ false); + is_ethernet, downstream, updatetime, /* is_tcp */ false, kver); } } @@ -652,25 +647,25 @@ DEFINE_BPF_PROG_KVER("schedcls/tether_downstream4_rawip$5_8", TETHERING_UID, TETHERING_GID, sched_cls_tether_downstream4_rawip_5_8, KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ false, /* downstream */ true, /* updatetime */ true); + return do_forward4(skb, RAWIP, DOWNSTREAM, UPDATETIME, KVER(5, 8, 0)); } DEFINE_BPF_PROG_KVER("schedcls/tether_upstream4_rawip$5_8", TETHERING_UID, TETHERING_GID, sched_cls_tether_upstream4_rawip_5_8, KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ false, /* downstream */ false, /* updatetime */ true); + return do_forward4(skb, RAWIP, UPSTREAM, UPDATETIME, KVER(5, 8, 0)); } DEFINE_BPF_PROG_KVER("schedcls/tether_downstream4_ether$5_8", TETHERING_UID, TETHERING_GID, sched_cls_tether_downstream4_ether_5_8, KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ true, /* downstream */ true, /* updatetime */ true); + return do_forward4(skb, ETHER, DOWNSTREAM, UPDATETIME, KVER(5, 8, 0)); } DEFINE_BPF_PROG_KVER("schedcls/tether_upstream4_ether$5_8", TETHERING_UID, TETHERING_GID, sched_cls_tether_upstream4_ether_5_8, KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ true, /* downstream */ false, /* updatetime */ true); + return do_forward4(skb, ETHER, UPSTREAM, UPDATETIME, KVER(5, 8, 0)); } // Full featured (optional) implementations for 4.14-S, 4.19-S & 5.4-S kernels @@ -681,7 +676,7 @@ sched_cls_tether_downstream4_rawip_opt, KVER(4, 14, 0), KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ false, /* downstream */ true, /* updatetime */ true); + return do_forward4(skb, RAWIP, DOWNSTREAM, UPDATETIME, KVER(4, 14, 0)); } DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$opt", @@ -689,7 +684,7 @@ sched_cls_tether_upstream4_rawip_opt, KVER(4, 14, 0), KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ false, /* downstream */ false, /* updatetime */ true); + return do_forward4(skb, RAWIP, UPSTREAM, UPDATETIME, KVER(4, 14, 0)); } DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_ether$opt", @@ -697,7 +692,7 @@ sched_cls_tether_downstream4_ether_opt, KVER(4, 14, 0), KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ true, /* downstream */ true, /* updatetime */ true); + return do_forward4(skb, ETHER, DOWNSTREAM, UPDATETIME, KVER(4, 14, 0)); } DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_ether$opt", @@ -705,7 +700,7 @@ sched_cls_tether_upstream4_ether_opt, KVER(4, 14, 0), KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ true, /* downstream */ false, /* updatetime */ true); + return do_forward4(skb, ETHER, UPSTREAM, UPDATETIME, KVER(4, 14, 0)); } // Partial (TCP-only: will not update 'last_used' field) implementations for 4.14+ kernels. @@ -725,13 +720,13 @@ DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_rawip$5_4", TETHERING_UID, TETHERING_GID, sched_cls_tether_downstream4_rawip_5_4, KVER(5, 4, 0), KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ false, /* downstream */ true, /* updatetime */ false); + return do_forward4(skb, RAWIP, DOWNSTREAM, NO_UPDATETIME, KVER(5, 4, 0)); } DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$5_4", TETHERING_UID, TETHERING_GID, sched_cls_tether_upstream4_rawip_5_4, KVER(5, 4, 0), KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ false, /* downstream */ false, /* updatetime */ false); + return do_forward4(skb, RAWIP, UPSTREAM, NO_UPDATETIME, KVER(5, 4, 0)); } // RAWIP: Optional for 4.14/4.19 (R) kernels -- which support bpf_skb_change_head(). @@ -742,7 +737,7 @@ sched_cls_tether_downstream4_rawip_4_14, KVER(4, 14, 0), KVER(5, 4, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ false, /* downstream */ true, /* updatetime */ false); + return do_forward4(skb, RAWIP, DOWNSTREAM, NO_UPDATETIME, KVER(4, 14, 0)); } DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$4_14", @@ -750,7 +745,7 @@ sched_cls_tether_upstream4_rawip_4_14, KVER(4, 14, 0), KVER(5, 4, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ false, /* downstream */ false, /* updatetime */ false); + return do_forward4(skb, RAWIP, UPSTREAM, NO_UPDATETIME, KVER(4, 14, 0)); } // ETHER: Required for 4.14-Q/R, 4.19-Q/R & 5.4-R kernels. @@ -758,13 +753,13 @@ DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_ether$4_14", TETHERING_UID, TETHERING_GID, sched_cls_tether_downstream4_ether_4_14, KVER(4, 14, 0), KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ true, /* downstream */ true, /* updatetime */ false); + return do_forward4(skb, ETHER, DOWNSTREAM, NO_UPDATETIME, KVER(4, 14, 0)); } DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_ether$4_14", TETHERING_UID, TETHERING_GID, sched_cls_tether_upstream4_ether_4_14, KVER(4, 14, 0), KVER(5, 8, 0)) (struct __sk_buff* skb) { - return do_forward4(skb, /* is_ethernet */ true, /* downstream */ false, /* updatetime */ false); + return do_forward4(skb, ETHER, UPSTREAM, NO_UPDATETIME, KVER(4, 14, 0)); } // Placeholder (no-op) implementations for older Q kernels @@ -820,9 +815,9 @@ if ((void*)(eth + 1) > data_end) return XDP_PASS; if (eth->h_proto == htons(ETH_P_IPV6)) - return do_xdp_forward6(ctx, /* is_ethernet */ true, downstream); + return do_xdp_forward6(ctx, ETHER, downstream); if (eth->h_proto == htons(ETH_P_IP)) - return do_xdp_forward4(ctx, /* is_ethernet */ true, downstream); + return do_xdp_forward4(ctx, ETHER, downstream); // Anything else we don't know how to handle... return XDP_PASS; @@ -836,8 +831,8 @@ if (data_end - data < 1) return XDP_PASS; const uint8_t v = (*(uint8_t*)data) >> 4; - if (v == 6) return do_xdp_forward6(ctx, /* is_ethernet */ false, downstream); - if (v == 4) return do_xdp_forward4(ctx, /* is_ethernet */ false, downstream); + if (v == 6) return do_xdp_forward6(ctx, RAWIP, downstream); + if (v == 4) return do_xdp_forward4(ctx, RAWIP, downstream); // Anything else we don't know how to handle... return XDP_PASS; @@ -848,22 +843,22 @@ DEFINE_XDP_PROG("xdp/tether_downstream_ether", xdp_tether_downstream_ether) { - return do_xdp_forward_ether(ctx, /* downstream */ true); + return do_xdp_forward_ether(ctx, DOWNSTREAM); } DEFINE_XDP_PROG("xdp/tether_downstream_rawip", xdp_tether_downstream_rawip) { - return do_xdp_forward_rawip(ctx, /* downstream */ true); + return do_xdp_forward_rawip(ctx, DOWNSTREAM); } DEFINE_XDP_PROG("xdp/tether_upstream_ether", xdp_tether_upstream_ether) { - return do_xdp_forward_ether(ctx, /* downstream */ false); + return do_xdp_forward_ether(ctx, UPSTREAM); } DEFINE_XDP_PROG("xdp/tether_upstream_rawip", xdp_tether_upstream_rawip) { - return do_xdp_forward_rawip(ctx, /* downstream */ false); + return do_xdp_forward_rawip(ctx, UPSTREAM); } LICENSE("Apache 2.0");
diff --git a/bpf_progs/offload@inprocess.c b/bpf_progs/offload@inprocess.c deleted file mode 120000 index 4092e0d..0000000 --- a/bpf_progs/offload@inprocess.c +++ /dev/null
@@ -1 +0,0 @@ -offload.c \ No newline at end of file
diff --git a/bpf_progs/test.c b/bpf_progs/test.c index d1f780f..091743c 100644 --- a/bpf_progs/test.c +++ b/bpf_progs/test.c
@@ -32,13 +32,7 @@ // Warning: values other than AID_ROOT don't work for map uid on BpfLoader < v0.21 #define TETHERING_UID AID_ROOT -#ifdef INPROCESS -#define DEFAULT_BPF_MAP_SELINUX_CONTEXT "fs_bpf_net_shared" -#define DEFAULT_BPF_PROG_SELINUX_CONTEXT "fs_bpf_net_shared" -#define TETHERING_GID AID_SYSTEM -#else #define TETHERING_GID AID_NETWORK_STACK -#endif // This is non production code, only used for testing // Needed because the bitmap array definition is non-kosher for pre-T OS devices.
diff --git a/bpf_progs/test@inprocess.c b/bpf_progs/test@inprocess.c deleted file mode 120000 index aeebb26..0000000 --- a/bpf_progs/test@inprocess.c +++ /dev/null
@@ -1 +0,0 @@ -test.c \ No newline at end of file
diff --git a/framework-t/Android.bp b/framework-t/Android.bp index d40fad9..ffa2857 100644 --- a/framework-t/Android.bp +++ b/framework-t/Android.bp
@@ -46,6 +46,7 @@ libs: [ "unsupportedappusage", "app-compat-annotations", + "androidx.annotation_annotation", ], impl_only_libs: [ // The build system will use framework-bluetooth module_current stubs, because @@ -139,7 +140,7 @@ "//packages/modules/Connectivity/apex", "//packages/modules/Connectivity/service", // For R8 only "//packages/modules/Connectivity/service-t", - "//packages/modules/Connectivity/nearby/service", + "//packages/modules/Connectivity/nearby:__subpackages__", "//frameworks/base", // Tests using hidden APIs @@ -156,7 +157,6 @@ "//frameworks/opt/telephony/tests/telephonytests", "//packages/modules/CaptivePortalLogin/tests", "//packages/modules/Connectivity/Tethering/tests:__subpackages__", - "//packages/modules/Connectivity/nearby/tests:__subpackages__", "//packages/modules/Connectivity/tests:__subpackages__", "//packages/modules/IPsec/tests/iketests", "//packages/modules/NetworkStack/tests:__subpackages__", @@ -164,6 +164,7 @@ ], } +// This rule is not used anymore(b/268440216). platform_compat_config { name: "connectivity-t-platform-compat-config", src: ":framework-connectivity-t",
diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 391a562..b8eb1f6 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp
@@ -16,15 +16,13 @@ filegroup { name: "framework-connectivity-tiramisu-updatable-sources", + defaults: ["framework-sources-module-defaults"], srcs: [ "src/**/*.java", "src/**/*.aidl", ], path: "src", - visibility: [ - "//frameworks/base", - "//packages/modules/Connectivity:__subpackages__", - ], + visibility: ["//packages/modules/Connectivity:__subpackages__"], } cc_library_shared {
diff --git a/framework-t/api/current.txt b/framework-t/api/current.txt index eb77288..86745d4 100644 --- a/framework-t/api/current.txt +++ b/framework-t/api/current.txt
@@ -192,15 +192,20 @@ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void discoverServices(@NonNull String, int, @NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.nsd.NsdManager.DiscoveryListener); method public void registerService(android.net.nsd.NsdServiceInfo, int, android.net.nsd.NsdManager.RegistrationListener); method public void registerService(@NonNull android.net.nsd.NsdServiceInfo, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.nsd.NsdManager.RegistrationListener); - method public void resolveService(android.net.nsd.NsdServiceInfo, android.net.nsd.NsdManager.ResolveListener); - method public void resolveService(@NonNull android.net.nsd.NsdServiceInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.nsd.NsdManager.ResolveListener); + method public void registerServiceInfoCallback(@NonNull android.net.nsd.NsdServiceInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.nsd.NsdManager.ServiceInfoCallback); + method @Deprecated public void resolveService(android.net.nsd.NsdServiceInfo, android.net.nsd.NsdManager.ResolveListener); + method @Deprecated public void resolveService(@NonNull android.net.nsd.NsdServiceInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.nsd.NsdManager.ResolveListener); method public void stopServiceDiscovery(android.net.nsd.NsdManager.DiscoveryListener); + method public void stopServiceResolution(@NonNull android.net.nsd.NsdManager.ResolveListener); method public void unregisterService(android.net.nsd.NsdManager.RegistrationListener); + method public void unregisterServiceInfoCallback(@NonNull android.net.nsd.NsdManager.ServiceInfoCallback); field public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED"; field public static final String EXTRA_NSD_STATE = "nsd_state"; field public static final int FAILURE_ALREADY_ACTIVE = 3; // 0x3 + field public static final int FAILURE_BAD_PARAMETERS = 6; // 0x6 field public static final int FAILURE_INTERNAL_ERROR = 0; // 0x0 field public static final int FAILURE_MAX_LIMIT = 4; // 0x4 + field public static final int FAILURE_OPERATION_NOT_RUNNING = 5; // 0x5 field public static final int NSD_STATE_DISABLED = 1; // 0x1 field public static final int NSD_STATE_ENABLED = 2; // 0x2 field public static final int PROTOCOL_DNS_SD = 1; // 0x1 @@ -223,22 +228,33 @@ } public static interface NsdManager.ResolveListener { + method public default void onResolutionStopped(@NonNull android.net.nsd.NsdServiceInfo); method public void onResolveFailed(android.net.nsd.NsdServiceInfo, int); method public void onServiceResolved(android.net.nsd.NsdServiceInfo); + method public default void onStopResolutionFailed(@NonNull android.net.nsd.NsdServiceInfo, int); + } + + public static interface NsdManager.ServiceInfoCallback { + method public void onServiceInfoCallbackRegistrationFailed(int); + method public void onServiceInfoCallbackUnregistered(); + method public void onServiceLost(); + method public void onServiceUpdated(@NonNull android.net.nsd.NsdServiceInfo); } public final class NsdServiceInfo implements android.os.Parcelable { ctor public NsdServiceInfo(); method public int describeContents(); method public java.util.Map<java.lang.String,byte[]> getAttributes(); - method public java.net.InetAddress getHost(); + method @Deprecated public java.net.InetAddress getHost(); + method @NonNull public java.util.List<java.net.InetAddress> getHostAddresses(); method @Nullable public android.net.Network getNetwork(); method public int getPort(); method public String getServiceName(); method public String getServiceType(); method public void removeAttribute(String); method public void setAttribute(String, String); - method public void setHost(java.net.InetAddress); + method @Deprecated public void setHost(java.net.InetAddress); + method public void setHostAddresses(@NonNull java.util.List<java.net.InetAddress>); method public void setNetwork(@Nullable android.net.Network); method public void setPort(int); method public void setServiceName(String);
diff --git a/framework-t/api/system-current.txt b/framework-t/api/system-current.txt index c2d245c..87b0a64 100644 --- a/framework-t/api/system-current.txt +++ b/framework-t/api/system-current.txt
@@ -260,6 +260,7 @@ public class IpSecManager { method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException; method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; + method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void startTunnelModeTransformMigration(@NonNull android.net.IpSecTransform, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress); } public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
diff --git a/framework-t/src/android/net/IIpSecService.aidl b/framework-t/src/android/net/IIpSecService.aidl index 933256a..88ffd0e 100644 --- a/framework-t/src/android/net/IIpSecService.aidl +++ b/framework-t/src/android/net/IIpSecService.aidl
@@ -66,6 +66,12 @@ IpSecTransformResponse createTransform( in IpSecConfig c, in IBinder binder, in String callingPackage); + void migrateTransform( + int transformId, + in String newSourceAddress, + in String newDestinationAddress, + in String callingPackage); + void deleteTransform(int transformId); void applyTransportModeTransform(
diff --git a/framework-t/src/android/net/IpSecManager.java b/framework-t/src/android/net/IpSecManager.java index 9cceac2..3afa6ef 100644 --- a/framework-t/src/android/net/IpSecManager.java +++ b/framework-t/src/android/net/IpSecManager.java
@@ -37,6 +37,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.modules.utils.build.SdkLevel; import dalvik.system.CloseGuard; @@ -65,6 +66,24 @@ private static final String TAG = "IpSecManager"; /** + * Feature flag to declare the kernel support of updating IPsec SAs. + * + * <p>Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device + * has the requisite kernel support for migrating IPsec tunnels to new source/destination + * addresses. + * + * <p>This feature implies that the device supports XFRM Migration (CONFIG_XFRM_MIGRATE) and has + * the kernel fixes to allow XFRM Migration correctly + * + * @see android.content.pm.PackageManager#FEATURE_IPSEC_TUNNEL_MIGRATION + * @hide + */ + // Redefine this flag here so that IPsec code shipped in a mainline module can build on old + // platforms before FEATURE_IPSEC_TUNNEL_MIGRATION API is released. + public static final String FEATURE_IPSEC_TUNNEL_MIGRATION = + "android.software.ipsec_tunnel_migration"; + + /** * Used when applying a transform to direct traffic through an {@link IpSecTransform} * towards the host. * @@ -254,7 +273,7 @@ } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - mCloseGuard.open("open"); + mCloseGuard.open("close"); } /** @hide */ @@ -591,7 +610,7 @@ } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - mCloseGuard.open("constructor"); + mCloseGuard.open("close"); } /** Get the encapsulation socket's file descriptor. */ @@ -804,16 +823,18 @@ * Update the underlying network for this IpSecTunnelInterface. * * <p>This new underlying network will be used for all transforms applied AFTER this call is - * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to - * this tunnel interface, traffic will still use the old SA, and be routed on the old + * complete. Before {@link IpSecTransform}(s) with matching addresses are applied to this + * tunnel interface, traffic will still use the old transform, and be routed on the old * underlying network. * * <p>To migrate IPsec tunnel mode traffic, a caller should: * * <ol> * <li>Update the IpSecTunnelInterface’s underlying network. - * <li>Apply {@link IpSecTransform}(s) with matching addresses to this - * IpSecTunnelInterface. + * <li>Apply the new {@link IpSecTransform}(s) to this IpSecTunnelInterface. These can be + * new {@link IpSecTransform}(s) with matching addresses, or {@link IpSecTransform}(s) + * that have started migration (see {@link + * IpSecManager#startTunnelModeTransformMigration}). * </ol> * * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel. @@ -822,7 +843,6 @@ * method will throw an {@link IllegalArgumentException}. If the IpSecTunnelInterface is * later added to this network, all outbound traffic will be blackholed. */ - // TODO: b/169171001 Update the documentation when transform migration is supported. // The purpose of making updating network and applying transforms separate is to leave open // the possibility to support lossless migration procedures. To do that, Android platform // will need to support multiple inbound tunnel mode transforms, just like it can support @@ -871,7 +891,7 @@ } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - mCloseGuard.open("constructor"); + mCloseGuard.open("close"); } /** @@ -988,6 +1008,60 @@ } /** + * Migrate an active Tunnel Mode IPsec Transform to new source/destination addresses. + * + * <p>Begins the process of migrating a transform and cache the new addresses. To complete the + * migration once started, callers MUST apply the same transform to the appropriate tunnel using + * {@link IpSecManager#applyTunnelModeTransform}. Otherwise, the address update will not be + * committed and the transform will still only process traffic between the current source and + * destination address. One common use case is that the control plane will start the migration + * process and then hand off the transform to the IPsec caller to perform the actual migration + * when the tunnel is ready. + * + * <p>If this method is called multiple times before {@link + * IpSecManager#applyTunnelModeTransform} is called, when the transform is applied, it will be + * migrated to the addresses from the last call. + * + * <p>The provided source and destination addresses MUST share the same address family, but they + * can have a different family from the current addresses. + * + * <p>Transform migration is only supported for tunnel mode transforms. Calling this method on + * other types of transforms will throw an {@code UnsupportedOperationException}. + * + * @see IpSecTunnelInterface#setUnderlyingNetwork + * @param transform a tunnel mode {@link IpSecTransform} + * @param newSourceAddress the new source address + * @param newDestinationAddress the new destination address + * @hide + */ + @SystemApi + @RequiresFeature(FEATURE_IPSEC_TUNNEL_MIGRATION) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) + public void startTunnelModeTransformMigration( + @NonNull IpSecTransform transform, + @NonNull InetAddress newSourceAddress, + @NonNull InetAddress newDestinationAddress) { + if (!SdkLevel.isAtLeastU()) { + throw new UnsupportedOperationException( + "Transform migration only supported for Android 14+"); + } + + Objects.requireNonNull(transform, "transform was null"); + Objects.requireNonNull(newSourceAddress, "newSourceAddress was null"); + Objects.requireNonNull(newDestinationAddress, "newDestinationAddress was null"); + + try { + mService.migrateTransform( + transform.getResourceId(), + newSourceAddress.getHostAddress(), + newDestinationAddress.getHostAddress(), + mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * @hide */ public IpSecTransformResponse createTransform(IpSecConfig config, IBinder binder,
diff --git a/framework-t/src/android/net/IpSecTransform.java b/framework-t/src/android/net/IpSecTransform.java index 68ae5de..c236b6c 100644 --- a/framework-t/src/android/net/IpSecTransform.java +++ b/framework-t/src/android/net/IpSecTransform.java
@@ -126,7 +126,7 @@ checkResultStatus(status); mResourceId = result.resourceId; Log.d(TAG, "Added Transform with Id " + mResourceId); - mCloseGuard.open("build"); + mCloseGuard.open("close"); } catch (ServiceSpecificException e) { throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e); }
diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index edfd21c..947a092 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java
@@ -32,6 +32,7 @@ import android.net.wifi.WifiInfo; import android.service.NetworkIdentityProto; import android.telephony.TelephonyManager; +import android.util.Log; import android.util.proto.ProtoOutputStream; import com.android.net.module.util.BitUtils; @@ -406,10 +407,18 @@ setOemManaged(getOemBitfield(snapshot.getNetworkCapabilities())); if (mType == TYPE_WIFI) { - final TransportInfo transportInfo = snapshot.getNetworkCapabilities() - .getTransportInfo(); + final NetworkCapabilities nc = snapshot.getNetworkCapabilities(); + final TransportInfo transportInfo = nc.getTransportInfo(); if (transportInfo instanceof WifiInfo) { final WifiInfo info = (WifiInfo) transportInfo; + // Log.wtf to catch trying to set a null wifiNetworkKey into NetworkIdentity. + // See b/266598304. The problematic data that has null wifi network key is + // thrown out when storing data, which is handled by the service. + if (info.getNetworkKey() == null) { + Log.wtf(TAG, "WifiInfo contains a null wifiNetworkKey and it will" + + " be set into NetworkIdentity, netId=" + snapshot.getNetwork() + + "NetworkCapabilities=" + nc); + } setWifiNetworkKey(info.getNetworkKey()); } } else if (mType == TYPE_TEST) {
diff --git a/framework-t/src/android/net/NetworkStatsAccess.java b/framework-t/src/android/net/NetworkStatsAccess.java index b64fbdb..23902dc 100644 --- a/framework-t/src/android/net/NetworkStatsAccess.java +++ b/framework-t/src/android/net/NetworkStatsAccess.java
@@ -17,7 +17,6 @@ package android.net; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_TETHERING; @@ -33,6 +32,8 @@ import android.os.UserHandle; import android.telephony.TelephonyManager; +import com.android.net.module.util.PermissionUtils; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -100,6 +101,7 @@ * <li>Device owners. * <li>Carrier-privileged applications. * <li>The system UID. + * <li>NetworkStack application. * </ul> */ int DEVICE = 3; @@ -111,22 +113,23 @@ final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class); final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - boolean hasCarrierPrivileges; - final long token = Binder.clearCallingIdentity(); + final boolean hasCarrierPrivileges; + final boolean isDeviceOwner; + long token = Binder.clearCallingIdentity(); try { hasCarrierPrivileges = tm != null && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; + isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage); } finally { Binder.restoreCallingIdentity(token); } - final boolean isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage); final int appId = UserHandle.getAppId(callingUid); - final boolean isNetworkStack = context.checkPermission( - android.Manifest.permission.NETWORK_STACK, callingPid, callingUid) - == PERMISSION_GRANTED; + final boolean isNetworkStack = PermissionUtils.checkAnyPermissionOf( + context, callingPid, callingUid, android.Manifest.permission.NETWORK_STACK, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); if (hasCarrierPrivileges || isDeviceOwner || appId == Process.SYSTEM_UID || isNetworkStack) { @@ -135,15 +138,20 @@ return NetworkStatsAccess.Level.DEVICE; } - boolean hasAppOpsPermission = hasAppOpsPermission(context, callingUid, callingPackage); + final boolean hasAppOpsPermission = + hasAppOpsPermission(context, callingUid, callingPackage); if (hasAppOpsPermission || context.checkCallingOrSelfPermission( READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) { return NetworkStatsAccess.Level.DEVICESUMMARY; } - //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. - boolean isProfileOwner = mDpm != null && (mDpm.isProfileOwnerApp(callingPackage) - || mDpm.isDeviceOwnerApp(callingPackage)); + final boolean isProfileOwner; + token = Binder.clearCallingIdentity(); + try { + isProfileOwner = mDpm != null && mDpm.isProfileOwnerApp(callingPackage); + } finally { + Binder.restoreCallingIdentity(token); + } if (isProfileOwner) { // Apps with the AppOps permission, profile owners, and apps with the privileged // permission can access data usage for all apps in this user/profile.
diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index c0ae822..33bd884 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java
@@ -47,17 +47,22 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import android.util.ArraySet; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkIdentityUtils; -import com.android.net.module.util.NetworkStatsUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.SortedSet; @@ -71,6 +76,8 @@ */ @SystemApi(client = MODULE_LIBRARIES) public final class NetworkTemplate implements Parcelable { + private static final String TAG = NetworkTemplate.class.getSimpleName(); + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "MATCH_" }, value = { @@ -89,18 +96,6 @@ public static final int MATCH_WIFI = 4; /** Match rule to match ethernet networks. */ public static final int MATCH_ETHERNET = 5; - /** - * Match rule to match all cellular networks. - * - * @hide - */ - public static final int MATCH_MOBILE_WILDCARD = 6; - /** - * Match rule to match all wifi networks. - * - * @hide - */ - public static final int MATCH_WIFI_WILDCARD = 7; /** Match rule to match bluetooth networks. */ public static final int MATCH_BLUETOOTH = 8; /** @@ -178,8 +173,6 @@ case MATCH_MOBILE: case MATCH_WIFI: case MATCH_ETHERNET: - case MATCH_MOBILE_WILDCARD: - case MATCH_WIFI_WILDCARD: case MATCH_BLUETOOTH: case MATCH_PROXY: case MATCH_CARRIER: @@ -191,6 +184,23 @@ } } + private static Set<String> setOf(@Nullable final String item) { + if (item == null) { + // Set.of will throw if item is null + final Set<String> set = new HashSet<>(); + set.add(null); + return Collections.unmodifiableSet(set); + } else { + return Set.of(item); + } + } + + private static void throwAtLeastU() { + if (SdkLevel.isAtLeastU()) { + throw new UnsupportedOperationException("Method not supported on Android U or above"); + } + } + /** * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. @@ -203,7 +213,7 @@ publicAlternatives = "Use {@code Builder} instead.") public static NetworkTemplate buildTemplateMobileAll(@NonNull String subscriberId) { return new NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES) - .setSubscriberIds(Set.of(subscriberId)).build(); + .setSubscriberIds(setOf(subscriberId)).build(); } /** @@ -258,8 +268,122 @@ return new NetworkTemplate.Builder(MATCH_ETHERNET).build(); } + /** + * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style + * networks together. + * + * @hide + */ + // TODO(b/270089918): Remove this method. This can only be done after there are no more callers, + // including in OEM code which can access this by linking against the framework. + public static NetworkTemplate buildTemplateBluetooth() { + // TODO : this is part of hidden-o txt, does that mean it should be annotated with + // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps + // targeting O- crash on those devices. + return new NetworkTemplate.Builder(MATCH_BLUETOOTH).build(); + } + + /** + * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style + * networks together. + * + * @hide + */ + // TODO(b/270089918): Remove this method. This can only be done after there are no more callers, + // including in OEM code which can access this by linking against the framework. + public static NetworkTemplate buildTemplateProxy() { + // TODO : this is part of hidden-o txt, does that mean it should be annotated with + // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps + // targeting O- crash on those devices. + return new NetworkTemplate(MATCH_PROXY, null, null); + } + + /** + * Template to match all metered carrier networks with the given IMSI. + * + * @hide + */ + // TODO(b/273963543): Remove this method. This can only be done after there are no more callers, + // including in OEM code which can access this by linking against the framework. + public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) { + throwAtLeastU(); + return new NetworkTemplate.Builder(MATCH_CARRIER) + // Set.of will throw if subscriberId is null, which is the historical + // behavior and should be preserved. + .setSubscriberIds(Set.of(subscriberId)) + .setMeteredness(METERED_YES) + .build(); + } + + /** + * Template to match cellular networks with the given IMSI, {@code ratType} and + * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when + * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. + * + * @hide + */ + // TODO(b/273963543): Remove this method. This can only be done after there are no more callers, + // including in OEM code which can access this by linking against the framework. + public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, + int ratType, int metered) { + throwAtLeastU(); + return new NetworkTemplate.Builder(MATCH_MOBILE) + .setSubscriberIds(TextUtils.isEmpty(subscriberId) + ? Collections.emptySet() + : Set.of(subscriberId)) + .setMeteredness(metered) + .setRatType(ratType) + .build(); + } + + /** + * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the + * given key of the wifi network. + * + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} + * to know details about the key. + * @hide + */ + // TODO(b/273963543): Remove this method. This can only be done after there are no more callers, + // including in OEM code which can access this by linking against the framework. + public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) { + // TODO : this is part of hidden-o txt, does that mean it should be annotated with + // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps + // targeting O- crash on those devices. + return new NetworkTemplate.Builder(MATCH_WIFI) + // Set.of will throw if wifiNetworkKey is null, which is the historical + // behavior and should be preserved. + .setWifiNetworkKeys(Set.of(wifiNetworkKey)) + .build(); + } + + /** + * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given + * key of the wifi network and IMSI. + * + * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless + * of key of the wifi network. + * + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} + * to know details about the key. + * @param subscriberId the IMSI associated to this wifi network. + * + * @hide + */ + // TODO(b/273963543): Remove this method. This can only be done after there are no more callers, + // including in OEM code which can access this by linking against the framework. + public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey, + @Nullable String subscriberId) { + throwAtLeastU(); + return new NetworkTemplate.Builder(MATCH_WIFI) + .setSubscriberIds(setOf(subscriberId)) + .setWifiNetworkKeys(wifiNetworkKey == null + ? Collections.emptySet() + : Set.of(wifiNetworkKey)) + .build(); + } + private final int mMatchRule; - private final String mSubscriberId; /** * Ugh, templates are designed to target a single subscriber, but we might @@ -280,23 +404,33 @@ private final int mRoaming; private final int mDefaultNetwork; private final int mRatType; - /** - * The subscriber Id match rule defines how the template should match networks with - * specific subscriberId(s). See NetworkTemplate#SUBSCRIBER_ID_MATCH_RULE_* for more detail. - */ - private final int mSubscriberIdMatchRule; // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. private final int mOemManaged; - private static void checkValidSubscriberIdMatchRule(int matchRule, int subscriberIdMatchRule) { + private static void checkValidMatchSubscriberIds(int matchRule, String[] matchSubscriberIds) { switch (matchRule) { - case MATCH_MOBILE: + // CARRIER templates must always specify a valid subscriber ID. + // MOBILE templates can have empty matchSubscriberIds but it must not contain a null + // subscriber ID. case MATCH_CARRIER: - // MOBILE and CARRIER templates must always specify a subscriber ID. - if (subscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL) { - throw new IllegalArgumentException("Invalid SubscriberIdMatchRule " - + "on match rule: " + getMatchRuleName(matchRule)); + if (matchSubscriberIds.length == 0) { + throw new IllegalArgumentException("matchSubscriberIds may not contain" + + " null for rule " + getMatchRuleName(matchRule)); + } + if (CollectionUtils.contains(matchSubscriberIds, null)) { + throw new IllegalArgumentException("matchSubscriberIds may not contain" + + " null for rule " + getMatchRuleName(matchRule)); + } + break; + case MATCH_MOBILE: + // Prevent from crash for b/273963543, where the OEMs still call into unsupported + // buildTemplateMobileAll with null subscriberId and get crashed. + final int firstSdk = Build.VERSION.DEVICE_INITIAL_SDK_INT; + if (firstSdk > Build.VERSION_CODES.TIRAMISU + && CollectionUtils.contains(matchSubscriberIds, null)) { + throw new IllegalArgumentException("checkValidMatchSubscriberIds list of ids" + + " may not contain null for rule " + getMatchRuleName(matchRule)); } return; default: @@ -312,32 +446,81 @@ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, publicAlternatives = "Use {@code Builder} instead.") public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) { - this(matchRule, subscriberId, new String[] { subscriberId }, wifiNetworkKey); + // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates + // to metered networks. It is now possible to match mobile with any meteredness, but + // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this + // constructor passes METERED_YES for these types. + // For backwards compatibility, still accept old wildcard match rules (6 and 7 for + // MATCH_{MOBILE,WIFI}_WILDCARD) but convert into functionally equivalent non-wildcard + // ones. + this(getBackwardsCompatibleMatchRule(matchRule), + subscriberId != null ? new String[] { subscriberId } : new String[0], + wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], + getMeterednessForBackwardsCompatibility(matchRule), ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); + if (matchRule == 6 || matchRule == 7) { + Log.e(TAG, "Use MATCH_MOBILE with empty subscriberIds or MATCH_WIFI with empty " + + "wifiNetworkKeys instead of template with matchRule=" + matchRule); + } + } + + private static int getBackwardsCompatibleMatchRule(int matchRule) { + // Backwards compatibility old constants + // Old MATCH_MOBILE_WILDCARD + if (6 == matchRule) return MATCH_MOBILE; + // Old MATCH_WIFI_WILDCARD + if (7 == matchRule) return MATCH_WIFI; + return matchRule; + } + + private static int getMeterednessForBackwardsCompatibility(int matchRule) { + if (getBackwardsCompatibleMatchRule(matchRule) == MATCH_MOBILE + || matchRule == MATCH_CARRIER) { + return METERED_YES; + } + return METERED_ALL; } /** @hide */ + // TODO(b/270089918): Remove this method after no callers. public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String wifiNetworkKey) { // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates // to metered networks. It is now possible to match mobile with any meteredness, but // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this - //constructor passes METERED_YES for these types. - this(matchRule, subscriberId, matchSubscriberIds, + // constructor passes METERED_YES for these types. + this(getBackwardsCompatibleMatchRule(matchRule), matchSubscriberIds, wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], - (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD - || matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL, + getMeterednessForBackwardsCompatibility(matchRule), ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); + OEM_MANAGED_ALL); + // TODO : this is part of hidden-o txt, does that mean it should be annotated with + // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps + // targeting O- crash on those devices. } /** @hide */ + // TODO(b/269974916): Remove this method after Android U is released. + // This is only used by CTS of Android T. public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String[] matchWifiNetworkKeys, int metered, int roaming, int defaultNetwork, int ratType, int oemManaged, int subscriberIdMatchRule) { + // subscriberId and subscriberIdMatchRule aren't used since they are replaced by + // matchSubscriberIds, which could be null to indicate the intention of matching any + // subscriberIds. + this(getBackwardsCompatibleMatchRule(matchRule), + matchSubscriberIds == null ? new String[]{} : matchSubscriberIds, + matchWifiNetworkKeys, metered, roaming, defaultNetwork, ratType, oemManaged); + throwAtLeastU(); + } + + /** @hide */ + public NetworkTemplate(int matchRule, String[] matchSubscriberIds, + String[] matchWifiNetworkKeys, int metered, int roaming, int defaultNetwork, + int ratType, int oemManaged) { Objects.requireNonNull(matchWifiNetworkKeys); Objects.requireNonNull(matchSubscriberIds); mMatchRule = matchRule; - mSubscriberId = subscriberId; mMatchSubscriberIds = matchSubscriberIds; mMatchWifiNetworkKeys = matchWifiNetworkKeys; mMetered = metered; @@ -345,8 +528,7 @@ mDefaultNetwork = defaultNetwork; mRatType = ratType; mOemManaged = oemManaged; - mSubscriberIdMatchRule = subscriberIdMatchRule; - checkValidSubscriberIdMatchRule(matchRule, subscriberIdMatchRule); + checkValidMatchSubscriberIds(matchRule, matchSubscriberIds); if (!isKnownMatchRule(matchRule)) { throw new IllegalArgumentException("Unknown network template rule " + matchRule + " will not match any identity."); @@ -355,7 +537,6 @@ private NetworkTemplate(Parcel in) { mMatchRule = in.readInt(); - mSubscriberId = in.readString(); mMatchSubscriberIds = in.createStringArray(); mMatchWifiNetworkKeys = in.createStringArray(); mMetered = in.readInt(); @@ -363,13 +544,11 @@ mDefaultNetwork = in.readInt(); mRatType = in.readInt(); mOemManaged = in.readInt(); - mSubscriberIdMatchRule = in.readInt(); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mMatchRule); - dest.writeString(mSubscriberId); dest.writeStringArray(mMatchSubscriberIds); dest.writeStringArray(mMatchWifiNetworkKeys); dest.writeInt(mMetered); @@ -377,7 +556,6 @@ dest.writeInt(mDefaultNetwork); dest.writeInt(mRatType); dest.writeInt(mOemManaged); - dest.writeInt(mSubscriberIdMatchRule); } @Override @@ -389,10 +567,6 @@ public String toString() { final StringBuilder builder = new StringBuilder("NetworkTemplate: "); builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); - if (mSubscriberId != null) { - builder.append(", subscriberId=").append( - NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); - } if (mMatchSubscriberIds != null) { builder.append(", matchSubscriberIds=").append( Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds))); @@ -414,15 +588,14 @@ if (mOemManaged != OEM_MANAGED_ALL) { builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); } - builder.append(", subscriberIdMatchRule=") - .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule)); return builder.toString(); } @Override public int hashCode() { - return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys), - mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged, mSubscriberIdMatchRule); + return Objects.hash(mMatchRule, Arrays.hashCode(mMatchSubscriberIds), + Arrays.hashCode(mMatchWifiNetworkKeys), mMetered, mRoaming, mDefaultNetwork, + mRatType, mOemManaged); } @Override @@ -430,34 +603,28 @@ if (obj instanceof NetworkTemplate) { final NetworkTemplate other = (NetworkTemplate) obj; return mMatchRule == other.mMatchRule - && Objects.equals(mSubscriberId, other.mSubscriberId) && mMetered == other.mMetered && mRoaming == other.mRoaming && mDefaultNetwork == other.mDefaultNetwork && mRatType == other.mRatType && mOemManaged == other.mOemManaged - && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule + && Arrays.equals(mMatchSubscriberIds, other.mMatchSubscriberIds) && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys); } return false; } - private static String subscriberIdMatchRuleToString(int rule) { - switch (rule) { - case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT: - return "EXACT_MATCH"; - case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL: - return "ALL"; - default: - return "Unknown rule " + rule; - } - } - + // TODO(b/270089918): Remove this method. This can only be done after there are no more callers, + // including in OEM code which can access this by linking against the framework. /** @hide */ public boolean isMatchRuleMobile() { + // TODO : this is part of hidden-o txt, does that mean it should be annotated with + // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps + // targeting O- crash on those devices. switch (mMatchRule) { case MATCH_MOBILE: - case MATCH_MOBILE_WILDCARD: + // Old MATCH_MOBILE_WILDCARD + case 6: return true; default: return false; @@ -467,28 +634,22 @@ /** * Get match rule of the template. See {@code MATCH_*}. */ - @UnsupportedAppUsage public int getMatchRule() { - // Wildcard rules are not exposed. For external callers, convert wildcard rules to - // exposed rules before returning. - switch (mMatchRule) { - case MATCH_MOBILE_WILDCARD: - return MATCH_MOBILE; - case MATCH_WIFI_WILDCARD: - return MATCH_WIFI; - default: - return mMatchRule; - } + return mMatchRule; } /** * Get subscriber Id of the template. + * + * @deprecated User should use {@link #getSubscriberIds} instead. * @hide */ + @Deprecated @Nullable - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, + publicAlternatives = "Caller should use {@code getSubscriberIds} instead.") public String getSubscriberId() { - return mSubscriberId; + return CollectionUtils.isEmpty(mMatchSubscriberIds) ? null : mMatchSubscriberIds[0]; } /** @@ -575,10 +736,6 @@ return matchesWifi(ident); case MATCH_ETHERNET: return matchesEthernet(ident); - case MATCH_MOBILE_WILDCARD: - return matchesMobileWildcard(ident); - case MATCH_WIFI_WILDCARD: - return matchesWifiWildcard(ident); case MATCH_BLUETOOTH: return matchesBluetooth(ident); case MATCH_PROXY: @@ -627,13 +784,13 @@ /** * Check if this template matches {@code subscriberId}. Returns true if this - * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a - * {@code mMatchSubscriberIds} array that contains {@code subscriberId}. + * template was created with a {@code mMatchSubscriberIds} array that contains + * {@code subscriberId} or if {@code mMatchSubscriberIds} is empty. * * @hide */ public boolean matchesSubscriberId(@Nullable String subscriberId) { - return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL + return mMatchSubscriberIds.length == 0 || CollectionUtils.contains(mMatchSubscriberIds, subscriberId); } @@ -646,7 +803,15 @@ * to know details about the key. */ private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) { - Objects.requireNonNull(wifiNetworkKey); + // Note that this code accepts null wifi network keys because of a past bug where wifi + // code was sending a null network key for some connected networks, which isn't expected + // and ended up stored in the data on many devices. + // A null network key in the data matches a wildcard template (one where + // {@code mMatchWifiNetworkKeys} is empty), but not one where {@code MatchWifiNetworkKeys} + // contains null. See b/266598304. + if (wifiNetworkKey == null) { + return CollectionUtils.isEmpty(mMatchWifiNetworkKeys); + } return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) || CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey); } @@ -659,9 +824,9 @@ // TODO: consider matching against WiMAX subscriber identity return true; } else { - return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds) - && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) - && matchesCollapsedRatType(ident); + return (CollectionUtils.isEmpty(mMatchSubscriberIds) + || CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)) + && (ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident)); } } @@ -673,6 +838,8 @@ case TYPE_WIFI: return matchesSubscriberId(ident.mSubscriberId) && matchesWifiNetworkKey(ident.mWifiNetworkKey); + case TYPE_WIFI_P2P: + return CollectionUtils.isEmpty(mMatchWifiNetworkKeys); default: return false; } @@ -708,24 +875,6 @@ || CollectionUtils.contains(mMatchWifiNetworkKeys, ident.mWifiNetworkKey))); } - private boolean matchesMobileWildcard(NetworkIdentity ident) { - if (ident.mType == TYPE_WIMAX) { - return true; - } else { - return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident); - } - } - - private boolean matchesWifiWildcard(NetworkIdentity ident) { - switch (ident.mType) { - case TYPE_WIFI: - case TYPE_WIFI_P2P: - return true; - default: - return false; - } - } - /** * Check if matches Bluetooth network template. */ @@ -751,10 +900,6 @@ return "WIFI"; case MATCH_ETHERNET: return "ETHERNET"; - case MATCH_MOBILE_WILDCARD: - return "MOBILE_WILDCARD"; - case MATCH_WIFI_WILDCARD: - return "WIFI_WILDCARD"; case MATCH_BLUETOOTH: return "BLUETOOTH"; case MATCH_PROXY: @@ -788,8 +933,7 @@ * subscribers. * <p> * For example, given an incoming template matching B, and the currently - * active merge set [A,B], we'd return a new template that primarily matches - * A, but also matches B. + * active merge set [A,B], we'd return a new template that matches both A and B. * * @hide */ @@ -798,21 +942,68 @@ + "Callers should have their own logic to merge template for" + " different IMSIs and stop calling this function.") public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { + return normalizeImpl(template, Collections.singletonList(merged)); + } + + /** + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary + * for key purposes, and expand the template to match all other merged + * subscribers. + * + * There can be multiple merged subscriberIds for multi-SIM devices. + * + * <p> + * For example, given an incoming template matching B, and the currently + * active merge set [A,B], we'd return a new template that matches both A and B. + * + * @hide + */ + // TODO(b/273963543): Remove this method. This can only be done after there are no more callers, + // including in OEM code which can access this by linking against the framework. + public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) { + throwAtLeastU(); + return normalizeImpl(template, mergedList); + } + + /** + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary + * for key purposes, and expand the template to match all other merged + * subscribers. + * + * There can be multiple merged subscriberIds for multi-SIM devices. + * + * <p> + * For example, given an incoming template matching B, and the currently + * active merge set [A,B], we'd return a new template that matches both A and B. + * + * @hide + */ + private static NetworkTemplate normalizeImpl(NetworkTemplate template, + List<String[]> mergedList) { // Now there are several types of network which uses SubscriberId to store network // information. For instances: // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. // The TYPE_CARRIER means that the network associate to specific carrier network. - if (template.mSubscriberId == null) return template; - if (CollectionUtils.contains(merged, template.mSubscriberId)) { - // Requested template subscriber is part of the merge group; return - // a template that matches all merged subscribers. - final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys; - // TODO: Use NetworkTemplate.Builder to build a template after NetworkTemplate - // could handle incompatible subscriberIds. See b/217805241. - return new NetworkTemplate(template.mMatchRule, merged[0], merged, - CollectionUtils.isEmpty(matchWifiNetworkKeys) - ? null : matchWifiNetworkKeys[0]); + if (CollectionUtils.isEmpty(template.mMatchSubscriberIds)) return template; + + for (String[] merged : mergedList) { + if (CollectionUtils.contains(merged, template.mMatchSubscriberIds[0])) { + // Requested template subscriber is part of the merge group; return + // a template that matches all merged subscribers. + final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys; + // TODO: Use NetworkTemplate.Builder to build a template after NetworkTemplate + // could handle incompatible subscriberIds. See b/217805241. + return new NetworkTemplate(template.mMatchRule, merged, + CollectionUtils.isEmpty(matchWifiNetworkKeys) + ? new String[0] : new String[] { matchWifiNetworkKeys[0] }, + (template.mMatchRule == MATCH_MOBILE + || template.mMatchRule == MATCH_CARRIER) + ? METERED_YES : METERED_ALL, + ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); + } } return template; @@ -979,10 +1170,7 @@ * @param matchRule the target match rule to be checked. */ private static void assertRequestableMatchRule(final int matchRule) { - if (!isKnownMatchRule(matchRule) - || matchRule == MATCH_PROXY - || matchRule == MATCH_MOBILE_WILDCARD - || matchRule == MATCH_WIFI_WILDCARD) { + if (!isKnownMatchRule(matchRule) || matchRule == MATCH_PROXY) { throw new IllegalArgumentException("Invalid match rule: " + getMatchRuleName(matchRule)); } @@ -1003,20 +1191,6 @@ } /** - * For backward compatibility, deduce match rule to a wildcard match rule - * if the Subscriber Ids are empty. - */ - private int getWildcardDeducedMatchRule() { - if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) { - return MATCH_MOBILE_WILDCARD; - } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty() - && mMatchWifiNetworkKeys.isEmpty()) { - return MATCH_WIFI_WILDCARD; - } - return mMatchRule; - } - - /** * Builds the instance of the NetworkTemplate. * * @return the built instance of NetworkTemplate. @@ -1024,14 +1198,10 @@ @NonNull public NetworkTemplate build() { assertRequestableParameters(); - final int subscriberIdMatchRule = mMatchSubscriberIds.isEmpty() - ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL - : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT; - return new NetworkTemplate(getWildcardDeducedMatchRule(), - mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(), + return new NetworkTemplate(mMatchRule, mMatchSubscriberIds.toArray(new String[0]), mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming, - mDefaultNetwork, mRatType, mOemManaged, subscriberIdMatchRule); + mDefaultNetwork, mRatType, mOemManaged); } } }
diff --git a/framework-t/src/android/net/nsd/INsdManager.aidl b/framework-t/src/android/net/nsd/INsdManager.aidl index 89e9cdb..9d14b1a 100644 --- a/framework-t/src/android/net/nsd/INsdManager.aidl +++ b/framework-t/src/android/net/nsd/INsdManager.aidl
@@ -26,5 +26,5 @@ * {@hide} */ interface INsdManager { - INsdServiceConnector connect(INsdManagerCallback cb); + INsdServiceConnector connect(INsdManagerCallback cb, boolean useJavaBackend); }
diff --git a/framework-t/src/android/net/nsd/INsdManagerCallback.aidl b/framework-t/src/android/net/nsd/INsdManagerCallback.aidl index 1a262ec..d89bfa9 100644 --- a/framework-t/src/android/net/nsd/INsdManagerCallback.aidl +++ b/framework-t/src/android/net/nsd/INsdManagerCallback.aidl
@@ -36,4 +36,10 @@ void onUnregisterServiceSucceeded(int listenerKey); void onResolveServiceFailed(int listenerKey, int error); void onResolveServiceSucceeded(int listenerKey, in NsdServiceInfo info); + void onStopResolutionFailed(int listenerKey, int error); + void onStopResolutionSucceeded(int listenerKey); + void onServiceInfoCallbackRegistrationFailed(int listenerKey, int error); + void onServiceUpdated(int listenerKey, in NsdServiceInfo info); + void onServiceUpdatedLost(int listenerKey); + void onServiceInfoCallbackUnregistered(int listenerKey); }
diff --git a/framework-t/src/android/net/nsd/INsdServiceConnector.aidl b/framework-t/src/android/net/nsd/INsdServiceConnector.aidl index b06ae55..5533154 100644 --- a/framework-t/src/android/net/nsd/INsdServiceConnector.aidl +++ b/framework-t/src/android/net/nsd/INsdServiceConnector.aidl
@@ -32,4 +32,7 @@ void stopDiscovery(int listenerKey); void resolveService(int listenerKey, in NsdServiceInfo serviceInfo); void startDaemon(); + void stopResolution(int listenerKey); + void registerServiceInfoCallback(int listenerKey, in NsdServiceInfo serviceInfo); + void unregisterServiceInfoCallback(int listenerKey); } \ No newline at end of file
diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java index fb3b1d6..2930cbd 100644 --- a/framework-t/src/android/net/nsd/NsdManager.java +++ b/framework-t/src/android/net/nsd/NsdManager.java
@@ -16,6 +16,10 @@ package android.net.nsd; +import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_PLATFORM_MDNS_BACKEND; +import static android.net.connectivity.ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER; + +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -23,8 +27,6 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; import android.app.compat.CompatChanges; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; import android.content.Context; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; @@ -44,6 +46,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; import java.util.concurrent.Executor; @@ -134,28 +138,6 @@ private static final boolean DBG = false; /** - * When enabled, apps targeting < Android 12 are considered legacy for - * the NSD native daemon. - * The platform will only keep the daemon running as long as there are - * any legacy apps connected. - * - * After Android 12, direct communication with the native daemon might not work since the native - * daemon won't always stay alive. Using the NSD APIs from NsdManager as the replacement is - * recommended. - * Another alternative could be bundling your own mdns solutions instead of - * depending on the system mdns native daemon. - * - * This compatibility change applies to Android 13 and later only. To toggle behavior on - * Android 12 and Android 12L, use RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS. - * - * @hide - */ - @ChangeId - @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S) - // This was a platform change ID with value 191844585L before T - public static final long RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER = 235355681L; - - /** * Broadcast intent action to indicate whether network service discovery is * enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state * information as int. @@ -230,7 +212,6 @@ /** @hide */ public static final int DAEMON_CLEANUP = 18; - /** @hide */ public static final int DAEMON_STARTUP = 19; @@ -242,6 +223,30 @@ /** @hide */ public static final int UNREGISTER_CLIENT = 22; + /** @hide */ + public static final int MDNS_DISCOVERY_MANAGER_EVENT = 23; + + /** @hide */ + public static final int STOP_RESOLUTION = 24; + /** @hide */ + public static final int STOP_RESOLUTION_FAILED = 25; + /** @hide */ + public static final int STOP_RESOLUTION_SUCCEEDED = 26; + + /** @hide */ + public static final int REGISTER_SERVICE_CALLBACK = 27; + /** @hide */ + public static final int REGISTER_SERVICE_CALLBACK_FAILED = 28; + /** @hide */ + public static final int SERVICE_UPDATED = 29; + /** @hide */ + public static final int SERVICE_UPDATED_LOST = 30; + + /** @hide */ + public static final int UNREGISTER_SERVICE_CALLBACK = 31; + /** @hide */ + public static final int UNREGISTER_SERVICE_CALLBACK_SUCCEEDED = 32; + /** Dns based service discovery protocol */ public static final int PROTOCOL_DNS_SD = 0x0001; @@ -267,6 +272,18 @@ EVENT_NAMES.put(DAEMON_CLEANUP, "DAEMON_CLEANUP"); EVENT_NAMES.put(DAEMON_STARTUP, "DAEMON_STARTUP"); EVENT_NAMES.put(MDNS_SERVICE_EVENT, "MDNS_SERVICE_EVENT"); + EVENT_NAMES.put(STOP_RESOLUTION, "STOP_RESOLUTION"); + EVENT_NAMES.put(STOP_RESOLUTION_FAILED, "STOP_RESOLUTION_FAILED"); + EVENT_NAMES.put(STOP_RESOLUTION_SUCCEEDED, "STOP_RESOLUTION_SUCCEEDED"); + EVENT_NAMES.put(REGISTER_SERVICE_CALLBACK, "REGISTER_SERVICE_CALLBACK"); + EVENT_NAMES.put(REGISTER_SERVICE_CALLBACK_FAILED, "REGISTER_SERVICE_CALLBACK_FAILED"); + EVENT_NAMES.put(SERVICE_UPDATED, "SERVICE_UPDATED"); + EVENT_NAMES.put(UNREGISTER_SERVICE_CALLBACK, "UNREGISTER_SERVICE_CALLBACK"); + EVENT_NAMES.put(UNREGISTER_SERVICE_CALLBACK_SUCCEEDED, + "UNREGISTER_SERVICE_CALLBACK_SUCCEEDED"); + EVENT_NAMES.put(MDNS_DISCOVERY_MANAGER_EVENT, "MDNS_DISCOVERY_MANAGER_EVENT"); + EVENT_NAMES.put(REGISTER_CLIENT, "REGISTER_CLIENT"); + EVENT_NAMES.put(UNREGISTER_CLIENT, "UNREGISTER_CLIENT"); } /** @hide */ @@ -412,6 +429,10 @@ private final DiscoveryListener mWrapped; private final Executor mWrappedExecutor; private final ArraySet<TrackedNsdInfo> mFoundInfo = new ArraySet<>(); + // When this flag is set to true, no further service found or lost callbacks should be + // handled. This flag indicates that the network for this DelegatingDiscoveryListener is + // lost, and any further callbacks would be redundant. + private boolean mAllServicesLost = false; private DelegatingDiscoveryListener(Network network, DiscoveryListener listener, Executor executor) { @@ -428,6 +449,7 @@ serviceInfo.setNetwork(mNetwork); mWrappedExecutor.execute(() -> mWrapped.onServiceLost(serviceInfo)); } + mAllServicesLost = true; } @Override @@ -469,12 +491,22 @@ @Override public void onServiceFound(NsdServiceInfo serviceInfo) { + if (mAllServicesLost) { + // This DelegatingDiscoveryListener no longer has a network connection. Ignore + // the callback. + return; + } mFoundInfo.add(new TrackedNsdInfo(serviceInfo)); mWrappedExecutor.execute(() -> mWrapped.onServiceFound(serviceInfo)); } @Override public void onServiceLost(NsdServiceInfo serviceInfo) { + if (mAllServicesLost) { + // This DelegatingDiscoveryListener no longer has a network connection. Ignore + // the callback. + return; + } mFoundInfo.remove(new TrackedNsdInfo(serviceInfo)); mWrappedExecutor.execute(() -> mWrapped.onServiceLost(serviceInfo)); } @@ -497,7 +529,8 @@ mHandler = new ServiceHandler(t.getLooper()); try { - mService = service.connect(new NsdCallbackImpl(mHandler)); + mService = service.connect(new NsdCallbackImpl(mHandler), CompatChanges.isChangeEnabled( + ENABLE_PLATFORM_MDNS_BACKEND)); } catch (RemoteException e) { throw new RuntimeException("Failed to connect to NsdService"); } @@ -592,6 +625,36 @@ public void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) { sendInfo(RESOLVE_SERVICE_SUCCEEDED, listenerKey, info); } + + @Override + public void onStopResolutionFailed(int listenerKey, int error) { + sendError(STOP_RESOLUTION_FAILED, listenerKey, error); + } + + @Override + public void onStopResolutionSucceeded(int listenerKey) { + sendNoArg(STOP_RESOLUTION_SUCCEEDED, listenerKey); + } + + @Override + public void onServiceInfoCallbackRegistrationFailed(int listenerKey, int error) { + sendError(REGISTER_SERVICE_CALLBACK_FAILED, listenerKey, error); + } + + @Override + public void onServiceUpdated(int listenerKey, NsdServiceInfo info) { + sendInfo(SERVICE_UPDATED, listenerKey, info); + } + + @Override + public void onServiceUpdatedLost(int listenerKey) { + sendNoArg(SERVICE_UPDATED_LOST, listenerKey); + } + + @Override + public void onServiceInfoCallbackUnregistered(int listenerKey) { + sendNoArg(UNREGISTER_SERVICE_CALLBACK_SUCCEEDED, listenerKey); + } } /** @@ -615,6 +678,37 @@ */ public static final int FAILURE_MAX_LIMIT = 4; + /** + * Indicates that the stop operation failed because it is not running. + * This failure is passed with {@link ResolveListener#onStopResolutionFailed}. + */ + public static final int FAILURE_OPERATION_NOT_RUNNING = 5; + + /** + * Indicates that the service has failed to resolve because of bad parameters. + * + * This failure is passed with + * {@link ServiceInfoCallback#onServiceInfoCallbackRegistrationFailed}. + */ + public static final int FAILURE_BAD_PARAMETERS = 6; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + FAILURE_OPERATION_NOT_RUNNING, + }) + public @interface StopOperationFailureCode { + } + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + FAILURE_ALREADY_ACTIVE, + FAILURE_BAD_PARAMETERS, + }) + public @interface ResolutionFailureCode { + } + /** Interface for callback invocation for service discovery */ public interface DiscoveryListener { @@ -643,12 +737,97 @@ public void onServiceUnregistered(NsdServiceInfo serviceInfo); } - /** Interface for callback invocation for service resolution */ + /** + * Callback for use with {@link NsdManager#resolveService} to resolve the service info and use + * with {@link NsdManager#stopServiceResolution} to stop resolution. + */ public interface ResolveListener { - public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode); + /** + * Called on the internal thread or with an executor passed to + * {@link NsdManager#resolveService} to report the resolution was failed with an error. + * + * A resolution operation would call either onServiceResolved or onResolveFailed once based + * on the result. + */ + void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode); - public void onServiceResolved(NsdServiceInfo serviceInfo); + /** + * Called on the internal thread or with an executor passed to + * {@link NsdManager#resolveService} to report the resolved service info. + * + * A resolution operation would call either onServiceResolved or onResolveFailed once based + * on the result. + */ + void onServiceResolved(NsdServiceInfo serviceInfo); + + /** + * Called on the internal thread or with an executor passed to + * {@link NsdManager#resolveService} to report the resolution was stopped. + * + * A stop resolution operation would call either onResolutionStopped or + * onStopResolutionFailed once based on the result. + */ + default void onResolutionStopped(@NonNull NsdServiceInfo serviceInfo) { } + + /** + * Called once on the internal thread or with an executor passed to + * {@link NsdManager#resolveService} to report that stopping resolution failed with an + * error. + * + * A stop resolution operation would call either onResolutionStopped or + * onStopResolutionFailed once based on the result. + */ + default void onStopResolutionFailed(@NonNull NsdServiceInfo serviceInfo, + @StopOperationFailureCode int errorCode) { } + } + + /** + * Callback to listen to service info updates. + * + * For use with {@link NsdManager#registerServiceInfoCallback} to register, and with + * {@link NsdManager#unregisterServiceInfoCallback} to stop listening. + */ + public interface ServiceInfoCallback { + + /** + * Reports that registering the callback failed with an error. + * + * Called on the executor passed to {@link NsdManager#registerServiceInfoCallback}. + * + * onServiceInfoCallbackRegistrationFailed will be called exactly once when the callback + * could not be registered. No other callback will be sent in that case. + */ + void onServiceInfoCallbackRegistrationFailed(@ResolutionFailureCode int errorCode); + + /** + * Reports updated service info. + * + * Called on the executor passed to {@link NsdManager#registerServiceInfoCallback}. Any + * service updates will be notified via this callback until + * {@link NsdManager#unregisterServiceInfoCallback} is called. This will only be called once + * the service is found, so may never be called if the service is never present. + */ + void onServiceUpdated(@NonNull NsdServiceInfo serviceInfo); + + /** + * Reports when the service that this callback listens to becomes unavailable. + * + * Called on the executor passed to {@link NsdManager#registerServiceInfoCallback}. The + * service may become available again, in which case {@link #onServiceUpdated} will be + * called. + */ + void onServiceLost(); + + /** + * Reports that service info updates have stopped. + * + * Called on the executor passed to {@link NsdManager#registerServiceInfoCallback}. + * + * A callback unregistration operation will call onServiceInfoCallbackUnregistered + * once. After this, the callback may be reused. + */ + void onServiceInfoCallbackUnregistered(); } @VisibleForTesting @@ -741,6 +920,33 @@ executor.execute(() -> ((ResolveListener) listener).onServiceResolved( (NsdServiceInfo) obj)); break; + case STOP_RESOLUTION_FAILED: + removeListener(key); + executor.execute(() -> ((ResolveListener) listener).onStopResolutionFailed( + ns, errorCode)); + break; + case STOP_RESOLUTION_SUCCEEDED: + removeListener(key); + executor.execute(() -> ((ResolveListener) listener).onResolutionStopped( + ns)); + break; + case REGISTER_SERVICE_CALLBACK_FAILED: + removeListener(key); + executor.execute(() -> ((ServiceInfoCallback) listener) + .onServiceInfoCallbackRegistrationFailed(errorCode)); + break; + case SERVICE_UPDATED: + executor.execute(() -> ((ServiceInfoCallback) listener) + .onServiceUpdated((NsdServiceInfo) obj)); + break; + case SERVICE_UPDATED_LOST: + executor.execute(() -> ((ServiceInfoCallback) listener).onServiceLost()); + break; + case UNREGISTER_SERVICE_CALLBACK_SUCCEEDED: + removeListener(key); + executor.execute(() -> ((ServiceInfoCallback) listener) + .onServiceInfoCallbackUnregistered()); + break; default: Log.d(TAG, "Ignored " + message); break; @@ -1052,7 +1258,14 @@ * @param serviceInfo service to be resolved * @param listener to receive callback upon success or failure. Cannot be null. * Cannot be in use for an active service resolution. + * + * @deprecated the returned ServiceInfo may get stale at any time after resolution, including + * immediately after the callback is called, and may not contain some service information that + * could be delivered later, like additional host addresses. Prefer using + * {@link #registerServiceInfoCallback}, which will keep the application up-to-date with the + * state of the service. */ + @Deprecated public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { resolveService(serviceInfo, Runnable::run, listener); } @@ -1064,7 +1277,14 @@ * @param serviceInfo service to be resolved * @param executor Executor to run listener callbacks with * @param listener to receive callback upon success or failure. + * + * @deprecated the returned ServiceInfo may get stale at any time after resolution, including + * immediately after the callback is called, and may not contain some service information that + * could be delivered later, like additional host addresses. Prefer using + * {@link #registerServiceInfoCallback}, which will keep the application up-to-date with the + * state of the service. */ + @Deprecated public void resolveService(@NonNull NsdServiceInfo serviceInfo, @NonNull Executor executor, @NonNull ResolveListener listener) { checkServiceInfo(serviceInfo); @@ -1076,6 +1296,85 @@ } } + /** + * Stop service resolution initiated with {@link #resolveService}. + * + * A successful stop is notified with a call to {@link ResolveListener#onResolutionStopped}. + * + * <p> Upon failure to stop service resolution for example if resolution is done or the + * requester stops resolution repeatedly, the application is notified + * {@link ResolveListener#onStopResolutionFailed} with {@link #FAILURE_OPERATION_NOT_RUNNING} + * + * @param listener This should be a listener object that was passed to {@link #resolveService}. + * It identifies the resolution that should be stopped and notifies of a + * successful or unsuccessful stop. Throws {@code IllegalArgumentException} if + * the listener was not passed to resolveService before. + */ + public void stopServiceResolution(@NonNull ResolveListener listener) { + int id = getListenerKey(listener); + try { + mService.stopResolution(id); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Register a callback to listen for updates to a service. + * + * An application can listen to a service to continuously monitor availability of given service. + * The callback methods will be called on the passed executor. And service updates are sent with + * continuous calls to {@link ServiceInfoCallback#onServiceUpdated}. + * + * This is different from {@link #resolveService} which provides one shot service information. + * + * <p> An application can listen to a service once a time. It needs to cancel the registration + * before registering other callbacks. Upon failure to register a callback for example if + * it's a duplicated registration, the application is notified through + * {@link ServiceInfoCallback#onServiceInfoCallbackRegistrationFailed} with + * {@link #FAILURE_BAD_PARAMETERS}. + * + * @param serviceInfo the service to receive updates for + * @param executor Executor to run callbacks with + * @param listener to receive callback upon service update + */ + public void registerServiceInfoCallback(@NonNull NsdServiceInfo serviceInfo, + @NonNull Executor executor, @NonNull ServiceInfoCallback listener) { + checkServiceInfo(serviceInfo); + int key = putListener(listener, executor, serviceInfo); + try { + mService.registerServiceInfoCallback(key, serviceInfo); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Unregister a callback registered with {@link #registerServiceInfoCallback}. + * + * A successful unregistration is notified with a call to + * {@link ServiceInfoCallback#onServiceInfoCallbackUnregistered}. The same callback can only be + * reused after this is called. + * + * <p>If the callback is not already registered, this will throw with + * {@link IllegalArgumentException}. + * + * @param listener This should be a listener object that was passed to + * {@link #registerServiceInfoCallback}. It identifies the registration that + * should be unregistered and notifies of a successful or unsuccessful stop. + * Throws {@code IllegalArgumentException} if the listener was not passed to + * {@link #registerServiceInfoCallback} before. + */ + public void unregisterServiceInfoCallback(@NonNull ServiceInfoCallback listener) { + // Will throw IllegalArgumentException if the listener is not known + int id = getListenerKey(listener); + try { + mService.unregisterServiceInfoCallback(id); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + private static void checkListener(Object listener) { Objects.requireNonNull(listener, "listener cannot be null"); }
diff --git a/framework-t/src/android/net/nsd/NsdServiceInfo.java b/framework-t/src/android/net/nsd/NsdServiceInfo.java index 6438a60..caeecdd 100644 --- a/framework-t/src/android/net/nsd/NsdServiceInfo.java +++ b/framework-t/src/android/net/nsd/NsdServiceInfo.java
@@ -26,10 +26,14 @@ import android.util.ArrayMap; import android.util.Log; +import com.android.net.module.util.InetAddressUtils; + import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Map; /** @@ -46,7 +50,7 @@ private final ArrayMap<String, byte[]> mTxtRecord = new ArrayMap<>(); - private InetAddress mHost; + private final List<InetAddress> mHostAddresses = new ArrayList<>(); private int mPort; @@ -84,17 +88,32 @@ mServiceType = s; } - /** Get the host address. The host address is valid for a resolved service. */ + /** + * Get the host address. The host address is valid for a resolved service. + * + * @deprecated Use {@link #getHostAddresses()} to get the entire list of addresses for the host. + */ + @Deprecated public InetAddress getHost() { - return mHost; + return mHostAddresses.size() == 0 ? null : mHostAddresses.get(0); } - /** Set the host address */ + /** + * Set the host address + * + * @deprecated Use {@link #setHostAddresses(List)} to set multiple addresses for the host. + */ + @Deprecated public void setHost(InetAddress s) { - mHost = s; + setHostAddresses(Collections.singletonList(s)); } - /** Get port number. The port number is valid for a resolved service. */ + /** + * Get port number. The port number is valid for a resolved service. + * + * The port is valid for all addresses. + * @see #getHostAddresses() + */ public int getPort() { return mPort; } @@ -105,6 +124,24 @@ } /** + * Get the host addresses. + * + * All host addresses are valid for the resolved service. + * All addresses share the same port + * @see #getPort() + */ + @NonNull + public List<InetAddress> getHostAddresses() { + return new ArrayList<>(mHostAddresses); + } + + /** Set the host addresses */ + public void setHostAddresses(@NonNull List<InetAddress> addresses) { + mHostAddresses.clear(); + mHostAddresses.addAll(addresses); + } + + /** * Unpack txt information from a base-64 encoded byte array. * * @param txtRecordsRawBytes The raw base64 encoded byte array. @@ -359,7 +396,7 @@ StringBuilder sb = new StringBuilder(); sb.append("name: ").append(mServiceName) .append(", type: ").append(mServiceType) - .append(", host: ").append(mHost) + .append(", hostAddresses: ").append(TextUtils.join(", ", mHostAddresses)) .append(", port: ").append(mPort) .append(", network: ").append(mNetwork); @@ -377,12 +414,6 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeString(mServiceName); dest.writeString(mServiceType); - if (mHost != null) { - dest.writeInt(1); - dest.writeByteArray(mHost.getAddress()); - } else { - dest.writeInt(0); - } dest.writeInt(mPort); // TXT record key/value pairs. @@ -401,6 +432,10 @@ dest.writeParcelable(mNetwork, 0); dest.writeInt(mInterfaceIndex); + dest.writeInt(mHostAddresses.size()); + for (InetAddress address : mHostAddresses) { + InetAddressUtils.parcelInetAddress(dest, address, flags); + } } /** Implement the Parcelable interface */ @@ -410,13 +445,6 @@ NsdServiceInfo info = new NsdServiceInfo(); info.mServiceName = in.readString(); info.mServiceType = in.readString(); - - if (in.readInt() == 1) { - try { - info.mHost = InetAddress.getByAddress(in.createByteArray()); - } catch (java.net.UnknownHostException e) {} - } - info.mPort = in.readInt(); // TXT record key/value pairs. @@ -432,6 +460,10 @@ } info.mNetwork = in.readParcelable(null, Network.class); info.mInterfaceIndex = in.readInt(); + int size = in.readInt(); + for (int i = 0; i < size; i++) { + info.mHostAddresses.add(InetAddressUtils.unparcelInetAddress(in)); + } return info; }
diff --git a/framework/Android.bp b/framework/Android.bp index 485961c..123f02a 100644 --- a/framework/Android.bp +++ b/framework/Android.bp
@@ -45,14 +45,12 @@ // TODO: use a java_library in the bootclasspath instead filegroup { name: "framework-connectivity-sources", + defaults: ["framework-sources-module-defaults"], srcs: [ ":framework-connectivity-internal-sources", ":framework-connectivity-aidl-export-sources", ], - visibility: [ - "//frameworks/base", - "//packages/modules/Connectivity:__subpackages__", - ], + visibility: ["//packages/modules/Connectivity:__subpackages__"], } java_defaults { @@ -80,7 +78,9 @@ "framework-connectivity-t.stubs.module_lib", ], impl_only_libs: [ - "framework-tethering.stubs.module_lib", + // TODO: figure out why just using "framework-tethering" uses the stubs, even though both + // framework-connectivity and framework-tethering are in the same APEX. + "framework-tethering.impl", "framework-wifi.stubs.module_lib", "net-utils-device-common", ], @@ -105,21 +105,41 @@ java_library { name: "framework-connectivity-pre-jarjar", - defaults: ["framework-connectivity-defaults"], + defaults: [ + "framework-connectivity-defaults", + ], + static_libs: [ + "cronet_aml_api_java", + "cronet_aml_java", + ], libs: [ // This cannot be in the defaults clause above because if it were, it would be used // to generate the connectivity stubs. That would create a circular dependency - // because the tethering stubs depend on the connectivity stubs (e.g., + // because the tethering impl depend on the connectivity stubs (e.g., // TetheringRequest depends on LinkAddress). - "framework-tethering.stubs.module_lib", + "framework-tethering.impl", "framework-wifi.stubs.module_lib", ], visibility: ["//packages/modules/Connectivity:__subpackages__"] } +java_defaults { + name: "CronetJavaDefaults", + srcs: [":cronet_aml_api_sources"], + libs: [ + "androidx.annotation_annotation", + ], + impl_only_static_libs: [ + "cronet_aml_java", + ], +} + java_sdk_library { name: "framework-connectivity", - defaults: ["framework-connectivity-defaults"], + defaults: [ + "framework-connectivity-defaults", + "CronetJavaDefaults", + ], installable: true, jarjar_rules: ":framework-connectivity-jarjar-rules", permitted_packages: ["android.net"], @@ -147,6 +167,7 @@ "//frameworks/opt/net/ethernet/tests:__subpackages__", "//frameworks/opt/telephony/tests/telephonytests", "//packages/modules/CaptivePortalLogin/tests", + "//packages/modules/Connectivity/Cronet/tests:__subpackages__", "//packages/modules/Connectivity/Tethering/tests:__subpackages__", "//packages/modules/Connectivity/tests:__subpackages__", "//packages/modules/IPsec/tests/iketests", @@ -183,6 +204,7 @@ "libnativehelper", ], header_libs: [ + "bpf_headers", "dnsproxyd_protocol_headers", ], stl: "none", @@ -243,3 +265,24 @@ "//packages/modules/Connectivity/service", ], } + +// Library providing limited APIs within the connectivity module, so that R+ components like +// Tethering have a controlled way to depend on newer components like framework-connectivity that +// are not loaded on R. +java_library { + name: "connectivity-internal-api-util", + sdk_version: "module_current", + libs: [ + "androidx.annotation_annotation", + "framework-connectivity.impl", + ], + jarjar_rules: ":framework-connectivity-jarjar-rules", + srcs: [ + // Files listed here MUST all be annotated with @RequiresApi(Build.VERSION_CODES.TIRAMISU), + // so that API checks are enforced for R+ users of this library + "src/android/net/connectivity/TiramisuConnectivityInternalApiUtil.java", + ], + visibility: [ + "//packages/modules/Connectivity/Tethering:__subpackages__", + ], +}
diff --git a/framework/api/current.txt b/framework/api/current.txt index 547b7e2..6860c3c 100644 --- a/framework/api/current.txt +++ b/framework/api/current.txt
@@ -360,6 +360,7 @@ field public static final int TRANSPORT_CELLULAR = 0; // 0x0 field public static final int TRANSPORT_ETHERNET = 3; // 0x3 field public static final int TRANSPORT_LOWPAN = 6; // 0x6 + field public static final int TRANSPORT_THREAD = 9; // 0x9 field public static final int TRANSPORT_USB = 8; // 0x8 field public static final int TRANSPORT_VPN = 4; // 0x4 field public static final int TRANSPORT_WIFI = 1; // 0x1 @@ -524,3 +525,292 @@ } +package android.net.http { + + public abstract class BidirectionalStream { + ctor public BidirectionalStream(); + method public abstract void cancel(); + method public abstract void flush(); + method @NonNull public abstract android.net.http.HeaderBlock getHeaders(); + method @NonNull public abstract String getHttpMethod(); + method public abstract int getPriority(); + method public abstract int getTrafficStatsTag(); + method public abstract int getTrafficStatsUid(); + method public abstract boolean hasTrafficStatsTag(); + method public abstract boolean hasTrafficStatsUid(); + method public abstract boolean isDelayRequestHeadersUntilFirstFlushEnabled(); + method public abstract boolean isDone(); + method public abstract void read(@NonNull java.nio.ByteBuffer); + method public abstract void start(); + method public abstract void write(@NonNull java.nio.ByteBuffer, boolean); + field public static final int STREAM_PRIORITY_HIGHEST = 4; // 0x4 + field public static final int STREAM_PRIORITY_IDLE = 0; // 0x0 + field public static final int STREAM_PRIORITY_LOW = 2; // 0x2 + field public static final int STREAM_PRIORITY_LOWEST = 1; // 0x1 + field public static final int STREAM_PRIORITY_MEDIUM = 3; // 0x3 + } + + public abstract static class BidirectionalStream.Builder { + ctor public BidirectionalStream.Builder(); + method @NonNull public abstract android.net.http.BidirectionalStream.Builder addHeader(@NonNull String, @NonNull String); + method @NonNull public abstract android.net.http.BidirectionalStream build(); + method @NonNull public abstract android.net.http.BidirectionalStream.Builder setDelayRequestHeadersUntilFirstFlushEnabled(boolean); + method @NonNull public abstract android.net.http.BidirectionalStream.Builder setHttpMethod(@NonNull String); + method @NonNull public abstract android.net.http.BidirectionalStream.Builder setPriority(int); + method @NonNull public abstract android.net.http.BidirectionalStream.Builder setTrafficStatsTag(int); + method @NonNull public abstract android.net.http.BidirectionalStream.Builder setTrafficStatsUid(int); + } + + public static interface BidirectionalStream.Callback { + method public void onCanceled(@NonNull android.net.http.BidirectionalStream, @Nullable android.net.http.UrlResponseInfo); + method public void onFailed(@NonNull android.net.http.BidirectionalStream, @Nullable android.net.http.UrlResponseInfo, @NonNull android.net.http.HttpException); + method public void onReadCompleted(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer, boolean); + method public void onResponseHeadersReceived(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo); + method public void onResponseTrailersReceived(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull android.net.http.HeaderBlock); + method public void onStreamReady(@NonNull android.net.http.BidirectionalStream); + method public void onSucceeded(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo); + method public void onWriteCompleted(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer, boolean); + } + + public abstract class CallbackException extends android.net.http.HttpException { + ctor protected CallbackException(@Nullable String, @Nullable Throwable); + } + + public class ConnectionMigrationOptions { + method public int getAllowNonDefaultNetworkUsage(); + method public int getDefaultNetworkMigration(); + method public int getPathDegradationMigration(); + field public static final int MIGRATION_OPTION_DISABLED = 2; // 0x2 + field public static final int MIGRATION_OPTION_ENABLED = 1; // 0x1 + field public static final int MIGRATION_OPTION_UNSPECIFIED = 0; // 0x0 + } + + public static final class ConnectionMigrationOptions.Builder { + ctor public ConnectionMigrationOptions.Builder(); + method @NonNull public android.net.http.ConnectionMigrationOptions build(); + method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setAllowNonDefaultNetworkUsage(int); + method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setDefaultNetworkMigration(int); + method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setPathDegradationMigration(int); + } + + public final class DnsOptions { + method public int getPersistHostCache(); + method @Nullable public java.time.Duration getPersistHostCachePeriod(); + method public int getPreestablishConnectionsToStaleDnsResults(); + method public int getStaleDns(); + method @Nullable public android.net.http.DnsOptions.StaleDnsOptions getStaleDnsOptions(); + method public int getUseHttpStackDnsResolver(); + field public static final int DNS_OPTION_DISABLED = 2; // 0x2 + field public static final int DNS_OPTION_ENABLED = 1; // 0x1 + field public static final int DNS_OPTION_UNSPECIFIED = 0; // 0x0 + } + + public static final class DnsOptions.Builder { + ctor public DnsOptions.Builder(); + method @NonNull public android.net.http.DnsOptions build(); + method @NonNull public android.net.http.DnsOptions.Builder setPersistHostCache(int); + method @NonNull public android.net.http.DnsOptions.Builder setPersistHostCachePeriod(@NonNull java.time.Duration); + method @NonNull public android.net.http.DnsOptions.Builder setPreestablishConnectionsToStaleDnsResults(int); + method @NonNull public android.net.http.DnsOptions.Builder setStaleDns(int); + method @NonNull public android.net.http.DnsOptions.Builder setStaleDnsOptions(@NonNull android.net.http.DnsOptions.StaleDnsOptions); + method @NonNull public android.net.http.DnsOptions.Builder setUseHttpStackDnsResolver(int); + } + + public static class DnsOptions.StaleDnsOptions { + method public int getAllowCrossNetworkUsage(); + method @Nullable public java.time.Duration getFreshLookupTimeout(); + method @Nullable public java.time.Duration getMaxExpiredDelay(); + method public int getUseStaleOnNameNotResolved(); + } + + public static final class DnsOptions.StaleDnsOptions.Builder { + ctor public DnsOptions.StaleDnsOptions.Builder(); + method @NonNull public android.net.http.DnsOptions.StaleDnsOptions build(); + method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setAllowCrossNetworkUsage(int); + method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setFreshLookupTimeout(@NonNull java.time.Duration); + method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setMaxExpiredDelay(@NonNull java.time.Duration); + method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setUseStaleOnNameNotResolved(int); + } + + public abstract class HeaderBlock { + ctor public HeaderBlock(); + method @NonNull public abstract java.util.List<java.util.Map.Entry<java.lang.String,java.lang.String>> getAsList(); + method @NonNull public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> getAsMap(); + } + + public abstract class HttpEngine { + method public void bindToNetwork(@Nullable android.net.Network); + method @NonNull public abstract java.net.URLStreamHandlerFactory createUrlStreamHandlerFactory(); + method @NonNull public static String getVersionString(); + method @NonNull public abstract android.net.http.BidirectionalStream.Builder newBidirectionalStreamBuilder(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.http.BidirectionalStream.Callback); + method @NonNull public abstract android.net.http.UrlRequest.Builder newUrlRequestBuilder(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.http.UrlRequest.Callback); + method @NonNull public abstract java.net.URLConnection openConnection(@NonNull java.net.URL) throws java.io.IOException; + method public abstract void shutdown(); + } + + public static class HttpEngine.Builder { + ctor public HttpEngine.Builder(@NonNull android.content.Context); + method @NonNull public android.net.http.HttpEngine.Builder addPublicKeyPins(@NonNull String, @NonNull java.util.Set<byte[]>, boolean, @NonNull java.time.Instant); + method @NonNull public android.net.http.HttpEngine.Builder addQuicHint(@NonNull String, int, int); + method @NonNull public android.net.http.HttpEngine build(); + method @NonNull public String getDefaultUserAgent(); + method @NonNull public android.net.http.HttpEngine.Builder setConnectionMigrationOptions(@NonNull android.net.http.ConnectionMigrationOptions); + method @NonNull public android.net.http.HttpEngine.Builder setDnsOptions(@NonNull android.net.http.DnsOptions); + method @NonNull public android.net.http.HttpEngine.Builder setEnableBrotli(boolean); + method @NonNull public android.net.http.HttpEngine.Builder setEnableHttp2(boolean); + method @NonNull public android.net.http.HttpEngine.Builder setEnableHttpCache(int, long); + method @NonNull public android.net.http.HttpEngine.Builder setEnablePublicKeyPinningBypassForLocalTrustAnchors(boolean); + method @NonNull public android.net.http.HttpEngine.Builder setEnableQuic(boolean); + method @NonNull public android.net.http.HttpEngine.Builder setQuicOptions(@NonNull android.net.http.QuicOptions); + method @NonNull public android.net.http.HttpEngine.Builder setStoragePath(@NonNull String); + method @NonNull public android.net.http.HttpEngine.Builder setUserAgent(@NonNull String); + field public static final int HTTP_CACHE_DISABLED = 0; // 0x0 + field public static final int HTTP_CACHE_DISK = 3; // 0x3 + field public static final int HTTP_CACHE_DISK_NO_HTTP = 2; // 0x2 + field public static final int HTTP_CACHE_IN_MEMORY = 1; // 0x1 + } + + public class HttpException extends java.io.IOException { + ctor public HttpException(@Nullable String, @Nullable Throwable); + } + + public final class InlineExecutionProhibitedException extends java.util.concurrent.RejectedExecutionException { + ctor public InlineExecutionProhibitedException(); + } + + public abstract class NetworkException extends android.net.http.HttpException { + ctor public NetworkException(@Nullable String, @Nullable Throwable); + method public abstract int getErrorCode(); + method public abstract boolean isImmediatelyRetryable(); + field public static final int ERROR_ADDRESS_UNREACHABLE = 9; // 0x9 + 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 android.net.http.NetworkException { + ctor protected QuicException(@Nullable String, @Nullable Throwable); + } + + public class QuicOptions { + method @NonNull public java.util.Set<java.lang.String> getAllowedQuicHosts(); + method @Nullable public String getHandshakeUserAgent(); + method @Nullable public java.time.Duration getIdleConnectionTimeout(); + method public int getInMemoryServerConfigsCacheSize(); + method public boolean hasInMemoryServerConfigsCacheSize(); + } + + public static final class QuicOptions.Builder { + ctor public QuicOptions.Builder(); + method @NonNull public android.net.http.QuicOptions.Builder addAllowedQuicHost(@NonNull String); + method @NonNull public android.net.http.QuicOptions build(); + method @NonNull public android.net.http.QuicOptions.Builder setHandshakeUserAgent(@NonNull String); + method @NonNull public android.net.http.QuicOptions.Builder setIdleConnectionTimeout(@NonNull java.time.Duration); + method @NonNull public android.net.http.QuicOptions.Builder setInMemoryServerConfigsCacheSize(int); + } + + public abstract class UploadDataProvider implements java.io.Closeable { + ctor public UploadDataProvider(); + method public void close() throws java.io.IOException; + method public abstract long getLength() throws java.io.IOException; + method public abstract void read(@NonNull android.net.http.UploadDataSink, @NonNull java.nio.ByteBuffer) throws java.io.IOException; + method public abstract void rewind(@NonNull android.net.http.UploadDataSink) throws java.io.IOException; + } + + public abstract class UploadDataSink { + ctor public UploadDataSink(); + method public abstract void onReadError(@NonNull Exception); + method public abstract void onReadSucceeded(boolean); + method public abstract void onRewindError(@NonNull Exception); + method public abstract void onRewindSucceeded(); + } + + public abstract class UrlRequest { + method public abstract void cancel(); + method public abstract void followRedirect(); + method @NonNull public abstract android.net.http.HeaderBlock getHeaders(); + method @Nullable public abstract String getHttpMethod(); + method public abstract int getPriority(); + method public abstract void getStatus(@NonNull android.net.http.UrlRequest.StatusListener); + method public abstract int getTrafficStatsTag(); + method public abstract int getTrafficStatsUid(); + method public abstract boolean hasTrafficStatsTag(); + method public abstract boolean hasTrafficStatsUid(); + method public abstract boolean isCacheDisabled(); + method public abstract boolean isDirectExecutorAllowed(); + method public abstract boolean isDone(); + method public abstract void read(@NonNull java.nio.ByteBuffer); + method public abstract void start(); + 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.Builder { + method @NonNull public abstract android.net.http.UrlRequest.Builder addHeader(@NonNull String, @NonNull String); + method @NonNull public abstract android.net.http.UrlRequest.Builder bindToNetwork(@Nullable android.net.Network); + method @NonNull public abstract android.net.http.UrlRequest build(); + method @NonNull public abstract android.net.http.UrlRequest.Builder setCacheDisabled(boolean); + method @NonNull public abstract android.net.http.UrlRequest.Builder setDirectExecutorAllowed(boolean); + method @NonNull public abstract android.net.http.UrlRequest.Builder setHttpMethod(@NonNull String); + method @NonNull public abstract android.net.http.UrlRequest.Builder setPriority(int); + method @NonNull public abstract android.net.http.UrlRequest.Builder setTrafficStatsTag(int); + method @NonNull public abstract android.net.http.UrlRequest.Builder setTrafficStatsUid(int); + method @NonNull public abstract android.net.http.UrlRequest.Builder setUploadDataProvider(@NonNull android.net.http.UploadDataProvider, @NonNull java.util.concurrent.Executor); + } + + public static interface UrlRequest.Callback { + method public void onCanceled(@NonNull android.net.http.UrlRequest, @Nullable android.net.http.UrlResponseInfo); + method public void onFailed(@NonNull android.net.http.UrlRequest, @Nullable android.net.http.UrlResponseInfo, @NonNull android.net.http.HttpException); + method public void onReadCompleted(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer) throws java.lang.Exception; + method public void onRedirectReceived(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo, @NonNull String) throws java.lang.Exception; + method public void onResponseStarted(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo) throws java.lang.Exception; + method public void onSucceeded(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.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 static interface UrlRequest.StatusListener { + method public void onStatus(int); + } + + public abstract class UrlResponseInfo { + ctor public UrlResponseInfo(); + method @NonNull public abstract android.net.http.HeaderBlock getHeaders(); + method public abstract int getHttpStatusCode(); + method @NonNull public abstract String getHttpStatusText(); + method @NonNull public abstract String getNegotiatedProtocol(); + method public abstract long getReceivedByteCount(); + method @NonNull public abstract String getUrl(); + method @NonNull public abstract java.util.List<java.lang.String> getUrlChain(); + method public abstract boolean wasCached(); + } + +} +
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt index 752c347..193bd92 100644 --- a/framework/api/module-lib-current.txt +++ b/framework/api/module-lib-current.txt
@@ -15,7 +15,7 @@ method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.LinkProperties getRedactedLinkPropertiesForPackage(@NonNull android.net.LinkProperties, int, @NonNull String); method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.NetworkCapabilities getRedactedNetworkCapabilitiesForPackage(@NonNull android.net.NetworkCapabilities, int, @NonNull String); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkAllowList(int); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkDenyList(int); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void replaceFirewallChain(int, @NonNull int[]); @@ -31,6 +31,7 @@ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreferences(@NonNull android.os.UserHandle, @NonNull java.util.List<android.net.ProfileNetworkPreference>, @Nullable java.util.concurrent.Executor, @Nullable Runnable); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setUidFirewallRule(int, int, int); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setVpnDefaultForUids(@NonNull String, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network); method public void systemReady(); @@ -62,6 +63,7 @@ field public static final int FIREWALL_RULE_DENY = 2; // 0x2 field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0 field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1 + field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING = 3; // 0x3 field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK = 2; // 0x2 }
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt index c7872a0..4a2ed8a 100644 --- a/framework/api/system-current.txt +++ b/framework/api/system-current.txt
@@ -470,7 +470,9 @@ } public abstract class SocketKeepalive implements java.lang.AutoCloseable { + method public final void start(@IntRange(from=0xa, to=0xe10) int, int, @Nullable android.net.Network); field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf + field public static final int FLAG_AUTOMATIC_ON_OFF = 1; // 0x1 field public static final int SUCCESS = 0; // 0x0 } @@ -512,10 +514,11 @@ } public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo { - ctor public VpnTransportInfo(int, @Nullable String, boolean); + ctor public VpnTransportInfo(int, @Nullable String, boolean, boolean); + method public boolean areLongLivedTcpConnectionsExpensive(); method public int describeContents(); - method public boolean getBypassable(); method public int getType(); + method public boolean isBypassable(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR; }
diff --git a/framework/cronet_disabled/api/current.txt b/framework/cronet_disabled/api/current.txt new file mode 100644 index 0000000..672e3e2 --- /dev/null +++ b/framework/cronet_disabled/api/current.txt
@@ -0,0 +1,527 @@ +// Signature format: 2.0 +package android.net { + + public class CaptivePortal implements android.os.Parcelable { + method public int describeContents(); + method public void ignoreNetwork(); + method public void reportCaptivePortalDismissed(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR; + } + + public class ConnectivityDiagnosticsManager { + method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback); + method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback); + } + + public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback { + ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback(); + method public void onConnectivityReportAvailable(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport); + method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport); + method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean); + } + + public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable { + ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle); + method public int describeContents(); + method @NonNull public android.os.PersistableBundle getAdditionalInfo(); + method @NonNull public android.net.LinkProperties getLinkProperties(); + method @NonNull public android.net.Network getNetwork(); + method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); + method public long getReportTimestamp(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR; + field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted"; + field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded"; + field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult"; + field public static final int NETWORK_PROBE_DNS = 4; // 0x4 + field public static final int NETWORK_PROBE_FALLBACK = 32; // 0x20 + field public static final int NETWORK_PROBE_HTTP = 8; // 0x8 + field public static final int NETWORK_PROBE_HTTPS = 16; // 0x10 + field public static final int NETWORK_PROBE_PRIVATE_DNS = 64; // 0x40 + field public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; // 0x0 + field public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; // 0x2 + field public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; // 0x3 + field public static final int NETWORK_VALIDATION_RESULT_VALID = 1; // 0x1 + } + + public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable { + ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle); + method public int describeContents(); + method public int getDetectionMethod(); + method @NonNull public android.net.LinkProperties getLinkProperties(); + method @NonNull public android.net.Network getNetwork(); + method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); + method public long getReportTimestamp(); + method @NonNull public android.os.PersistableBundle getStallDetails(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR; + field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1 + field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2 + field public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts"; + field public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = "tcpMetricsCollectionPeriodMillis"; + field public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate"; + } + + public class ConnectivityManager { + method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); + method public boolean bindProcessToNetwork(@Nullable android.net.Network); + method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback); + method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork(); + method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo(); + method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo(); + method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks(); + method @Deprecated public boolean getBackgroundDataSetting(); + method @Nullable public android.net.Network getBoundNetworkForProcess(); + method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress); + method @Nullable public android.net.ProxyInfo getDefaultProxy(); + method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network); + method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network); + method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int); + method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network); + method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference(); + method @Nullable public byte[] getNetworkWatchlistConfigHash(); + method @Deprecated @Nullable public static android.net.Network getProcessDefaultNetwork(); + method public int getRestrictBackgroundStatus(); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered(); + method public boolean isDefaultNetworkActive(); + method @Deprecated public static boolean isNetworkTypeValid(int); + method public void registerBestMatchingNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); + method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent); + method public void releaseNetworkRequest(@NonNull android.app.PendingIntent); + method public void removeDefaultNetworkActiveListener(@NonNull android.net.ConnectivityManager.OnNetworkActiveListener); + method @Deprecated public void reportBadNetwork(@Nullable android.net.Network); + method public void reportNetworkConnectivity(@Nullable android.net.Network, boolean); + method public boolean requestBandwidthUpdate(@NonNull android.net.Network); + method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback); + method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); + method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int); + method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler, int); + method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent); + method @Deprecated public void setNetworkPreference(int); + method @Deprecated public static boolean setProcessDefaultNetwork(@Nullable android.net.Network); + method public void unregisterNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback); + method public void unregisterNetworkCallback(@NonNull android.app.PendingIntent); + field @Deprecated public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; + field public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL"; + field public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED"; + field @Deprecated public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; + field @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1 + field public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL"; + field public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; + field @Deprecated public static final String EXTRA_EXTRA_INFO = "extraInfo"; + field @Deprecated public static final String EXTRA_IS_FAILOVER = "isFailover"; + field public static final String EXTRA_NETWORK = "android.net.extra.NETWORK"; + field @Deprecated public static final String EXTRA_NETWORK_INFO = "networkInfo"; + field public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST"; + field @Deprecated public static final String EXTRA_NETWORK_TYPE = "networkType"; + field public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity"; + field @Deprecated public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork"; + field public static final String EXTRA_REASON = "reason"; + field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1 + field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4 + field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2 + field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1 + field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3 + field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2 + field @Deprecated public static final int TYPE_BLUETOOTH = 7; // 0x7 + field @Deprecated public static final int TYPE_DUMMY = 8; // 0x8 + field @Deprecated public static final int TYPE_ETHERNET = 9; // 0x9 + field @Deprecated public static final int TYPE_MOBILE = 0; // 0x0 + field @Deprecated public static final int TYPE_MOBILE_DUN = 4; // 0x4 + field @Deprecated public static final int TYPE_MOBILE_HIPRI = 5; // 0x5 + field @Deprecated public static final int TYPE_MOBILE_MMS = 2; // 0x2 + field @Deprecated public static final int TYPE_MOBILE_SUPL = 3; // 0x3 + field @Deprecated public static final int TYPE_VPN = 17; // 0x11 + field @Deprecated public static final int TYPE_WIFI = 1; // 0x1 + field @Deprecated public static final int TYPE_WIMAX = 6; // 0x6 + } + + public static class ConnectivityManager.NetworkCallback { + ctor public ConnectivityManager.NetworkCallback(); + ctor public ConnectivityManager.NetworkCallback(int); + method public void onAvailable(@NonNull android.net.Network); + method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean); + method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities); + method public void onLinkPropertiesChanged(@NonNull android.net.Network, @NonNull android.net.LinkProperties); + method public void onLosing(@NonNull android.net.Network, int); + method public void onLost(@NonNull android.net.Network); + method public void onUnavailable(); + field public static final int FLAG_INCLUDE_LOCATION_INFO = 1; // 0x1 + } + + public static interface ConnectivityManager.OnNetworkActiveListener { + method public void onNetworkActive(); + } + + public class DhcpInfo implements android.os.Parcelable { + ctor public DhcpInfo(); + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpInfo> CREATOR; + field public int dns1; + field public int dns2; + field public int gateway; + field public int ipAddress; + field public int leaseDuration; + field public int netmask; + field public int serverAddress; + } + + public final class DnsResolver { + method @NonNull public static android.net.DnsResolver getInstance(); + method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>); + method public void query(@Nullable android.net.Network, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>); + method public void rawQuery(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>); + method public void rawQuery(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>); + field public static final int CLASS_IN = 1; // 0x1 + field public static final int ERROR_PARSE = 0; // 0x0 + field public static final int ERROR_SYSTEM = 1; // 0x1 + field public static final int FLAG_EMPTY = 0; // 0x0 + field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4 + field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2 + field public static final int FLAG_NO_RETRY = 1; // 0x1 + field public static final int TYPE_A = 1; // 0x1 + field public static final int TYPE_AAAA = 28; // 0x1c + } + + public static interface DnsResolver.Callback<T> { + method public void onAnswer(@NonNull T, int); + method public void onError(@NonNull android.net.DnsResolver.DnsException); + } + + public static class DnsResolver.DnsException extends java.lang.Exception { + ctor public DnsResolver.DnsException(int, @Nullable Throwable); + field public final int code; + } + + public class InetAddresses { + method public static boolean isNumericAddress(@NonNull String); + method @NonNull public static java.net.InetAddress parseNumericAddress(@NonNull String); + } + + public final class IpConfiguration implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.net.ProxyInfo getHttpProxy(); + method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR; + } + + public static final class IpConfiguration.Builder { + ctor public IpConfiguration.Builder(); + method @NonNull public android.net.IpConfiguration build(); + method @NonNull public android.net.IpConfiguration.Builder setHttpProxy(@Nullable android.net.ProxyInfo); + method @NonNull public android.net.IpConfiguration.Builder setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration); + } + + public final class IpPrefix implements android.os.Parcelable { + ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int); + method public boolean contains(@NonNull java.net.InetAddress); + method public int describeContents(); + method @NonNull public java.net.InetAddress getAddress(); + method @IntRange(from=0, to=128) public int getPrefixLength(); + method @NonNull public byte[] getRawAddress(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR; + } + + public class LinkAddress implements android.os.Parcelable { + method public int describeContents(); + method public java.net.InetAddress getAddress(); + method public int getFlags(); + method @IntRange(from=0, to=128) public int getPrefixLength(); + method public int getScope(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR; + } + + public final class LinkProperties implements android.os.Parcelable { + ctor public LinkProperties(); + method public boolean addRoute(@NonNull android.net.RouteInfo); + method public void clear(); + method public int describeContents(); + method @Nullable public java.net.Inet4Address getDhcpServerAddress(); + method @NonNull public java.util.List<java.net.InetAddress> getDnsServers(); + method @Nullable public String getDomains(); + method @Nullable public android.net.ProxyInfo getHttpProxy(); + method @Nullable public String getInterfaceName(); + method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses(); + method public int getMtu(); + method @Nullable public android.net.IpPrefix getNat64Prefix(); + method @Nullable public String getPrivateDnsServerName(); + method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(); + method public boolean isPrivateDnsActive(); + method public boolean isWakeOnLanSupported(); + method public void setDhcpServerAddress(@Nullable java.net.Inet4Address); + method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>); + method public void setDomains(@Nullable String); + method public void setHttpProxy(@Nullable android.net.ProxyInfo); + method public void setInterfaceName(@Nullable String); + method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>); + method public void setMtu(int); + method public void setNat64Prefix(@Nullable android.net.IpPrefix); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR; + } + + public final class MacAddress implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public static android.net.MacAddress fromBytes(@NonNull byte[]); + method @NonNull public static android.net.MacAddress fromString(@NonNull String); + method public int getAddressType(); + method @Nullable public java.net.Inet6Address getLinkLocalIpv6FromEui48Mac(); + method public boolean isLocallyAssigned(); + method public boolean matches(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress); + method @NonNull public byte[] toByteArray(); + method @NonNull public String toOuiString(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.net.MacAddress BROADCAST_ADDRESS; + field @NonNull public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR; + field public static final int TYPE_BROADCAST = 3; // 0x3 + field public static final int TYPE_MULTICAST = 2; // 0x2 + field public static final int TYPE_UNICAST = 1; // 0x1 + } + + public class Network implements android.os.Parcelable { + method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException; + method public void bindSocket(java.net.Socket) throws java.io.IOException; + method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException; + method public int describeContents(); + method public static android.net.Network fromNetworkHandle(long); + method public java.net.InetAddress[] getAllByName(String) throws java.net.UnknownHostException; + method public java.net.InetAddress getByName(String) throws java.net.UnknownHostException; + method public long getNetworkHandle(); + method public javax.net.SocketFactory getSocketFactory(); + method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException; + method public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException; + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.Network> CREATOR; + } + + public final class NetworkCapabilities implements android.os.Parcelable { + ctor public NetworkCapabilities(); + ctor public NetworkCapabilities(android.net.NetworkCapabilities); + method public int describeContents(); + method @NonNull public int[] getCapabilities(); + method @NonNull public int[] getEnterpriseIds(); + method public int getLinkDownstreamBandwidthKbps(); + method public int getLinkUpstreamBandwidthKbps(); + method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier(); + method public int getOwnerUid(); + method public int getSignalStrength(); + method @Nullable public android.net.TransportInfo getTransportInfo(); + method public boolean hasCapability(int); + method public boolean hasEnterpriseId(int); + method public boolean hasTransport(int); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR; + field public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; // 0x11 + field public static final int NET_CAPABILITY_CBS = 5; // 0x5 + field public static final int NET_CAPABILITY_DUN = 2; // 0x2 + field public static final int NET_CAPABILITY_EIMS = 10; // 0xa + field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d + field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13 + field public static final int NET_CAPABILITY_FOTA = 3; // 0x3 + field public static final int NET_CAPABILITY_HEAD_UNIT = 32; // 0x20 + field public static final int NET_CAPABILITY_IA = 7; // 0x7 + field public static final int NET_CAPABILITY_IMS = 4; // 0x4 + field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc + field public static final int NET_CAPABILITY_MCX = 23; // 0x17 + field public static final int NET_CAPABILITY_MMS = 0; // 0x0 + field public static final int NET_CAPABILITY_MMTEL = 33; // 0x21 + field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14 + field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb + field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd + field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12 + field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15 + field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf + field public static final int NET_CAPABILITY_PRIORITIZE_BANDWIDTH = 35; // 0x23 + field public static final int NET_CAPABILITY_PRIORITIZE_LATENCY = 34; // 0x22 + field public static final int NET_CAPABILITY_RCS = 8; // 0x8 + field public static final int NET_CAPABILITY_SUPL = 1; // 0x1 + field public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; // 0x19 + field public static final int NET_CAPABILITY_TRUSTED = 14; // 0xe + field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10 + field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6 + field public static final int NET_CAPABILITY_XCAP = 9; // 0x9 + field public static final int NET_ENTERPRISE_ID_1 = 1; // 0x1 + field public static final int NET_ENTERPRISE_ID_2 = 2; // 0x2 + field public static final int NET_ENTERPRISE_ID_3 = 3; // 0x3 + field public static final int NET_ENTERPRISE_ID_4 = 4; // 0x4 + field public static final int NET_ENTERPRISE_ID_5 = 5; // 0x5 + field public static final int SIGNAL_STRENGTH_UNSPECIFIED = -2147483648; // 0x80000000 + field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2 + field public static final int TRANSPORT_CELLULAR = 0; // 0x0 + field public static final int TRANSPORT_ETHERNET = 3; // 0x3 + field public static final int TRANSPORT_LOWPAN = 6; // 0x6 + field public static final int TRANSPORT_THREAD = 9; // 0x9 + field public static final int TRANSPORT_USB = 8; // 0x8 + field public static final int TRANSPORT_VPN = 4; // 0x4 + field public static final int TRANSPORT_WIFI = 1; // 0x1 + field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5 + } + + @Deprecated public class NetworkInfo implements android.os.Parcelable { + ctor @Deprecated public NetworkInfo(int, int, @Nullable String, @Nullable String); + method @Deprecated public int describeContents(); + method @Deprecated @NonNull public android.net.NetworkInfo.DetailedState getDetailedState(); + method @Deprecated public String getExtraInfo(); + method @Deprecated public String getReason(); + method @Deprecated public android.net.NetworkInfo.State getState(); + method @Deprecated public int getSubtype(); + method @Deprecated public String getSubtypeName(); + method @Deprecated public int getType(); + method @Deprecated public String getTypeName(); + method @Deprecated public boolean isAvailable(); + method @Deprecated public boolean isConnected(); + method @Deprecated public boolean isConnectedOrConnecting(); + method @Deprecated public boolean isFailover(); + method @Deprecated public boolean isRoaming(); + method @Deprecated public void setDetailedState(@NonNull android.net.NetworkInfo.DetailedState, @Nullable String, @Nullable String); + method @Deprecated public void writeToParcel(android.os.Parcel, int); + field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR; + } + + @Deprecated public enum NetworkInfo.DetailedState { + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState AUTHENTICATING; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState BLOCKED; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CAPTIVE_PORTAL_CHECK; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTED; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTING; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTED; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTING; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState FAILED; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState IDLE; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState OBTAINING_IPADDR; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SCANNING; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SUSPENDED; + enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK; + } + + @Deprecated public enum NetworkInfo.State { + enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTED; + enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTING; + enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTED; + enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTING; + enum_constant @Deprecated public static final android.net.NetworkInfo.State SUSPENDED; + enum_constant @Deprecated public static final android.net.NetworkInfo.State UNKNOWN; + } + + public class NetworkRequest implements android.os.Parcelable { + method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities); + method public int describeContents(); + method @NonNull public int[] getCapabilities(); + method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier(); + method @NonNull public int[] getTransportTypes(); + method public boolean hasCapability(int); + method public boolean hasTransport(int); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR; + } + + public static class NetworkRequest.Builder { + ctor public NetworkRequest.Builder(); + ctor public NetworkRequest.Builder(@NonNull android.net.NetworkRequest); + method public android.net.NetworkRequest.Builder addCapability(int); + method public android.net.NetworkRequest.Builder addTransportType(int); + method public android.net.NetworkRequest build(); + method @NonNull public android.net.NetworkRequest.Builder clearCapabilities(); + method public android.net.NetworkRequest.Builder removeCapability(int); + method public android.net.NetworkRequest.Builder removeTransportType(int); + method @NonNull public android.net.NetworkRequest.Builder setIncludeOtherUidNetworks(boolean); + method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String); + method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier); + } + + public class ParseException extends java.lang.RuntimeException { + ctor public ParseException(@NonNull String); + ctor public ParseException(@NonNull String, @NonNull Throwable); + field public String response; + } + + public class ProxyInfo implements android.os.Parcelable { + ctor public ProxyInfo(@Nullable android.net.ProxyInfo); + method public static android.net.ProxyInfo buildDirectProxy(String, int); + method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>); + method public static android.net.ProxyInfo buildPacProxy(android.net.Uri); + method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int); + method public int describeContents(); + method public String[] getExclusionList(); + method public String getHost(); + method public android.net.Uri getPacFileUrl(); + method public int getPort(); + method public boolean isValid(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR; + } + + public final class RouteInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.IpPrefix getDestination(); + method @Nullable public java.net.InetAddress getGateway(); + method @Nullable public String getInterface(); + method public int getType(); + method public boolean hasGateway(); + method public boolean isDefaultRoute(); + method public boolean matches(java.net.InetAddress); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR; + field public static final int RTN_THROW = 9; // 0x9 + field public static final int RTN_UNICAST = 1; // 0x1 + field public static final int RTN_UNREACHABLE = 7; // 0x7 + } + + public abstract class SocketKeepalive implements java.lang.AutoCloseable { + method public final void close(); + method public final void start(@IntRange(from=0xa, to=0xe10) int); + method public final void stop(); + field public static final int ERROR_HARDWARE_ERROR = -31; // 0xffffffe1 + field public static final int ERROR_INSUFFICIENT_RESOURCES = -32; // 0xffffffe0 + field public static final int ERROR_INVALID_INTERVAL = -24; // 0xffffffe8 + field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb + field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9 + field public static final int ERROR_INVALID_NETWORK = -20; // 0xffffffec + field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea + field public static final int ERROR_INVALID_SOCKET = -25; // 0xffffffe7 + field public static final int ERROR_SOCKET_NOT_IDLE = -26; // 0xffffffe6 + field public static final int ERROR_UNSUPPORTED = -30; // 0xffffffe2 + } + + public static class SocketKeepalive.Callback { + ctor public SocketKeepalive.Callback(); + method public void onDataReceived(); + method public void onError(int); + method public void onStarted(); + method public void onStopped(); + } + + public final class StaticIpConfiguration implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<java.net.InetAddress> getDnsServers(); + method @Nullable public String getDomains(); + method @Nullable public java.net.InetAddress getGateway(); + method @NonNull public android.net.LinkAddress getIpAddress(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR; + } + + public static final class StaticIpConfiguration.Builder { + ctor public StaticIpConfiguration.Builder(); + method @NonNull public android.net.StaticIpConfiguration build(); + method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>); + method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String); + method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress); + method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@NonNull android.net.LinkAddress); + } + + public interface TransportInfo { + } + +} +
diff --git a/framework/cronet_disabled/api/lint-baseline.txt b/framework/cronet_disabled/api/lint-baseline.txt new file mode 100644 index 0000000..2f4004a --- /dev/null +++ b/framework/cronet_disabled/api/lint-baseline.txt
@@ -0,0 +1,4 @@ +// Baseline format: 1.0 +VisiblySynchronized: android.net.NetworkInfo#toString(): + Internal locks must not be exposed (synchronizing on this or class is still + externally observable): method android.net.NetworkInfo.toString()
diff --git a/framework/cronet_disabled/api/module-lib-current.txt b/framework/cronet_disabled/api/module-lib-current.txt new file mode 100644 index 0000000..193bd92 --- /dev/null +++ b/framework/cronet_disabled/api/module-lib-current.txt
@@ -0,0 +1,239 @@ +// Signature format: 2.0 +package android.net { + + public final class ConnectivityFrameworkInitializer { + method public static void registerServiceWrappers(); + } + + public class ConnectivityManager { + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void addUidToMeteredNetworkAllowList(int); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void addUidToMeteredNetworkDenyList(int); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void factoryReset(); + method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshots(); + method @Nullable public android.net.ProxyInfo getGlobalProxy(); + method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange(); + method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.LinkProperties getRedactedLinkPropertiesForPackage(@NonNull android.net.LinkProperties, int, @NonNull String); + method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.NetworkCapabilities getRedactedNetworkCapabilitiesForPackage(@NonNull android.net.NetworkCapabilities, int, @NonNull String); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkAllowList(int); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkDenyList(int); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void replaceFirewallChain(int, @NonNull int[]); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); + method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setFirewallChainEnabled(int, boolean); + method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean); + method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable); + method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreferences(@NonNull android.os.UserHandle, @NonNull java.util.List<android.net.ProfileNetworkPreference>, @Nullable java.util.concurrent.Executor, @Nullable Runnable); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setUidFirewallRule(int, int, int); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setVpnDefaultForUids(@NonNull String, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network); + method public void systemReady(); + field public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE"; + field public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.action.PROMPT_LOST_VALIDATION"; + field public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = "android.net.action.PROMPT_PARTIAL_CONNECTIVITY"; + field public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED"; + field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000 + field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000 + field public static final int BLOCKED_METERED_REASON_MASK = -65536; // 0xffff0000 + field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000 + field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4 + field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1 + field public static final int BLOCKED_REASON_DOZE = 2; // 0x2 + field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10 + field public static final int BLOCKED_REASON_LOW_POWER_STANDBY = 32; // 0x20 + field public static final int BLOCKED_REASON_NONE = 0; // 0x0 + field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8 + field public static final int FIREWALL_CHAIN_DOZABLE = 1; // 0x1 + field public static final int FIREWALL_CHAIN_LOW_POWER_STANDBY = 5; // 0x5 + field public static final int FIREWALL_CHAIN_OEM_DENY_1 = 7; // 0x7 + field public static final int FIREWALL_CHAIN_OEM_DENY_2 = 8; // 0x8 + field public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9; // 0x9 + field public static final int FIREWALL_CHAIN_POWERSAVE = 3; // 0x3 + field public static final int FIREWALL_CHAIN_RESTRICTED = 4; // 0x4 + field public static final int FIREWALL_CHAIN_STANDBY = 2; // 0x2 + field public static final int FIREWALL_RULE_ALLOW = 1; // 0x1 + field public static final int FIREWALL_RULE_DEFAULT = 0; // 0x0 + field public static final int FIREWALL_RULE_DENY = 2; // 0x2 + field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0 + field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1 + field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING = 3; // 0x3 + field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK = 2; // 0x2 + } + + public static class ConnectivityManager.NetworkCallback { + method public void onBlockedStatusChanged(@NonNull android.net.Network, int); + } + + public class ConnectivitySettingsManager { + method public static void clearGlobalProxy(@NonNull android.content.Context); + method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context); + method public static int getCaptivePortalMode(@NonNull android.content.Context, int); + method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method @NonNull public static android.util.Range<java.lang.Integer> getDnsResolverSampleRanges(@NonNull android.content.Context); + method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int); + method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context); + method public static long getIngressRateLimitInBytesPerSecond(@NonNull android.content.Context); + method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean); + method @NonNull public static java.util.Set<java.lang.Integer> getMobileDataPreferredUids(@NonNull android.content.Context); + method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context); + method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context); + method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int); + method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context); + method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context); + method public static int getPrivateDnsMode(@NonNull android.content.Context); + method @NonNull public static java.util.Set<java.lang.Integer> getUidsAllowedOnRestrictedNetworks(@NonNull android.content.Context); + method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean); + method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String); + method public static void setCaptivePortalMode(@NonNull android.content.Context, int); + method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setDnsResolverSampleRanges(@NonNull android.content.Context, @NonNull android.util.Range<java.lang.Integer>); + method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int); + method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo); + method public static void setIngressRateLimitInBytesPerSecond(@NonNull android.content.Context, @IntRange(from=-1L, to=4294967295L) long); + method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean); + method public static void setMobileDataPreferredUids(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>); + method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int); + method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String); + method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int); + method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int); + method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String); + method public static void setPrivateDnsMode(@NonNull android.content.Context, int); + method public static void setUidsAllowedOnRestrictedNetworks(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>); + method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean); + method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); + field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2 + field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0 + field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1 + field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2 + field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0 + field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1 + field public static final int PRIVATE_DNS_MODE_OFF = 1; // 0x1 + field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2 + field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3 + } + + public final class DhcpOption implements android.os.Parcelable { + ctor public DhcpOption(byte, @Nullable byte[]); + method public int describeContents(); + method public byte getType(); + method @Nullable public byte[] getValue(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpOption> CREATOR; + } + + public final class NetworkAgentConfig implements android.os.Parcelable { + method @Nullable public String getSubscriberId(); + method public boolean isBypassableVpn(); + method public boolean isVpnValidationRequired(); + } + + public static final class NetworkAgentConfig.Builder { + method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean); + method @NonNull public android.net.NetworkAgentConfig.Builder setLocalRoutesExcludedForVpn(boolean); + method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String); + method @NonNull public android.net.NetworkAgentConfig.Builder setVpnRequiresValidation(boolean); + } + + public final class NetworkCapabilities implements android.os.Parcelable { + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public java.util.Set<java.lang.Integer> getAllowedUids(); + method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids(); + method public boolean hasForbiddenCapability(int); + field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL + field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L + field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L + field public static final long REDACT_FOR_NETWORK_SETTINGS = 4L; // 0x4L + field public static final long REDACT_NONE = 0L; // 0x0L + field public static final int TRANSPORT_TEST = 7; // 0x7 + } + + public static final class NetworkCapabilities.Builder { + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAllowedUids(@NonNull java.util.Set<java.lang.Integer>); + method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>); + } + + public class NetworkRequest implements android.os.Parcelable { + method @NonNull public int[] getEnterpriseIds(); + method @NonNull public int[] getForbiddenCapabilities(); + method public boolean hasEnterpriseId(int); + method public boolean hasForbiddenCapability(int); + } + + public static class NetworkRequest.Builder { + method @NonNull public android.net.NetworkRequest.Builder addForbiddenCapability(int); + method @NonNull public android.net.NetworkRequest.Builder removeForbiddenCapability(int); + method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>); + } + + public final class ProfileNetworkPreference implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public int[] getExcludedUids(); + method @NonNull public int[] getIncludedUids(); + method public int getPreference(); + method public int getPreferenceEnterpriseId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.ProfileNetworkPreference> CREATOR; + } + + public static final class ProfileNetworkPreference.Builder { + ctor public ProfileNetworkPreference.Builder(); + method @NonNull public android.net.ProfileNetworkPreference build(); + method @NonNull public android.net.ProfileNetworkPreference.Builder setExcludedUids(@NonNull int[]); + method @NonNull public android.net.ProfileNetworkPreference.Builder setIncludedUids(@NonNull int[]); + method @NonNull public android.net.ProfileNetworkPreference.Builder setPreference(int); + method @NonNull public android.net.ProfileNetworkPreference.Builder setPreferenceEnterpriseId(int); + } + + public final class TestNetworkInterface implements android.os.Parcelable { + ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String); + method public int describeContents(); + method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor(); + method @NonNull public String getInterfaceName(); + method @Nullable public android.net.MacAddress getMacAddress(); + method public int getMtu(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR; + } + + public class TestNetworkManager { + method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public android.net.TestNetworkInterface createTapInterface(); + method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>); + method @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder); + method @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public void teardownTestNetwork(@NonNull android.net.Network); + field public static final String TEST_TAP_PREFIX = "testtap"; + } + + public final class TestNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { + ctor public TestNetworkSpecifier(@NonNull String); + method public int describeContents(); + method @Nullable public String getInterfaceName(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkSpecifier> CREATOR; + } + + public interface TransportInfo { + method public default long getApplicableRedactions(); + method @NonNull public default android.net.TransportInfo makeCopy(long); + } + + public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo { + ctor @Deprecated public VpnTransportInfo(int, @Nullable String); + method @Nullable public String getSessionId(); + method @NonNull public android.net.VpnTransportInfo makeCopy(long); + } + +} +
diff --git a/Cronet/api/module-lib-removed.txt b/framework/cronet_disabled/api/module-lib-removed.txt similarity index 100% rename from Cronet/api/module-lib-removed.txt rename to framework/cronet_disabled/api/module-lib-removed.txt
diff --git a/framework/cronet_disabled/api/removed.txt b/framework/cronet_disabled/api/removed.txt new file mode 100644 index 0000000..303a1e6 --- /dev/null +++ b/framework/cronet_disabled/api/removed.txt
@@ -0,0 +1,11 @@ +// Signature format: 2.0 +package android.net { + + public class ConnectivityManager { + method @Deprecated public boolean requestRouteToHost(int, int); + method @Deprecated public int startUsingNetworkFeature(int, String); + method @Deprecated public int stopUsingNetworkFeature(int, String); + } + +} +
diff --git a/framework/cronet_disabled/api/system-current.txt b/framework/cronet_disabled/api/system-current.txt new file mode 100644 index 0000000..4a2ed8a --- /dev/null +++ b/framework/cronet_disabled/api/system-current.txt
@@ -0,0 +1,544 @@ +// Signature format: 2.0 +package android.net { + + public class CaptivePortal implements android.os.Parcelable { + method @Deprecated public void logEvent(int, @NonNull String); + method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork(); + method public void useNetwork(); + field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64 + field public static final int APP_RETURN_DISMISSED = 0; // 0x0 + field public static final int APP_RETURN_UNWANTED = 1; // 0x1 + field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2 + } + + public final class CaptivePortalData implements android.os.Parcelable { + method public int describeContents(); + method public long getByteLimit(); + method public long getExpiryTimeMillis(); + method public long getRefreshTimeMillis(); + method @Nullable public android.net.Uri getUserPortalUrl(); + method public int getUserPortalUrlSource(); + method @Nullable public CharSequence getVenueFriendlyName(); + method @Nullable public android.net.Uri getVenueInfoUrl(); + method public int getVenueInfoUrlSource(); + method public boolean isCaptive(); + method public boolean isSessionExtendable(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0 + field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1 + field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR; + } + + public static class CaptivePortalData.Builder { + ctor public CaptivePortalData.Builder(); + ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData); + method @NonNull public android.net.CaptivePortalData build(); + method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long); + method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean); + method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long); + method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long); + method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean); + method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri); + method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int); + method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable CharSequence); + method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri); + method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int); + } + + public class ConnectivityManager { + method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback); + method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback); + method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl(); + method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported(); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider); + method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.QosCallback); + method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback); + method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean); + method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable Runnable); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi(); + method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle); + method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback); + method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler); + method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider); + method public void unregisterQosCallback(@NonNull android.net.QosCallback); + method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback); + field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC"; + field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; + field public static final int TETHERING_BLUETOOTH = 2; // 0x2 + field public static final int TETHERING_USB = 1; // 0x1 + field public static final int TETHERING_WIFI = 0; // 0x0 + field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd + field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 + field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb + field public static final int TYPE_NONE = -1; // 0xffffffff + field @Deprecated public static final int TYPE_PROXY = 16; // 0x10 + field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd + } + + @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback { + ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback(); + method @Deprecated public void onTetheringFailed(); + method @Deprecated public void onTetheringStarted(); + } + + @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener { + method @Deprecated public void onTetheringEntitlementResult(int); + } + + @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback { + ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback(); + method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network); + } + + public final class DscpPolicy implements android.os.Parcelable { + method @Nullable public java.net.InetAddress getDestinationAddress(); + method @Nullable public android.util.Range<java.lang.Integer> getDestinationPortRange(); + method public int getDscpValue(); + method public int getPolicyId(); + method public int getProtocol(); + method @Nullable public java.net.InetAddress getSourceAddress(); + method public int getSourcePort(); + field @NonNull public static final android.os.Parcelable.Creator<android.net.DscpPolicy> CREATOR; + field public static final int PROTOCOL_ANY = -1; // 0xffffffff + field public static final int SOURCE_PORT_ANY = -1; // 0xffffffff + } + + public static final class DscpPolicy.Builder { + ctor public DscpPolicy.Builder(int, int); + method @NonNull public android.net.DscpPolicy build(); + method @NonNull public android.net.DscpPolicy.Builder setDestinationAddress(@NonNull java.net.InetAddress); + method @NonNull public android.net.DscpPolicy.Builder setDestinationPortRange(@NonNull android.util.Range<java.lang.Integer>); + method @NonNull public android.net.DscpPolicy.Builder setProtocol(int); + method @NonNull public android.net.DscpPolicy.Builder setSourceAddress(@NonNull java.net.InetAddress); + method @NonNull public android.net.DscpPolicy.Builder setSourcePort(int); + } + + public final class InvalidPacketException extends java.lang.Exception { + ctor public InvalidPacketException(int); + method public int getError(); + field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb + field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9 + field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea + } + + public final class IpConfiguration implements android.os.Parcelable { + ctor public IpConfiguration(); + ctor public IpConfiguration(@NonNull android.net.IpConfiguration); + method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment(); + method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings(); + method public void setHttpProxy(@Nullable android.net.ProxyInfo); + method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment); + method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings); + method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration); + } + + public enum IpConfiguration.IpAssignment { + enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP; + enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC; + enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED; + } + + public enum IpConfiguration.ProxySettings { + enum_constant public static final android.net.IpConfiguration.ProxySettings NONE; + enum_constant public static final android.net.IpConfiguration.ProxySettings PAC; + enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC; + enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED; + } + + public final class IpPrefix implements android.os.Parcelable { + ctor public IpPrefix(@NonNull String); + } + + public class KeepalivePacketData { + ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull byte[]) throws android.net.InvalidPacketException; + method @NonNull public java.net.InetAddress getDstAddress(); + method public int getDstPort(); + method @NonNull public byte[] getPacket(); + method @NonNull public java.net.InetAddress getSrcAddress(); + method public int getSrcPort(); + } + + public class LinkAddress implements android.os.Parcelable { + ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int); + ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long); + ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int); + ctor public LinkAddress(@NonNull String); + ctor public LinkAddress(@NonNull String, int, int); + method public long getDeprecationTime(); + method public long getExpirationTime(); + method public boolean isGlobalPreferred(); + method public boolean isIpv4(); + method public boolean isIpv6(); + method public boolean isSameAddressAs(@Nullable android.net.LinkAddress); + field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL + field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL + } + + public final class LinkProperties implements android.os.Parcelable { + ctor public LinkProperties(@Nullable android.net.LinkProperties); + ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean); + method public boolean addDnsServer(@NonNull java.net.InetAddress); + method public boolean addLinkAddress(@NonNull android.net.LinkAddress); + method public boolean addPcscfServer(@NonNull java.net.InetAddress); + method @NonNull public java.util.List<java.net.InetAddress> getAddresses(); + method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames(); + method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses(); + method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes(); + method @Nullable public android.net.Uri getCaptivePortalApiUrl(); + method @Nullable public android.net.CaptivePortalData getCaptivePortalData(); + method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers(); + method @Nullable public String getTcpBufferSizes(); + method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers(); + method public boolean hasGlobalIpv6Address(); + method public boolean hasIpv4Address(); + method public boolean hasIpv4DefaultRoute(); + method public boolean hasIpv4DnsServer(); + method public boolean hasIpv6DefaultRoute(); + method public boolean hasIpv6DnsServer(); + method public boolean isIpv4Provisioned(); + method public boolean isIpv6Provisioned(); + method public boolean isProvisioned(); + method public boolean isReachable(@NonNull java.net.InetAddress); + method public boolean removeDnsServer(@NonNull java.net.InetAddress); + method public boolean removeLinkAddress(@NonNull android.net.LinkAddress); + method public boolean removeRoute(@NonNull android.net.RouteInfo); + method public void setCaptivePortalApiUrl(@Nullable android.net.Uri); + method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData); + method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>); + method public void setPrivateDnsServerName(@Nullable String); + method public void setTcpBufferSizes(@Nullable String); + method public void setUsePrivateDns(boolean); + method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>); + } + + public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable { + ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException; + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR; + } + + public class Network implements android.os.Parcelable { + ctor public Network(@NonNull android.net.Network); + method public int getNetId(); + method @NonNull public android.net.Network getPrivateDnsBypassingCopy(); + } + + public abstract class NetworkAgent { + ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider); + ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider); + method @Nullable public android.net.Network getNetwork(); + method public void markConnected(); + method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData); + method public void onAutomaticReconnectDisabled(); + method public void onBandwidthUpdateRequested(); + method public void onDscpPolicyStatusUpdated(int, int); + method public void onNetworkCreated(); + method public void onNetworkDestroyed(); + method public void onNetworkUnwanted(); + method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter); + method public void onQosCallbackUnregistered(int); + method public void onRemoveKeepalivePacketFilter(int); + method public void onSaveAcceptUnvalidated(boolean); + method public void onSignalStrengthThresholdsUpdated(@NonNull int[]); + method public void onStartSocketKeepalive(int, @NonNull java.time.Duration, @NonNull android.net.KeepalivePacketData); + method public void onStopSocketKeepalive(int); + method public void onValidationStatus(int, @Nullable android.net.Uri); + method @NonNull public android.net.Network register(); + method public void sendAddDscpPolicy(@NonNull android.net.DscpPolicy); + method public void sendLinkProperties(@NonNull android.net.LinkProperties); + method public void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities); + method public void sendNetworkScore(@NonNull android.net.NetworkScore); + method public void sendNetworkScore(@IntRange(from=0, to=99) int); + method public final void sendQosCallbackError(int, int); + method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes); + method public final void sendQosSessionLost(int, int, int); + method public void sendRemoveAllDscpPolicies(); + method public void sendRemoveDscpPolicy(int); + method public final void sendSocketKeepaliveEvent(int, int); + method @Deprecated public void setLegacySubtype(int, @NonNull String); + method public void setLingerDuration(@NonNull java.time.Duration); + method public void setTeardownDelayMillis(@IntRange(from=0, to=0x1388) int); + method public void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>); + method public void unregister(); + method public void unregisterAfterReplacement(@IntRange(from=0, to=0x1388) int); + field public static final int DSCP_POLICY_STATUS_DELETED = 4; // 0x4 + field public static final int DSCP_POLICY_STATUS_INSUFFICIENT_PROCESSING_RESOURCES = 3; // 0x3 + field public static final int DSCP_POLICY_STATUS_POLICY_NOT_FOUND = 5; // 0x5 + field public static final int DSCP_POLICY_STATUS_REQUESTED_CLASSIFIER_NOT_SUPPORTED = 2; // 0x2 + field public static final int DSCP_POLICY_STATUS_REQUEST_DECLINED = 1; // 0x1 + field public static final int DSCP_POLICY_STATUS_SUCCESS = 0; // 0x0 + field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2 + field public static final int VALIDATION_STATUS_VALID = 1; // 0x1 + } + + public final class NetworkAgentConfig implements android.os.Parcelable { + method public int describeContents(); + method public int getLegacyType(); + method @NonNull public String getLegacyTypeName(); + method public boolean isExplicitlySelected(); + method public boolean isPartialConnectivityAcceptable(); + method public boolean isUnvalidatedConnectivityAcceptable(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR; + } + + public static final class NetworkAgentConfig.Builder { + ctor public NetworkAgentConfig.Builder(); + method @NonNull public android.net.NetworkAgentConfig build(); + method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean); + method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyExtraInfo(@NonNull String); + method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubType(int); + method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubTypeName(@NonNull String); + method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int); + method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String); + method @NonNull public android.net.NetworkAgentConfig.Builder setNat64DetectionEnabled(boolean); + method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean); + method @NonNull public android.net.NetworkAgentConfig.Builder setProvisioningNotificationEnabled(boolean); + method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean); + } + + public final class NetworkCapabilities implements android.os.Parcelable { + method @NonNull public int[] getAdministratorUids(); + method @Nullable public static String getCapabilityCarrierName(int); + method @Nullable public String getSsid(); + method @NonNull public java.util.Set<java.lang.Integer> getSubscriptionIds(); + method @NonNull public int[] getTransportTypes(); + method @Nullable public java.util.List<android.net.Network> getUnderlyingNetworks(); + method public boolean isPrivateDnsBroken(); + method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities); + field public static final int NET_CAPABILITY_BIP = 31; // 0x1f + field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c + field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16 + field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a + field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18 + field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b + field public static final int NET_CAPABILITY_VSIM = 30; // 0x1e + } + + public static final class NetworkCapabilities.Builder { + ctor public NetworkCapabilities.Builder(); + ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities); + method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int); + method @NonNull public android.net.NetworkCapabilities.Builder addEnterpriseId(int); + method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int); + method @NonNull public android.net.NetworkCapabilities build(); + method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int); + method @NonNull public android.net.NetworkCapabilities.Builder removeEnterpriseId(int); + method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]); + method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int); + method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int); + method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String); + method @NonNull public android.net.NetworkCapabilities.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>); + method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>); + method @NonNull public static android.net.NetworkCapabilities.Builder withoutDefaultCapabilities(); + } + + public class NetworkProvider { + ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest); + method public int getProviderId(); + method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest); + method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void registerNetworkOffer(@NonNull android.net.NetworkScore, @NonNull android.net.NetworkCapabilities, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkProvider.NetworkOfferCallback); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkOffer(@NonNull android.net.NetworkProvider.NetworkOfferCallback); + field public static final int ID_NONE = -1; // 0xffffffff + } + + public static interface NetworkProvider.NetworkOfferCallback { + method public void onNetworkNeeded(@NonNull android.net.NetworkRequest); + method public void onNetworkUnneeded(@NonNull android.net.NetworkRequest); + } + + public class NetworkReleasedException extends java.lang.Exception { + ctor public NetworkReleasedException(); + } + + public class NetworkRequest implements android.os.Parcelable { + method @Nullable public String getRequestorPackageName(); + method public int getRequestorUid(); + } + + public static class NetworkRequest.Builder { + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int); + method @NonNull public android.net.NetworkRequest.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>); + } + + public final class NetworkScore implements android.os.Parcelable { + method public int describeContents(); + method public int getKeepConnectedReason(); + method public int getLegacyInt(); + method public boolean isExiting(); + method public boolean isTransportPrimary(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR; + field public static final int KEEP_CONNECTED_FOR_HANDOVER = 1; // 0x1 + field public static final int KEEP_CONNECTED_NONE = 0; // 0x0 + } + + public static final class NetworkScore.Builder { + ctor public NetworkScore.Builder(); + method @NonNull public android.net.NetworkScore build(); + method @NonNull public android.net.NetworkScore.Builder setExiting(boolean); + method @NonNull public android.net.NetworkScore.Builder setKeepConnectedReason(int); + method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int); + method @NonNull public android.net.NetworkScore.Builder setTransportPrimary(boolean); + } + + public final class OemNetworkPreferences implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.OemNetworkPreferences> CREATOR; + field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1; // 0x1 + field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2; // 0x2 + field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3; // 0x3 + field public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4; // 0x4 + field public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0; // 0x0 + } + + public static final class OemNetworkPreferences.Builder { + ctor public OemNetworkPreferences.Builder(); + ctor public OemNetworkPreferences.Builder(@NonNull android.net.OemNetworkPreferences); + method @NonNull public android.net.OemNetworkPreferences.Builder addNetworkPreference(@NonNull String, int); + method @NonNull public android.net.OemNetworkPreferences build(); + method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String); + } + + public abstract class QosCallback { + ctor public QosCallback(); + method public void onError(@NonNull android.net.QosCallbackException); + method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes); + method public void onQosSessionLost(@NonNull android.net.QosSession); + } + + public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException { + } + + public final class QosCallbackException extends java.lang.Exception { + ctor public QosCallbackException(@NonNull String); + ctor public QosCallbackException(@NonNull Throwable); + } + + public abstract class QosFilter { + method @NonNull public abstract android.net.Network getNetwork(); + method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int); + method public boolean matchesProtocol(int); + method public abstract boolean matchesRemoteAddress(@NonNull java.net.InetAddress, int, int); + } + + public final class QosSession implements android.os.Parcelable { + ctor public QosSession(int, int); + method public int describeContents(); + method public int getSessionId(); + method public int getSessionType(); + method public long getUniqueId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR; + field public static final int TYPE_EPS_BEARER = 1; // 0x1 + field public static final int TYPE_NR_BEARER = 2; // 0x2 + } + + public interface QosSessionAttributes { + } + + public final class QosSocketInfo implements android.os.Parcelable { + ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException; + ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.DatagramSocket) throws java.io.IOException; + method public int describeContents(); + method @NonNull public java.net.InetSocketAddress getLocalSocketAddress(); + method @NonNull public android.net.Network getNetwork(); + method @Nullable public java.net.InetSocketAddress getRemoteSocketAddress(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR; + } + + public final class RouteInfo implements android.os.Parcelable { + ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int); + ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int); + method public int getMtu(); + } + + public abstract class SocketKeepalive implements java.lang.AutoCloseable { + method public final void start(@IntRange(from=0xa, to=0xe10) int, int, @Nullable android.net.Network); + field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf + field public static final int FLAG_AUTOMATIC_ON_OFF = 1; // 0x1 + field public static final int SUCCESS = 0; // 0x0 + } + + public class SocketLocalAddressChangedException extends java.lang.Exception { + ctor public SocketLocalAddressChangedException(); + } + + public class SocketNotBoundException extends java.lang.Exception { + ctor public SocketNotBoundException(); + } + + public class SocketNotConnectedException extends java.lang.Exception { + ctor public SocketNotConnectedException(); + } + + public class SocketRemoteAddressChangedException extends java.lang.Exception { + ctor public SocketRemoteAddressChangedException(); + } + + public final class StaticIpConfiguration implements android.os.Parcelable { + ctor public StaticIpConfiguration(); + ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration); + method public void addDnsServer(@NonNull java.net.InetAddress); + method public void clear(); + method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String); + } + + public final class TcpKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable { + ctor public TcpKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[], int, int, int, int, int, int) throws android.net.InvalidPacketException; + method public int describeContents(); + method public int getIpTos(); + method public int getIpTtl(); + method public int getTcpAck(); + method public int getTcpSeq(); + method public int getTcpWindow(); + method public int getTcpWindowScale(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.TcpKeepalivePacketData> CREATOR; + } + + public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo { + ctor public VpnTransportInfo(int, @Nullable String, boolean, boolean); + method public boolean areLongLivedTcpConnectionsExpensive(); + method public int describeContents(); + method public int getType(); + method public boolean isBypassable(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR; + } + +} + +package android.net.apf { + + public final class ApfCapabilities implements android.os.Parcelable { + ctor public ApfCapabilities(int, int, int); + method public int describeContents(); + method public static boolean getApfDrop8023Frames(); + method @NonNull public static int[] getApfEtherTypeBlackList(); + method public boolean hasDataAccess(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR; + field public final int apfPacketFormat; + field public final int apfVersionSupported; + field public final int maximumApfProgramSize; + } + +} +
diff --git a/framework/cronet_disabled/api/system-lint-baseline.txt b/framework/cronet_disabled/api/system-lint-baseline.txt new file mode 100644 index 0000000..9a97707 --- /dev/null +++ b/framework/cronet_disabled/api/system-lint-baseline.txt
@@ -0,0 +1 @@ +// Baseline format: 1.0
diff --git a/Cronet/api/system-removed.txt b/framework/cronet_disabled/api/system-removed.txt similarity index 100% rename from Cronet/api/system-removed.txt rename to framework/cronet_disabled/api/system-removed.txt
diff --git a/framework/jarjar-excludes.txt b/framework/jarjar-excludes.txt index 1311765..9b48d57 100644 --- a/framework/jarjar-excludes.txt +++ b/framework/jarjar-excludes.txt
@@ -23,3 +23,8 @@ # TODO (b/217115866): add jarjar rules for Nearby android\.nearby\..+ + +# Don't touch anything that's already under android.net.http (cronet) +# This is required since android.net.http contains api classes and hidden classes. +# TODO: Remove this after hidden classes are moved to different package +android\.net\.http\..+ \ No newline at end of file
diff --git a/framework/jni/android_net_NetworkUtils.cpp b/framework/jni/android_net_NetworkUtils.cpp index 38e0059..ca297e5 100644 --- a/framework/jni/android_net_NetworkUtils.cpp +++ b/framework/jni/android_net_NetworkUtils.cpp
@@ -23,6 +23,7 @@ #include <netinet/in.h> #include <string.h> +#include <bpf/BpfClassic.h> #include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS #include <nativehelper/JNIPlatformHelp.h> #include <utils/Log.h> @@ -55,11 +56,10 @@ static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jclass clazz, jobject javaFd) { - struct sock_filter filter_code[] = { - // Reject all. - BPF_STMT(BPF_RET | BPF_K, 0) + static struct sock_filter filter_code[] = { + BPF_REJECT, }; - struct sock_fprog filter = { + static const struct sock_fprog filter = { sizeof(filter_code) / sizeof(filter_code[0]), filter_code, };
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java index 39c5af2..2315521 100644 --- a/framework/src/android/net/ConnectivityManager.java +++ b/framework/src/android/net/ConnectivityManager.java
@@ -1232,16 +1232,19 @@ } /** - * Preference for {@link ProfileNetworkPreference#setPreference(int)}. + * Preference for {@link ProfileNetworkPreference.Builder#setPreference(int)}. * See {@link #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)} - * Specify that the traffic for this user should by follow the default rules. + * Specify that the traffic for this user should by follow the default rules: + * applications in the profile designated by the UserHandle behave like any + * other application and use the system default network as their default + * network. Compare other PROFILE_NETWORK_PREFERENCE_* settings. * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; /** - * Preference for {@link ProfileNetworkPreference#setPreference(int)}. + * Preference for {@link ProfileNetworkPreference.Builder#setPreference(int)}. * See {@link #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)} * Specify that the traffic for this user should by default go on a network with * {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE}, and on the system default network @@ -1252,16 +1255,38 @@ public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; /** - * Preference for {@link ProfileNetworkPreference#setPreference(int)}. + * Preference for {@link ProfileNetworkPreference.Builder#setPreference(int)}. * See {@link #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)} * Specify that the traffic for this user should by default go on a network with * {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE} and if no such network is available - * should not go on the system default network + * should not have a default network at all (that is, network accesses that + * do not specify a network explicitly terminate with an error), even if there + * is a system default network available to apps outside this preference. + * The apps can still use a non-enterprise network if they request it explicitly + * provided that specific network doesn't require any specific permission they + * do not hold. * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK = 2; + /** + * Preference for {@link ProfileNetworkPreference.Builder#setPreference(int)}. + * See {@link #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)} + * Specify that the traffic for this user should by default go on a network with + * {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE}. + * If there is no such network, the apps will have no default + * network at all, even if there are available non-enterprise networks on the + * device (that is, network accesses that do not specify a network explicitly + * terminate with an error). Additionally, the designated apps should be + * blocked from using any non-enterprise network even if they specify it + * explicitly, unless they hold specific privilege overriding this (see + * {@link android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}). + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING = 3; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { @@ -1378,6 +1403,17 @@ } } + private static UidRange[] getUidRangeArray(@NonNull Collection<Range<Integer>> ranges) { + Objects.requireNonNull(ranges); + final UidRange[] rangesArray = new UidRange[ranges.size()]; + int index = 0; + for (Range<Integer> range : ranges) { + rangesArray[index++] = new UidRange(range.getLower(), range.getUpper()); + } + + return rangesArray; + } + /** * Adds or removes a requirement for given UID ranges to use the VPN. * @@ -1397,6 +1433,12 @@ * {@link NetworkCallback#onBlockedStatusChanged} callbacks called after the changes take * effect. * <p> + * This method will block the specified UIDs from accessing non-VPN networks, but does not + * affect what the UIDs get as their default network. + * Compare {@link #setVpnDefaultForUids(String, Collection)}, which declares that the UIDs + * should only have a VPN as their default network, but does not block them from accessing other + * networks if they request them explicitly with the {@link Network} API. + * <p> * This method should be called only by the VPN code. * * @param ranges the UID ranges to restrict @@ -1416,11 +1458,7 @@ // This method is not necessarily expected to be used outside the system server, so // parceling may not be necessary, but it could be used out-of-process, e.g., by the network // stack process, or by tests. - UidRange[] rangesArray = new UidRange[ranges.size()]; - int index = 0; - for (Range<Integer> range : ranges) { - rangesArray[index++] = new UidRange(range.getLower(), range.getUpper()); - } + final UidRange[] rangesArray = getUidRangeArray(ranges); try { mService.setRequireVpnForUids(requireVpn, rangesArray); } catch (RemoteException e) { @@ -1429,6 +1467,57 @@ } /** + * Inform the system that this VPN session should manage the passed UIDs. + * + * A VPN with the specified session ID may call this method to inform the system that the UIDs + * in the specified range are subject to a VPN. + * When this is called, the system will only choose a VPN for the default network of the UIDs in + * the specified ranges. + * + * This method declares that the UIDs in the range will only have a VPN for their default + * network, but does not block the UIDs from accessing other networks (permissions allowing) by + * explicitly requesting it with the {@link Network} API. + * Compare {@link #setRequireVpnForUids(boolean, Collection)}, which does not affect what + * network the UIDs get as default, but will block them from accessing non-VPN networks. + * + * @param session The VPN session which manages the passed UIDs. + * @param ranges The uid ranges which will treat VPN as their only default network. + * + * @hide + */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + @SystemApi(client = MODULE_LIBRARIES) + public void setVpnDefaultForUids(@NonNull String session, + @NonNull Collection<Range<Integer>> ranges) { + Objects.requireNonNull(ranges); + final UidRange[] rangesArray = getUidRangeArray(ranges); + try { + mService.setVpnNetworkPreference(session, rangesArray); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Temporarily set automaticOnOff keeplaive TCP polling alarm timer to 1 second. + * + * TODO: Remove this when the TCP polling design is replaced with callback. + * @param timeMs The time of expiry, with System.currentTimeMillis() base. The value should be + * set no more than 5 minutes in the future. + * @hide + */ + public void setTestLowTcpPollingTimerForKeepalive(long timeMs) { + try { + mService.setTestLowTcpPollingTimerForKeepalive(timeMs); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Informs ConnectivityService of whether the legacy lockdown VPN, as implemented by * LockdownVpnTracker, is in use. This is deprecated for new devices starting from Android 12 * but is still supported for backwards compatibility. @@ -2140,9 +2229,13 @@ /** The requested keepalive was successfully started. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void onStarted() {} + /** The keepalive was resumed after being paused by the system. */ + public void onResumed() {} /** The keepalive was successfully stopped. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void onStopped() {} + /** The keepalive was paused automatically by the system. */ + public void onPaused() {} /** An error occurred. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void onError(int error) {} @@ -2206,16 +2299,12 @@ private final ISocketKeepaliveCallback mCallback; private final ExecutorService mExecutor; - private volatile Integer mSlot; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void stop() { try { mExecutor.execute(() -> { try { - if (mSlot != null) { - mService.stopKeepalive(mNetwork, mSlot); - } + mService.stopKeepalive(mCallback); } catch (RemoteException e) { Log.e(TAG, "Error stopping packet keepalive: ", e); throw e.rethrowFromSystemServer(); @@ -2233,11 +2322,10 @@ mExecutor = Executors.newSingleThreadExecutor(); mCallback = new ISocketKeepaliveCallback.Stub() { @Override - public void onStarted(int slot) { + public void onStarted() { final long token = Binder.clearCallingIdentity(); try { mExecutor.execute(() -> { - mSlot = slot; callback.onStarted(); }); } finally { @@ -2246,11 +2334,22 @@ } @Override + public void onResumed() { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + callback.onResumed(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override public void onStopped() { final long token = Binder.clearCallingIdentity(); try { mExecutor.execute(() -> { - mSlot = null; callback.onStopped(); }); } finally { @@ -2260,11 +2359,23 @@ } @Override + public void onPaused() { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + callback.onPaused(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + mExecutor.shutdown(); + } + + @Override public void onError(int error) { final long token = Binder.clearCallingIdentity(); try { mExecutor.execute(() -> { - mSlot = null; callback.onError(error); }); } finally { @@ -2410,7 +2521,7 @@ @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public @NonNull SocketKeepalive createSocketKeepalive(@NonNull Network network, @NonNull Socket socket, - @NonNull Executor executor, + @NonNull @CallbackExecutor Executor executor, @NonNull Callback callback) { ParcelFileDescriptor dup; try { @@ -2424,6 +2535,26 @@ } /** + * Get the supported keepalive count for each transport configured in resource overlays. + * + * @return An array of supported keepalive count for each transport type. + * @hide + */ + @RequiresPermission(anyOf = { android.Manifest.permission.NETWORK_SETTINGS, + // CTS 13 used QUERY_ALL_PACKAGES to get the resource value, which was implemented + // as below in KeepaliveUtils. Also allow that permission so that KeepaliveUtils can + // use this method and avoid breaking released CTS. Apps that have this permission + // can query the resource themselves anyway. + android.Manifest.permission.QUERY_ALL_PACKAGES }) + public int[] getSupportedKeepalives() { + try { + return mService.getSupportedKeepalives(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Ensure that a network route exists to deliver traffic to the specified * host via the specified network interface. An attempt to add a route that * already exists is ignored, but treated as successful. @@ -4790,6 +4921,7 @@ @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}) public void registerSystemDefaultNetworkCallback(@NonNull NetworkCallback networkCallback, @NonNull Handler handler) { @@ -5382,9 +5514,9 @@ * @return {@code uid} if the connection is found and the app has permission to observe it * (e.g., if it is associated with the calling VPN app's VpnService tunnel) or {@link * android.os.Process#INVALID_UID} if the connection is not found. - * @throws {@link SecurityException} if the caller is not the active VpnService for the current + * @throws SecurityException if the caller is not the active VpnService for the current * user. - * @throws {@link IllegalArgumentException} if an unsupported protocol is requested. + * @throws IllegalArgumentException if an unsupported protocol is requested. */ public int getConnectionOwnerUid( int protocol, @NonNull InetSocketAddress local, @NonNull InetSocketAddress remote) { @@ -5924,6 +6056,30 @@ } /** + * Get firewall rule of specified firewall chain on specified uid. + * + * @param chain target chain. + * @param uid target uid + * @return either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY + * @throws UnsupportedOperationException if called on pre-T devices. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + * @hide + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_STACK, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK + }) + public int getUidFirewallRule(@FirewallChain final int chain, final int uid) { + try { + return mService.getUidFirewallRule(chain, uid); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Enables or disables the specified firewall chain. * * @param chain target chain. @@ -5992,4 +6148,13 @@ throw e.rethrowFromSystemServer(); } } + + /** @hide */ + public IBinder getCompanionDeviceManagerProxyService() { + try { + return mService.getCompanionDeviceManagerProxyService(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } }
diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java index 822e67d..67dacb8 100644 --- a/framework/src/android/net/ConnectivitySettingsManager.java +++ b/framework/src/android/net/ConnectivitySettingsManager.java
@@ -28,6 +28,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Context; +import android.content.pm.PackageManager; import android.net.ConnectivityManager.MultipathPreference; import android.os.Binder; import android.os.Build; @@ -36,6 +37,7 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; +import android.util.Log; import android.util.Range; import com.android.net.module.util.ConnectivitySettingsUtils; @@ -55,6 +57,7 @@ */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public class ConnectivitySettingsManager { + private static final String TAG = ConnectivitySettingsManager.class.getSimpleName(); private ConnectivitySettingsManager() {} @@ -696,10 +699,20 @@ /** * Set global http proxy settings from given {@link ProxyInfo}. * + * <p class="note"> + * While a {@link ProxyInfo} for a PAC proxy can be specified, not all devices support + * PAC proxies. In particular, smaller devices like watches often do not have the capabilities + * necessary to interpret the PAC file. In such cases, calling this API with a PAC proxy + * results in undefined behavior, including possibly breaking networking for applications. + * You can test for this by checking for the presence of {@link PackageManager.FEATURE_WEBVIEW}. + * </p> + * * @param context The {@link Context} to set the setting. * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from * {@link ProxyInfo#buildPacProxy(Uri)} or * {@link ProxyInfo#buildDirectProxy(String, int, List)} + * @throws UnsupportedOperationException if |proxyInfo| codes for a PAC proxy but the system + * does not support PAC proxies. */ public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) { final String host = proxyInfo.getHost(); @@ -707,6 +720,14 @@ final String exclusionList = proxyInfo.getExclusionListAsString(); final String pacFileUrl = proxyInfo.getPacFileUrl().toString(); + + if (!TextUtils.isEmpty(pacFileUrl)) { + final PackageManager pm = context.getPackageManager(); + if (null != pm && !pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) { + Log.wtf(TAG, "PAC proxy can't be installed on a device without FEATURE_WEBVIEW"); + } + } + if (TextUtils.isEmpty(pacFileUrl)) { Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host); Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl index 29fea00..ebe8bca 100644 --- a/framework/src/android/net/IConnectivityManager.aidl +++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -188,12 +188,14 @@ void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId, int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr, - String dstAddr); + String dstAddr, boolean automaticOnOffKeepalives, in Network underpinnedNetwork); void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds, in ISocketKeepaliveCallback cb); - void stopKeepalive(in Network network, int slot); + void stopKeepalive(in ISocketKeepaliveCallback cb); + + int[] getSupportedKeepalives(); String getCaptivePortalServerUrl(); @@ -242,9 +244,17 @@ void setUidFirewallRule(int chain, int uid, int rule); + int getUidFirewallRule(int chain, int uid); + void setFirewallChainEnabled(int chain, boolean enable); boolean getFirewallChainEnabled(int chain); void replaceFirewallChain(int chain, in int[] uids); + + IBinder getCompanionDeviceManagerProxyService(); + + void setVpnNetworkPreference(String session, in UidRange[] ranges); + + void setTestLowTcpPollingTimerForKeepalive(long timeMs); }
diff --git a/framework/src/android/net/ISocketKeepaliveCallback.aidl b/framework/src/android/net/ISocketKeepaliveCallback.aidl index 020fbca..0a1de6c 100644 --- a/framework/src/android/net/ISocketKeepaliveCallback.aidl +++ b/framework/src/android/net/ISocketKeepaliveCallback.aidl
@@ -24,11 +24,15 @@ oneway interface ISocketKeepaliveCallback { /** The keepalive was successfully started. */ - void onStarted(int slot); + void onStarted(); /** The keepalive was successfully stopped. */ void onStopped(); /** The keepalive was stopped because of an error. */ void onError(int error); /** The keepalive on a TCP socket was stopped because the socket received data. */ void onDataReceived(); + /** The keepalive was paused by the system because it's not necessary right now. */ + void onPaused(); + /** The keepalive was resumed by the system after being suspended. */ + void onResumed(); }
diff --git a/framework/src/android/net/LinkAddress.java b/framework/src/android/net/LinkAddress.java index d48b8c7..90f55b3 100644 --- a/framework/src/android/net/LinkAddress.java +++ b/framework/src/android/net/LinkAddress.java
@@ -487,17 +487,23 @@ */ @SystemApi public boolean isGlobalPreferred() { - /** - * Note that addresses flagged as IFA_F_OPTIMISTIC are - * simultaneously flagged as IFA_F_TENTATIVE (when the tentative - * state has cleared either DAD has succeeded or failed, and both - * flags are cleared regardless). - */ - int flags = getFlags(); return (scope == RT_SCOPE_UNIVERSE && !isIpv6ULA() - && (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L - && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L)); + && isPreferred()); + } + + /** + * Checks if the address is a preferred address. + * + * @hide + */ + public boolean isPreferred() { + // Note that addresses flagged as IFA_F_OPTIMISTIC are simultaneously flagged as + // IFA_F_TENTATIVE (when the tentative state has cleared either DAD has succeeded or + // failed, and both flags are cleared regardless). + int flags = getFlags(); + return (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L + && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L); } /**
diff --git a/framework/src/android/net/LinkProperties.java b/framework/src/android/net/LinkProperties.java index b7ee846..9fb9bc6 100644 --- a/framework/src/android/net/LinkProperties.java +++ b/framework/src/android/net/LinkProperties.java
@@ -16,19 +16,18 @@ package android.net; +import static android.net.connectivity.ConnectivityCompatChanges.EXCLUDED_ROUTES; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.compat.CompatChanges; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; -import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.LinkPropertiesUtils; @@ -58,17 +57,6 @@ * */ public final class LinkProperties implements Parcelable { - /** - * The {@link #getRoutes()} now can contain excluded as well as included routes. Use - * {@link RouteInfo#getType()} to determine route type. - * - * @hide - */ - @ChangeId - @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) - @VisibleForTesting - public static final long EXCLUDED_ROUTES = 186082280; - // The interface described by the network link. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private String mIfaceName; @@ -1468,6 +1456,10 @@ * @hide */ public boolean isIdenticalPcscfs(@NonNull LinkProperties target) { + // Per 3GPP TS 24.229, B.2.2.1 PDP context activation and P-CSCF discovery + // list order is important, so on U+ compare one by one + if (SdkLevel.isAtLeastU()) return target.getPcscfServers().equals(mPcscfs); + // but for safety old behaviour on pre-U: Collection<InetAddress> targetPcscfs = target.getPcscfServers(); return (mPcscfs.size() == targetPcscfs.size()) ? mPcscfs.containsAll(targetPcscfs) : false;
diff --git a/framework/src/android/net/NattSocketKeepalive.java b/framework/src/android/net/NattSocketKeepalive.java index 56cc923..a83b5b4 100644 --- a/framework/src/android/net/NattSocketKeepalive.java +++ b/framework/src/android/net/NattSocketKeepalive.java
@@ -47,13 +47,42 @@ mResourceId = resourceId; } + /** + * Request that keepalive be started with the given {@code intervalSec}. + * + * When a VPN is running with the network for this keepalive as its underlying network, the + * system can monitor the TCP connections on that VPN to determine whether this keepalive is + * necessary. To enable this behavior, pass {@link SocketKeepalive#FLAG_AUTOMATIC_ON_OFF} into + * the flags. When this is enabled, the system will disable sending keepalive packets when + * there are no TCP connections over the VPN(s) running over this network to save battery, and + * restart sending them as soon as any TCP connection is opened over one of the VPN networks. + * When no VPN is running on top of this network, this flag has no effect, i.e. the keepalives + * are always sent with the specified interval. + * + * Also {@see SocketKeepalive}. + * + * @param intervalSec The target interval in seconds between keepalive packet transmissions. + * The interval should be between 10 seconds and 3600 seconds. Otherwise, + * the supplied {@link Callback} will see a call to + * {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}. + * @param flags Flags to enable/disable available options on this keepalive. + * @param underpinnedNetwork The underpinned network of this keepalive. + * + * @hide + */ @Override - protected void startImpl(int intervalSec) { + protected void startImpl(int intervalSec, int flags, Network underpinnedNetwork) { + if (0 != (flags & ~FLAG_AUTOMATIC_ON_OFF)) { + throw new IllegalArgumentException("Illegal flag value for " + + this.getClass().getSimpleName() + " : " + flags); + } + final boolean automaticOnOffKeepalives = 0 != (flags & FLAG_AUTOMATIC_ON_OFF); mExecutor.execute(() -> { try { mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId, - intervalSec, mCallback, - mSource.getHostAddress(), mDestination.getHostAddress()); + intervalSec, mCallback, mSource.getHostAddress(), + mDestination.getHostAddress(), automaticOnOffKeepalives, + underpinnedNetwork); } catch (RemoteException e) { Log.e(TAG, "Error starting socket keepalive: ", e); throw e.rethrowFromSystemServer(); @@ -65,9 +94,7 @@ protected void stopImpl() { mExecutor.execute(() -> { try { - if (mSlot != null) { - mService.stopKeepalive(mNetwork, mSlot); - } + mService.stopKeepalive(mCallback); } catch (RemoteException e) { Log.e(TAG, "Error stopping socket keepalive: ", e); throw e.rethrowFromSystemServer();
diff --git a/framework/src/android/net/NetworkAgent.java b/framework/src/android/net/NetworkAgent.java index 1486619..177f7e3 100644 --- a/framework/src/android/net/NetworkAgent.java +++ b/framework/src/android/net/NetworkAgent.java
@@ -283,7 +283,6 @@ * arg2 = interval in seconds * obj = KeepalivePacketData object describing the data to be sent * - * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. * @hide */ public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11; @@ -291,7 +290,9 @@ /** * Requests that the specified keepalive packet be stopped. * - * arg1 = hardware slot number of the keepalive to stop. + * arg1 = unused + * arg2 = error code (SUCCESS) + * obj = callback to identify the keepalive * * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. * @hide @@ -434,6 +435,14 @@ public static final int CMD_DSCP_POLICY_STATUS = BASE + 28; /** + * Sent by the NetworkAgent to ConnectivityService to notify that this network is expected to be + * replaced within the specified time by a similar network. + * arg1 = timeout in milliseconds + * @hide + */ + public static final int EVENT_UNREGISTER_AFTER_REPLACEMENT = BASE + 29; + + /** * DSCP policy was successfully added. */ public static final int DSCP_POLICY_STATUS_SUCCESS = 0; @@ -475,14 +484,6 @@ @Retention(RetentionPolicy.SOURCE) public @interface DscpPolicyStatus {} - /** - * Sent by the NetworkAgent to ConnectivityService to notify that this network is expected to be - * replaced within the specified time by a similar network. - * arg1 = timeout in milliseconds - * @hide - */ - public static final int EVENT_UNREGISTER_AFTER_REPLACEMENT = BASE + 29; - private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) { final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType, config.legacyTypeName, config.legacySubTypeName);
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java index e07601f..92e9599 100644 --- a/framework/src/android/net/NetworkCapabilities.java +++ b/framework/src/android/net/NetworkCapabilities.java
@@ -18,6 +18,7 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import static com.android.net.module.util.BitUtils.appendStringRepresentationOfBitMaskToStringBuilder; +import static com.android.net.module.util.BitUtils.describeDifferences; import android.annotation.IntDef; import android.annotation.LongDef; @@ -52,18 +53,70 @@ import java.util.StringJoiner; /** - * Representation of the capabilities of an active network. Instances are - * typically obtained through - * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} - * or {@link ConnectivityManager#getNetworkCapabilities(Network)}. - * <p> - * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of - * network selection. Rather than indicate a need for Wi-Fi because an - * application needs high bandwidth and risk obsolescence when a new, fast - * network appears (like LTE), the application should specify it needs high - * bandwidth. Similarly if an application needs an unmetered network for a bulk - * transfer it can specify that rather than assuming all cellular based - * connections are metered and all Wi-Fi based connections are not. + * Representation of the capabilities of an active network. + * + * <p>@see <a href="https://developer.android.com/training/basics/network-ops/reading-network-state> + * this general guide</a> on how to use NetworkCapabilities and related classes. + * + * <p>NetworkCapabilities represent what a network can do and what its + * characteristics are like. The principal attribute of NetworkCapabilities + * is in the capabilities bits, which are checked with + * {@link #hasCapability(int)}. See the list of capabilities and each + * capability for a description of what it means. + * + * <p>Some prime examples include {@code NET_CAPABILITY_MMS}, which means that the + * network is capable of sending MMS. A network without this capability + * is not capable of sending MMS. + * <p>The {@code NET_CAPABILITY_INTERNET} capability means that the network is + * configured to reach the general Internet. It may or may not actually + * provide connectivity ; the {@code NET_CAPABILITY_VALIDATED} bit indicates that + * the system found actual connectivity to the general Internet the last + * time it checked. Apps interested in actual connectivity should usually + * look at both these capabilities. + * <p>The {@code NET_CAPABILITY_NOT_METERED} capability is set for networks that + * do not bill the user for consumption of bytes. Applications are + * encouraged to consult this to determine appropriate usage, and to + * limit usage of metered network where possible, including deferring + * big downloads until such a time that an unmetered network is connected. + * Also see {@link android.app.job.JobScheduler} to help with scheduling such + * downloads, in particular + * {@link android.app.job.JobInfo.Builder#setRequiredNetwork(NetworkRequest)}. + * <p>NetworkCapabilities contain a number of other capabilities that + * represent what modern networks can and can't do. Look up the individual + * capabilities in this class to learn about each of them. + * + * <p>NetworkCapabilities typically represent attributes that can apply to + * any network. The attributes that apply only to specific transports like + * cellular or Wi-Fi can be found in the specifier (for requestable attributes) + * or in the transport info (for non-requestable ones). See + * {@link #getNetworkSpecifier} and {@link #getTransportInfo}. An app would + * downcast these to the specific class for the transport they need if they + * are interested in transport-specific attributes. Also see + * {@link android.net.wifi.WifiNetworkSpecifier} or + * {@link android.net.wifi.WifiInfo} for some examples of each of these. + * + * <p>NetworkCapabilities also contains other attributes like the estimated + * upstream and downstream bandwidth and the specific transport of that + * network (e.g. {@link #TRANSPORT_CELLULAR}). Generally, apps should normally + * have little reason to check for the type of transport ; for example, to + * query whether a network costs money to the user, do not look at the + * transport, but instead look at the absence or presence of + * {@link #NET_CAPABILITY_NOT_METERED} which will correctly account for + * metered Wi-Fis and free of charge cell connections. + * + * <p>The system communicates with apps about connected networks and uses + * NetworkCapabilities to express these capabilities about these networks. + * Apps should register callbacks with the {@link ConnectivityManager#requestNetwork} + * or {@link ConnectivityManager#registerNetworkCallback} family of methods + * to learn about the capabilities of a network on a continuous basis + * and be able to react to changes to capabilities. For quick debugging Android also + * provides {@link ConnectivityManager#getNetworkCapabilities(Network)}, + * but the dynamic nature of networking makes this ill-suited to production + * code since capabilities obtained in this way can go stale immediately. + * + * <p>Also see {@link NetworkRequest} which uses the same capabilities + * together with {@link ConnectivityManager#requestNetwork} for how to + * request the system brings up the kind of network your application needs. */ public final class NetworkCapabilities implements Parcelable { private static final String TAG = "NetworkCapabilities"; @@ -621,11 +674,19 @@ /** * Indicates that this network should be able to prioritize latency for the internet. + * + * Starting with {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, requesting this capability with + * {@link ConnectivityManager#requestNetwork} requires declaration in the self-certified + * network capabilities. See {@link NetworkRequest} for the self-certification documentation. */ public static final int NET_CAPABILITY_PRIORITIZE_LATENCY = 34; /** * Indicates that this network should be able to prioritize bandwidth for the internet. + * + * Starting with {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, requesting this capability with + * {@link ConnectivityManager#requestNetwork} requires declaration in the self-certified + * network capabilities. See {@link NetworkRequest} for the self-certification documentation. */ public static final int NET_CAPABILITY_PRIORITIZE_BANDWIDTH = 35; @@ -696,10 +757,10 @@ NET_CAPABILITY_PARTIAL_CONNECTIVITY); /** - * Capabilities that are allowed for test networks. This list must be set so that it is safe - * for an unprivileged user to create a network with these capabilities via shell. As such, - * it must never contain capabilities that are generally useful to the system, such as - * INTERNET, IMS, SUPL, etc. + * Capabilities that are allowed for all test networks. This list must be set so that it is safe + * for an unprivileged user to create a network with these capabilities via shell. As such, it + * must never contain capabilities that are generally useful to the system, such as INTERNET, + * IMS, SUPL, etc. */ private static final long TEST_NETWORKS_ALLOWED_CAPABILITIES = BitUtils.packBitList( @@ -713,6 +774,14 @@ NET_CAPABILITY_NOT_VCN_MANAGED); /** + * Extra allowed capabilities for test networks that do not have TRANSPORT_CELLULAR. Test + * networks with TRANSPORT_CELLULAR must not have those capabilities in order to mitigate + * the risk of being used by running apps. + */ + private static final long TEST_NETWORKS_EXTRA_ALLOWED_CAPABILITIES_ON_NON_CELL = + BitUtils.packBitList(NET_CAPABILITY_CBS, NET_CAPABILITY_DUN, NET_CAPABILITY_RCS); + + /** * Adds the given capability to this {@code NetworkCapability} instance. * Note that when searching for a network to satisfy a request, all capabilities * requested must be satisfied. @@ -1065,14 +1134,22 @@ mTransportTypes = (originalTransportTypes & UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS) | (1 << TRANSPORT_TEST); - - // SubIds are only allowed for Test Networks that only declare TRANSPORT_TEST. - setSubscriptionIds(originalSubIds); } else { // If the test network is restricted, then it may declare any transport. mTransportTypes = (originalTransportTypes | (1 << TRANSPORT_TEST)); } + + if (hasSingleTransport(TRANSPORT_TEST)) { + // SubIds are only allowed for Test Networks that only declare TRANSPORT_TEST. + setSubscriptionIds(originalSubIds); + } + mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES; + if (!hasTransport(TRANSPORT_CELLULAR)) { + mNetworkCapabilities |= + (originalCapabilities & TEST_NETWORKS_EXTRA_ALLOWED_CAPABILITIES_ON_NON_CELL); + } + mNetworkSpecifier = originalSpecifier; mSignalStrength = originalSignalStrength; mTransportInfo = originalTransportInfo; @@ -1109,6 +1186,7 @@ TRANSPORT_LOWPAN, TRANSPORT_TEST, TRANSPORT_USB, + TRANSPORT_THREAD, }) public @interface Transport { } @@ -1160,10 +1238,15 @@ */ public static final int TRANSPORT_USB = 8; + /** + * Indicates this network uses a Thread transport. + */ + public static final int TRANSPORT_THREAD = 9; + /** @hide */ public static final int MIN_TRANSPORT = TRANSPORT_CELLULAR; /** @hide */ - public static final int MAX_TRANSPORT = TRANSPORT_USB; + public static final int MAX_TRANSPORT = TRANSPORT_THREAD; private static final int ALL_VALID_TRANSPORTS; static { @@ -1188,7 +1271,8 @@ "WIFI_AWARE", "LOWPAN", "TEST", - "USB" + "USB", + "THREAD", }; /** @@ -1264,6 +1348,18 @@ } /** + * Gets the transports as an int. Internal callers only. + * + * Prefer getTransportTypes/hasTransportType if not immediately collapsing back into a scalar. + * + * @return a long integer representing the transport types. + * @hide + */ + public long getTransportTypesInternal() { + return mTransportTypes; + } + + /** * Sets all the transports set on this {@code NetworkCapability} instance. * This overwrites any existing transports. * @@ -2069,30 +2165,14 @@ * Returns a short but human-readable string of updates from an older set of capabilities. * @param old the old capabilities to diff from * @return a string fit for logging differences, or null if no differences. - * this never returns the empty string. + * this never returns the empty string. See BitUtils#describeDifferences. * @hide */ @Nullable public String describeCapsDifferencesFrom(@Nullable final NetworkCapabilities old) { final long oldCaps = null == old ? 0 : old.mNetworkCapabilities; - final long changed = oldCaps ^ mNetworkCapabilities; - if (0 == changed) return null; - // If the control reaches here, there are changes (additions, removals, or both) so - // the code below is guaranteed to add something to the string and can't return "". - final long removed = oldCaps & changed; - final long added = mNetworkCapabilities & changed; - final StringBuilder sb = new StringBuilder(); - if (0 != removed) { - sb.append("-"); - appendStringRepresentationOfBitMaskToStringBuilder(sb, removed, - NetworkCapabilities::capabilityNameOf, "-"); - } - if (0 != added) { - sb.append("+"); - appendStringRepresentationOfBitMaskToStringBuilder(sb, added, - NetworkCapabilities::capabilityNameOf, "+"); - } - return sb.toString(); + return describeDifferences(oldCaps, mNetworkCapabilities, + NetworkCapabilities::capabilityNameOf); } /**
diff --git a/framework/src/android/net/NetworkInfo.java b/framework/src/android/net/NetworkInfo.java index b7ec519..7aa9847 100644 --- a/framework/src/android/net/NetworkInfo.java +++ b/framework/src/android/net/NetworkInfo.java
@@ -334,6 +334,24 @@ } /** + * Indicates whether this network is suspended. + * @deprecated Apps should instead use the + * {@link android.net.ConnectivityManager.NetworkCallback} API to + * learn about connectivity changes. See + * {@link ConnectivityManager#registerDefaultNetworkCallback} and + * {@link ConnectivityManager#registerNetworkCallback}. These will + * give a more accurate picture of the connectivity state of + * the device and let apps react more easily and quickly to changes. + * @hide + */ + @Deprecated + public boolean isSuspended() { + synchronized (this) { + return mState == State.SUSPENDED; + } + } + + /** * Indicates whether network connectivity is possible. A network is unavailable * when a persistent or semi-persistent condition prevents the possibility * of connecting to that network. Examples include
diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java index b7a6076..6c351d0 100644 --- a/framework/src/android/net/NetworkRequest.java +++ b/framework/src/android/net/NetworkRequest.java
@@ -54,9 +54,92 @@ import java.util.Set; /** - * Defines a request for a network, made through {@link NetworkRequest.Builder} and used - * to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes - * via {@link ConnectivityManager#registerNetworkCallback}. + * An object describing a network that the application is interested in. + * + * <p>@see <a href="https://developer.android.com/training/basics/network-ops/reading-network-state> + * this general guide</a> on how to use NetworkCapabilities and related classes. + * + * NetworkRequest defines a request for a network, made through + * {@link NetworkRequest.Builder} and used to request a network via + * {@link ConnectivityManager#requestNetwork} or to listen for changes + * via the {@link ConnectivityManager#registerNetworkCallback} family of + * functions. + * + * <p>{@link ConnectivityManager#requestNetwork} will try to find a connected + * network matching the NetworkRequest, and return it if there is one. + * As long as the request is outstanding, the system will try to find the best + * possible network that matches the request. The request will keep up the + * currently best connected network, and if a better one is found (e.g. cheaper + * or faster) the system will bring up that better network to better serve the + * request. A request filed with {@link ConnectivityManager#requestNetwork} will + * only match one network at a time (the one the system thinks is best), even if + * other networks can match the request that are being kept up by other requests. + * + * For example, an application needing a network with + * {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} should use + * {@link ConnectivityManager#requestNetwork} to request the system keeps one up. + * A general cellular network can satisfy this request, but if the system finds + * a free Wi-Fi network which is expected to be faster, it will try and connect + * to that Wi-Fi network and switch the request over to it once it is connected. + * The cell network may stay connected if there are outstanding requests (from + * the same app or from other apps on the system) that match the cell network + * but not the Wi-Fi network, such as a request with {@link NetworkCapabilities#NET_CAPABILITY_MMS}. + * + * When a network is no longer needed to serve any request, the system can + * tear it down at any time and usually does so immediately, so make sure to + * keep up requests for the networks your app needs. + * + * <p>By contrast, requests filed with {@link ConnectivityManager#registerNetworkCallback} + * will receive callbacks for all matching networks, and will not cause the system to + * keep up the networks they match. Use this to listen to networks that the device is + * connected to, but that you don't want the system to keep up for your use case. + * + * <p>Applications build a NetworkRequest and pass it to one of the + * {@link ConnectivityManager} methods above together with a + * {@link ConnectivityManager.NetworkCallback} object. The callback + * will then start receiving method calls about networks that match + * the request. + * + * <p>Networks are brought up and/or matched according to the capabilities + * set in the builder. For example, a request with + * {@link NetworkCapabilities#NET_CAPABILITY_MMS} lets the system match + * and/or bring up a network that is capable to send MMS. A request with + * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} matches a network + * that doesn't charge the user for usage. See + * {@link NetworkCapabilities} for a list of capabilities and their + * description. + * + * <p>While all capabilities can be matched with the + * {@link ConnectivityManager#registerNetworkCallback} family of methods, + * not all capabilities can be used to request that the system brings + * up a network with {@link ConnectivityManager#requestNetwork}. For example, + * an application cannot use {@link ConnectivityManager#requestNetwork} to + * ask the system to bring up a network with + * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}, because the + * system won't know if a network has a captive portal before it connects + * to that network. Similarly, some capabilities may require a specific + * permission or privilege to be requested. + * + * Look up the specific capability and the {@link ConnectivityManager#requestNetwork} + * method for limitations applicable to each capability. + * + * <p>Also, starting with {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, some capabilities + * require the application to self-certify by explicitly adding the + * {@link android.content.pm.PackageManager#PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES} + * property in the AndroidManifest.xml, which points to an XML resource file. In the + * XML resource file, the application declares what kind of network capabilities the application + * wants to have. + * + * Here is an example self-certification XML resource file : + * <pre> + * {@code + * <network-capabilities-declaration xmlns:android="http://schemas.android.com/apk/res/android"> + * <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_LATENCY"/> + * <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_BANDWIDTH"/> + * </network-capabilities-declaration> + * } + * </pre> + * Look up the specific capability to learn whether its usage requires this self-certification. */ public class NetworkRequest implements Parcelable { /**
diff --git a/framework/src/android/net/SocketKeepalive.java b/framework/src/android/net/SocketKeepalive.java index 57cf5e3..f915e72 100644 --- a/framework/src/android/net/SocketKeepalive.java +++ b/framework/src/android/net/SocketKeepalive.java
@@ -16,6 +16,8 @@ package android.net; +import static android.annotation.SystemApi.Client.PRIVILEGED_APPS; + import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -63,6 +65,12 @@ public static final int SUCCESS = 0; /** + * Success when trying to suspend. + * @hide + */ + public static final int SUCCESS_PAUSED = 1; + + /** * No keepalive. This should only be internally as it indicates There is no keepalive. * It should not propagate to applications. * @hide @@ -141,9 +149,7 @@ public static final int ERROR_INSUFFICIENT_RESOURCES = -32; /** - * There was no such slot. This should only be internally as it indicates - * a programming error in the system server. It should not propagate to - * applications. + * There was no such slot, or no keepalive running on this slot. * @hide */ @SystemApi @@ -174,6 +180,27 @@ public @interface KeepaliveEvent {} /** + * Whether the system automatically toggles keepalive when no TCP connection is open on the VPN. + * + * If this flag is present, the system will monitor the VPN(s) running on top of the specified + * network for open TCP connections. When no such connections are open, it will turn off the + * keepalives to conserve battery power. When there is at least one such connection it will + * turn on the keepalives to make sure functionality is preserved. + * + * This only works with {@link NattSocketKeepalive}. + * @hide + */ + @SystemApi + public static final int FLAG_AUTOMATIC_ON_OFF = 1 << 0; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "FLAG_"}, flag = true, value = { + FLAG_AUTOMATIC_ON_OFF + }) + public @interface StartFlags {} + + /** * The minimum interval in seconds between keepalive packet transmissions. * * @hide @@ -226,9 +253,6 @@ @NonNull protected final Executor mExecutor; /** @hide */ @NonNull protected final ISocketKeepaliveCallback mCallback; - // TODO: remove slot since mCallback could be used to identify which keepalive to stop. - /** @hide */ - @Nullable protected Integer mSlot; /** @hide */ public SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network, @@ -240,11 +264,10 @@ mExecutor = executor; mCallback = new ISocketKeepaliveCallback.Stub() { @Override - public void onStarted(int slot) { + public void onStarted() { final long token = Binder.clearCallingIdentity(); try { mExecutor.execute(() -> { - mSlot = slot; callback.onStarted(); }); } finally { @@ -253,11 +276,22 @@ } @Override + public void onResumed() { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + callback.onResumed(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override public void onStopped() { final long token = Binder.clearCallingIdentity(); try { executor.execute(() -> { - mSlot = null; callback.onStopped(); }); } finally { @@ -266,11 +300,22 @@ } @Override + public void onPaused() { + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + callback.onPaused(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override public void onError(int error) { final long token = Binder.clearCallingIdentity(); try { executor.execute(() -> { - mSlot = null; callback.onError(error); }); } finally { @@ -283,7 +328,6 @@ final long token = Binder.clearCallingIdentity(); try { executor.execute(() -> { - mSlot = null; callback.onDataReceived(); }); } finally { @@ -294,13 +338,15 @@ } /** - * Request that keepalive be started with the given {@code intervalSec}. See - * {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception - * when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be - * thrown into the {@code executor}. This is typically not important to catch because the remote - * party is the system, so if it is not in shape to communicate through binder the system is - * probably going down anyway. If the caller cares regardless, it can use a custom - * {@link Executor} to catch the {@link RemoteException}. + * Request that keepalive be started with the given {@code intervalSec}. + * + * See {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an + * exception when invoking start or stop of the {@link SocketKeepalive}, a + * {@link RuntimeException} caused by a {@link RemoteException} will be thrown into the + * {@link Executor}. This is typically not important to catch because the remote party is + * the system, so if it is not in shape to communicate through binder the system is going + * down anyway. If the caller still cares, it can use a custom {@link Executor} to catch the + * {@link RuntimeException}. * * @param intervalSec The target interval in seconds between keepalive packet transmissions. * The interval should be between 10 seconds and 3600 seconds, otherwise @@ -308,11 +354,39 @@ */ public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC) int intervalSec) { - startImpl(intervalSec); + startImpl(intervalSec, 0 /* flags */, null /* underpinnedNetwork */); + } + + /** + * Request that keepalive be started with the given {@code intervalSec}. + * + * See {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an + * exception when invoking start or stop of the {@link SocketKeepalive}, a + * {@link RuntimeException} caused by a {@link RemoteException} will be thrown into the + * {@link Executor}. This is typically not important to catch because the remote party is + * the system, so if it is not in shape to communicate through binder the system is going + * down anyway. If the caller still cares, it can use a custom {@link Executor} to catch the + * {@link RuntimeException}. + * + * @param intervalSec The target interval in seconds between keepalive packet transmissions. + * The interval should be between 10 seconds and 3600 seconds. Otherwise, + * the supplied {@link Callback} will see a call to + * {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}. + * @param flags Flags to enable/disable available options on this keepalive. + * @param underpinnedNetwork an optional network running over mNetwork that this + * keepalive is intended to keep up, e.g. an IPSec + * tunnel running over mNetwork. + * @hide + */ + @SystemApi(client = PRIVILEGED_APPS) + public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC) + int intervalSec, @StartFlags int flags, @Nullable Network underpinnedNetwork) { + startImpl(intervalSec, flags, underpinnedNetwork); } /** @hide */ - protected abstract void startImpl(int intervalSec); + protected abstract void startImpl(int intervalSec, @StartFlags int flags, + Network underpinnedNetwork); /** * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped} @@ -346,8 +420,18 @@ public static class Callback { /** The requested keepalive was successfully started. */ public void onStarted() {} + /** + * The keepalive was resumed by the system after being suspended. + * @hide + **/ + public void onResumed() {} /** The keepalive was successfully stopped. */ public void onStopped() {} + /** + * The keepalive was paused by the system because it's not necessary right now. + * @hide + **/ + public void onPaused() {} /** An error occurred. */ public void onError(@ErrorCode int error) {} /** The keepalive on a TCP socket was stopped because the socket received data. This is
diff --git a/framework/src/android/net/TcpSocketKeepalive.java b/framework/src/android/net/TcpSocketKeepalive.java index 7131784..696889f 100644 --- a/framework/src/android/net/TcpSocketKeepalive.java +++ b/framework/src/android/net/TcpSocketKeepalive.java
@@ -50,7 +50,17 @@ * acknowledgement. */ @Override - protected void startImpl(int intervalSec) { + protected void startImpl(int intervalSec, int flags, Network underpinnedNetwork) { + if (0 != flags) { + throw new IllegalArgumentException("Illegal flag value for " + + this.getClass().getSimpleName() + " : " + flags); + } + + if (underpinnedNetwork != null) { + throw new IllegalArgumentException("Illegal underpinned network for " + + this.getClass().getSimpleName() + " : " + underpinnedNetwork); + } + mExecutor.execute(() -> { try { mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback); @@ -65,9 +75,7 @@ protected void stopImpl() { mExecutor.execute(() -> { try { - if (mSlot != null) { - mService.stopKeepalive(mNetwork, mSlot); - } + mService.stopKeepalive(mCallback); } catch (RemoteException e) { Log.e(TAG, "Error stopping packet keepalive: ", e); throw e.rethrowFromSystemServer();
diff --git a/framework/src/android/net/TestNetworkManager.java b/framework/src/android/net/TestNetworkManager.java index b64299f..416c6de 100644 --- a/framework/src/android/net/TestNetworkManager.java +++ b/framework/src/android/net/TestNetworkManager.java
@@ -260,7 +260,7 @@ /** * Create a tap interface with or without carrier for testing purposes. * - * Note: setting carrierUp = false is not supported until kernel version 5.0. + * Note: setting carrierUp = false is not supported until kernel version 6.0. * * @param carrierUp whether the created interface has a carrier or not. * @param bringUp whether to bring up the interface before returning it. @@ -280,6 +280,8 @@ /** * Create a tap interface for testing purposes. * + * Note: setting carrierUp = false is not supported until kernel version 6.0. + * * @param carrierUp whether the created interface has a carrier or not. * @param bringUp whether to bring up the interface before returning it. * @param disableIpv6ProvisioningDelay whether to disable DAD and RS delay.
diff --git a/framework/src/android/net/VpnTransportInfo.java b/framework/src/android/net/VpnTransportInfo.java index ebad477..6bb00c8 100644 --- a/framework/src/android/net/VpnTransportInfo.java +++ b/framework/src/android/net/VpnTransportInfo.java
@@ -52,6 +52,8 @@ private final boolean mBypassable; + private final boolean mLongLivedTcpConnectionsExpensive; + // TODO: Refer to Build.VERSION_CODES when it's available in every branch. private static final int UPSIDE_DOWN_CAKE = 34; @@ -70,11 +72,12 @@ @SystemApi(client = MODULE_LIBRARIES) public VpnTransportInfo makeCopy(@RedactionType long redactions) { return new VpnTransportInfo(mType, - ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : mSessionId, mBypassable); + ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : mSessionId, + mBypassable, mLongLivedTcpConnectionsExpensive); } /** - * @deprecated please use {@link VpnTransportInfo(int,String,boolean)} instead. + * @deprecated please use {@link VpnTransportInfo(int,String,boolean,boolean)}. * @hide */ @Deprecated @@ -83,17 +86,22 @@ // When the module runs on older SDKs, |bypassable| will always be false since the old Vpn // code will call this constructor. For Settings VPNs, this is always correct as they are // never bypassable. For VpnManager and VpnService types, this may be wrong since both of - // them have a choice. However, on these SDKs VpnTransportInfo#getBypassable is not + // them have a choice. However, on these SDKs VpnTransportInfo#isBypassable is not // available anyway, so this should be harmless. False is a better choice than true here // regardless because it is the default value for both VpnManager and VpnService if the app // does not do anything about it. - this(type, sessionId, false /* bypassable */); + this(type, sessionId, false /* bypassable */, false /* longLivedTcpConnectionsExpensive */); } - public VpnTransportInfo(int type, @Nullable String sessionId, boolean bypassable) { + /** + * Construct a new VpnTransportInfo object. + */ + public VpnTransportInfo(int type, @Nullable String sessionId, boolean bypassable, + boolean longLivedTcpConnectionsExpensive) { this.mType = type; this.mSessionId = sessionId; this.mBypassable = bypassable; + this.mLongLivedTcpConnectionsExpensive = longLivedTcpConnectionsExpensive; } /** @@ -103,7 +111,7 @@ * {@code UnsupportedOperationException} if called. */ @RequiresApi(UPSIDE_DOWN_CAKE) - public boolean getBypassable() { + public boolean isBypassable() { if (!SdkLevel.isAtLeastU()) { throw new UnsupportedOperationException("Not supported before U"); } @@ -112,6 +120,37 @@ } /** + * Returns whether long-lived TCP connections are expensive on the VPN network. + * + * If there are long-lived TCP connections over the VPN, over some networks the + * VPN needs to regularly send packets to keep the network alive to keep these + * connections working, which wakes up the device radio. On some networks, this + * can become extremely expensive in terms of battery. The system knows to send + * these keepalive packets only when necessary, i.e. when there are long-lived + * TCP connections opened over the VPN, meaning on these networks establishing + * a long-lived TCP connection will have a very noticeable impact on battery + * life. + * + * VPNs can be bypassable or not. When the VPN is not bypassable, the user has + * expressed explicit intent to have no connection outside of the VPN, so even + * privileged apps with permission to bypass non-bypassable VPNs should not do + * so. See {@link #isBypassable()}. + * For bypassable VPNs however, the user expects apps choose reasonable tradeoffs + * about whether they use the VPN. + * + * Components that establish long-lived, encrypted TCP connections are encouraged + * to look up this value to decide whether to open their connection over a VPN + * or to bypass it. While VPNs do not typically provide privacy or security + * benefits to encrypted connections, the user generally still expects the + * connections to choose to use the VPN by default, but also do not expect this + * comes at the price of drastically reduced battery life. This method provides + * a hint about whether the battery cost of opening such a connection is high. + */ + public boolean areLongLivedTcpConnectionsExpensive() { + return mLongLivedTcpConnectionsExpensive; + } + + /** * Returns the session Id of this VpnTransportInfo. * @hide */ @@ -134,18 +173,21 @@ VpnTransportInfo that = (VpnTransportInfo) o; return (this.mType == that.mType) && TextUtils.equals(this.mSessionId, that.mSessionId) - && (this.mBypassable == that.mBypassable); + && (this.mBypassable == that.mBypassable) + && (this.mLongLivedTcpConnectionsExpensive + == that.mLongLivedTcpConnectionsExpensive); } @Override public int hashCode() { - return Objects.hash(mType, mSessionId, mBypassable); + return Objects.hash(mType, mSessionId, mBypassable, mLongLivedTcpConnectionsExpensive); } @Override public String toString() { - return String.format("VpnTransportInfo{type=%d, sessionId=%s, bypassable=%b}", - mType, mSessionId, mBypassable); + return String.format("VpnTransportInfo{type=%d, sessionId=%s, bypassable=%b " + + "longLivedTcpConnectionsExpensive=%b}", + mType, mSessionId, mBypassable, mLongLivedTcpConnectionsExpensive); } @Override @@ -158,12 +200,14 @@ dest.writeInt(mType); dest.writeString(mSessionId); dest.writeBoolean(mBypassable); + dest.writeBoolean(mLongLivedTcpConnectionsExpensive); } public static final @NonNull Creator<VpnTransportInfo> CREATOR = new Creator<VpnTransportInfo>() { public VpnTransportInfo createFromParcel(Parcel in) { - return new VpnTransportInfo(in.readInt(), in.readString(), in.readBoolean()); + return new VpnTransportInfo( + in.readInt(), in.readString(), in.readBoolean(), in.readBoolean()); } public VpnTransportInfo[] newArray(int size) { return new VpnTransportInfo[size];
diff --git a/framework/src/android/net/apf/ApfCapabilities.java b/framework/src/android/net/apf/ApfCapabilities.java index 64f14a1..fae2499 100644 --- a/framework/src/android/net/apf/ApfCapabilities.java +++ b/framework/src/android/net/apf/ApfCapabilities.java
@@ -19,9 +19,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.content.Context; -import android.content.res.Resources; -import android.net.ConnectivityResources; import android.os.Parcel; import android.os.Parcelable; @@ -36,8 +33,6 @@ */ @SystemApi public final class ApfCapabilities implements Parcelable { - private static ConnectivityResources sResources; - /** * Version of APF instruction set supported for packet filtering. 0 indicates no support for * packet filtering using APF programs. @@ -67,15 +62,6 @@ apfPacketFormat = in.readInt(); } - @NonNull - private static synchronized ConnectivityResources getResources(@NonNull Context ctx) { - if (sResources == null) { - sResources = new ConnectivityResources(ctx); - } - return sResources; - } - - @Override public int describeContents() { return 0;
diff --git a/framework/src/android/net/connectivity/ConnectivityCompatChanges.java b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java new file mode 100644 index 0000000..dfe5867 --- /dev/null +++ b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
@@ -0,0 +1,89 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net.connectivity; + +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; +import android.compat.annotation.EnabledSince; +import android.os.Build; + +/** + * The class contains all CompatChanges for the Connectivity module. + * + * <p>This is the centralized place for the CompatChanges used in the Connectivity module. + * Putting all the CompatChanges in single place makes it possible to manage them under a single + * platform_compat_config. + * @hide + */ +public final class ConnectivityCompatChanges { + + /** + * The {@link android.net.LinkProperties#getRoutes()} now can contain excluded as well as + * included routes. Use {@link android.net.RouteInfo#getType()} to determine route type. + * + * @hide + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) + public static final long EXCLUDED_ROUTES = 186082280; + + /** + * When enabled, apps targeting < Android 12 are considered legacy for + * the NSD native daemon. + * The platform will only keep the daemon running as long as there are + * any legacy apps connected. + * + * After Android 12, direct communication with the native daemon might not work since the native + * daemon won't always stay alive. Using the NSD APIs from NsdManager as the replacement is + * recommended. + * Another alternative could be bundling your own mdns solutions instead of + * depending on the system mdns native daemon. + * + * This compatibility change applies to Android 13 and later only. To toggle behavior on + * Android 12 and Android 12L, use RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS. + * + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S) + // This was a platform change ID with value 191844585L before T + public static final long RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER = 235355681L; + + /** + * The self certified capabilities check should be enabled after android 13. + * + * <p> See {@link android.net.NetworkCapabilities} for more details. + * + * @hide + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + public static final long ENABLE_SELF_CERTIFIED_CAPABILITIES_DECLARATION = 266524688; + + /** + * Apps targeting < Android 14 use a legacy NSD backend. + * + * The legacy apps use a legacy native daemon as NsdManager backend, but other apps use a + * platform-integrated mDNS implementation as backend. + * + * @hide + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + public static final long ENABLE_PLATFORM_MDNS_BACKEND = 270306772L; + private ConnectivityCompatChanges() { + } +}
diff --git a/framework/src/android/net/connectivity/TiramisuConnectivityInternalApiUtil.java b/framework/src/android/net/connectivity/TiramisuConnectivityInternalApiUtil.java new file mode 100644 index 0000000..d65858f --- /dev/null +++ b/framework/src/android/net/connectivity/TiramisuConnectivityInternalApiUtil.java
@@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.connectivity; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.os.Build; +import android.os.IBinder; + +import androidx.annotation.RequiresApi; + +/** + * Utility providing limited access to module-internal APIs which are only available on Android T+, + * as this class is only in the bootclasspath on T+ as part of framework-connectivity. + * + * R+ module components like Tethering cannot depend on all hidden symbols from + * framework-connectivity. They only have access to stable API stubs where newer APIs can be + * accessed after an API level check (enforced by the linter), or to limited hidden symbols in this + * class which is also annotated with @RequiresApi (so API level checks are also enforced by the + * linter). + * @hide + */ +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +public class TiramisuConnectivityInternalApiUtil { + + /** + * Get a service binder token for + * {@link com.android.server.connectivity.wear.CompanionDeviceManagerProxyService}. + */ + public static IBinder getCompanionDeviceManagerProxyService(Context ctx) { + final ConnectivityManager cm = ctx.getSystemService(ConnectivityManager.class); + return cm.getCompanionDeviceManagerProxyService(); + } +}
diff --git a/framework/src/android/net/util/KeepaliveUtils.java b/framework/src/android/net/util/KeepaliveUtils.java index 8d7a0b3..07b8c45 100644 --- a/framework/src/android/net/util/KeepaliveUtils.java +++ b/framework/src/android/net/util/KeepaliveUtils.java
@@ -18,11 +18,8 @@ import android.annotation.NonNull; import android.content.Context; -import android.content.res.Resources; -import android.net.ConnectivityResources; +import android.net.ConnectivityManager; import android.net.NetworkCapabilities; -import android.text.TextUtils; -import android.util.AndroidRuntimeException; /** * Collection of utilities for socket keepalive offload. @@ -33,64 +30,20 @@ public static final String TAG = "KeepaliveUtils"; - public static class KeepaliveDeviceConfigurationException extends AndroidRuntimeException { - public KeepaliveDeviceConfigurationException(final String msg) { - super(msg); - } - } - /** * Read supported keepalive count for each transport type from overlay resource. This should be * used to create a local variable store of resource customization, and use it as the input for - * {@link getSupportedKeepalivesForNetworkCapabilities}. + * {@link #getSupportedKeepalivesForNetworkCapabilities}. * * @param context The context to read resource from. * @return An array of supported keepalive count for each transport type. + * @deprecated This is used by CTS 13, but can be removed after switching it to + * {@link ConnectivityManager#getSupportedKeepalives()}. */ @NonNull + @Deprecated public static int[] getSupportedKeepalives(@NonNull Context context) { - String[] res = null; - try { - final ConnectivityResources connRes = new ConnectivityResources(context); - // TODO: use R.id.config_networkSupportedKeepaliveCount directly - final int id = connRes.get().getIdentifier("config_networkSupportedKeepaliveCount", - "array", connRes.getResourcesContext().getPackageName()); - res = new ConnectivityResources(context).get().getStringArray(id); - } catch (Resources.NotFoundException unused) { - } - if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource"); - - final int[] ret = new int[NetworkCapabilities.MAX_TRANSPORT + 1]; - for (final String row : res) { - if (TextUtils.isEmpty(row)) { - throw new KeepaliveDeviceConfigurationException("Empty string"); - } - final String[] arr = row.split(","); - if (arr.length != 2) { - throw new KeepaliveDeviceConfigurationException("Invalid parameter length"); - } - - int transport; - int supported; - try { - transport = Integer.parseInt(arr[0]); - supported = Integer.parseInt(arr[1]); - } catch (NumberFormatException e) { - throw new KeepaliveDeviceConfigurationException("Invalid number format"); - } - - if (!NetworkCapabilities.isValidTransport(transport)) { - throw new KeepaliveDeviceConfigurationException("Invalid transport " + transport); - } - - if (supported < 0) { - throw new KeepaliveDeviceConfigurationException( - "Invalid supported count " + supported + " for " - + NetworkCapabilities.transportNameOf(transport)); - } - ret[transport] = supported; - } - return ret; + return context.getSystemService(ConnectivityManager.class).getSupportedKeepalives(); } /**
diff --git a/nearby/framework/Android.bp b/nearby/framework/Android.bp index e223b54..278f823 100644 --- a/nearby/framework/Android.bp +++ b/nearby/framework/Android.bp
@@ -32,10 +32,10 @@ filegroup { name: "framework-nearby-sources", + defaults: ["framework-sources-module-defaults"], srcs: [ ":framework-nearby-java-sources", ], - visibility: ["//frameworks/base"], } // Build of only framework-nearby (not as part of connectivity) for @@ -45,6 +45,7 @@ srcs: [":framework-nearby-java-sources"], sdk_version: "module_current", libs: [ + "androidx.annotation_annotation", "framework-annotations-lib", "framework-bluetooth", ],
diff --git a/nearby/halfsheet/Android.bp b/nearby/halfsheet/Android.bp index 2d0d327..8011dc6 100644 --- a/nearby/halfsheet/Android.bp +++ b/nearby/halfsheet/Android.bp
@@ -27,7 +27,7 @@ certificate: ":com.android.nearby.halfsheetcertificate", libs: [ "framework-bluetooth", - "framework-connectivity-t", + "framework-connectivity-t.impl", "nearby-service-string", ], static_libs: [
diff --git a/nearby/halfsheet/res/values-ky/strings.xml b/nearby/halfsheet/res/values-ky/strings.xml index 812e0e8..b0dfe20 100644 --- a/nearby/halfsheet/res/values-ky/strings.xml +++ b/nearby/halfsheet/res/values-ky/strings.xml
@@ -25,5 +25,5 @@ <string name="paring_action_save" msgid="6259357442067880136">"Сактоо"</string> <string name="paring_action_connect" msgid="4801102939608129181">"Туташуу"</string> <string name="paring_action_launch" msgid="8940808384126591230">"Жөндөө"</string> - <string name="paring_action_settings" msgid="424875657242864302">"Жөндөөлөр"</string> + <string name="paring_action_settings" msgid="424875657242864302">"Параметрлер"</string> </resources>
diff --git a/nearby/halfsheet/src/com/android/nearby/halfsheet/HalfSheetActivity.java b/nearby/halfsheet/src/com/android/nearby/halfsheet/HalfSheetActivity.java index 2a38b8a..07e5776 100644 --- a/nearby/halfsheet/src/com/android/nearby/halfsheet/HalfSheetActivity.java +++ b/nearby/halfsheet/src/com/android/nearby/halfsheet/HalfSheetActivity.java
@@ -16,6 +16,8 @@ package com.android.nearby.halfsheet; +import static android.Manifest.permission.ACCESS_FINE_LOCATION; + import static com.android.nearby.halfsheet.fragment.DevicePairingFragment.APP_LAUNCH_FRAGMENT_TYPE; import static com.android.server.nearby.common.bluetooth.fastpair.FastPairConstants.EXTRA_MODEL_ID; import static com.android.server.nearby.common.fastpair.service.UserActionHandlerBase.EXTRA_MAC_ADDRESS; @@ -226,7 +228,8 @@ EXTRA_HALF_SHEET_IS_RETROACTIVE, getIntent().getBooleanExtra(EXTRA_HALF_SHEET_IS_RETROACTIVE, false)) - .putExtra(EXTRA_MAC_ADDRESS, mScanFastPairStoreItem.getAddress())); + .putExtra(EXTRA_MAC_ADDRESS, mScanFastPairStoreItem.getAddress()), + ACCESS_FINE_LOCATION); } }
diff --git a/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/BroadcastUtils.java b/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/BroadcastUtils.java index 467997c..2f1e90a 100644 --- a/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/BroadcastUtils.java +++ b/nearby/halfsheet/src/com/android/nearby/halfsheet/utils/BroadcastUtils.java
@@ -31,6 +31,13 @@ context.sendBroadcast(intent); } + /** + * Helps send a broadcast with specified receiver permission. + */ + public static void sendBroadcast(Context context, Intent intent, String receiverPermission) { + context.sendBroadcast(intent, receiverPermission); + } + private BroadcastUtils() { } }
diff --git a/nearby/tests/cts/fastpair/AndroidManifest.xml b/nearby/tests/cts/fastpair/AndroidManifest.xml index 96e2783..9e1ec70 100644 --- a/nearby/tests/cts/fastpair/AndroidManifest.xml +++ b/nearby/tests/cts/fastpair/AndroidManifest.xml
@@ -30,7 +30,5 @@ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.nearby.cts" android:label="CTS tests for android.nearby Fast Pair"> - <meta-data android:name="listener" - android:value="com.android.cts.runner.CtsTestRunListener"/> </instrumentation> </manifest>
diff --git a/nearby/tests/integration/untrusted/src/androidx/test/uiautomator/LogcatWaitMixin.java b/nearby/tests/integration/untrusted/src/androidx/test/uiautomator/LogcatWaitMixin.java index 86e39dc..8b5ac12 100644 --- a/nearby/tests/integration/untrusted/src/androidx/test/uiautomator/LogcatWaitMixin.java +++ b/nearby/tests/integration/untrusted/src/androidx/test/uiautomator/LogcatWaitMixin.java
@@ -54,7 +54,7 @@ @NonNull String specificLog, @NonNull Date startTime) { return new Condition<UiDevice, Boolean>() { @Override - Boolean apply(UiDevice device) { + public Boolean apply(UiDevice device) { String logcatLogs; try { logcatLogs = device.executeShellCommand("logcat -v time -v year -d");
diff --git a/nearby/tests/multidevices/README.md b/nearby/tests/multidevices/README.md index b64667c..9d086de 100644 --- a/nearby/tests/multidevices/README.md +++ b/nearby/tests/multidevices/README.md
@@ -43,14 +43,24 @@ * Adjust Bluetooth profile configurations. \ The Fast Pair provider simulator is an opposite role to the seeker. It needs to enable/disable the following Bluetooth profile: - * Disable A2DP (profile_supported_a2dp) - * Disable the AVRCP controller (profile_supported_avrcp_controller) - * Enable A2DP sink (profile_supported_a2dp_sink) - * Enable the HFP client connection service (profile_supported_hfpclient, - hfp_client_connection_service_enabled) - * Enable the AVRCP target (profile_supported_avrcp_target) - * Enable the automatic audio focus request - (a2dp_sink_automatically_request_audio_focus) + * Disable A2DP source (bluetooth.profile.a2dp.source.enabled) + * Enable A2DP sink (bluetooth.profile.a2dp.sink.enabled) + * Disable the AVRCP controller (bluetooth.profile.avrcp.controller.enabled) + * Enable the AVRCP target (bluetooth.profile.avrcp.target.enabled) + * Enable the HFP service (bluetooth.profile.hfp.ag.enabled, bluetooth.profile.hfp.hf.enabled) + +```makefile +# The Bluetooth profiles that Fast Pair provider simulator expect to have enabled. +PRODUCT_PRODUCT_PROPERTIES += \ + bluetooth.device.default_name=FastPairProviderSimulator \ + bluetooth.profile.a2dp.source.enabled=false \ + bluetooth.profile.a2dp.sink.enabled=true \ + bluetooth.profile.avrcp.controller.enabled=false \ + bluetooth.profile.avrcp.target.enabled=true \ + bluetooth.profile.hfp.ag.enabled=true \ + bluetooth.profile.hfp.hf.enabled=true +``` + * Adjust Bluetooth TX power limitation in Bluetooth module and disable the Fast Pair in Google Play service (aka GMS)
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java b/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java index e916c53..75fafb0 100644 --- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java +++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java
@@ -657,9 +657,7 @@ int desiredIoCapability = getIoCapabilityFromModelId(modelId); - mBluetoothController.setIoCapability( - /*ioCapabilityClassic=*/ desiredIoCapability, - /*ioCapabilityBLE=*/ desiredIoCapability); + mBluetoothController.setIoCapability(desiredIoCapability); runOnUiThread(() -> { updateStringStatusView( @@ -950,9 +948,7 @@ } // Recover the IO capability. - mBluetoothController.setIoCapability( - /*ioCapabilityClassic=*/ IO_CAPABILITY_IO, /*ioCapabilityBLE=*/ - IO_CAPABILITY_KBDISP); + mBluetoothController.setIoCapability(IO_CAPABILITY_IO); super.onDestroy(); }
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt index 0cc0c92..345e8d2 100644 --- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt +++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt
@@ -50,23 +50,16 @@ } /** - * Sets the Input/Output capability of the device for both classic Bluetooth and BLE operations. + * Sets the Input/Output capability of the device for classic Bluetooth operations. * Note: In order to let changes take effect, this method will make sure the Bluetooth stack is * restarted by blocking calling thread. * * @param ioCapabilityClassic One of {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_NONE}, * ``` * {@link #IO_CAPABILITY_KBDISP} or more in {@link BluetoothAdapter}. - * @param ioCapabilityBLE - * ``` - * One of {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_NONE}, {@link - * ``` - * #IO_CAPABILITY_KBDISP} or more in {@link BluetoothAdapter}. - * ``` */ - fun setIoCapability(ioCapabilityClassic: Int, ioCapabilityBLE: Int) { + fun setIoCapability(ioCapabilityClassic: Int) { bluetoothAdapter.ioCapability = ioCapabilityClassic - bluetoothAdapter.leIoCapability = ioCapabilityBLE // Toggling airplane mode on/off to restart Bluetooth stack and reset the BLE. try { @@ -273,4 +266,4 @@ private const val TURN_AIRPLANE_MODE_OFF = 0 private const val TURN_AIRPLANE_MODE_ON = 1 } -} \ No newline at end of file +}
diff --git a/nearby/tests/multidevices/clients/test_support/snippet_helper/tests/Android.bp b/nearby/tests/multidevices/clients/test_support/snippet_helper/tests/Android.bp index 284d5c2..ec0392c 100644 --- a/nearby/tests/multidevices/clients/test_support/snippet_helper/tests/Android.bp +++ b/nearby/tests/multidevices/clients/test_support/snippet_helper/tests/Android.bp
@@ -35,4 +35,5 @@ // timeout in seconds. timeout: 36000, }, -} \ No newline at end of file + upstream: true, +}
diff --git a/nearby/tests/multidevices/host/Android.bp b/nearby/tests/multidevices/host/Android.bp index b81032d..b6c1c9d 100644 --- a/nearby/tests/multidevices/host/Android.bp +++ b/nearby/tests/multidevices/host/Android.bp
@@ -22,7 +22,10 @@ name: "NearbyMultiDevicesTestSuite", main: "suite_main.py", srcs: ["*.py"], - libs: ["NearbyMultiDevicesHostHelper"], + libs: [ + "NearbyMultiDevicesHostHelper", + "mobly", + ], test_suites: [ "general-tests", "mts-tethering", @@ -38,6 +41,11 @@ // Package the JSON metadata with the Mobly test. "test_data/**/*", ], + version: { + py3: { + embedded_launcher: true, + }, + }, } python_library_host {
diff --git a/nearby/tests/multidevices/host/AndroidTest.xml b/nearby/tests/multidevices/host/AndroidTest.xml index c1f6a70..fff0ed1 100644 --- a/nearby/tests/multidevices/host/AndroidTest.xml +++ b/nearby/tests/multidevices/host/AndroidTest.xml
@@ -42,11 +42,6 @@ <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> <option name="run-command" value="wm dismiss-keyguard" /> </target_preparer> - <target_preparer class="com.android.tradefed.targetprep.PythonVirtualenvPreparer"> - <!-- Any python dependencies can be specified and will be installed with pip --> - <!-- TODO(b/225958696): Import python dependencies --> - <option name="dep-module" value="mobly" /> - </target_preparer> <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device --> <option name="screen-always-on" value="on" />
diff --git a/nearby/tests/multidevices/host/suite_main.py b/nearby/tests/multidevices/host/suite_main.py index 4f5d48c..9a580fb 100644 --- a/nearby/tests/multidevices/host/suite_main.py +++ b/nearby/tests/multidevices/host/suite_main.py
@@ -31,11 +31,9 @@ ] -def _valid_argument(arg: str) -> bool: - return arg.startswith(('--config', '-c', '--tests', '--test_case')) - - if __name__ == '__main__': logging.basicConfig(filename=_BOOTSTRAP_LOGGING_FILENAME, level=logging.INFO) - suite_runner.run_suite(argv=[arg for arg in sys.argv if _valid_argument(arg)], - test_classes=_TEST_CLASSES_LIST) + if '--' in sys.argv: + index = sys.argv.index('--') + sys.argv = sys.argv[:1] + sys.argv[index + 1:] + suite_runner.run_suite(test_classes=_TEST_CLASSES_LIST)
diff --git a/nearby/tests/robotests/Android.bp b/nearby/tests/robotests/Android.bp index 56c0107..70fa0c3 100644 --- a/nearby/tests/robotests/Android.bp +++ b/nearby/tests/robotests/Android.bp
@@ -42,15 +42,14 @@ "androidx.lifecycle_lifecycle-runtime", "androidx.mediarouter_mediarouter-nodeps", "error_prone_annotations", - "mockito-robolectric-prebuilt", "service-nearby-pre-jarjar", "truth-prebuilt", "robolectric_android-all-stub", - "Robolectric_all-target", ], test_options: { // timeout in seconds. timeout: 36000, }, + upstream: true, }
diff --git a/netd/Android.bp b/netd/Android.bp index c731b8b..473460d 100644 --- a/netd/Android.bp +++ b/netd/Android.bp
@@ -63,6 +63,7 @@ ], srcs: [ "BpfHandlerTest.cpp", + "BpfBaseTest.cpp" ], static_libs: [ "libnetd_updatable", @@ -72,6 +73,7 @@ "libcutils", "liblog", "libnetdutils", + "libprocessgroup", ], compile_multilib: "both", multilib: {
diff --git a/netd/BpfBaseTest.cpp b/netd/BpfBaseTest.cpp new file mode 100644 index 0000000..c979a7b --- /dev/null +++ b/netd/BpfBaseTest.cpp
@@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018 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 <string> + +#include <fcntl.h> +#include <inttypes.h> +#include <limits.h> +#include <linux/inet_diag.h> +#include <linux/sock_diag.h> +#include <net/if.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#include <gtest/gtest.h> + +#include <cutils/qtaguid.h> +#include <processgroup/processgroup.h> + +#include <android-base/stringprintf.h> +#include <android-base/strings.h> +#include <netdutils/NetNativeTestBase.h> + +#include "bpf/BpfMap.h" +#include "bpf/BpfUtils.h" +#include "netd.h" + +using android::base::Result; + +namespace android { +namespace bpf { + +// Use the upper limit of uid to avoid conflict with real app uids. We can't use UID_MAX because +// it's -1, which is INVALID_UID. +constexpr uid_t TEST_UID = UID_MAX - 1; +constexpr uint32_t TEST_TAG = 42; + +class BpfBasicTest : public NetNativeTestBase { + protected: + BpfBasicTest() {} +}; + +TEST_F(BpfBasicTest, TestCgroupMounted) { + std::string cg2_path; + ASSERT_EQ(true, CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &cg2_path)); + ASSERT_EQ(0, access(cg2_path.c_str(), R_OK)); + ASSERT_EQ(0, access((cg2_path + "/cgroup.controllers").c_str(), R_OK)); +} + +TEST_F(BpfBasicTest, TestTagSocket) { + BpfMap<uint64_t, UidTagValue> cookieTagMap(COOKIE_TAG_MAP_PATH); + ASSERT_TRUE(cookieTagMap.isValid()); + int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0); + ASSERT_LE(0, sock); + uint64_t cookie = getSocketCookie(sock); + ASSERT_NE(NONEXISTENT_COOKIE, cookie); + ASSERT_EQ(0, qtaguid_tagSocket(sock, TEST_TAG, TEST_UID)); + Result<UidTagValue> tagResult = cookieTagMap.readValue(cookie); + ASSERT_RESULT_OK(tagResult); + ASSERT_EQ(TEST_UID, tagResult.value().uid); + ASSERT_EQ(TEST_TAG, tagResult.value().tag); + ASSERT_EQ(0, qtaguid_untagSocket(sock)); + tagResult = cookieTagMap.readValue(cookie); + ASSERT_FALSE(tagResult.ok()); + ASSERT_EQ(ENOENT, tagResult.error().code()); +} + +TEST_F(BpfBasicTest, TestCloseSocketWithoutUntag) { + BpfMap<uint64_t, UidTagValue> cookieTagMap(COOKIE_TAG_MAP_PATH); + ASSERT_TRUE(cookieTagMap.isValid()); + int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0); + ASSERT_LE(0, sock); + uint64_t cookie = getSocketCookie(sock); + ASSERT_NE(NONEXISTENT_COOKIE, cookie); + ASSERT_EQ(0, qtaguid_tagSocket(sock, TEST_TAG, TEST_UID)); + Result<UidTagValue> tagResult = cookieTagMap.readValue(cookie); + ASSERT_RESULT_OK(tagResult); + ASSERT_EQ(TEST_UID, tagResult.value().uid); + ASSERT_EQ(TEST_TAG, tagResult.value().tag); + ASSERT_EQ(0, close(sock)); + // Check map periodically until sk destroy handler have done its job. + for (int i = 0; i < 1000; i++) { + usleep(5000); // 5ms + tagResult = cookieTagMap.readValue(cookie); + if (!tagResult.ok()) { + ASSERT_EQ(ENOENT, tagResult.error().code()); + return; + } + } + FAIL() << "socket tag still exist after 5s"; +} + +} +}
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp index 7950ff7..8081d12 100644 --- a/netd/BpfHandler.cpp +++ b/netd/BpfHandler.cpp
@@ -32,7 +32,6 @@ namespace net { using base::unique_fd; -using bpf::NONEXISTENT_COOKIE; using bpf::getSocketCookie; using bpf::retrieveProgram; using netdutils::Status; @@ -93,7 +92,7 @@ // 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)) { + if (bpf::isAtLeastKernelVersion(4, 14, 0)) { RETURN_IF_NOT_OK( attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE)); } @@ -185,7 +184,7 @@ } uint64_t sock_cookie = getSocketCookie(sockFd); - if (sock_cookie == NONEXISTENT_COOKIE) return -errno; + if (!sock_cookie) return -errno; UidTagValue newKey = {.uid = (uint32_t)chargeUid, .tag = tag}; @@ -249,7 +248,7 @@ int BpfHandler::untagSocket(int sockFd) { uint64_t sock_cookie = getSocketCookie(sockFd); - if (sock_cookie == NONEXISTENT_COOKIE) return -errno; + if (!sock_cookie) return -errno; if (!mCookieTagMap.isValid()) return -EPERM; base::Result<void> res = mCookieTagMap.deleteValue(sock_cookie);
diff --git a/netd/BpfHandler.h b/netd/BpfHandler.h index 925a725..a6da4eb 100644 --- a/netd/BpfHandler.h +++ b/netd/BpfHandler.h
@@ -18,7 +18,7 @@ #include <netdutils/Status.h> #include "bpf/BpfMap.h" -#include "bpf_shared.h" +#include "netd.h" using android::bpf::BpfMap; using android::bpf::BpfMapRO;
diff --git a/service-t/Android.bp b/service-t/Android.bp index 2e7a4f3..7de749c 100644 --- a/service-t/Android.bp +++ b/service-t/Android.bp
@@ -50,7 +50,9 @@ "framework-configinfrastructure", "framework-connectivity-pre-jarjar", "framework-connectivity-t-pre-jarjar", - "framework-tethering", + // TODO: use framework-tethering-pre-jarjar when it is separated from framework-tethering + "framework-tethering.impl", + "framework-wifi", "service-connectivity-pre-jarjar", "service-nearby-pre-jarjar", "ServiceConnectivityResources", @@ -73,3 +75,47 @@ "//packages/modules/IPsec/tests/iketests", ], } + +// Test building mDNS as a standalone, so that it can be imported into other repositories as-is. +// The mDNS code is platform code so it should use framework-annotations-lib, contrary to apps that +// should use sdk_version: "system_current" and only androidx.annotation_annotation. But this build +// rule verifies that the mDNS code can be built into apps, if code transformations are applied to +// the annotations. +// When using "system_current", framework annotations are not available; they would appear as +// package-private as they are marked as such in the system_current stubs. So build against +// core_platform and add the stubs manually in "libs". See http://b/147773144#comment7. +java_library { + name: "service-connectivity-mdns-standalone-build-test", + sdk_version: "core_platform", + srcs: [ + ":service-mdns-droidstubs", + "src/com/android/server/connectivity/mdns/**/*.java", + ], + exclude_srcs: [ + "src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java", + "src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java" + ], + static_libs: [ + "net-utils-device-common-mdns-standalone-build-test", + ], + libs: [ + "framework-annotations-lib", + "android_system_stubs_current", + "androidx.annotation_annotation", + ], + visibility: [ + "//visibility:private", + ], +} + +droidstubs { + name: "service-mdns-droidstubs", + srcs: ["src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java"], + libs: [ + "net-utils-device-common-mdns-standalone-build-test", + "service-connectivity-tiramisu-pre-jarjar" + ], + visibility: [ + "//visibility:private", + ], +} \ No newline at end of file
diff --git a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp index a3299a7..a16757b 100644 --- a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp +++ b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
@@ -170,23 +170,10 @@ return 0; } -static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jint limitUid, - jobjectArray limitIfacesObj, jint limitTag) { - - std::vector<std::string> limitIfaces; - if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { - int num = env->GetArrayLength(limitIfacesObj); - for (int i = 0; i < num; i++) { - jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); - ScopedUtfChars string8(env, string); - if (string8.c_str() != NULL) { - limitIfaces.push_back(std::string(string8.c_str())); - } - } - } +static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats) { std::vector<stats_line> lines; - if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) + if (parseBpfNetworkStatsDetail(&lines) < 0) return -1; return statsLinesToNetworkStats(env, clazz, stats, lines); @@ -202,15 +189,15 @@ } static const JNINativeMethod gMethods[] = { - { "nativeReadNetworkStatsDetail", - "(Landroid/net/NetworkStats;I[Ljava/lang/String;I)I", + { "nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;)I", (void*) readNetworkStatsDetail }, { "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I", (void*) readNetworkStatsDev }, }; int register_android_server_net_NetworkStatsFactory(JNIEnv* env) { - int err = jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsFactory", gMethods, + int err = jniRegisterNativeMethods(env, + "android/net/connectivity/com/android/server/net/NetworkStatsFactory", gMethods, NELEM(gMethods)); gStringClass = env->FindClass("java/lang/String"); gStringClass = static_cast<jclass>(env->NewGlobalRef(gStringClass));
diff --git a/service-t/jni/com_android_server_net_NetworkStatsService.cpp b/service-t/jni/com_android_server_net_NetworkStatsService.cpp index 39cbaf7..dab9d07 100644 --- a/service-t/jni/com_android_server_net_NetworkStatsService.cpp +++ b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
@@ -30,9 +30,11 @@ #include "bpf/BpfUtils.h" #include "netdbpf/BpfNetworkStats.h" +#include "netdbpf/NetworkTraceHandler.h" using android::bpf::bpfGetUidStats; using android::bpf::bpfGetIfaceStats; +using android::bpf::NetworkTraceHandler; namespace android { @@ -67,7 +69,7 @@ } } -static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) { +static jlong nativeGetTotalStat(JNIEnv* env, jclass clazz, jint type) { Stats stats = {}; if (bpfGetIfaceStats(NULL, &stats) == 0) { @@ -77,7 +79,7 @@ } } -static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { +static jlong nativeGetIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { ScopedUtfChars iface8(env, iface); if (iface8.c_str() == NULL) { return UNKNOWN; @@ -92,7 +94,7 @@ } } -static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { +static jlong nativeGetUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { Stats stats = {}; if (bpfGetUidStats(uid, &stats) == 0) { @@ -102,15 +104,21 @@ } } +static void nativeInitNetworkTracing(JNIEnv* env, jclass clazz) { + NetworkTraceHandler::InitPerfettoTracing(); +} + static const JNINativeMethod gMethods[] = { - {"nativeGetTotalStat", "(I)J", (void*)getTotalStat}, - {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)getIfaceStat}, - {"nativeGetUidStat", "(II)J", (void*)getUidStat}, + {"nativeGetTotalStat", "(I)J", (void*)nativeGetTotalStat}, + {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)nativeGetIfaceStat}, + {"nativeGetUidStat", "(II)J", (void*)nativeGetUidStat}, + {"nativeInitNetworkTracing", "()V", (void*)nativeInitNetworkTracing}, }; int register_android_server_net_NetworkStatsService(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods, - NELEM(gMethods)); + return jniRegisterNativeMethods(env, + "android/net/connectivity/com/android/server/net/NetworkStatsService", gMethods, + NELEM(gMethods)); } }
diff --git a/service-t/native/libs/libnetworkstats/Android.bp b/service-t/native/libs/libnetworkstats/Android.bp index 5b3d314..0dfd0af 100644 --- a/service-t/native/libs/libnetworkstats/Android.bp +++ b/service-t/native/libs/libnetworkstats/Android.bp
@@ -24,12 +24,21 @@ host_supported: false, header_libs: ["bpf_connectivity_headers"], srcs: [ - "BpfNetworkStats.cpp" + "BpfNetworkStats.cpp", + "NetworkTraceHandler.cpp", + "NetworkTracePoller.cpp", ], shared_libs: [ "libbase", + "libcutils", "liblog", ], + static_libs: [ + "libperfetto_client_experimental", + ], + export_static_lib_headers: [ + "libperfetto_client_experimental", + ], export_include_dirs: ["include"], cflags: [ "-Wall", @@ -54,6 +63,8 @@ header_libs: ["bpf_connectivity_headers"], srcs: [ "BpfNetworkStatsTest.cpp", + "NetworkTraceHandlerTest.cpp", + "NetworkTracePollerTest.cpp", ], cflags: [ "-Wall", @@ -64,10 +75,15 @@ static_libs: [ "libgmock", "libnetworkstats", + "libperfetto_client_experimental", + "libprotobuf-cpp-lite", + "perfetto_trace_protos", ], shared_libs: [ "libbase", "liblog", + "libcutils", + "libandroid_net", ], compile_multilib: "both", multilib: {
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp index 28de881..1bc8ca5 100644 --- a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp +++ b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
@@ -26,7 +26,7 @@ #include "android-base/strings.h" #include "android-base/unique_fd.h" #include "bpf/BpfMap.h" -#include "bpf_shared.h" +#include "netd.h" #include "netdbpf/BpfNetworkStats.h" #ifdef LOG_TAG @@ -109,13 +109,12 @@ return newLine; } -int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>* lines, - const std::vector<std::string>& limitIfaces, int limitTag, - int limitUid, const BpfMap<StatsKey, StatsValue>& statsMap, +int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>& lines, + const BpfMap<StatsKey, StatsValue>& statsMap, const BpfMap<uint32_t, IfaceValue>& ifaceMap) { int64_t unknownIfaceBytesTotal = 0; const auto processDetailUidStats = - [lines, &limitIfaces, &limitTag, &limitUid, &unknownIfaceBytesTotal, &ifaceMap]( + [&lines, &unknownIfaceBytesTotal, &ifaceMap]( const StatsKey& key, const BpfMap<StatsKey, StatsValue>& statsMap) -> Result<void> { char ifname[IFNAMSIZ]; @@ -123,23 +122,17 @@ &unknownIfaceBytesTotal)) { return Result<void>(); } - std::string ifnameStr(ifname); - if (limitIfaces.size() > 0 && - std::find(limitIfaces.begin(), limitIfaces.end(), ifnameStr) == limitIfaces.end()) { - // Nothing matched; skip this line. - return Result<void>(); - } - if (limitTag != TAG_ALL && uint32_t(limitTag) != key.tag) { - return Result<void>(); - } - if (limitUid != UID_ALL && uint32_t(limitUid) != key.uid) { - return Result<void>(); - } Result<StatsValue> statsEntry = statsMap.readValue(key); if (!statsEntry.ok()) { return base::ResultError(statsEntry.error().message(), statsEntry.error().code()); } - lines->push_back(populateStatsEntry(key, statsEntry.value(), ifname)); + stats_line newLine = populateStatsEntry(key, statsEntry.value(), ifname); + lines.push_back(newLine); + if (newLine.tag) { + // account tagged traffic in the untagged stats (for historical reasons?) + newLine.tag = 0; + lines.push_back(newLine); + } return Result<void>(); }; Result<void> res = statsMap.iterate(processDetailUidStats); @@ -162,9 +155,7 @@ return 0; } -int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines, - const std::vector<std::string>& limitIfaces, int limitTag, - int limitUid) { +int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines) { static BpfMapRO<uint32_t, IfaceValue> ifaceIndexNameMap(IFACE_INDEX_NAME_MAP_PATH); static BpfMapRO<uint32_t, uint32_t> configurationMap(CONFIGURATION_MAP_PATH); static BpfMap<StatsKey, StatsValue> statsMapA(STATS_MAP_A_PATH); @@ -195,8 +186,7 @@ // TODO: the above comment feels like it may be obsolete / out of date, // since we no longer swap the map via netd binder rpc - though we do // still swap it. - int ret = parseBpfNetworkStatsDetailInternal(lines, limitIfaces, limitTag, limitUid, - *inactiveStatsMap, ifaceIndexNameMap); + int ret = parseBpfNetworkStatsDetailInternal(*lines, *inactiveStatsMap, ifaceIndexNameMap); if (ret) { ALOGE("parse detail network stats failed: %s", strerror(errno)); return ret; @@ -211,11 +201,11 @@ return 0; } -int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines, +int parseBpfNetworkStatsDevInternal(std::vector<stats_line>& lines, const BpfMap<uint32_t, StatsValue>& statsMap, const BpfMap<uint32_t, IfaceValue>& ifaceMap) { int64_t unknownIfaceBytesTotal = 0; - const auto processDetailIfaceStats = [lines, &unknownIfaceBytesTotal, &ifaceMap, &statsMap]( + const auto processDetailIfaceStats = [&lines, &unknownIfaceBytesTotal, &ifaceMap, &statsMap]( const uint32_t& key, const StatsValue& value, const BpfMap<uint32_t, StatsValue>&) { char ifname[IFNAMSIZ]; @@ -227,7 +217,7 @@ .tag = (uint32_t)TAG_NONE, .counterSet = (uint32_t)SET_ALL, }; - lines->push_back(populateStatsEntry(fakeKey, value, ifname)); + lines.push_back(populateStatsEntry(fakeKey, value, ifname)); return Result<void>(); }; Result<void> res = statsMap.iterateWithValue(processDetailIfaceStats); @@ -244,33 +234,28 @@ int parseBpfNetworkStatsDev(std::vector<stats_line>* lines) { static BpfMapRO<uint32_t, IfaceValue> ifaceIndexNameMap(IFACE_INDEX_NAME_MAP_PATH); static BpfMapRO<uint32_t, StatsValue> ifaceStatsMap(IFACE_STATS_MAP_PATH); - return parseBpfNetworkStatsDevInternal(lines, ifaceStatsMap, ifaceIndexNameMap); + return parseBpfNetworkStatsDevInternal(*lines, ifaceStatsMap, ifaceIndexNameMap); } -uint64_t combineUidTag(const uid_t uid, const uint32_t tag) { - return (uint64_t)uid << 32 | tag; -} - -void groupNetworkStats(std::vector<stats_line>* lines) { - if (lines->size() <= 1) return; - std::sort(lines->begin(), lines->end()); +void groupNetworkStats(std::vector<stats_line>& lines) { + if (lines.size() <= 1) return; + std::sort(lines.begin(), lines.end()); // Similar to std::unique(), but aggregates the duplicates rather than discarding them. - size_t nextOutput = 0; - for (size_t i = 1; i < lines->size(); i++) { - if (lines->at(nextOutput) == lines->at(i)) { - lines->at(nextOutput) += lines->at(i); + size_t currentOutput = 0; + for (size_t i = 1; i < lines.size(); i++) { + // note that == operator only compares the 'key' portion: iface/uid/tag/set + if (lines[currentOutput] == lines[i]) { + // while += operator only affects the 'data' portion: {rx,tx}{Bytes,Packets} + lines[currentOutput] += lines[i]; } else { - nextOutput++; - if (nextOutput != i) { - lines->at(nextOutput) = lines->at(i); - } + // okay, we're done aggregating the current line, move to the next one + lines[++currentOutput] = lines[i]; } } - if (lines->size() != nextOutput + 1) { - lines->resize(nextOutput + 1); - } + // possibly shrink the vector - currentOutput is the last line with valid data + lines.resize(currentOutput + 1); } // True if lhs equals to rhs, only compare iface, uid, tag and set.
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp index 6f9c8c2..ccd3f5e 100644 --- a/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp +++ b/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
@@ -225,18 +225,11 @@ ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID2, &result2, mFakeAppUidStatsMap)); expectStatsEqual(value2, result2); std::vector<stats_line> lines; - std::vector<std::string> ifaces; populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET1, value1, mFakeStatsMap); populateFakeStats(TEST_UID2, 0, IFACE_INDEX3, TEST_COUNTERSET1, value1, mFakeStatsMap); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1, - mFakeStatsMap, mFakeIfaceIndexNameMap)); - ASSERT_EQ((unsigned long)2, lines.size()); - lines.clear(); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2, - mFakeStatsMap, mFakeIfaceIndexNameMap)); - ASSERT_EQ((unsigned long)1, lines.size()); - expectStatsLineEqual(value1, IFACE_NAME3, TEST_UID2, TEST_COUNTERSET1, 0, lines.front()); + ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap)); + ASSERT_EQ((unsigned long)3, lines.size()); } TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) { @@ -297,24 +290,8 @@ mFakeStatsMap); populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); std::vector<stats_line> lines; - std::vector<std::string> ifaces; - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap, - mFakeIfaceIndexNameMap)); - ASSERT_EQ((unsigned long)4, lines.size()); - lines.clear(); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1, - mFakeStatsMap, mFakeIfaceIndexNameMap)); - ASSERT_EQ((unsigned long)3, lines.size()); - lines.clear(); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TEST_TAG, TEST_UID1, - mFakeStatsMap, mFakeIfaceIndexNameMap)); - ASSERT_EQ((unsigned long)2, lines.size()); - lines.clear(); - ifaces.push_back(std::string(IFACE_NAME1)); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TEST_TAG, TEST_UID1, - mFakeStatsMap, mFakeIfaceIndexNameMap)); - ASSERT_EQ((unsigned long)1, lines.size()); - expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines.front()); + ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap)); + ASSERT_EQ((unsigned long)7, lines.size()); } TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) { @@ -326,30 +303,15 @@ .txPackets = TEST_PACKET1, .txBytes = TEST_BYTES1, }; - populateFakeStats(0, 0, 0, OVERFLOW_COUNTERSET, value1, mFakeStatsMap); + // next stats entry will be ignored due to ifindex 0 not being present in mFakeIfaceIndexNameMap + populateFakeStats(0, 0, 0, TEST_COUNTERSET1, value1, mFakeStatsMap); populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, value1, mFakeStatsMap); populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET1, value1, mFakeStatsMap); populateFakeStats(TEST_UID2, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); std::vector<stats_line> lines; - std::vector<std::string> ifaces; - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap, - mFakeIfaceIndexNameMap)); + ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap)); ASSERT_EQ((unsigned long)4, lines.size()); - lines.clear(); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1, - mFakeStatsMap, mFakeIfaceIndexNameMap)); - ASSERT_EQ((unsigned long)3, lines.size()); - lines.clear(); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2, - mFakeStatsMap, mFakeIfaceIndexNameMap)); - ASSERT_EQ((unsigned long)1, lines.size()); - expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, 0, lines.front()); - lines.clear(); - ifaces.push_back(std::string(IFACE_NAME1)); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1, - mFakeStatsMap, mFakeIfaceIndexNameMap)); - ASSERT_EQ((unsigned long)2, lines.size()); } TEST_F(BpfNetworkStatsHelperTest, TestUnknownIfaceError) { @@ -386,10 +348,8 @@ ifname, curKey, &unknownIfaceBytesTotal)); ASSERT_EQ(-1, unknownIfaceBytesTotal); std::vector<stats_line> lines; - std::vector<std::string> ifaces; // TODO: find a way to test the total of unknown Iface Bytes go above limit. - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap, - mFakeIfaceIndexNameMap)); + ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap)); ASSERT_EQ((unsigned long)1, lines.size()); expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines.front()); } @@ -421,7 +381,7 @@ EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY)); std::vector<stats_line> lines; ASSERT_EQ(0, - parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap)); + parseBpfNetworkStatsDevInternal(lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap)); ASSERT_EQ((unsigned long)4, lines.size()); expectStatsLineEqual(value1, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]); @@ -449,28 +409,32 @@ .txPackets = TEST_PACKET0, .txBytes = TEST_BYTES0, }; - StatsValue value3 = { + StatsValue value3 = { // value1 *2 .rxPackets = TEST_PACKET0 * 2, .rxBytes = TEST_BYTES0 * 2, .txPackets = TEST_PACKET1 * 2, .txBytes = TEST_BYTES1 * 2, }; + StatsValue value5 = { // value2 + value3 + .rxPackets = TEST_PACKET1 + TEST_PACKET0 * 2, + .rxBytes = TEST_BYTES1 + TEST_BYTES0 * 2, + .txPackets = TEST_PACKET0 + TEST_PACKET1 * 2, + .txBytes = TEST_BYTES0 + TEST_BYTES1 * 2, + }; std::vector<stats_line> lines; - std::vector<std::string> ifaces; // Test empty stats. - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap, - mFakeIfaceIndexNameMap)); + ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap)); ASSERT_EQ((size_t) 0, lines.size()); lines.clear(); // Test 1 line stats. populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap, - mFakeIfaceIndexNameMap)); - ASSERT_EQ((size_t) 1, lines.size()); - expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[0]); + ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap)); + ASSERT_EQ((size_t) 2, lines.size()); // TEST_TAG != 0 -> 1 entry becomes 2 lines + expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[0]); + expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[1]); lines.clear(); // These items should not be grouped. @@ -479,25 +443,27 @@ populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, value2, mFakeStatsMap); populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap, - mFakeIfaceIndexNameMap)); - ASSERT_EQ((size_t) 5, lines.size()); + ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap)); + ASSERT_EQ((size_t) 9, lines.size()); lines.clear(); // These items should be grouped. populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap); populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap); - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap, - mFakeIfaceIndexNameMap)); - ASSERT_EQ((size_t) 5, lines.size()); + ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap)); + ASSERT_EQ((size_t) 9, lines.size()); // Verify Sorted & Grouped. - expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[0]); - expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET1, TEST_TAG, lines[1]); - expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG + 1, lines[2]); - expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, TEST_TAG, lines[3]); - expectStatsLineEqual(value2, IFACE_NAME2, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[4]); + expectStatsLineEqual(value5, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[0]); + expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET1, 0, lines[1]); + expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[2]); + expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET1, TEST_TAG, lines[3]); + expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG + 1, lines[4]); + expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, 0, lines[5]); + expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, TEST_TAG, lines[6]); + expectStatsLineEqual(value2, IFACE_NAME2, TEST_UID1, TEST_COUNTERSET0, 0, lines[7]); + expectStatsLineEqual(value2, IFACE_NAME2, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[8]); lines.clear(); // Perform test on IfaceStats. @@ -511,7 +477,7 @@ EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY)); ASSERT_EQ(0, - parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap)); + parseBpfNetworkStatsDevInternal(lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap)); ASSERT_EQ((size_t) 2, lines.size()); expectStatsLineEqual(value3, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]); @@ -530,41 +496,48 @@ .txPackets = TEST_PACKET1, .txBytes = TEST_BYTES1, }; + StatsValue value4 = { // value1 * 4 + .rxPackets = TEST_PACKET0 * 4, + .rxBytes = TEST_BYTES0 * 4, + .txPackets = TEST_PACKET1 * 4, + .txBytes = TEST_BYTES1 * 4, + }; // Mutate uid, 0 < TEST_UID1 < INT_MAX < INT_MIN < UINT_MAX. - populateFakeStats(0, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); - populateFakeStats(UINT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); - populateFakeStats(INT_MIN, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); - populateFakeStats(INT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); + populateFakeStats(0, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); + populateFakeStats(UINT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); + populateFakeStats(INT_MIN, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); + populateFakeStats(INT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); // Mutate tag, 0 < TEST_TAG < INT_MAX < INT_MIN < UINT_MAX. - populateFakeStats(TEST_UID1, INT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); - populateFakeStats(TEST_UID1, INT_MIN, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); - populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); + populateFakeStats(TEST_UID1, INT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); + populateFakeStats(TEST_UID1, INT_MIN, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); + populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); populateFakeStats(TEST_UID1, UINT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap); // TODO: Mutate counterSet and enlarge TEST_MAP_SIZE if overflow on counterSet is possible. std::vector<stats_line> lines; - std::vector<std::string> ifaces; - ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap, - mFakeIfaceIndexNameMap)); - ASSERT_EQ((size_t) 8, lines.size()); + ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap)); + ASSERT_EQ((size_t) 12, lines.size()); // Uid 0 first - expectStatsLineEqual(value1, IFACE_NAME1, 0, TEST_COUNTERSET0, TEST_TAG, lines[0]); + expectStatsLineEqual(value1, IFACE_NAME1, 0, TEST_COUNTERSET0, 0, lines[0]); + expectStatsLineEqual(value1, IFACE_NAME1, 0, TEST_COUNTERSET0, TEST_TAG, lines[1]); // Test uid, mutate tag. - expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[1]); - expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MAX, lines[2]); - expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MIN, lines[3]); - expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, UINT_MAX, lines[4]); + expectStatsLineEqual(value4, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[2]); + expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MAX, lines[3]); + expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MIN, lines[4]); + expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, UINT_MAX, lines[5]); // Mutate uid. - expectStatsLineEqual(value1, IFACE_NAME1, INT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[5]); - expectStatsLineEqual(value1, IFACE_NAME1, INT_MIN, TEST_COUNTERSET0, TEST_TAG, lines[6]); - expectStatsLineEqual(value1, IFACE_NAME1, UINT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[7]); - lines.clear(); + expectStatsLineEqual(value1, IFACE_NAME1, INT_MAX, TEST_COUNTERSET0, 0, lines[6]); + expectStatsLineEqual(value1, IFACE_NAME1, INT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[7]); + expectStatsLineEqual(value1, IFACE_NAME1, INT_MIN, TEST_COUNTERSET0, 0, lines[8]); + expectStatsLineEqual(value1, IFACE_NAME1, INT_MIN, TEST_COUNTERSET0, TEST_TAG, lines[9]); + expectStatsLineEqual(value1, IFACE_NAME1, UINT_MAX, TEST_COUNTERSET0, 0, lines[10]); + expectStatsLineEqual(value1, IFACE_NAME1, UINT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[11]); } } // namespace bpf } // namespace android
diff --git a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp new file mode 100644 index 0000000..c5f9631 --- /dev/null +++ b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
@@ -0,0 +1,303 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "NetworkTrace" + +#include "netdbpf/NetworkTraceHandler.h" + +#include <arpa/inet.h> +#include <bpf/BpfUtils.h> +#include <log/log.h> +#include <perfetto/config/android/network_trace_config.pbzero.h> +#include <perfetto/trace/android/network_trace.pbzero.h> +#include <perfetto/trace/profiling/profile_packet.pbzero.h> +#include <perfetto/tracing/platform.h> +#include <perfetto/tracing/tracing.h> + +// Note: this is initializing state for a templated Perfetto type that resides +// in the `perfetto` namespace. This must be defined in the global scope. +PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::bpf::NetworkTraceHandler); + +namespace android { +namespace bpf { +using ::android::bpf::internal::NetworkTracePoller; +using ::perfetto::protos::pbzero::NetworkPacketBundle; +using ::perfetto::protos::pbzero::NetworkPacketEvent; +using ::perfetto::protos::pbzero::NetworkPacketTraceConfig; +using ::perfetto::protos::pbzero::TracePacket; +using ::perfetto::protos::pbzero::TrafficDirection; + +// Bundling takes groups of packets with similar contextual fields (generally, +// all fields except timestamp and length) and summarises them in a single trace +// packet. For example, rather than +// +// {.timestampNs = 1, .uid = 1000, .tag = 123, .len = 72} +// {.timestampNs = 2, .uid = 1000, .tag = 123, .len = 100} +// {.timestampNs = 5, .uid = 1000, .tag = 123, .len = 456} +// +// The output will be something like +// { +// .timestamp = 1 +// .ctx = {.uid = 1000, .tag = 123} +// .timestamp = [0, 1, 4], // delta encoded +// .length = [72, 100, 456], // should be zipped with timestamps +// } +// +// Most workloads have many packets from few contexts. Bundling greatly reduces +// the amount of redundant information written, thus reducing the overall trace +// size. Interning ids are similarly based on unique bundle contexts. + +// Based on boost::hash_combine +template <typename T, typename... Rest> +void HashCombine(std::size_t& seed, const T& val, const Rest&... rest) { + seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + (HashCombine(seed, rest), ...); +} + +// Details summarises the timestamp and lengths of packets in a bundle. +struct BundleDetails { + std::vector<std::pair<uint64_t, uint32_t>> time_and_len; + uint64_t minTs = std::numeric_limits<uint64_t>::max(); + uint64_t maxTs = std::numeric_limits<uint64_t>::min(); + uint32_t bytes = 0; +}; + +#define AGG_FIELDS(x) \ + (x).ifindex, (x).uid, (x).tag, (x).sport, (x).dport, (x).egress, \ + (x).ipProto, (x).tcpFlags + +std::size_t BundleHash::operator()(const BundleKey& a) const { + std::size_t seed = 0; + HashCombine(seed, AGG_FIELDS(a)); + return seed; +} + +bool BundleEq::operator()(const BundleKey& a, const BundleKey& b) const { + return std::tie(AGG_FIELDS(a)) == std::tie(AGG_FIELDS(b)); +} + +// static +void NetworkTraceHandler::RegisterDataSource() { + ALOGD("Registering Perfetto data source"); + perfetto::DataSourceDescriptor dsd; + dsd.set_name("android.network_packets"); + NetworkTraceHandler::Register(dsd); +} + +// static +void NetworkTraceHandler::InitPerfettoTracing() { + perfetto::TracingInitArgs args = {}; + args.backends |= perfetto::kSystemBackend; + // The following line disables the Perfetto system consumer. Perfetto inlines + // the call to `Initialize` which allows the compiler to see that the branch + // with the SystemConsumerTracingBackend is not used. With LTO enabled, this + // strips the Perfetto consumer code and reduces the size of this binary by + // around 270KB total. Be careful when changing this value. + args.enable_system_consumer = false; + perfetto::Tracing::Initialize(args); + NetworkTraceHandler::RegisterDataSource(); +} + +// static +NetworkTracePoller NetworkTraceHandler::sPoller( + [](const std::vector<PacketTrace>& packets) { + // Trace calls the provided callback for each active session. The context + // gets a reference to the NetworkTraceHandler instance associated with + // the session and delegates writing. The corresponding handler will write + // with the setting specified in the trace config. + NetworkTraceHandler::Trace([&](NetworkTraceHandler::TraceContext ctx) { + ctx.GetDataSourceLocked()->Write(packets, ctx); + }); + }); + +void NetworkTraceHandler::OnSetup(const SetupArgs& args) { + const std::string& raw = args.config->network_packet_trace_config_raw(); + NetworkPacketTraceConfig::Decoder config(raw); + + mPollMs = config.poll_ms(); + if (mPollMs < 100) { + ALOGI("poll_ms is missing or below the 100ms minimum. Increasing to 100ms"); + mPollMs = 100; + } + + mInternLimit = config.intern_limit(); + mAggregationThreshold = config.aggregation_threshold(); + mDropLocalPort = config.drop_local_port(); + mDropRemotePort = config.drop_remote_port(); + mDropTcpFlags = config.drop_tcp_flags(); +} + +void NetworkTraceHandler::OnStart(const StartArgs&) { + if (mIsTest) return; // Don't touch non-hermetic bpf in test. + mStarted = sPoller.Start(mPollMs); +} + +void NetworkTraceHandler::OnStop(const StopArgs&) { + if (mIsTest) return; // Don't touch non-hermetic bpf in test. + if (mStarted) sPoller.Stop(); + mStarted = false; + + // Although this shouldn't be required, there seems to be some cases when we + // don't fill enough of a Perfetto Chunk for Perfetto to automatically commit + // the traced data. This manually flushes OnStop so we commit at least once. + NetworkTraceHandler::Trace([&](NetworkTraceHandler::TraceContext ctx) { + perfetto::LockedHandle<NetworkTraceHandler> handle = + ctx.GetDataSourceLocked(); + // Trace is called for all active handlers, only flush our context. Since + // handle doesn't have a `.get()`, use `*` and `&` to get what it points to. + if (&(*handle) != this) return; + ctx.Flush(); + }); +} + +void NetworkTraceHandler::Write(const std::vector<PacketTrace>& packets, + NetworkTraceHandler::TraceContext& ctx) { + // TODO: remove this fallback once Perfetto stable has support for bundles. + if (!mInternLimit && !mAggregationThreshold) { + for (const PacketTrace& pkt : packets) { + auto dst = ctx.NewTracePacket(); + dst->set_timestamp(pkt.timestampNs); + auto* event = dst->set_network_packet(); + event->set_length(pkt.length); + Fill(pkt, event); + } + return; + } + + uint64_t minTs = std::numeric_limits<uint64_t>::max(); + std::unordered_map<BundleKey, BundleDetails, BundleHash, BundleEq> bundles; + for (const PacketTrace& pkt : packets) { + BundleKey key = pkt; + + // Dropping fields should remove them from the output and remove them from + // the aggregation key. In order to do the latter without changing the hash + // function, set the dropped fields to zero. + if (mDropTcpFlags) key.tcpFlags = 0; + if (mDropLocalPort) (key.egress ? key.sport : key.dport) = 0; + if (mDropRemotePort) (key.egress ? key.dport : key.sport) = 0; + + minTs = std::min(minTs, pkt.timestampNs); + + BundleDetails& bundle = bundles[key]; + bundle.time_and_len.emplace_back(pkt.timestampNs, pkt.length); + bundle.minTs = std::min(bundle.minTs, pkt.timestampNs); + bundle.maxTs = std::max(bundle.maxTs, pkt.timestampNs); + bundle.bytes += pkt.length; + } + + NetworkTraceState* incr_state = ctx.GetIncrementalState(); + for (const auto& kv : bundles) { + const BundleKey& key = kv.first; + const BundleDetails& details = kv.second; + + auto dst = ctx.NewTracePacket(); + dst->set_timestamp(details.minTs); + + // Incremental state is only used when interning. Set the flag based on + // whether state was cleared. Leave the flag empty in non-intern configs. + if (mInternLimit > 0) { + if (incr_state->cleared) { + dst->set_sequence_flags(TracePacket::SEQ_INCREMENTAL_STATE_CLEARED); + incr_state->cleared = false; + } else { + dst->set_sequence_flags(TracePacket::SEQ_NEEDS_INCREMENTAL_STATE); + } + } + + auto* event = FillWithInterning(incr_state, key, dst.get()); + + int count = details.time_and_len.size(); + if (!mAggregationThreshold || count < mAggregationThreshold) { + protozero::PackedVarInt offsets; + protozero::PackedVarInt lengths; + for (const auto& kv : details.time_and_len) { + offsets.Append(kv.first - details.minTs); + lengths.Append(kv.second); + } + + event->set_packet_timestamps(offsets); + event->set_packet_lengths(lengths); + } else { + event->set_total_duration(details.maxTs - details.minTs); + event->set_total_length(details.bytes); + event->set_total_packets(count); + } + } +} + +void NetworkTraceHandler::Fill(const PacketTrace& src, + NetworkPacketEvent* event) { + event->set_direction(src.egress ? TrafficDirection::DIR_EGRESS + : TrafficDirection::DIR_INGRESS); + event->set_uid(src.uid); + event->set_tag(src.tag); + + if (!mDropLocalPort) { + event->set_local_port(ntohs(src.egress ? src.sport : src.dport)); + } + if (!mDropRemotePort) { + event->set_remote_port(ntohs(src.egress ? src.dport : src.sport)); + } + if (!mDropTcpFlags) { + event->set_tcp_flags(src.tcpFlags); + } + + event->set_ip_proto(src.ipProto); + + char ifname[IF_NAMESIZE] = {}; + if (if_indextoname(src.ifindex, ifname) == ifname) { + event->set_interface(std::string(ifname)); + } else { + event->set_interface("error"); + } +} + +NetworkPacketBundle* NetworkTraceHandler::FillWithInterning( + NetworkTraceState* state, const BundleKey& key, TracePacket* dst) { + uint64_t iid = 0; + bool found = false; + + if (state->iids.size() < mInternLimit) { + auto [iter, success] = state->iids.try_emplace(key, state->iids.size() + 1); + iid = iter->second; + found = true; + + if (success) { + // If we successfully empaced, record the newly interned data. + auto* packet_context = dst->set_interned_data()->add_packet_context(); + Fill(key, packet_context->set_ctx()); + packet_context->set_iid(iid); + } + } else { + auto iter = state->iids.find(key); + if (iter != state->iids.end()) { + iid = iter->second; + found = true; + } + } + + auto* event = dst->set_network_packet_bundle(); + if (found) { + event->set_iid(iid); + } else { + Fill(key, event->set_ctx()); + } + + return event; +} + +} // namespace bpf +} // namespace android
diff --git a/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp b/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp new file mode 100644 index 0000000..f2c1a86 --- /dev/null +++ b/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp
@@ -0,0 +1,395 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <vector> + +#include "netdbpf/NetworkTraceHandler.h" +#include "protos/perfetto/config/android/network_trace_config.gen.h" +#include "protos/perfetto/trace/android/network_trace.pb.h" +#include "protos/perfetto/trace/trace.pb.h" +#include "protos/perfetto/trace/trace_packet.pb.h" + +namespace android { +namespace bpf { +using ::perfetto::protos::NetworkPacketEvent; +using ::perfetto::protos::NetworkPacketTraceConfig; +using ::perfetto::protos::Trace; +using ::perfetto::protos::TracePacket; +using ::perfetto::protos::TrafficDirection; + +class NetworkTraceHandlerTest : public testing::Test { + protected: + // Starts a tracing session with the handler under test. + std::unique_ptr<perfetto::TracingSession> StartTracing( + NetworkPacketTraceConfig settings) { + perfetto::TracingInitArgs args; + args.backends = perfetto::kInProcessBackend; + perfetto::Tracing::Initialize(args); + + perfetto::DataSourceDescriptor dsd; + dsd.set_name("test.network_packets"); + NetworkTraceHandler::Register(dsd, /*isTest=*/true); + + perfetto::TraceConfig cfg; + cfg.add_buffers()->set_size_kb(1024); + auto* config = cfg.add_data_sources()->mutable_config(); + config->set_name("test.network_packets"); + config->set_network_packet_trace_config_raw(settings.SerializeAsString()); + + auto session = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend); + session->Setup(cfg); + session->StartBlocking(); + return session; + } + + // Stops the trace session and reports all relevant trace packets. + bool StopTracing(perfetto::TracingSession* session, + std::vector<TracePacket>* output) { + session->StopBlocking(); + + Trace trace; + std::vector<char> raw_trace = session->ReadTraceBlocking(); + if (!trace.ParseFromArray(raw_trace.data(), raw_trace.size())) { + ADD_FAILURE() << "trace.ParseFromArray failed"; + return false; + } + + // This is a real trace and includes irrelevant trace packets such as trace + // metadata. The following strips the results to just the packets we want. + for (const auto& pkt : trace.packet()) { + if (pkt.has_network_packet() || pkt.has_network_packet_bundle()) { + output->emplace_back(pkt); + } + } + + return true; + } + + // This runs a trace with a single call to Write. + bool TraceAndSortPackets(const std::vector<PacketTrace>& input, + std::vector<TracePacket>* output, + NetworkPacketTraceConfig config = {}) { + auto session = StartTracing(config); + NetworkTraceHandler::Trace([&](NetworkTraceHandler::TraceContext ctx) { + ctx.GetDataSourceLocked()->Write(input, ctx); + ctx.Flush(); + }); + + if (!StopTracing(session.get(), output)) { + return false; + } + + // Sort to provide deterministic ordering regardless of Perfetto internals + // or implementation-defined (e.g. hash map) reshuffling. + std::sort(output->begin(), output->end(), + [](const TracePacket& a, const TracePacket& b) { + return a.timestamp() < b.timestamp(); + }); + + return true; + } +}; + +TEST_F(NetworkTraceHandlerTest, WriteBasicFields) { + std::vector<PacketTrace> input = { + PacketTrace{ + .timestampNs = 1000, + .length = 100, + .uid = 10, + .tag = 123, + .ipProto = 6, + .tcpFlags = 1, + }, + }; + + std::vector<TracePacket> events; + ASSERT_TRUE(TraceAndSortPackets(input, &events)); + + ASSERT_EQ(events.size(), 1); + EXPECT_THAT(events[0].timestamp(), 1000); + EXPECT_THAT(events[0].network_packet().uid(), 10); + EXPECT_THAT(events[0].network_packet().tag(), 123); + EXPECT_THAT(events[0].network_packet().ip_proto(), 6); + EXPECT_THAT(events[0].network_packet().tcp_flags(), 1); + EXPECT_THAT(events[0].network_packet().length(), 100); + EXPECT_THAT(events[0].has_sequence_flags(), false); +} + +TEST_F(NetworkTraceHandlerTest, WriteDirectionAndPorts) { + std::vector<PacketTrace> input = { + PacketTrace{ + .timestampNs = 1, + .sport = htons(8080), + .dport = htons(443), + .egress = true, + }, + PacketTrace{ + .timestampNs = 2, + .sport = htons(443), + .dport = htons(8080), + .egress = false, + }, + }; + + std::vector<TracePacket> events; + ASSERT_TRUE(TraceAndSortPackets(input, &events)); + + ASSERT_EQ(events.size(), 2); + EXPECT_THAT(events[0].network_packet().local_port(), 8080); + EXPECT_THAT(events[0].network_packet().remote_port(), 443); + EXPECT_THAT(events[0].network_packet().direction(), + TrafficDirection::DIR_EGRESS); + EXPECT_THAT(events[1].network_packet().local_port(), 8080); + EXPECT_THAT(events[1].network_packet().remote_port(), 443); + EXPECT_THAT(events[1].network_packet().direction(), + TrafficDirection::DIR_INGRESS); +} + +TEST_F(NetworkTraceHandlerTest, BasicBundling) { + // TODO: remove this once bundling becomes default. Until then, set arbitrary + // aggregation threshold to enable bundling. + NetworkPacketTraceConfig config; + config.set_aggregation_threshold(10); + + std::vector<PacketTrace> input = { + PacketTrace{.uid = 123, .timestampNs = 2, .length = 200}, + PacketTrace{.uid = 123, .timestampNs = 1, .length = 100}, + PacketTrace{.uid = 123, .timestampNs = 4, .length = 300}, + + PacketTrace{.uid = 456, .timestampNs = 2, .length = 400}, + PacketTrace{.uid = 456, .timestampNs = 4, .length = 100}, + }; + + std::vector<TracePacket> events; + ASSERT_TRUE(TraceAndSortPackets(input, &events, config)); + + ASSERT_EQ(events.size(), 2); + + EXPECT_THAT(events[0].timestamp(), 1); + EXPECT_THAT(events[0].network_packet_bundle().ctx().uid(), 123); + EXPECT_THAT(events[0].network_packet_bundle().packet_lengths(), + testing::ElementsAre(200, 100, 300)); + EXPECT_THAT(events[0].network_packet_bundle().packet_timestamps(), + testing::ElementsAre(1, 0, 3)); + + EXPECT_THAT(events[1].timestamp(), 2); + EXPECT_THAT(events[1].network_packet_bundle().ctx().uid(), 456); + EXPECT_THAT(events[1].network_packet_bundle().packet_lengths(), + testing::ElementsAre(400, 100)); + EXPECT_THAT(events[1].network_packet_bundle().packet_timestamps(), + testing::ElementsAre(0, 2)); +} + +TEST_F(NetworkTraceHandlerTest, AggregationThreshold) { + // With an aggregation threshold of 3, the set of packets with uid=123 will + // be aggregated (3>=3) whereas packets with uid=456 get per-packet info. + NetworkPacketTraceConfig config; + config.set_aggregation_threshold(3); + + std::vector<PacketTrace> input = { + PacketTrace{.uid = 123, .timestampNs = 2, .length = 200}, + PacketTrace{.uid = 123, .timestampNs = 1, .length = 100}, + PacketTrace{.uid = 123, .timestampNs = 4, .length = 300}, + + PacketTrace{.uid = 456, .timestampNs = 2, .length = 400}, + PacketTrace{.uid = 456, .timestampNs = 4, .length = 100}, + }; + + std::vector<TracePacket> events; + ASSERT_TRUE(TraceAndSortPackets(input, &events, config)); + + ASSERT_EQ(events.size(), 2); + + EXPECT_EQ(events[0].timestamp(), 1); + EXPECT_EQ(events[0].network_packet_bundle().ctx().uid(), 123); + EXPECT_EQ(events[0].network_packet_bundle().total_duration(), 3); + EXPECT_EQ(events[0].network_packet_bundle().total_packets(), 3); + EXPECT_EQ(events[0].network_packet_bundle().total_length(), 600); + + EXPECT_EQ(events[1].timestamp(), 2); + EXPECT_EQ(events[1].network_packet_bundle().ctx().uid(), 456); + EXPECT_THAT(events[1].network_packet_bundle().packet_lengths(), + testing::ElementsAre(400, 100)); + EXPECT_THAT(events[1].network_packet_bundle().packet_timestamps(), + testing::ElementsAre(0, 2)); +} + +TEST_F(NetworkTraceHandlerTest, DropLocalPort) { + NetworkPacketTraceConfig config; + config.set_drop_local_port(true); + config.set_aggregation_threshold(10); + + __be16 a = htons(10000); + __be16 b = htons(10001); + std::vector<PacketTrace> input = { + // Recall that local is `src` for egress and `dst` for ingress. + PacketTrace{.timestampNs = 1, .length = 2, .egress = true, .sport = a}, + PacketTrace{.timestampNs = 2, .length = 4, .egress = false, .dport = a}, + PacketTrace{.timestampNs = 3, .length = 6, .egress = true, .sport = b}, + PacketTrace{.timestampNs = 4, .length = 8, .egress = false, .dport = b}, + }; + + std::vector<TracePacket> events; + ASSERT_TRUE(TraceAndSortPackets(input, &events, config)); + ASSERT_EQ(events.size(), 2); + + // Despite having different local ports, drop and bundle by remaining fields. + EXPECT_EQ(events[0].network_packet_bundle().ctx().direction(), + TrafficDirection::DIR_EGRESS); + EXPECT_THAT(events[0].network_packet_bundle().packet_lengths(), + testing::ElementsAre(2, 6)); + + EXPECT_EQ(events[1].network_packet_bundle().ctx().direction(), + TrafficDirection::DIR_INGRESS); + EXPECT_THAT(events[1].network_packet_bundle().packet_lengths(), + testing::ElementsAre(4, 8)); + + // Local port shouldn't be in output. + EXPECT_FALSE(events[0].network_packet_bundle().ctx().has_local_port()); + EXPECT_FALSE(events[1].network_packet_bundle().ctx().has_local_port()); +} + +TEST_F(NetworkTraceHandlerTest, DropRemotePort) { + NetworkPacketTraceConfig config; + config.set_drop_remote_port(true); + config.set_aggregation_threshold(10); + + __be16 a = htons(443); + __be16 b = htons(80); + std::vector<PacketTrace> input = { + // Recall that remote is `dst` for egress and `src` for ingress. + PacketTrace{.timestampNs = 1, .length = 2, .egress = true, .dport = a}, + PacketTrace{.timestampNs = 2, .length = 4, .egress = false, .sport = a}, + PacketTrace{.timestampNs = 3, .length = 6, .egress = true, .dport = b}, + PacketTrace{.timestampNs = 4, .length = 8, .egress = false, .sport = b}, + }; + + std::vector<TracePacket> events; + ASSERT_TRUE(TraceAndSortPackets(input, &events, config)); + ASSERT_EQ(events.size(), 2); + + // Despite having different remote ports, drop and bundle by remaining fields. + EXPECT_EQ(events[0].network_packet_bundle().ctx().direction(), + TrafficDirection::DIR_EGRESS); + EXPECT_THAT(events[0].network_packet_bundle().packet_lengths(), + testing::ElementsAre(2, 6)); + + EXPECT_EQ(events[1].network_packet_bundle().ctx().direction(), + TrafficDirection::DIR_INGRESS); + EXPECT_THAT(events[1].network_packet_bundle().packet_lengths(), + testing::ElementsAre(4, 8)); + + // Remote port shouldn't be in output. + EXPECT_FALSE(events[0].network_packet_bundle().ctx().has_remote_port()); + EXPECT_FALSE(events[1].network_packet_bundle().ctx().has_remote_port()); +} + +TEST_F(NetworkTraceHandlerTest, DropTcpFlags) { + NetworkPacketTraceConfig config; + config.set_drop_tcp_flags(true); + config.set_aggregation_threshold(10); + + std::vector<PacketTrace> input = { + PacketTrace{.timestampNs = 1, .uid = 123, .length = 1, .tcpFlags = 1}, + PacketTrace{.timestampNs = 2, .uid = 123, .length = 2, .tcpFlags = 2}, + PacketTrace{.timestampNs = 3, .uid = 456, .length = 3, .tcpFlags = 1}, + PacketTrace{.timestampNs = 4, .uid = 456, .length = 4, .tcpFlags = 2}, + }; + + std::vector<TracePacket> events; + ASSERT_TRUE(TraceAndSortPackets(input, &events, config)); + + ASSERT_EQ(events.size(), 2); + + // Despite having different tcp flags, drop and bundle by remaining fields. + EXPECT_EQ(events[0].network_packet_bundle().ctx().uid(), 123); + EXPECT_THAT(events[0].network_packet_bundle().packet_lengths(), + testing::ElementsAre(1, 2)); + + EXPECT_EQ(events[1].network_packet_bundle().ctx().uid(), 456); + EXPECT_THAT(events[1].network_packet_bundle().packet_lengths(), + testing::ElementsAre(3, 4)); + + // Tcp flags shouldn't be in output. + EXPECT_FALSE(events[0].network_packet_bundle().ctx().has_tcp_flags()); + EXPECT_FALSE(events[1].network_packet_bundle().ctx().has_tcp_flags()); +} + +TEST_F(NetworkTraceHandlerTest, Interning) { + NetworkPacketTraceConfig config; + config.set_intern_limit(2); + + // The test writes 4 packets coming from three sources (uids). With an intern + // limit of 2, the first two sources should be interned. This test splits this + // into individual writes since internally an unordered map is used and would + // otherwise non-deterministically choose what to intern (this is fine for + // real use, but not good for test assertions). + std::vector<std::vector<PacketTrace>> inputs = { + {PacketTrace{.timestampNs = 1, .uid = 123}}, + {PacketTrace{.timestampNs = 2, .uid = 456}}, + {PacketTrace{.timestampNs = 3, .uid = 789}}, + {PacketTrace{.timestampNs = 4, .uid = 123}}, + }; + + auto session = StartTracing(config); + + NetworkTraceHandler::Trace([&](NetworkTraceHandler::TraceContext ctx) { + ctx.GetDataSourceLocked()->Write(inputs[0], ctx); + ctx.GetDataSourceLocked()->Write(inputs[1], ctx); + ctx.GetDataSourceLocked()->Write(inputs[2], ctx); + ctx.GetDataSourceLocked()->Write(inputs[3], ctx); + ctx.Flush(); + }); + + std::vector<TracePacket> events; + ASSERT_TRUE(StopTracing(session.get(), &events)); + + ASSERT_EQ(events.size(), 4); + + // First time seen, emit new interned data, bundle uses iid instead of ctx. + EXPECT_EQ(events[0].network_packet_bundle().iid(), 1); + ASSERT_EQ(events[0].interned_data().packet_context().size(), 1); + EXPECT_EQ(events[0].interned_data().packet_context(0).iid(), 1); + EXPECT_EQ(events[0].interned_data().packet_context(0).ctx().uid(), 123); + EXPECT_EQ(events[0].sequence_flags(), + TracePacket::SEQ_INCREMENTAL_STATE_CLEARED); + + // First time seen, emit new interned data, bundle uses iid instead of ctx. + EXPECT_EQ(events[1].network_packet_bundle().iid(), 2); + ASSERT_EQ(events[1].interned_data().packet_context().size(), 1); + EXPECT_EQ(events[1].interned_data().packet_context(0).iid(), 2); + EXPECT_EQ(events[1].interned_data().packet_context(0).ctx().uid(), 456); + EXPECT_EQ(events[1].sequence_flags(), + TracePacket::SEQ_NEEDS_INCREMENTAL_STATE); + + // Not enough room in intern table (limit 2), inline the context. + EXPECT_EQ(events[2].network_packet_bundle().ctx().uid(), 789); + EXPECT_EQ(events[2].interned_data().packet_context().size(), 0); + EXPECT_EQ(events[2].sequence_flags(), + TracePacket::SEQ_NEEDS_INCREMENTAL_STATE); + + // Second time seen, no need to re-emit interned data, only record iid. + EXPECT_EQ(events[3].network_packet_bundle().iid(), 1); + EXPECT_EQ(events[3].interned_data().packet_context().size(), 0); + EXPECT_EQ(events[3].sequence_flags(), + TracePacket::SEQ_NEEDS_INCREMENTAL_STATE); +} + +} // namespace bpf +} // namespace android
diff --git a/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp b/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp new file mode 100644 index 0000000..d538368 --- /dev/null +++ b/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
@@ -0,0 +1,147 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "NetworkTrace" +#define ATRACE_TAG ATRACE_TAG_NETWORK + +#include "netdbpf/NetworkTracePoller.h" + +#include <bpf/BpfUtils.h> +#include <cutils/trace.h> +#include <log/log.h> +#include <perfetto/tracing/platform.h> +#include <perfetto/tracing/tracing.h> + +namespace android { +namespace bpf { +namespace internal { + +void NetworkTracePoller::SchedulePolling() { + // Schedules another run of ourselves to recursively poll periodically. + mTaskRunner->PostDelayedTask( + [this]() { + mMutex.lock(); + SchedulePolling(); + ConsumeAllLocked(); + mMutex.unlock(); + }, + mPollMs); +} + +bool NetworkTracePoller::Start(uint32_t pollMs) { + ALOGD("Starting datasource"); + + std::scoped_lock<std::mutex> lock(mMutex); + if (mSessionCount > 0) { + if (mPollMs != pollMs) { + // Nothing technical prevents mPollMs from changing, it's just unclear + // what the right behavior is. Taking the min of active values could poll + // too frequently giving some sessions too much data. Taking the max could + // be too infrequent. For now, do nothing. + ALOGI("poll_ms can't be changed while running, ignoring poll_ms=%d", + pollMs); + } + mSessionCount++; + return true; + } + + auto status = mConfigurationMap.init(PACKET_TRACE_ENABLED_MAP_PATH); + if (!status.ok()) { + ALOGW("Failed to bind config map: %s", status.error().message().c_str()); + return false; + } + + auto rb = BpfRingbuf<PacketTrace>::Create(PACKET_TRACE_RINGBUF_PATH); + if (!rb.ok()) { + ALOGW("Failed to create ringbuf: %s", rb.error().message().c_str()); + return false; + } + + mRingBuffer = std::move(*rb); + + auto res = mConfigurationMap.writeValue(0, true, BPF_ANY); + if (!res.ok()) { + ALOGW("Failed to enable tracing: %s", res.error().message().c_str()); + return false; + } + + // Start a task runner to run ConsumeAll every mPollMs milliseconds. + mTaskRunner = perfetto::Platform::GetDefaultPlatform()->CreateTaskRunner({}); + mPollMs = pollMs; + SchedulePolling(); + + mSessionCount++; + return true; +} + +bool NetworkTracePoller::Stop() { + ALOGD("Stopping datasource"); + + std::scoped_lock<std::mutex> lock(mMutex); + if (mSessionCount == 0) return false; // This should never happen + + // If this isn't the last session, don't clean up yet. + if (--mSessionCount > 0) return true; + + auto res = mConfigurationMap.writeValue(0, false, BPF_ANY); + if (!res.ok()) { + ALOGW("Failed to disable tracing: %s", res.error().message().c_str()); + } + + // Make sure everything in the system has actually seen the 'false' we just + // wrote, things should now be well and truly disabled. + synchronizeKernelRCU(); + + // Drain remaining events from the ring buffer now that tracing is disabled. + // This prevents the next trace from seeing stale events and allows writing + // the last batch of events to Perfetto. + ConsumeAllLocked(); + + mTaskRunner.reset(); + mRingBuffer.reset(); + + return res.ok(); +} + +bool NetworkTracePoller::ConsumeAll() { + std::scoped_lock<std::mutex> lock(mMutex); + return ConsumeAllLocked(); +} + +bool NetworkTracePoller::ConsumeAllLocked() { + if (mRingBuffer == nullptr) { + ALOGW("Tracing is not active"); + return false; + } + + std::vector<PacketTrace> packets; + base::Result<int> ret = mRingBuffer->ConsumeAll( + [&](const PacketTrace& pkt) { packets.push_back(pkt); }); + if (!ret.ok()) { + ALOGW("Failed to poll ringbuf: %s", ret.error().message().c_str()); + return false; + } + + ATRACE_INT("NetworkTracePackets", packets.size()); + + mCallback(packets); + + return true; +} + +} // namespace internal +} // namespace bpf +} // namespace android
diff --git a/service-t/native/libs/libnetworkstats/NetworkTracePollerTest.cpp b/service-t/native/libs/libnetworkstats/NetworkTracePollerTest.cpp new file mode 100644 index 0000000..df07bbe --- /dev/null +++ b/service-t/native/libs/libnetworkstats/NetworkTracePollerTest.cpp
@@ -0,0 +1,241 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/unique_fd.h> +#include <android/multinetwork.h> +#include <arpa/inet.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <inttypes.h> +#include <net/if.h> +#include <netinet/tcp.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#include <chrono> +#include <thread> +#include <vector> + +#include "netdbpf/NetworkTracePoller.h" + +using ::testing::AllOf; +using ::testing::AnyOf; +using ::testing::Each; +using ::testing::Eq; +using ::testing::Field; +using ::testing::Test; + +namespace android { +namespace bpf { +namespace internal { +// Use uint32 max to cause the handler to never Loop. Instead, the tests will +// manually drive things by calling ConsumeAll explicitly. +constexpr uint32_t kNeverPoll = std::numeric_limits<uint32_t>::max(); + +__be16 bindAndListen(int s) { + sockaddr_in sin = {.sin_family = AF_INET}; + socklen_t len = sizeof(sin); + if (bind(s, (sockaddr*)&sin, sizeof(sin))) return 0; + if (listen(s, 1)) return 0; + if (getsockname(s, (sockaddr*)&sin, &len)) return 0; + return sin.sin_port; +} + +// This takes tcp flag constants from the standard library and makes them usable +// with the flags we get from BPF. The standard library flags are big endian +// whereas the BPF flags are reported in host byte order. BPF also trims the +// flags down to the 8 single-bit flag bits (fin, syn, rst, etc). +constexpr inline uint8_t FlagToHost(__be32 be_unix_flags) { + return ntohl(be_unix_flags) >> 16; +} + +// Pretty prints all fields for a list of packets (useful for debugging). +struct PacketPrinter { + const std::vector<PacketTrace>& data; + static constexpr char kTcpFlagNames[] = "FSRPAUEC"; + + friend std::ostream& operator<<(std::ostream& os, const PacketPrinter& d) { + os << "Packet count: " << d.data.size(); + for (const PacketTrace& info : d.data) { + os << "\nifidx=" << info.ifindex; + os << ", len=" << info.length; + os << ", uid=" << info.uid; + os << ", tag=" << info.tag; + os << ", sport=" << info.sport; + os << ", dport=" << info.dport; + os << ", direction=" << (info.egress ? "egress" : "ingress"); + os << ", proto=" << static_cast<int>(info.ipProto); + os << ", ip=" << static_cast<int>(info.ipVersion); + os << ", flags="; + for (int i = 0; i < 8; i++) { + os << ((info.tcpFlags & (1 << i)) ? kTcpFlagNames[i] : '.'); + } + } + return os; + } +}; + +class NetworkTracePollerTest : public testing::Test { + protected: + void SetUp() { + if (access(PACKET_TRACE_RINGBUF_PATH, R_OK)) { + GTEST_SKIP() << "Network tracing is not enabled/loaded on this build."; + } + if (sizeof(void*) != 8) { + GTEST_SKIP() << "Network tracing requires 64-bit build."; + } + } +}; + +TEST_F(NetworkTracePollerTest, PollWhileInactive) { + NetworkTracePoller handler([&](const std::vector<PacketTrace>& pkt) {}); + + // One succeed after start and before stop. + EXPECT_FALSE(handler.ConsumeAll()); + ASSERT_TRUE(handler.Start(kNeverPoll)); + EXPECT_TRUE(handler.ConsumeAll()); + ASSERT_TRUE(handler.Stop()); + EXPECT_FALSE(handler.ConsumeAll()); +} + +TEST_F(NetworkTracePollerTest, ConcurrentSessions) { + // Simulate two concurrent sessions (two starts followed by two stops). Check + // that tracing is stopped only after both sessions finish. + NetworkTracePoller handler([&](const std::vector<PacketTrace>& pkt) {}); + + ASSERT_TRUE(handler.Start(kNeverPoll)); + EXPECT_TRUE(handler.ConsumeAll()); + + ASSERT_TRUE(handler.Start(kNeverPoll)); + EXPECT_TRUE(handler.ConsumeAll()); + + ASSERT_TRUE(handler.Stop()); + EXPECT_TRUE(handler.ConsumeAll()); + + ASSERT_TRUE(handler.Stop()); + EXPECT_FALSE(handler.ConsumeAll()); +} + +TEST_F(NetworkTracePollerTest, TraceTcpSession) { + __be16 server_port = 0; + std::vector<PacketTrace> packets, unmatched; + + // Record all packets with the bound address and current uid. This callback is + // involked only within ConsumeAll, at which point the port should have + // already been filled in and all packets have been processed. + NetworkTracePoller handler([&](const std::vector<PacketTrace>& pkts) { + for (const PacketTrace& pkt : pkts) { + if ((pkt.sport == server_port || pkt.dport == server_port) && + pkt.uid == getuid()) { + packets.push_back(pkt); + } else { + // There may be spurious packets not caused by the test. These are only + // captured so that we can report them to help debug certain errors. + unmatched.push_back(pkt); + } + } + }); + + ASSERT_TRUE(handler.Start(kNeverPoll)); + const uint32_t kClientTag = 2468; + const uint32_t kServerTag = 1357; + + // Go through a typical connection sequence between two v4 sockets using tcp. + // This covers connection handshake, shutdown, and one data packet. + { + android::base::unique_fd clientsocket(socket(AF_INET, SOCK_STREAM, 0)); + ASSERT_NE(-1, clientsocket) << "Failed to open client socket"; + ASSERT_EQ(android_tag_socket(clientsocket, kClientTag), 0); + + android::base::unique_fd serversocket(socket(AF_INET, SOCK_STREAM, 0)); + ASSERT_NE(-1, serversocket) << "Failed to open server socket"; + ASSERT_EQ(android_tag_socket(serversocket, kServerTag), 0); + + server_port = bindAndListen(serversocket); + ASSERT_NE(0, server_port) << "Can't bind to server port"; + + sockaddr_in addr = {.sin_family = AF_INET, .sin_port = server_port}; + ASSERT_EQ(0, connect(clientsocket, (sockaddr*)&addr, sizeof(addr))) + << "connect to loopback failed: " << strerror(errno); + + int accepted = accept(serversocket, nullptr, nullptr); + ASSERT_NE(-1, accepted) << "accept connection failed: " << strerror(errno); + + const char data[] = "abcdefghijklmnopqrstuvwxyz"; + EXPECT_EQ(send(clientsocket, data, sizeof(data), 0), sizeof(data)) + << "failed to send message: " << strerror(errno); + + char buff[100] = {}; + EXPECT_EQ(recv(accepted, buff, sizeof(buff), 0), sizeof(data)) + << "failed to receive message: " << strerror(errno); + + EXPECT_EQ(std::string(data), std::string(buff)); + } + + // Poll until we get all the packets (typically we get it first try). + for (int attempt = 0; attempt < 10; attempt++) { + ASSERT_TRUE(handler.ConsumeAll()); + if (packets.size() >= 12) break; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + ASSERT_TRUE(handler.Stop()); + + // There are 12 packets in total (6 messages: each seen by client & server): + // 1. Client connects to server with syn + // 2. Server responds with syn ack + // 3. Client responds with ack + // 4. Client sends data with psh ack + // 5. Server acks the data packet + // 6. Client closes connection with fin ack + ASSERT_EQ(packets.size(), 12) + << PacketPrinter{packets} + << "\nUnmatched packets: " << PacketPrinter{unmatched}; + + // All packets should be TCP packets. + EXPECT_THAT(packets, Each(Field(&PacketTrace::ipProto, Eq(IPPROTO_TCP)))); + + // Packet 1: client requests connection with server. + EXPECT_EQ(packets[0].egress, 1) << PacketPrinter{packets}; + EXPECT_EQ(packets[0].dport, server_port) << PacketPrinter{packets}; + EXPECT_EQ(packets[0].tag, kClientTag) << PacketPrinter{packets}; + EXPECT_EQ(packets[0].tcpFlags, FlagToHost(TCP_FLAG_SYN)) + << PacketPrinter{packets}; + + // Packet 2: server receives request from client. + EXPECT_EQ(packets[1].egress, 0) << PacketPrinter{packets}; + EXPECT_EQ(packets[1].dport, server_port) << PacketPrinter{packets}; + EXPECT_EQ(packets[1].tag, kServerTag) << PacketPrinter{packets}; + EXPECT_EQ(packets[1].tcpFlags, FlagToHost(TCP_FLAG_SYN)) + << PacketPrinter{packets}; + + // Packet 3: server replies back with syn ack. + EXPECT_EQ(packets[2].egress, 1) << PacketPrinter{packets}; + EXPECT_EQ(packets[2].sport, server_port) << PacketPrinter{packets}; + EXPECT_EQ(packets[2].tcpFlags, FlagToHost(TCP_FLAG_SYN | TCP_FLAG_ACK)) + << PacketPrinter{packets}; + + // Packet 4: client receives the server's syn ack. + EXPECT_EQ(packets[3].egress, 0) << PacketPrinter{packets}; + EXPECT_EQ(packets[3].sport, server_port) << PacketPrinter{packets}; + EXPECT_EQ(packets[3].tcpFlags, FlagToHost(TCP_FLAG_SYN | TCP_FLAG_ACK)) + << PacketPrinter{packets}; +} + +} // namespace internal +} // namespace bpf +} // namespace android
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h b/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h index 8ab7e25..133009f 100644 --- a/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h +++ b/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
@@ -18,7 +18,7 @@ #define _BPF_NETWORKSTATS_H #include <bpf/BpfMap.h> -#include "bpf_shared.h" +#include "netd.h" namespace android { namespace bpf { @@ -26,7 +26,7 @@ // TODO: set this to a proper value based on the map size; constexpr int TAG_STATS_MAP_SOFT_LIMIT = 3; constexpr int UID_ALL = -1; -constexpr int TAG_ALL = -1; +//constexpr int TAG_ALL = -1; constexpr int TAG_NONE = 0; constexpr int SET_ALL = -1; constexpr int SET_DEFAULT = 0; @@ -63,9 +63,8 @@ const BpfMap<uint32_t, StatsValue>& ifaceStatsMap, const BpfMap<uint32_t, IfaceValue>& ifaceNameMap); // For test only -int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>* lines, - const std::vector<std::string>& limitIfaces, int limitTag, - int limitUid, const BpfMap<StatsKey, StatsValue>& statsMap, +int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>& lines, + const BpfMap<StatsKey, StatsValue>& statsMap, const BpfMap<uint32_t, IfaceValue>& ifaceMap); // For test only int cleanStatsMapInternal(const base::unique_fd& cookieTagMap, const base::unique_fd& tagStatsMap); @@ -107,18 +106,16 @@ } // For test only -int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines, +int parseBpfNetworkStatsDevInternal(std::vector<stats_line>& lines, const BpfMap<uint32_t, StatsValue>& statsMap, const BpfMap<uint32_t, IfaceValue>& ifaceMap); int bpfGetUidStats(uid_t uid, Stats* stats); int bpfGetIfaceStats(const char* iface, Stats* stats); -int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines, - const std::vector<std::string>& limitIfaces, int limitTag, - int limitUid); +int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines); int parseBpfNetworkStatsDev(std::vector<stats_line>* lines); -void groupNetworkStats(std::vector<stats_line>* lines); +void groupNetworkStats(std::vector<stats_line>& lines); int cleanStatsMap(); } // namespace bpf } // namespace android
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h new file mode 100644 index 0000000..bc10e68 --- /dev/null +++ b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
@@ -0,0 +1,110 @@ +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <perfetto/base/task_runner.h> +#include <perfetto/tracing.h> + +#include <string> +#include <unordered_map> + +#include "netdbpf/NetworkTracePoller.h" + +// For PacketTrace struct definition +#include "netd.h" + +namespace android { +namespace bpf { + +// BundleKeys are PacketTraces where timestamp and length are ignored. +using BundleKey = PacketTrace; + +// BundleKeys are hashed using all fields except timestamp/length. +struct BundleHash { + std::size_t operator()(const BundleKey& a) const; +}; + +// BundleKeys are equal if all fields except timestamp/length are equal. +struct BundleEq { + bool operator()(const BundleKey& a, const BundleKey& b) const; +}; + +// Track the bundles we've interned and their corresponding intern id (iid). We +// use IncrementalState (rather than state in the Handler) so that we stay in +// sync with Perfetto's periodic state clearing (which helps recover from packet +// loss). When state is cleared, the state object is replaced with a new default +// constructed instance. +struct NetworkTraceState { + bool cleared = true; + std::unordered_map<BundleKey, uint64_t, BundleHash, BundleEq> iids; +}; + +// Inject our custom incremental state type using type traits. +struct NetworkTraceTraits : public perfetto::DefaultDataSourceTraits { + using IncrementalStateType = NetworkTraceState; +}; + +// NetworkTraceHandler implements the android.network_packets data source. This +// class is registered with Perfetto and is instantiated when tracing starts and +// destroyed when tracing ends. There is one instance per trace session. +class NetworkTraceHandler + : public perfetto::DataSource<NetworkTraceHandler, NetworkTraceTraits> { + public: + // Registers this DataSource. + static void RegisterDataSource(); + + // Connects to the system Perfetto daemon and registers the trace handler. + static void InitPerfettoTracing(); + + // When isTest is true, skip non-hermetic code. + NetworkTraceHandler(bool isTest = false) : mIsTest(isTest) {} + + // perfetto::DataSource overrides: + void OnSetup(const SetupArgs& args) override; + void OnStart(const StartArgs&) override; + void OnStop(const StopArgs&) override; + + // Writes the packets as Perfetto TracePackets, creating packets as needed + // using the provided callback (which allows easy testing). + void Write(const std::vector<PacketTrace>& packets, + NetworkTraceHandler::TraceContext& ctx); + + private: + // Convert a PacketTrace into a Perfetto trace packet. + void Fill(const PacketTrace& src, + ::perfetto::protos::pbzero::NetworkPacketEvent* event); + + // Fills in contextual information either inline or via interning. + ::perfetto::protos::pbzero::NetworkPacketBundle* FillWithInterning( + NetworkTraceState* state, const BundleKey& key, + ::perfetto::protos::pbzero::TracePacket* dst); + + static internal::NetworkTracePoller sPoller; + bool mStarted; + bool mIsTest; + + // Values from config, see proto for details. + uint32_t mPollMs; + uint32_t mInternLimit; + uint32_t mAggregationThreshold; + bool mDropLocalPort; + bool mDropRemotePort; + bool mDropTcpFlags; +}; + +} // namespace bpf +} // namespace android
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h new file mode 100644 index 0000000..adde51e --- /dev/null +++ b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h
@@ -0,0 +1,86 @@ +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <perfetto/base/task_runner.h> +#include <perfetto/tracing.h> + +#include <string> +#include <unordered_map> + +#include "android-base/thread_annotations.h" +#include "bpf/BpfMap.h" +#include "bpf/BpfRingbuf.h" + +// For PacketTrace struct definition +#include "netd.h" + +namespace android { +namespace bpf { +namespace internal { + +// NetworkTracePoller is responsible for interactions with the BPF ring buffer +// including polling. This class is an internal helper for NetworkTraceHandler, +// it is not meant to be used elsewhere. +class NetworkTracePoller { + public: + using EventSink = std::function<void(const std::vector<PacketTrace>&)>; + + // Testonly: initialize with a callback capable of intercepting data. + NetworkTracePoller(EventSink callback) : mCallback(std::move(callback)) {} + + // Starts tracing with the given poll interval. + bool Start(uint32_t pollMs) EXCLUDES(mMutex); + + // Stops tracing and release any held state. + bool Stop() EXCLUDES(mMutex); + + // Consumes all available events from the ringbuffer. + bool ConsumeAll() EXCLUDES(mMutex); + + private: + void SchedulePolling() REQUIRES(mMutex); + bool ConsumeAllLocked() REQUIRES(mMutex); + + std::mutex mMutex; + + // Records the number of successfully started active sessions so that only the + // first active session attempts setup and only the last cleans up. Note that + // the session count will remain zero if Start fails. It is expected that Stop + // will not be called for any trace session where Start fails. + int mSessionCount GUARDED_BY(mMutex); + + // How often to poll the ring buffer, defined by the trace config. + uint32_t mPollMs GUARDED_BY(mMutex); + + // The function to process PacketTrace, typically a Perfetto sink. + EventSink mCallback GUARDED_BY(mMutex); + + // The BPF ring buffer handle. + std::unique_ptr<BpfRingbuf<PacketTrace>> mRingBuffer GUARDED_BY(mMutex); + + // The packet tracing config map (really a 1-element array). + BpfMap<uint32_t, bool> mConfigurationMap GUARDED_BY(mMutex); + + // This must be the last member, causing it to be the first deleted. If it is + // not, members required for callbacks can be deleted before it's stopped. + std::unique_ptr<perfetto::base::TaskRunner> mTaskRunner GUARDED_BY(mMutex); +}; + +} // namespace internal +} // namespace bpf +} // namespace android
diff --git a/service-t/src/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java index 6cee08a..a884840 100644 --- a/service-t/src/com/android/server/IpSecService.java +++ b/service-t/src/com/android/server/IpSecService.java
@@ -17,6 +17,8 @@ package com.android.server; import static android.Manifest.permission.DUMP; +import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.net.IpSecManager.FEATURE_IPSEC_TUNNEL_MIGRATION; import static android.net.IpSecManager.INVALID_RESOURCE_ID; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; @@ -36,6 +38,7 @@ import android.net.IpSecAlgorithm; import android.net.IpSecConfig; import android.net.IpSecManager; +import android.net.IpSecMigrateInfoParcel; import android.net.IpSecSpiResponse; import android.net.IpSecTransform; import android.net.IpSecTransformResponse; @@ -63,6 +66,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.BinderUtils; import com.android.net.module.util.NetdUtils; import com.android.net.module.util.PermissionUtils; @@ -100,6 +104,7 @@ private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms private static final InetAddress INADDR_ANY; + private static final InetAddress IN6ADDR_ANY; @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10; @@ -108,6 +113,8 @@ static { try { INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); + IN6ADDR_ANY = InetAddress.getByAddress( + new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); } catch (UnknownHostException e) { throw new RuntimeException(e); } @@ -590,14 +597,19 @@ } /** - * Tracks an SA in the kernel, and manages cleanup paths. Once a TransformRecord is - * created, the SpiRecord that originally tracked the SAs will reliquish the - * responsibility of freeing the underlying SA to this class via the mOwnedByTransform flag. + * Tracks an SA in the kernel, and manages cleanup paths. Once a TransformRecord is created, the + * SpiRecord that originally tracked the SAs will reliquish the responsibility of freeing the + * underlying SA to this class via the mOwnedByTransform flag. + * + * <p>This class is not thread-safe, and expects that that users of this class will ensure + * synchronization and thread safety by holding the IpSecService.this instance lock */ private final class TransformRecord extends OwnedResourceRecord { private final IpSecConfig mConfig; private final SpiRecord mSpi; private final EncapSocketRecord mSocket; + private String mNewSourceAddress = null; + private String mNewDestinationAddress = null; TransformRecord( int resourceId, IpSecConfig config, SpiRecord spi, EncapSocketRecord socket) { @@ -621,6 +633,51 @@ return mSocket; } + @GuardedBy("IpSecService.this") + public String getNewSourceAddress() { + return mNewSourceAddress; + } + + @GuardedBy("IpSecService.this") + public String getNewDestinationAddress() { + return mNewDestinationAddress; + } + + private void verifyTunnelModeOrThrow() { + if (mConfig.getMode() != IpSecTransform.MODE_TUNNEL) { + throw new UnsupportedOperationException( + "Migration requested/called on non-tunnel-mode transform"); + } + } + + /** Start migrating this transform to new source and destination addresses */ + @GuardedBy("IpSecService.this") + public void startMigration(String newSourceAddress, String newDestinationAddress) { + verifyTunnelModeOrThrow(); + Objects.requireNonNull(newSourceAddress, "newSourceAddress was null"); + Objects.requireNonNull(newDestinationAddress, "newDestinationAddress was null"); + mNewSourceAddress = newSourceAddress; + mNewDestinationAddress = newDestinationAddress; + } + + /** Finish migration and update addresses. */ + @GuardedBy("IpSecService.this") + public void finishMigration() { + verifyTunnelModeOrThrow(); + mConfig.setSourceAddress(mNewSourceAddress); + mConfig.setDestinationAddress(mNewDestinationAddress); + mNewSourceAddress = null; + mNewDestinationAddress = null; + } + + /** Return if this transform is going to be migrated. */ + @GuardedBy("IpSecService.this") + public boolean isMigrating() { + verifyTunnelModeOrThrow(); + + return mNewSourceAddress != null; + } + /** always guarded by IpSecService#this */ @Override public void freeUnderlyingResources() { @@ -961,11 +1018,13 @@ private final class EncapSocketRecord extends OwnedResourceRecord { private FileDescriptor mSocket; private final int mPort; + private final int mFamily; // TODO: what about IPV6_ADDRFORM? - EncapSocketRecord(int resourceId, FileDescriptor socket, int port) { + EncapSocketRecord(int resourceId, FileDescriptor socket, int port, int family) { super(resourceId); mSocket = socket; mPort = port; + mFamily = family; } /** always guarded by IpSecService#this */ @@ -986,6 +1045,10 @@ return mSocket; } + public int getFamily() { + return mFamily; + } + @Override protected ResourceTracker getResourceTracker() { return getUserRecord().mSocketQuotaTracker; @@ -1158,15 +1221,16 @@ * and re-binding, during which the system could *technically* hand that port out to someone * else. */ - private int bindToRandomPort(FileDescriptor sockFd) throws IOException { + private int bindToRandomPort(FileDescriptor sockFd, int family, InetAddress localAddr) + throws IOException { for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) { try { - FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - Os.bind(probeSocket, INADDR_ANY, 0); + FileDescriptor probeSocket = Os.socket(family, SOCK_DGRAM, IPPROTO_UDP); + Os.bind(probeSocket, localAddr, 0); int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort(); Os.close(probeSocket); Log.v(TAG, "Binding to port " + port); - Os.bind(sockFd, INADDR_ANY, port); + Os.bind(sockFd, localAddr, port); return port; } catch (ErrnoException e) { // Someone miraculously claimed the port just after we closed probeSocket. @@ -1208,6 +1272,19 @@ @Override public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder) throws RemoteException { + // Experimental support for IPv6 UDP encap. + final int family; + final InetAddress localAddr; + if (SdkLevel.isAtLeastU() && port >= 65536) { + PermissionUtils.enforceNetworkStackPermissionOr(mContext, NETWORK_SETTINGS); + port -= 65536; + family = AF_INET6; + localAddr = IN6ADDR_ANY; + } else { + family = AF_INET; + localAddr = INADDR_ANY; + } + if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) { throw new IllegalArgumentException( "Specified port number must be a valid non-reserved UDP port"); @@ -1226,7 +1303,7 @@ FileDescriptor sockFd = null; try { - sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + sockFd = Os.socket(family, SOCK_DGRAM, IPPROTO_UDP); pFd = ParcelFileDescriptor.dup(sockFd); } finally { IoUtils.closeQuietly(sockFd); @@ -1243,15 +1320,16 @@ mNetd.ipSecSetEncapSocketOwner(pFd, callingUid); if (port != 0) { Log.v(TAG, "Binding to port " + port); - Os.bind(pFd.getFileDescriptor(), INADDR_ANY, port); + Os.bind(pFd.getFileDescriptor(), localAddr, port); } else { - port = bindToRandomPort(pFd.getFileDescriptor()); + port = bindToRandomPort(pFd.getFileDescriptor(), family, localAddr); } userRecord.mEncapSocketRecords.put( resourceId, new RefcountedResource<EncapSocketRecord>( - new EncapSocketRecord(resourceId, pFd.getFileDescriptor(), port), + new EncapSocketRecord(resourceId, pFd.getFileDescriptor(), port, + family), binder)); return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, pFd.getFileDescriptor()); @@ -1528,6 +1606,7 @@ */ private void checkIpSecConfig(IpSecConfig config) { UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + EncapSocketRecord encapSocketRecord = null; switch (config.getEncapType()) { case IpSecTransform.ENCAP_NONE: @@ -1535,7 +1614,7 @@ case IpSecTransform.ENCAP_ESPINUDP: case IpSecTransform.ENCAP_ESPINUDP_NON_IKE: // Retrieve encap socket record; will throw IllegalArgumentException if not found - userRecord.mEncapSocketRecords.getResourceOrThrow( + encapSocketRecord = userRecord.mEncapSocketRecords.getResourceOrThrow( config.getEncapSocketResourceId()); int port = config.getEncapRemotePort(); @@ -1589,10 +1668,9 @@ + ") have different address families."); } - // Throw an error if UDP Encapsulation is not used in IPv4. - if (config.getEncapType() != IpSecTransform.ENCAP_NONE && sourceFamily != AF_INET) { + if (encapSocketRecord != null && encapSocketRecord.getFamily() != destinationFamily) { throw new IllegalArgumentException( - "UDP Encapsulation is not supported for this address family"); + "UDP encapsulation socket and destination address families must match"); } switch (config.getMode()) { @@ -1630,6 +1708,14 @@ android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); } + private void enforceMigrateFeature() { + if (!mContext.getPackageManager().hasSystemFeature(FEATURE_IPSEC_TUNNEL_MIGRATION)) { + throw new UnsupportedOperationException( + "IPsec Tunnel migration requires" + + " PackageManager.FEATURE_IPSEC_TUNNEL_MIGRATION"); + } + } + private void createOrUpdateTransform( IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord) throws RemoteException { @@ -1726,6 +1812,45 @@ } /** + * Migrate an active Tunnel Mode IPsec Transform to new source/destination addresses. + * + * <p>Begins the process of migrating a transform and cache the new addresses. To complete the + * migration once started, callers MUST apply the same transform to the appropriate tunnel using + * {@link #applyTunnelModeTransform}. Otherwise, the address update will not be committed and + * the transform will still only process traffic between the current source and destination + * address. One common use case is that the control plane will start the migration process and + * then hand off the transform to the IPsec caller to perform the actual migration when the + * tunnel is ready. + * + * <p>If this method is called multiple times before {@link #applyTunnelModeTransform} is + * called, when the transform is applied, it will be migrated to the addresses from the last + * call. + * + * <p>The provided source and destination addresses MUST share the same address family, but they + * can have a different family from the current addresses. + * + * <p>Transform migration is only supported for tunnel mode transforms. Calling this method on + * other types of transforms will throw an {@code UnsupportedOperationException}. + */ + @Override + public synchronized void migrateTransform( + int transformId, + String newSourceAddress, + String newDestinationAddress, + String callingPackage) { + Objects.requireNonNull(newSourceAddress, "newSourceAddress was null"); + Objects.requireNonNull(newDestinationAddress, "newDestinationAddress was null"); + + enforceTunnelFeatureAndPermissions(callingPackage); + enforceMigrateFeature(); + + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + TransformRecord transformInfo = + userRecord.mTransformRecords.getResourceOrThrow(transformId); + transformInfo.startMigration(newSourceAddress, newDestinationAddress); + } + + /** * Delete a transport mode transform that was previously allocated by + registered with the * system server. If this is called on an inactive (or non-existent) transform, it will not * return an error. It's safe to de-allocate transforms that may have already been deleted for @@ -1784,12 +1909,15 @@ /** * Apply an active tunnel mode transform to a TunnelInterface, which will apply the IPsec - * security association as a correspondent policy to the provided interface + * security association as a correspondent policy to the provided interface. + * + * <p>If the transform is migrating, migrate the IPsec security association to new + * source/destination addresses, and mark the migration as finished. */ @Override public synchronized void applyTunnelModeTransform( - int tunnelResourceId, int direction, - int transformResourceId, String callingPackage) throws RemoteException { + int tunnelResourceId, int direction, int transformResourceId, String callingPackage) + throws RemoteException { enforceTunnelFeatureAndPermissions(callingPackage); checkDirection(direction); @@ -1868,6 +1996,32 @@ // Update SA with tunnel mark (ikey or okey based on direction) createOrUpdateTransform(c, transformResourceId, spiRecord, socketRecord); + + if (transformInfo.isMigrating()) { + if (!mContext.getPackageManager() + .hasSystemFeature(FEATURE_IPSEC_TUNNEL_MIGRATION)) { + Log.wtf( + TAG, + "Attempted to migrate a transform without" + + " FEATURE_IPSEC_TUNNEL_MIGRATION"); + } + + for (int selAddrFamily : ADDRESS_FAMILIES) { + final IpSecMigrateInfoParcel migrateInfo = + new IpSecMigrateInfoParcel( + Binder.getCallingUid(), + selAddrFamily, + direction, + c.getSourceAddress(), + c.getDestinationAddress(), + transformInfo.getNewSourceAddress(), + transformInfo.getNewDestinationAddress(), + c.getXfrmInterfaceId()); + + mNetd.ipSecMigrate(migrateInfo); + } + transformInfo.finishMigration(); + } } catch (ServiceSpecificException e) { if (e.errorCode == EINVAL) { throw new IllegalArgumentException(e.toString());
diff --git a/service-t/src/com/android/server/NetworkStatsServiceInitializer.java b/service-t/src/com/android/server/NetworkStatsServiceInitializer.java index 0ea126a..82a4fbd 100644 --- a/service-t/src/com/android/server/NetworkStatsServiceInitializer.java +++ b/service-t/src/com/android/server/NetworkStatsServiceInitializer.java
@@ -18,6 +18,7 @@ import android.content.Context; import android.net.TrafficStats; +import android.os.Build; import android.util.Log; import com.android.modules.utils.build.SdkLevel; @@ -46,6 +47,15 @@ /* allowIsolated= */ false); TrafficStats.init(getContext()); } + + // The following code registers the Perfetto Network Trace Handler on non-user builds. + // The enhanced tracing is intended to be used for debugging and diagnosing issues. This + // is conditional on the build type rather than `isDebuggable` to match the system_server + // selinux rules which only allow the Perfetto connection under the same circumstances. + if (SdkLevel.isAtLeastU() && !Build.TYPE.equals("user")) { + Log.i(TAG, "Initializing network tracing hooks"); + NetworkStatsService.nativeInitNetworkTracing(); + } } @Override
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java index 1226eea..c47c572 100644 --- a/service-t/src/com/android/server/NsdService.java +++ b/service-t/src/com/android/server/NsdService.java
@@ -17,12 +17,21 @@ package com.android.server; import static android.net.ConnectivityManager.NETID_UNSET; +import static android.net.nsd.NsdManager.MDNS_DISCOVERY_MANAGER_EVENT; import static android.net.nsd.NsdManager.MDNS_SERVICE_EVENT; +import static android.net.nsd.NsdManager.RESOLVE_SERVICE_SUCCEEDED; +import static android.provider.DeviceConfig.NAMESPACE_TETHERING; +import static com.android.modules.utils.build.SdkLevel.isAtLeastU; +import static com.android.server.connectivity.mdns.MdnsRecord.MAX_LABEL_LENGTH; + +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.net.INetd; +import android.net.InetAddresses; import android.net.LinkProperties; import android.net.Network; import android.net.mdns.aidl.DiscoveryInfo; @@ -36,29 +45,51 @@ import android.net.nsd.MDnsManager; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; +import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; +import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.util.SparseArray; -import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.net.module.util.DeviceConfigUtils; +import com.android.net.module.util.InetAddressUtils; import com.android.net.module.util.PermissionUtils; +import com.android.net.module.util.SharedLog; +import com.android.server.connectivity.mdns.ExecutorProvider; +import com.android.server.connectivity.mdns.MdnsAdvertiser; +import com.android.server.connectivity.mdns.MdnsDiscoveryManager; +import com.android.server.connectivity.mdns.MdnsMultinetworkSocketClient; +import com.android.server.connectivity.mdns.MdnsSearchOptions; +import com.android.server.connectivity.mdns.MdnsServiceBrowserListener; +import com.android.server.connectivity.mdns.MdnsServiceInfo; +import com.android.server.connectivity.mdns.MdnsSocketProvider; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Network Service Discovery Service handles remote service discovery operation requests by @@ -69,19 +100,72 @@ public class NsdService extends INsdManager.Stub { private static final String TAG = "NsdService"; private static final String MDNS_TAG = "mDnsConnector"; + /** + * Enable discovery using the Java DiscoveryManager, instead of the legacy mdnsresponder + * implementation. + */ + private static final String MDNS_DISCOVERY_MANAGER_VERSION = "mdns_discovery_manager_version"; + private static final String LOCAL_DOMAIN_NAME = "local"; - private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); + /** + * Enable advertising using the Java MdnsAdvertiser, instead of the legacy mdnsresponder + * implementation. + */ + private static final String MDNS_ADVERTISER_VERSION = "mdns_advertiser_version"; + + /** + * Comma-separated list of type:flag mappings indicating the flags to use to allowlist + * discovery/advertising using MdnsDiscoveryManager / MdnsAdvertiser for a given type. + * + * For example _mytype._tcp.local and _othertype._tcp.local would be configured with: + * _mytype._tcp:mytype,_othertype._tcp.local:othertype + * + * In which case the flags: + * "mdns_discovery_manager_allowlist_mytype_version", + * "mdns_advertiser_allowlist_mytype_version", + * "mdns_discovery_manager_allowlist_othertype_version", + * "mdns_advertiser_allowlist_othertype_version" + * would be used to toggle MdnsDiscoveryManager / MdnsAdvertiser for each type. The flags will + * be read with + * {@link DeviceConfigUtils#isFeatureEnabled(Context, String, String, String, boolean)}. + * + * @see #MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX + * @see #MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX + * @see #MDNS_ALLOWLIST_FLAG_SUFFIX + */ + private static final String MDNS_TYPE_ALLOWLIST_FLAGS = "mdns_type_allowlist_flags"; + + private static final String MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX = + "mdns_discovery_manager_allowlist_"; + private static final String MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX = + "mdns_advertiser_allowlist_"; + private static final String MDNS_ALLOWLIST_FLAG_SUFFIX = "_version"; + + public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); private static final long CLEANUP_DELAY_MS = 10000; private static final int IFACE_IDX_ANY = 0; + private static final SharedLog LOGGER = new SharedLog("serviceDiscovery"); private final Context mContext; private final NsdStateMachine mNsdStateMachine; private final MDnsManager mMDnsManager; private final MDnsEventCallback mMDnsEventCallback; - // WARNING : Accessing this value in any thread is not safe, it must only be changed in the + @NonNull + private final Dependencies mDeps; + @NonNull + private final MdnsMultinetworkSocketClient mMdnsSocketClient; + @NonNull + private final MdnsDiscoveryManager mMdnsDiscoveryManager; + @NonNull + private final MdnsSocketProvider mMdnsSocketProvider; + @NonNull + private final MdnsAdvertiser mAdvertiser; + private final SharedLog mServiceLogs = LOGGER.forSubComponent(TAG); + // WARNING : Accessing these values in any thread is not safe, it must only be changed in the // state machine thread. If change this outside state machine, it will need to introduce // synchronization. private boolean mIsDaemonStarted = false; + private boolean mIsMonitoringSocketsStarted = false; /** * Clients receiving asynchronous messages @@ -97,6 +181,137 @@ private int mUniqueId = 1; // The count of the connected legacy clients. private int mLegacyClientCount = 0; + // The number of client that ever connected. + private int mClientNumberId = 1; + + private static class MdnsListener implements MdnsServiceBrowserListener { + protected final int mClientId; + protected final int mTransactionId; + @NonNull + protected final NsdServiceInfo mReqServiceInfo; + @NonNull + protected final String mListenedServiceType; + + MdnsListener(int clientId, int transactionId, @NonNull NsdServiceInfo reqServiceInfo, + @NonNull String listenedServiceType) { + mClientId = clientId; + mTransactionId = transactionId; + mReqServiceInfo = reqServiceInfo; + mListenedServiceType = listenedServiceType; + } + + @NonNull + public String getListenedServiceType() { + return mListenedServiceType; + } + + @Override + public void onServiceFound(@NonNull MdnsServiceInfo serviceInfo) { } + + @Override + public void onServiceUpdated(@NonNull MdnsServiceInfo serviceInfo) { } + + @Override + public void onServiceRemoved(@NonNull MdnsServiceInfo serviceInfo) { } + + @Override + public void onServiceNameDiscovered(@NonNull MdnsServiceInfo serviceInfo) { } + + @Override + public void onServiceNameRemoved(@NonNull MdnsServiceInfo serviceInfo) { } + + @Override + public void onSearchStoppedWithError(int error) { } + + @Override + public void onSearchFailedToStart() { } + + @Override + public void onDiscoveryQuerySent(@NonNull List<String> subtypes, int transactionId) { } + + @Override + public void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode) { } + } + + private class DiscoveryListener extends MdnsListener { + + DiscoveryListener(int clientId, int transactionId, @NonNull NsdServiceInfo reqServiceInfo, + @NonNull String listenServiceType) { + super(clientId, transactionId, reqServiceInfo, listenServiceType); + } + + @Override + public void onServiceNameDiscovered(@NonNull MdnsServiceInfo serviceInfo) { + mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId, + NsdManager.SERVICE_FOUND, + new MdnsEvent(mClientId, serviceInfo)); + } + + @Override + public void onServiceNameRemoved(@NonNull MdnsServiceInfo serviceInfo) { + mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId, + NsdManager.SERVICE_LOST, + new MdnsEvent(mClientId, serviceInfo)); + } + } + + private class ResolutionListener extends MdnsListener { + + ResolutionListener(int clientId, int transactionId, @NonNull NsdServiceInfo reqServiceInfo, + @NonNull String listenServiceType) { + super(clientId, transactionId, reqServiceInfo, listenServiceType); + } + + @Override + public void onServiceFound(MdnsServiceInfo serviceInfo) { + mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId, + NsdManager.RESOLVE_SERVICE_SUCCEEDED, + new MdnsEvent(mClientId, serviceInfo)); + } + } + + private class ServiceInfoListener extends MdnsListener { + + ServiceInfoListener(int clientId, int transactionId, @NonNull NsdServiceInfo reqServiceInfo, + @NonNull String listenServiceType) { + super(clientId, transactionId, reqServiceInfo, listenServiceType); + } + + @Override + public void onServiceFound(@NonNull MdnsServiceInfo serviceInfo) { + mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId, + NsdManager.SERVICE_UPDATED, + new MdnsEvent(mClientId, serviceInfo)); + } + + @Override + public void onServiceUpdated(@NonNull MdnsServiceInfo serviceInfo) { + mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId, + NsdManager.SERVICE_UPDATED, + new MdnsEvent(mClientId, serviceInfo)); + } + + @Override + public void onServiceRemoved(@NonNull MdnsServiceInfo serviceInfo) { + mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId, + NsdManager.SERVICE_UPDATED_LOST, + new MdnsEvent(mClientId, serviceInfo)); + } + } + + /** + * Data class of mdns service callback information. + */ + private static class MdnsEvent { + final int mClientId; + @NonNull + final MdnsServiceInfo mMdnsServiceInfo; + + MdnsEvent(int clientId, @NonNull MdnsServiceInfo mdnsServiceInfo) { + mClientId = clientId; + mMdnsServiceInfo = mdnsServiceInfo; + } + } private class NsdStateMachine extends StateMachine { @@ -117,6 +332,7 @@ mMDnsManager.startDaemon(); mIsDaemonStarted = true; maybeScheduleStop(); + mServiceLogs.log("Start mdns_responder daemon"); } private void maybeStopDaemon() { @@ -127,6 +343,7 @@ mMDnsManager.unregisterEventListener(mMDnsEventCallback); mMDnsManager.stopDaemon(); mIsDaemonStarted = false; + mServiceLogs.log("Stop mdns_responder daemon"); } private boolean isAnyRequestActive() { @@ -148,6 +365,24 @@ this.removeMessages(NsdManager.DAEMON_CLEANUP); } + private void maybeStartMonitoringSockets() { + if (mIsMonitoringSocketsStarted) { + if (DBG) Log.d(TAG, "Socket monitoring is already started."); + return; + } + + mMdnsSocketProvider.startMonitoringSockets(); + mIsMonitoringSocketsStarted = true; + } + + private void maybeStopMonitoringSocketsIfNoActiveRequest() { + if (!mIsMonitoringSocketsStarted) return; + if (isAnyRequestActive()) return; + + mMdnsSocketProvider.requestStopWhenInactive(); + mIsMonitoringSocketsStarted = false; + } + NsdStateMachine(String name, Handler handler) { super(name, handler); addState(mDefaultState); @@ -164,13 +399,14 @@ final int clientId = msg.arg2; switch (msg.what) { case NsdManager.REGISTER_CLIENT: - final Pair<NsdServiceConnector, INsdManagerCallback> arg = - (Pair<NsdServiceConnector, INsdManagerCallback>) msg.obj; - final INsdManagerCallback cb = arg.second; + final ConnectorArgs arg = (ConnectorArgs) msg.obj; + final INsdManagerCallback cb = arg.callback; try { - cb.asBinder().linkToDeath(arg.first, 0); - cInfo = new ClientInfo(cb); - mClients.put(arg.first, cInfo); + cb.asBinder().linkToDeath(arg.connector, 0); + final String tag = "Client" + arg.uid + "-" + mClientNumberId++; + cInfo = new ClientInfo(cb, arg.useJavaBackend, + mServiceLogs.forSubComponent(tag)); + mClients.put(arg.connector, cInfo); } catch (RemoteException e) { Log.w(TAG, "Client " + clientId + " has already died"); } @@ -180,10 +416,11 @@ cInfo = mClients.remove(connector); if (cInfo != null) { cInfo.expungeAllRequests(); - if (cInfo.isLegacy()) { + if (cInfo.isPreSClient()) { mLegacyClientCount -= 1; } } + maybeStopMonitoringSocketsIfNoActiveRequest(); maybeScheduleStop(); break; case NsdManager.DISCOVER_SERVICES: @@ -221,6 +458,20 @@ clientId, NsdManager.FAILURE_INTERNAL_ERROR); } break; + case NsdManager.STOP_RESOLUTION: + cInfo = getClientInfoForReply(msg); + if (cInfo != null) { + cInfo.onStopResolutionFailed( + clientId, NsdManager.FAILURE_OPERATION_NOT_RUNNING); + } + break; + case NsdManager.REGISTER_SERVICE_CALLBACK: + cInfo = getClientInfoForReply(msg); + if (cInfo != null) { + cInfo.onServiceInfoCallbackRegistrationFailed( + clientId, NsdManager.FAILURE_BAD_PARAMETERS); + } + break; case NsdManager.DAEMON_CLEANUP: maybeStopDaemon(); break; @@ -230,7 +481,7 @@ cInfo = getClientInfoForReply(msg); if (cInfo != null) { cancelStop(); - cInfo.setLegacy(); + cInfo.setPreSClient(); mLegacyClientCount += 1; maybeStartDaemon(); } @@ -262,26 +513,63 @@ } private boolean requestLimitReached(ClientInfo clientInfo) { - if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) { + if (clientInfo.mClientRequests.size() >= ClientInfo.MAX_LIMIT) { if (DBG) Log.d(TAG, "Exceeded max outstanding requests " + clientInfo); return true; } return false; } - private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) { - clientInfo.mClientIds.put(clientId, globalId); - clientInfo.mClientRequests.put(clientId, what); + private void storeLegacyRequestMap(int clientId, int globalId, ClientInfo clientInfo, + int what) { + clientInfo.mClientRequests.put(clientId, new LegacyClientRequest(globalId, what)); mIdToClientInfoMap.put(globalId, clientInfo); // Remove the cleanup event because here comes a new request. cancelStop(); } + private void storeAdvertiserRequestMap(int clientId, int globalId, + ClientInfo clientInfo) { + clientInfo.mClientRequests.put(clientId, new AdvertiserClientRequest(globalId)); + mIdToClientInfoMap.put(globalId, clientInfo); + } + private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { - clientInfo.mClientIds.delete(clientId); - clientInfo.mClientRequests.delete(clientId); + final ClientRequest existing = clientInfo.mClientRequests.get(clientId); + if (existing == null) return; + clientInfo.mClientRequests.remove(clientId); mIdToClientInfoMap.remove(globalId); - maybeScheduleStop(); + + if (existing instanceof LegacyClientRequest) { + maybeScheduleStop(); + } else { + maybeStopMonitoringSocketsIfNoActiveRequest(); + } + } + + private void storeDiscoveryManagerRequestMap(int clientId, int globalId, + MdnsListener listener, ClientInfo clientInfo) { + clientInfo.mClientRequests.put(clientId, + new DiscoveryManagerRequest(globalId, listener)); + mIdToClientInfoMap.put(globalId, clientInfo); + } + + /** + * Truncate a service name to up to 63 UTF-8 bytes. + * + * See RFC6763 4.1.1: service instance names are UTF-8 and up to 63 bytes. Truncating + * names used in registerService follows historical behavior (see mdnsresponder + * handle_regservice_request). + */ + @NonNull + private String truncateServiceName(@NonNull String originalName) { + return MdnsUtils.truncateServiceName(originalName, MAX_LABEL_LENGTH); + } + + private void stopDiscoveryManagerRequest(ClientRequest request, int clientId, int id, + ClientInfo clientInfo) { + clientInfo.unregisterMdnsListenerFromRequest(request); + removeRequestMap(clientId, id, clientInfo); } @Override @@ -291,7 +579,7 @@ final int clientId = msg.arg2; final ListenerArgs args; switch (msg.what) { - case NsdManager.DISCOVER_SERVICES: + case NsdManager.DISCOVER_SERVICES: { if (DBG) Log.d(TAG, "Discover services"); args = (ListenerArgs) msg.obj; clientInfo = mClients.get(args.connector); @@ -309,22 +597,58 @@ break; } - maybeStartDaemon(); + final NsdServiceInfo info = args.serviceInfo; id = getUniqueId(); - if (discoverServices(id, args.serviceInfo)) { - if (DBG) { - Log.d(TAG, "Discover " + msg.arg2 + " " + id - + args.serviceInfo.getServiceType()); + final Pair<String, String> typeAndSubtype = + parseTypeAndSubtype(info.getServiceType()); + final String serviceType = typeAndSubtype == null + ? null : typeAndSubtype.first; + if (clientInfo.mUseJavaBackend + || mDeps.isMdnsDiscoveryManagerEnabled(mContext) + || useDiscoveryManagerForType(serviceType)) { + if (serviceType == null) { + clientInfo.onDiscoverServicesFailed(clientId, + NsdManager.FAILURE_INTERNAL_ERROR); + break; } - storeRequestMap(clientId, id, clientInfo, msg.what); - clientInfo.onDiscoverServicesStarted(clientId, args.serviceInfo); + + final String listenServiceType = serviceType + ".local"; + maybeStartMonitoringSockets(); + final MdnsListener listener = + new DiscoveryListener(clientId, id, info, listenServiceType); + final MdnsSearchOptions.Builder optionsBuilder = + MdnsSearchOptions.newBuilder() + .setNetwork(info.getNetwork()) + .setIsPassiveMode(true); + if (typeAndSubtype.second != null) { + // The parsing ensures subtype starts with an underscore. + // MdnsSearchOptions expects the underscore to not be present. + optionsBuilder.addSubtype(typeAndSubtype.second.substring(1)); + } + mMdnsDiscoveryManager.registerListener( + listenServiceType, listener, optionsBuilder.build()); + storeDiscoveryManagerRequestMap(clientId, id, listener, clientInfo); + clientInfo.onDiscoverServicesStarted(clientId, info); + clientInfo.log("Register a DiscoveryListener " + id + + " for service type:" + listenServiceType); } else { - stopServiceDiscovery(id); - clientInfo.onDiscoverServicesFailed(clientId, - NsdManager.FAILURE_INTERNAL_ERROR); + maybeStartDaemon(); + if (discoverServices(id, info)) { + if (DBG) { + Log.d(TAG, "Discover " + msg.arg2 + " " + id + + info.getServiceType()); + } + storeLegacyRequestMap(clientId, id, clientInfo, msg.what); + clientInfo.onDiscoverServicesStarted(clientId, info); + } else { + stopServiceDiscovery(id); + clientInfo.onDiscoverServicesFailed(clientId, + NsdManager.FAILURE_INTERNAL_ERROR); + } } break; - case NsdManager.STOP_DISCOVERY: + } + case NsdManager.STOP_DISCOVERY: { if (DBG) Log.d(TAG, "Stop service discovery"); args = (ListenerArgs) msg.obj; clientInfo = mClients.get(args.connector); @@ -336,22 +660,31 @@ break; } - try { - id = clientInfo.mClientIds.get(clientId); - } catch (NullPointerException e) { - clientInfo.onStopDiscoveryFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); + final ClientRequest request = clientInfo.mClientRequests.get(clientId); + if (request == null) { + Log.e(TAG, "Unknown client request in STOP_DISCOVERY"); break; } - removeRequestMap(clientId, id, clientInfo); - if (stopServiceDiscovery(id)) { + id = request.mGlobalId; + // Note isMdnsDiscoveryManagerEnabled may have changed to false at this + // point, so this needs to check the type of the original request to + // unregister instead of looking at the flag value. + if (request instanceof DiscoveryManagerRequest) { + stopDiscoveryManagerRequest(request, clientId, id, clientInfo); clientInfo.onStopDiscoverySucceeded(clientId); + clientInfo.log("Unregister the DiscoveryListener " + id); } else { - clientInfo.onStopDiscoveryFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); + removeRequestMap(clientId, id, clientInfo); + if (stopServiceDiscovery(id)) { + clientInfo.onStopDiscoverySucceeded(clientId); + } else { + clientInfo.onStopDiscoveryFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); + } } break; - case NsdManager.REGISTER_SERVICE: + } + case NsdManager.REGISTER_SERVICE: { if (DBG) Log.d(TAG, "Register service"); args = (ListenerArgs) msg.obj; clientInfo = mClients.get(args.connector); @@ -369,19 +702,48 @@ break; } - maybeStartDaemon(); id = getUniqueId(); - if (registerService(id, args.serviceInfo)) { - if (DBG) Log.d(TAG, "Register " + clientId + " " + id); - storeRequestMap(clientId, id, clientInfo, msg.what); - // Return success after mDns reports success + final NsdServiceInfo serviceInfo = args.serviceInfo; + final String serviceType = serviceInfo.getServiceType(); + final Pair<String, String> typeSubtype = parseTypeAndSubtype(serviceType); + final String registerServiceType = typeSubtype == null + ? null : typeSubtype.first; + if (clientInfo.mUseJavaBackend + || mDeps.isMdnsAdvertiserEnabled(mContext) + || useAdvertiserForType(registerServiceType)) { + if (registerServiceType == null) { + Log.e(TAG, "Invalid service type: " + serviceType); + clientInfo.onRegisterServiceFailed(clientId, + NsdManager.FAILURE_INTERNAL_ERROR); + break; + } + serviceInfo.setServiceType(registerServiceType); + serviceInfo.setServiceName(truncateServiceName( + serviceInfo.getServiceName())); + + maybeStartMonitoringSockets(); + // TODO: pass in the subtype as well. Including the subtype in the + // service type would generate service instance names like + // Name._subtype._sub._type._tcp, which is incorrect + // (it should be Name._type._tcp). + mAdvertiser.addService(id, serviceInfo, typeSubtype.second); + storeAdvertiserRequestMap(clientId, id, clientInfo); } else { - unregisterService(id); - clientInfo.onRegisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); + maybeStartDaemon(); + if (registerService(id, serviceInfo)) { + if (DBG) Log.d(TAG, "Register " + clientId + " " + id); + storeLegacyRequestMap(clientId, id, clientInfo, msg.what); + // Return success after mDns reports success + } else { + unregisterService(id); + clientInfo.onRegisterServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); + } + } break; - case NsdManager.UNREGISTER_SERVICE: + } + case NsdManager.UNREGISTER_SERVICE: { if (DBG) Log.d(TAG, "unregister service"); args = (ListenerArgs) msg.obj; clientInfo = mClients.get(args.connector); @@ -392,16 +754,31 @@ Log.e(TAG, "Unknown connector in unregistration"); break; } - id = clientInfo.mClientIds.get(clientId); + final ClientRequest request = clientInfo.mClientRequests.get(clientId); + if (request == null) { + Log.e(TAG, "Unknown client request in UNREGISTER_SERVICE"); + break; + } + id = request.mGlobalId; removeRequestMap(clientId, id, clientInfo); - if (unregisterService(id)) { + + // Note isMdnsAdvertiserEnabled may have changed to false at this point, + // so this needs to check the type of the original request to unregister + // instead of looking at the flag value. + if (request instanceof AdvertiserClientRequest) { + mAdvertiser.removeService(id); clientInfo.onUnregisterServiceSucceeded(clientId); } else { - clientInfo.onUnregisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); + if (unregisterService(id)) { + clientInfo.onUnregisterServiceSucceeded(clientId); + } else { + clientInfo.onUnregisterServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); + } } break; - case NsdManager.RESOLVE_SERVICE: + } + case NsdManager.RESOLVE_SERVICE: { if (DBG) Log.d(TAG, "Resolve service"); args = (ListenerArgs) msg.obj; clientInfo = mClients.get(args.connector); @@ -413,27 +790,167 @@ break; } - if (clientInfo.mResolvedService != null) { - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_ALREADY_ACTIVE); + final NsdServiceInfo info = args.serviceInfo; + id = getUniqueId(); + final Pair<String, String> typeSubtype = + parseTypeAndSubtype(info.getServiceType()); + final String serviceType = typeSubtype == null + ? null : typeSubtype.first; + if (clientInfo.mUseJavaBackend + || mDeps.isMdnsDiscoveryManagerEnabled(mContext) + || useDiscoveryManagerForType(serviceType)) { + if (serviceType == null) { + clientInfo.onResolveServiceFailed(clientId, + NsdManager.FAILURE_INTERNAL_ERROR); + break; + } + final String resolveServiceType = serviceType + ".local"; + + maybeStartMonitoringSockets(); + final MdnsListener listener = + new ResolutionListener(clientId, id, info, resolveServiceType); + final MdnsSearchOptions options = MdnsSearchOptions.newBuilder() + .setNetwork(info.getNetwork()) + .setIsPassiveMode(true) + .setResolveInstanceName(info.getServiceName()) + .build(); + mMdnsDiscoveryManager.registerListener( + resolveServiceType, listener, options); + storeDiscoveryManagerRequestMap(clientId, id, listener, clientInfo); + clientInfo.log("Register a ResolutionListener " + id + + " for service type:" + resolveServiceType); + } else { + if (clientInfo.mResolvedService != null) { + clientInfo.onResolveServiceFailed( + clientId, NsdManager.FAILURE_ALREADY_ACTIVE); + break; + } + + maybeStartDaemon(); + if (resolveService(id, info)) { + clientInfo.mResolvedService = new NsdServiceInfo(); + storeLegacyRequestMap(clientId, id, clientInfo, msg.what); + } else { + clientInfo.onResolveServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); + } + } + break; + } + case NsdManager.STOP_RESOLUTION: { + if (DBG) Log.d(TAG, "Stop service resolution"); + args = (ListenerArgs) msg.obj; + clientInfo = mClients.get(args.connector); + // If the binder death notification for a INsdManagerCallback was received + // before any calls are received by NsdService, the clientInfo would be + // cleared and cause NPE. Add a null check here to prevent this corner case. + if (clientInfo == null) { + Log.e(TAG, "Unknown connector in stop resolution"); break; } - maybeStartDaemon(); - id = getUniqueId(); - if (resolveService(id, args.serviceInfo)) { - clientInfo.mResolvedService = new NsdServiceInfo(); - storeRequestMap(clientId, id, clientInfo, msg.what); + final ClientRequest request = clientInfo.mClientRequests.get(clientId); + if (request == null) { + Log.e(TAG, "Unknown client request in STOP_RESOLUTION"); + break; + } + id = request.mGlobalId; + // Note isMdnsDiscoveryManagerEnabled may have changed to false at this + // point, so this needs to check the type of the original request to + // unregister instead of looking at the flag value. + if (request instanceof DiscoveryManagerRequest) { + stopDiscoveryManagerRequest(request, clientId, id, clientInfo); + clientInfo.onStopResolutionSucceeded(clientId); + clientInfo.log("Unregister the ResolutionListener " + id); } else { - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); + removeRequestMap(clientId, id, clientInfo); + if (stopResolveService(id)) { + clientInfo.onStopResolutionSucceeded(clientId); + } else { + clientInfo.onStopResolutionFailed( + clientId, NsdManager.FAILURE_OPERATION_NOT_RUNNING); + } + clientInfo.mResolvedService = null; } break; + } + case NsdManager.REGISTER_SERVICE_CALLBACK: { + if (DBG) Log.d(TAG, "Register a service callback"); + args = (ListenerArgs) msg.obj; + clientInfo = mClients.get(args.connector); + // If the binder death notification for a INsdManagerCallback was received + // before any calls are received by NsdService, the clientInfo would be + // cleared and cause NPE. Add a null check here to prevent this corner case. + if (clientInfo == null) { + Log.e(TAG, "Unknown connector in callback registration"); + break; + } + + final NsdServiceInfo info = args.serviceInfo; + id = getUniqueId(); + final Pair<String, String> typeAndSubtype = + parseTypeAndSubtype(info.getServiceType()); + final String serviceType = typeAndSubtype == null + ? null : typeAndSubtype.first; + if (serviceType == null) { + clientInfo.onServiceInfoCallbackRegistrationFailed(clientId, + NsdManager.FAILURE_BAD_PARAMETERS); + break; + } + final String resolveServiceType = serviceType + ".local"; + + maybeStartMonitoringSockets(); + final MdnsListener listener = + new ServiceInfoListener(clientId, id, info, resolveServiceType); + final MdnsSearchOptions options = MdnsSearchOptions.newBuilder() + .setNetwork(info.getNetwork()) + .setIsPassiveMode(true) + .setResolveInstanceName(info.getServiceName()) + .build(); + mMdnsDiscoveryManager.registerListener( + resolveServiceType, listener, options); + storeDiscoveryManagerRequestMap(clientId, id, listener, clientInfo); + clientInfo.log("Register a ServiceInfoListener " + id + + " for service type:" + resolveServiceType); + break; + } + case NsdManager.UNREGISTER_SERVICE_CALLBACK: { + if (DBG) Log.d(TAG, "Unregister a service callback"); + args = (ListenerArgs) msg.obj; + clientInfo = mClients.get(args.connector); + // If the binder death notification for a INsdManagerCallback was received + // before any calls are received by NsdService, the clientInfo would be + // cleared and cause NPE. Add a null check here to prevent this corner case. + if (clientInfo == null) { + Log.e(TAG, "Unknown connector in callback unregistration"); + break; + } + + final ClientRequest request = clientInfo.mClientRequests.get(clientId); + if (request == null) { + Log.e(TAG, "Unknown client request in UNREGISTER_SERVICE_CALLBACK"); + break; + } + id = request.mGlobalId; + if (request instanceof DiscoveryManagerRequest) { + stopDiscoveryManagerRequest(request, clientId, id, clientInfo); + clientInfo.onServiceInfoCallbackUnregistered(clientId); + clientInfo.log("Unregister the ServiceInfoListener " + id); + } else { + loge("Unregister failed with non-DiscoveryManagerRequest."); + } + break; + } case MDNS_SERVICE_EVENT: if (!handleMDnsServiceEvent(msg.arg1, msg.arg2, msg.obj)) { return NOT_HANDLED; } break; + case MDNS_DISCOVERY_MANAGER_EVENT: + if (!handleMdnsDiscoveryManagerEvent(msg.arg1, msg.arg2, msg.obj)) { + return NOT_HANDLED; + } + break; default: return NOT_HANDLED; } @@ -474,6 +991,12 @@ // interfaces that do not have an associated Network. break; } + if (foundNetId == INetd.DUMMY_NET_ID) { + // Ignore services on the dummy0 interface: they are only seen when + // discovering locally advertised services, and are not reachable + // through that interface. + break; + } setServiceNetworkForCallback(servInfo, info.netId, info.interfaceIdx); clientInfo.onServiceFound(clientId, servInfo); break; @@ -526,10 +1049,11 @@ String rest = fullName.substring(index); String type = rest.replace(".local.", ""); - clientInfo.mResolvedService.setServiceName(name); - clientInfo.mResolvedService.setServiceType(type); - clientInfo.mResolvedService.setPort(info.port); - clientInfo.mResolvedService.setTxtRecords(info.txtRecord); + final NsdServiceInfo serviceInfo = clientInfo.mResolvedService; + serviceInfo.setServiceName(name); + serviceInfo.setServiceType(type); + serviceInfo.setPort(info.port); + serviceInfo.setTxtRecords(info.txtRecord); // Network will be added after SERVICE_GET_ADDR_SUCCESS stopResolveService(id); @@ -537,7 +1061,8 @@ final int id2 = getUniqueId(); if (getAddrInfo(id2, info.hostname, info.interfaceIdx)) { - storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); + storeLegacyRequestMap(clientId, id2, clientInfo, + NsdManager.RESOLVE_SERVICE); } else { clientInfo.onResolveServiceFailed( clientId, NsdManager.FAILURE_INTERNAL_ERROR); @@ -549,17 +1074,17 @@ /* NNN resolveId errorCode */ stopResolveService(id); removeRequestMap(clientId, id, clientInfo); - clientInfo.mResolvedService = null; clientInfo.onResolveServiceFailed( clientId, NsdManager.FAILURE_INTERNAL_ERROR); + clientInfo.mResolvedService = null; break; case IMDnsEventListener.SERVICE_GET_ADDR_FAILED: /* NNN resolveId errorCode */ stopGetAddrInfo(id); removeRequestMap(clientId, id, clientInfo); - clientInfo.mResolvedService = null; clientInfo.onResolveServiceFailed( clientId, NsdManager.FAILURE_INTERNAL_ERROR); + clientInfo.mResolvedService = null; break; case IMDnsEventListener.SERVICE_GET_ADDR_SUCCESS: { /* NNN resolveId hostname ttl addr interfaceIdx netId */ @@ -596,9 +1121,167 @@ } return true; } + + @Nullable + private NsdServiceInfo buildNsdServiceInfoFromMdnsEvent( + final MdnsEvent event, int code) { + final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo; + final String[] typeArray = serviceInfo.getServiceType(); + final String joinedType; + if (typeArray.length == 0 + || !typeArray[typeArray.length - 1].equals(LOCAL_DOMAIN_NAME)) { + Log.wtf(TAG, "MdnsServiceInfo type does not end in .local: " + + Arrays.toString(typeArray)); + return null; + } else { + joinedType = TextUtils.join(".", + Arrays.copyOfRange(typeArray, 0, typeArray.length - 1)); + } + final String serviceType; + switch (code) { + case NsdManager.SERVICE_FOUND: + case NsdManager.SERVICE_LOST: + // For consistency with historical behavior, discovered service types have + // a dot at the end. + serviceType = joinedType + "."; + break; + case RESOLVE_SERVICE_SUCCEEDED: + // For consistency with historical behavior, resolved service types have + // a dot at the beginning. + serviceType = "." + joinedType; + break; + default: + serviceType = joinedType; + break; + } + final String serviceName = serviceInfo.getServiceInstanceName(); + final NsdServiceInfo servInfo = new NsdServiceInfo(serviceName, serviceType); + final Network network = serviceInfo.getNetwork(); + // In MdnsDiscoveryManagerEvent, the Network can be null which means it is a + // network for Tethering interface. In other words, the network == null means the + // network has netId = INetd.LOCAL_NET_ID. + setServiceNetworkForCallback( + servInfo, + network == null ? INetd.LOCAL_NET_ID : network.netId, + serviceInfo.getInterfaceIndex()); + return servInfo; + } + + private boolean handleMdnsDiscoveryManagerEvent( + int transactionId, int code, Object obj) { + final ClientInfo clientInfo = mIdToClientInfoMap.get(transactionId); + if (clientInfo == null) { + Log.e(TAG, String.format( + "id %d for %d has no client mapping", transactionId, code)); + return false; + } + + final MdnsEvent event = (MdnsEvent) obj; + final int clientId = event.mClientId; + final NsdServiceInfo info = buildNsdServiceInfoFromMdnsEvent(event, code); + // Errors are already logged if null + if (info == null) return false; + if (DBG) { + Log.d(TAG, String.format("MdnsDiscoveryManager event code=%s transactionId=%d", + NsdManager.nameOf(code), transactionId)); + } + switch (code) { + case NsdManager.SERVICE_FOUND: + clientInfo.onServiceFound(clientId, info); + break; + case NsdManager.SERVICE_LOST: + clientInfo.onServiceLost(clientId, info); + break; + case NsdManager.RESOLVE_SERVICE_SUCCEEDED: { + final ClientRequest request = clientInfo.mClientRequests.get(clientId); + if (request == null) { + Log.e(TAG, "Unknown client request in RESOLVE_SERVICE_SUCCEEDED"); + break; + } + final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo; + info.setPort(serviceInfo.getPort()); + + Map<String, String> attrs = serviceInfo.getAttributes(); + for (Map.Entry<String, String> kv : attrs.entrySet()) { + final String key = kv.getKey(); + try { + info.setAttribute(key, serviceInfo.getAttributeAsBytes(key)); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Invalid attribute", e); + } + } + final List<InetAddress> addresses = getInetAddresses(serviceInfo); + if (addresses.size() != 0) { + info.setHostAddresses(addresses); + clientInfo.onResolveServiceSucceeded(clientId, info); + } else { + // No address. Notify resolution failure. + clientInfo.onResolveServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); + } + + // Unregister the listener immediately like IMDnsEventListener design + if (!(request instanceof DiscoveryManagerRequest)) { + Log.wtf(TAG, "non-DiscoveryManager request in DiscoveryManager event"); + break; + } + stopDiscoveryManagerRequest(request, clientId, transactionId, clientInfo); + break; + } + case NsdManager.SERVICE_UPDATED: { + final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo; + info.setPort(serviceInfo.getPort()); + + Map<String, String> attrs = serviceInfo.getAttributes(); + for (Map.Entry<String, String> kv : attrs.entrySet()) { + final String key = kv.getKey(); + try { + info.setAttribute(key, serviceInfo.getAttributeAsBytes(key)); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Invalid attribute", e); + } + } + + final List<InetAddress> addresses = getInetAddresses(serviceInfo); + info.setHostAddresses(addresses); + clientInfo.onServiceUpdated(clientId, info); + break; + } + case NsdManager.SERVICE_UPDATED_LOST: + clientInfo.onServiceUpdatedLost(clientId); + break; + default: + return false; + } + return true; + } } } + @NonNull + private static List<InetAddress> getInetAddresses(@NonNull MdnsServiceInfo serviceInfo) { + final List<String> v4Addrs = serviceInfo.getIpv4Addresses(); + final List<String> v6Addrs = serviceInfo.getIpv6Addresses(); + final List<InetAddress> addresses = new ArrayList<>(v4Addrs.size() + v6Addrs.size()); + for (String ipv4Address : v4Addrs) { + try { + addresses.add(InetAddresses.parseNumericAddress(ipv4Address)); + } catch (IllegalArgumentException e) { + Log.wtf(TAG, "Invalid ipv4 address", e); + } + } + for (String ipv6Address : v6Addrs) { + try { + final Inet6Address addr = (Inet6Address) InetAddresses.parseNumericAddress( + ipv6Address); + addresses.add(InetAddressUtils.withScopeId(addr, serviceInfo.getInterfaceIndex())); + } catch (IllegalArgumentException e) { + Log.wtf(TAG, "Invalid ipv6 address", e); + } + } + return addresses; + } + private static void setServiceNetworkForCallback(NsdServiceInfo info, int netId, int ifaceIdx) { switch (netId) { case NETID_UNSET: @@ -648,14 +1331,181 @@ return sb.toString(); } + /** + * Check the given service type is valid and construct it to a service type + * which can use for discovery / resolution service. + * + * <p>The valid service type should be 2 labels, or 3 labels if the query is for a + * subtype (see RFC6763 7.1). Each label is up to 63 characters and must start with an + * underscore; they are alphanumerical characters or dashes or underscore, except the + * last one that is just alphanumerical. The last label must be _tcp or _udp. + * + * <p>The subtype may also be specified with a comma after the service type, for example + * _type._tcp,_subtype. + * + * @param serviceType the request service type for discovery / resolution service + * @return constructed service type or null if the given service type is invalid. + */ + @Nullable + public static Pair<String, String> parseTypeAndSubtype(String serviceType) { + if (TextUtils.isEmpty(serviceType)) return null; + + final String typeOrSubtypePattern = "_[a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]"; + final Pattern serviceTypePattern = Pattern.compile( + // Optional leading subtype (_subtype._type._tcp) + // (?: xxx) is a non-capturing parenthesis, don't capture the dot + "^(?:(" + typeOrSubtypePattern + ")\\.)?" + // Actual type (_type._tcp.local) + + "(" + typeOrSubtypePattern + "\\._(?:tcp|udp))" + // Drop '.' at the end of service type that is compatible with old backend. + // e.g. allow "_type._tcp.local." + + "\\.?" + // Optional subtype after comma, for "_type._tcp,_subtype" format + + "(?:,(" + typeOrSubtypePattern + "))?" + + "$"); + final Matcher matcher = serviceTypePattern.matcher(serviceType); + if (!matcher.matches()) return null; + // Use the subtype either at the beginning or after the comma + final String subtype = matcher.group(1) != null ? matcher.group(1) : matcher.group(3); + return new Pair<>(matcher.group(2), subtype); + } + @VisibleForTesting NsdService(Context ctx, Handler handler, long cleanupDelayMs) { + this(ctx, handler, cleanupDelayMs, new Dependencies()); + } + + @VisibleForTesting + NsdService(Context ctx, Handler handler, long cleanupDelayMs, Dependencies deps) { mCleanupDelayMs = cleanupDelayMs; mContext = ctx; mNsdStateMachine = new NsdStateMachine(TAG, handler); mNsdStateMachine.start(); mMDnsManager = ctx.getSystemService(MDnsManager.class); mMDnsEventCallback = new MDnsEventCallback(mNsdStateMachine); + mDeps = deps; + + mMdnsSocketProvider = deps.makeMdnsSocketProvider(ctx, handler.getLooper(), + LOGGER.forSubComponent("MdnsSocketProvider")); + // Netlink monitor starts on boot, and intentionally never stopped, to ensure that all + // address events are received. + handler.post(mMdnsSocketProvider::startNetLinkMonitor); + mMdnsSocketClient = + new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider); + mMdnsDiscoveryManager = deps.makeMdnsDiscoveryManager(new ExecutorProvider(), + mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager")); + handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager)); + mAdvertiser = deps.makeMdnsAdvertiser(handler.getLooper(), mMdnsSocketProvider, + new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser")); + } + + /** + * Dependencies of NsdService, for injection in tests. + */ + @VisibleForTesting + public static class Dependencies { + /** + * Check whether the MdnsDiscoveryManager feature is enabled. + * + * @param context The global context information about an app environment. + * @return true if the MdnsDiscoveryManager feature is enabled. + */ + public boolean isMdnsDiscoveryManagerEnabled(Context context) { + return isAtLeastU() || DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_TETHERING, + MDNS_DISCOVERY_MANAGER_VERSION, DeviceConfigUtils.TETHERING_MODULE_NAME, + false /* defaultEnabled */); + } + + /** + * Check whether the MdnsAdvertiser feature is enabled. + * + * @param context The global context information about an app environment. + * @return true if the MdnsAdvertiser feature is enabled. + */ + public boolean isMdnsAdvertiserEnabled(Context context) { + return isAtLeastU() || DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_TETHERING, + MDNS_ADVERTISER_VERSION, DeviceConfigUtils.TETHERING_MODULE_NAME, + false /* defaultEnabled */); + } + + /** + * Get the type allowlist flag value. + * @see #MDNS_TYPE_ALLOWLIST_FLAGS + */ + @Nullable + public String getTypeAllowlistFlags() { + return DeviceConfigUtils.getDeviceConfigProperty(NAMESPACE_TETHERING, + MDNS_TYPE_ALLOWLIST_FLAGS, null); + } + + /** + * @see DeviceConfigUtils#isFeatureEnabled(Context, String, String, String, boolean) + */ + public boolean isFeatureEnabled(Context context, String feature) { + return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_TETHERING, + feature, DeviceConfigUtils.TETHERING_MODULE_NAME, false /* defaultEnabled */); + } + + /** + * @see MdnsDiscoveryManager + */ + public MdnsDiscoveryManager makeMdnsDiscoveryManager( + @NonNull ExecutorProvider executorProvider, + @NonNull MdnsMultinetworkSocketClient socketClient, @NonNull SharedLog sharedLog) { + return new MdnsDiscoveryManager(executorProvider, socketClient, sharedLog); + } + + /** + * @see MdnsAdvertiser + */ + public MdnsAdvertiser makeMdnsAdvertiser( + @NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider, + @NonNull MdnsAdvertiser.AdvertiserCallback cb, @NonNull SharedLog sharedLog) { + return new MdnsAdvertiser(looper, socketProvider, cb, sharedLog); + } + + /** + * @see MdnsSocketProvider + */ + public MdnsSocketProvider makeMdnsSocketProvider(@NonNull Context context, + @NonNull Looper looper, @NonNull SharedLog sharedLog) { + return new MdnsSocketProvider(context, looper, sharedLog); + } + } + + /** + * Return whether a type is allowlisted to use the Java backend. + * @param type The service type + * @param flagPrefix One of {@link #MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX} or + * {@link #MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX}. + */ + private boolean isTypeAllowlistedForJavaBackend(@Nullable String type, + @NonNull String flagPrefix) { + if (type == null) return false; + final String typesConfig = mDeps.getTypeAllowlistFlags(); + if (TextUtils.isEmpty(typesConfig)) return false; + + final String mappingPrefix = type + ":"; + String mappedFlag = null; + for (String mapping : TextUtils.split(typesConfig, ",")) { + if (mapping.startsWith(mappingPrefix)) { + mappedFlag = mapping.substring(mappingPrefix.length()); + break; + } + } + + if (mappedFlag == null) return false; + + return mDeps.isFeatureEnabled(mContext, + flagPrefix + mappedFlag + MDNS_ALLOWLIST_FLAG_SUFFIX); + } + + private boolean useDiscoveryManagerForType(@Nullable String type) { + return isTypeAllowlistedForJavaBackend(type, MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX); + } + + private boolean useAdvertiserForType(@Nullable String type) { + return isTypeAllowlistedForJavaBackend(type, MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX); } public static NsdService create(Context context) { @@ -708,12 +1558,72 @@ } } + private class AdvertiserCallback implements MdnsAdvertiser.AdvertiserCallback { + @Override + public void onRegisterServiceSucceeded(int serviceId, NsdServiceInfo registeredInfo) { + final ClientInfo clientInfo = getClientInfoOrLog(serviceId); + if (clientInfo == null) return; + + final int clientId = getClientIdOrLog(clientInfo, serviceId); + if (clientId < 0) return; + + // onRegisterServiceSucceeded only has the service name in its info. This aligns with + // historical behavior. + final NsdServiceInfo cbInfo = new NsdServiceInfo(registeredInfo.getServiceName(), null); + clientInfo.onRegisterServiceSucceeded(clientId, cbInfo); + } + + @Override + public void onRegisterServiceFailed(int serviceId, int errorCode) { + final ClientInfo clientInfo = getClientInfoOrLog(serviceId); + if (clientInfo == null) return; + + final int clientId = getClientIdOrLog(clientInfo, serviceId); + if (clientId < 0) return; + + clientInfo.onRegisterServiceFailed(clientId, errorCode); + } + + private ClientInfo getClientInfoOrLog(int serviceId) { + final ClientInfo clientInfo = mIdToClientInfoMap.get(serviceId); + if (clientInfo == null) { + Log.e(TAG, String.format("Callback for service %d has no client", serviceId)); + } + return clientInfo; + } + + private int getClientIdOrLog(@NonNull ClientInfo info, int serviceId) { + final int clientId = info.getClientId(serviceId); + if (clientId < 0) { + Log.e(TAG, String.format("Client ID not found for service %d", serviceId)); + } + return clientId; + } + } + + private static class ConnectorArgs { + @NonNull public final NsdServiceConnector connector; + @NonNull public final INsdManagerCallback callback; + public final boolean useJavaBackend; + public final int uid; + + ConnectorArgs(@NonNull NsdServiceConnector connector, @NonNull INsdManagerCallback callback, + boolean useJavaBackend, int uid) { + this.connector = connector; + this.callback = callback; + this.useJavaBackend = useJavaBackend; + this.uid = uid; + } + } + @Override - public INsdServiceConnector connect(INsdManagerCallback cb) { + public INsdServiceConnector connect(INsdManagerCallback cb, boolean useJavaBackend) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService"); + if (DBG) Log.d(TAG, "New client connect. useJavaBackend=" + useJavaBackend); final INsdServiceConnector connector = new NsdServiceConnector(); - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.REGISTER_CLIENT, new Pair<>(connector, cb))); + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.REGISTER_CLIENT, + new ConnectorArgs((NsdServiceConnector) connector, cb, useJavaBackend, + Binder.getCallingUid()))); return connector; } @@ -763,6 +1673,26 @@ } @Override + public void stopResolution(int listenerKey) { + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( + NsdManager.STOP_RESOLUTION, 0, listenerKey, new ListenerArgs(this, null))); + } + + @Override + public void registerServiceInfoCallback(int listenerKey, NsdServiceInfo serviceInfo) { + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( + NsdManager.REGISTER_SERVICE_CALLBACK, 0, listenerKey, + new ListenerArgs(this, serviceInfo))); + } + + @Override + public void unregisterServiceInfoCallback(int listenerKey) { + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( + NsdManager.UNREGISTER_SERVICE_CALLBACK, 0, listenerKey, + new ListenerArgs(this, null))); + } + + @Override public void startDaemon() { mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( NsdManager.DAEMON_STARTUP, new ListenerArgs(this, null))); @@ -892,15 +1822,52 @@ } @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!PermissionUtils.checkDumpPermission(mContext, TAG, pw)) return; + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + if (!PermissionUtils.checkDumpPermission(mContext, TAG, writer)) return; - for (ClientInfo client : mClients.values()) { - pw.println("Client Info"); - pw.println(client); - } - + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + // Dump state machine logs mNsdStateMachine.dump(fd, pw, args); + + // Dump service and clients logs + pw.println(); + pw.println("Logs:"); + pw.increaseIndent(); + mServiceLogs.reverseDump(pw); + pw.decreaseIndent(); + } + + private abstract static class ClientRequest { + private final int mGlobalId; + + private ClientRequest(int globalId) { + mGlobalId = globalId; + } + } + + private static class LegacyClientRequest extends ClientRequest { + private final int mRequestCode; + + private LegacyClientRequest(int globalId, int requestCode) { + super(globalId); + mRequestCode = requestCode; + } + } + + private static class AdvertiserClientRequest extends ClientRequest { + private AdvertiserClientRequest(int globalId) { + super(globalId); + } + } + + private static class DiscoveryManagerRequest extends ClientRequest { + @NonNull + private final MdnsListener mListener; + + private DiscoveryManagerRequest(int globalId, @NonNull MdnsListener listener) { + super(globalId); + mListener = listener; + } } /* Information tracked per client */ @@ -911,56 +1878,85 @@ /* Remembers a resolved service until getaddrinfo completes */ private NsdServiceInfo mResolvedService; - /* A map from client id to unique id sent to mDns */ - private final SparseIntArray mClientIds = new SparseIntArray(); - - /* A map from client id to the type of the request we had received */ - private final SparseIntArray mClientRequests = new SparseIntArray(); + /* A map from client-side ID (listenerKey) to the request */ + private final SparseArray<ClientRequest> mClientRequests = new SparseArray<>(); // The target SDK of this client < Build.VERSION_CODES.S - private boolean mIsLegacy = false; + private boolean mIsPreSClient = false; + // The flag of using java backend if the client's target SDK >= U + private final boolean mUseJavaBackend; + // Store client logs + private final SharedLog mClientLogs; - private ClientInfo(INsdManagerCallback cb) { + private ClientInfo(INsdManagerCallback cb, boolean useJavaBackend, SharedLog sharedLog) { mCb = cb; - if (DBG) Log.d(TAG, "New client"); + mUseJavaBackend = useJavaBackend; + mClientLogs = sharedLog; + mClientLogs.log("New client. useJavaBackend=" + useJavaBackend); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("mResolvedService ").append(mResolvedService).append("\n"); - sb.append("mIsLegacy ").append(mIsLegacy).append("\n"); - for(int i = 0; i< mClientIds.size(); i++) { - int clientID = mClientIds.keyAt(i); - sb.append("clientId ").append(clientID). - append(" mDnsId ").append(mClientIds.valueAt(i)). - append(" type ").append(mClientRequests.get(clientID)).append("\n"); + sb.append("mIsLegacy ").append(mIsPreSClient).append("\n"); + for (int i = 0; i < mClientRequests.size(); i++) { + int clientID = mClientRequests.keyAt(i); + sb.append("clientId ") + .append(clientID) + .append(" mDnsId ").append(mClientRequests.valueAt(i).mGlobalId) + .append(" type ").append( + mClientRequests.valueAt(i).getClass().getSimpleName()) + .append("\n"); } return sb.toString(); } - private boolean isLegacy() { - return mIsLegacy; + private boolean isPreSClient() { + return mIsPreSClient; } - private void setLegacy() { - mIsLegacy = true; + private void setPreSClient() { + mIsPreSClient = true; + } + + private void unregisterMdnsListenerFromRequest(ClientRequest request) { + final MdnsListener listener = + ((DiscoveryManagerRequest) request).mListener; + mMdnsDiscoveryManager.unregisterListener( + listener.getListenedServiceType(), listener); } // Remove any pending requests from the global map when we get rid of a client, // and send cancellations to the daemon. private void expungeAllRequests() { - int globalId, clientId, i; + mClientLogs.log("Client unregistered. expungeAllRequests!"); // TODO: to keep handler responsive, do not clean all requests for that client at once. - for (i = 0; i < mClientIds.size(); i++) { - clientId = mClientIds.keyAt(i); - globalId = mClientIds.valueAt(i); + for (int i = 0; i < mClientRequests.size(); i++) { + final int clientId = mClientRequests.keyAt(i); + final ClientRequest request = mClientRequests.valueAt(i); + final int globalId = request.mGlobalId; mIdToClientInfoMap.remove(globalId); if (DBG) { Log.d(TAG, "Terminating client-ID " + clientId + " global-ID " + globalId + " type " + mClientRequests.get(clientId)); } - switch (mClientRequests.get(clientId)) { + + if (request instanceof DiscoveryManagerRequest) { + unregisterMdnsListenerFromRequest(request); + continue; + } + + if (request instanceof AdvertiserClientRequest) { + mAdvertiser.removeService(globalId); + continue; + } + + if (!(request instanceof LegacyClientRequest)) { + throw new IllegalStateException("Unknown request type: " + request.getClass()); + } + + switch (((LegacyClientRequest) request).mRequestCode) { case NsdManager.DISCOVER_SERVICES: stopServiceDiscovery(globalId); break; @@ -974,18 +1970,23 @@ break; } } - mClientIds.clear(); mClientRequests.clear(); } - // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id, - // return the corresponding listener id. mDnsClient id is also called a global id. + // mClientRequests is a sparse array of listener id -> ClientRequest. For a given + // mDnsClient id, return the corresponding listener id. mDnsClient id is also called a + // global id. private int getClientId(final int globalId) { - int idx = mClientIds.indexOfValue(globalId); - if (idx < 0) { - return idx; + for (int i = 0; i < mClientRequests.size(); i++) { + if (mClientRequests.valueAt(i).mGlobalId == globalId) { + return mClientRequests.keyAt(i); + } } - return mClientIds.keyAt(idx); + return -1; + } + + private void log(String message) { + mClientLogs.log(message); } void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) { @@ -1083,5 +2084,53 @@ Log.e(TAG, "Error calling onResolveServiceSucceeded", e); } } + + void onStopResolutionFailed(int listenerKey, int error) { + try { + mCb.onStopResolutionFailed(listenerKey, error); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onStopResolutionFailed", e); + } + } + + void onStopResolutionSucceeded(int listenerKey) { + try { + mCb.onStopResolutionSucceeded(listenerKey); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onStopResolutionSucceeded", e); + } + } + + void onServiceInfoCallbackRegistrationFailed(int listenerKey, int error) { + try { + mCb.onServiceInfoCallbackRegistrationFailed(listenerKey, error); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onServiceInfoCallbackRegistrationFailed", e); + } + } + + void onServiceUpdated(int listenerKey, NsdServiceInfo info) { + try { + mCb.onServiceUpdated(listenerKey, info); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onServiceUpdated", e); + } + } + + void onServiceUpdatedLost(int listenerKey) { + try { + mCb.onServiceUpdatedLost(listenerKey); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onServiceUpdatedLost", e); + } + } + + void onServiceInfoCallbackUnregistered(int listenerKey) { + try { + mCb.onServiceInfoCallbackUnregistered(listenerKey); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onServiceInfoCallbackUnregistered", e); + } + } } }
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/AbstractSocketNetlink.java similarity index 61% copy from service/mdns/com/android/server/connectivity/mdns/MdnsAdvertiser.java copy to service-t/src/com/android/server/connectivity/mdns/AbstractSocketNetlink.java index dee78fd..b792e46 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsAdvertiser.java +++ b/service-t/src/com/android/server/connectivity/mdns/AbstractSocketNetlink.java
@@ -16,14 +16,27 @@ package com.android.server.connectivity.mdns; -import android.util.Log; - /** - * MdnsAdvertiser manages advertising services per {@link com.android.server.NsdService} requests. - * - * TODO: implement + * The interface for netlink monitor. */ -public class MdnsAdvertiser { - private static final String TAG = MdnsAdvertiser.class.getSimpleName(); - public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); +public interface AbstractSocketNetlink { + + /** + * Returns if the netlink monitor is supported or not. By default, it is not supported. + */ + default boolean isSupported() { + return false; + } + + /** + * Starts the monitor. + */ + default void startMonitoring() { + } + + /** + * Stops the monitor. + */ + default void stopMonitoring() { + } }
diff --git a/service/mdns/com/android/server/connectivity/mdns/ConnectivityMonitor.java b/service-t/src/com/android/server/connectivity/mdns/ConnectivityMonitor.java similarity index 100% rename from service/mdns/com/android/server/connectivity/mdns/ConnectivityMonitor.java rename to service-t/src/com/android/server/connectivity/mdns/ConnectivityMonitor.java
diff --git a/service/mdns/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManager.java b/service-t/src/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManager.java similarity index 100% rename from service/mdns/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManager.java rename to service-t/src/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManager.java
diff --git a/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java b/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java new file mode 100644 index 0000000..866ecba --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
@@ -0,0 +1,250 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Network; +import android.text.TextUtils; +import android.util.Log; +import android.util.Pair; + +import com.android.server.connectivity.mdns.util.MdnsLogger; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.Callable; + +/** + * A {@link Callable} that builds and enqueues a mDNS query to send over the multicast socket. If a + * query is built and enqueued successfully, then call to {@link #call()} returns the transaction ID + * 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}. + */ +public class EnqueueMdnsQueryCallable implements Callable<Pair<Integer, List<String>>> { + + private static final String TAG = "MdnsQueryCallable"; + private static final MdnsLogger LOGGER = new MdnsLogger(TAG); + private static final List<Integer> castShellEmulatorMdnsPorts; + + static { + castShellEmulatorMdnsPorts = new ArrayList<>(); + String[] stringPorts = MdnsConfigs.castShellEmulatorMdnsPorts(); + + for (String port : stringPorts) { + try { + castShellEmulatorMdnsPorts.add(Integer.parseInt(port)); + } catch (NumberFormatException e) { + // Ignore. + } + } + } + + @NonNull + private final WeakReference<MdnsSocketClientBase> weakRequestSender; + @NonNull + private final MdnsPacketWriter packetWriter; + @NonNull + private final String[] serviceTypeLabels; + @NonNull + private final List<String> subtypes; + private final boolean expectUnicastResponse; + private final int transactionId; + @Nullable + private final Network network; + private final boolean sendDiscoveryQueries; + @NonNull + private final List<MdnsResponse> servicesToResolve; + + EnqueueMdnsQueryCallable( + @NonNull MdnsSocketClientBase requestSender, + @NonNull MdnsPacketWriter packetWriter, + @NonNull String serviceType, + @NonNull Collection<String> subtypes, + boolean expectUnicastResponse, + int transactionId, + @Nullable Network network, + boolean sendDiscoveryQueries, + @NonNull Collection<MdnsResponse> servicesToResolve) { + weakRequestSender = new WeakReference<>(requestSender); + this.packetWriter = packetWriter; + serviceTypeLabels = TextUtils.split(serviceType, "\\."); + this.subtypes = new ArrayList<>(subtypes); + this.expectUnicastResponse = expectUnicastResponse; + this.transactionId = transactionId; + this.network = network; + this.sendDiscoveryQueries = sendDiscoveryQueries; + this.servicesToResolve = new ArrayList<>(servicesToResolve); + } + + // Incompatible return type for override of Callable#call(). + @SuppressWarnings("nullness:override.return.invalid") + @Override + @Nullable + public Pair<Integer, List<String>> call() { + try { + MdnsSocketClientBase requestSender = weakRequestSender.get(); + if (requestSender == null) { + return null; + } + + int numQuestions = 0; + + if (sendDiscoveryQueries) { + numQuestions++; // Base service type + if (!subtypes.isEmpty()) { + numQuestions += subtypes.size(); + } + } + + // List of (name, type) to query + final ArrayList<Pair<String[], Integer>> missingKnownAnswerRecords = new ArrayList<>(); + for (MdnsResponse response : servicesToResolve) { + // TODO: also send queries to renew record TTL (as per RFC6762 7.1 no need to query + // if remaining TTL is more than half the original one, so send the queries if half + // the TTL has passed). + if (response.isComplete()) continue; + final String[] serviceName = response.getServiceName(); + if (serviceName == null) continue; + if (!response.hasTextRecord()) { + missingKnownAnswerRecords.add(new Pair<>(serviceName, MdnsRecord.TYPE_TXT)); + } + if (!response.hasServiceRecord()) { + missingKnownAnswerRecords.add(new Pair<>(serviceName, MdnsRecord.TYPE_SRV)); + // The hostname is not yet known, so queries for address records will be sent + // the next time the EnqueueMdnsQueryCallable is enqueued if the reply does not + // contain them. In practice, advertisers should include the address records + // when queried for SRV, although it's not a MUST requirement (RFC6763 12.2). + } else if (!response.hasInet4AddressRecord() && !response.hasInet6AddressRecord()) { + final String[] host = response.getServiceRecord().getServiceHost(); + missingKnownAnswerRecords.add(new Pair<>(host, MdnsRecord.TYPE_A)); + missingKnownAnswerRecords.add(new Pair<>(host, MdnsRecord.TYPE_AAAA)); + } + } + numQuestions += missingKnownAnswerRecords.size(); + + if (numQuestions == 0) { + // No query to send + return null; + } + + // Header. + packetWriter.writeUInt16(transactionId); // transaction ID + packetWriter.writeUInt16(MdnsConstants.FLAGS_QUERY); // flags + packetWriter.writeUInt16(numQuestions); // number of questions + packetWriter.writeUInt16(0); // number of answers (not yet known; will be written later) + packetWriter.writeUInt16(0); // number of authority entries + packetWriter.writeUInt16(0); // number of additional records + + // Question(s) for missing records on known answers + for (Pair<String[], Integer> question : missingKnownAnswerRecords) { + writeQuestion(question.first, question.second); + } + + // Question(s) for discovering other services with the type. There will be one question + // for each (fqdn+subtype, recordType) combination, as well as one for each (fqdn, + // recordType) combination. + if (sendDiscoveryQueries) { + for (String subtype : subtypes) { + String[] labels = new String[serviceTypeLabels.length + 2]; + labels[0] = MdnsConstants.SUBTYPE_PREFIX + subtype; + labels[1] = MdnsConstants.SUBTYPE_LABEL; + System.arraycopy(serviceTypeLabels, 0, labels, 2, serviceTypeLabels.length); + + writeQuestion(labels, MdnsRecord.TYPE_PTR); + } + writeQuestion(serviceTypeLabels, MdnsRecord.TYPE_PTR); + } + + if (requestSender instanceof MdnsMultinetworkSocketClient) { + sendPacketToIpv4AndIpv6(requestSender, MdnsConstants.MDNS_PORT, network); + for (Integer emulatorPort : castShellEmulatorMdnsPorts) { + sendPacketToIpv4AndIpv6(requestSender, emulatorPort, network); + } + } else if (requestSender instanceof MdnsSocketClient) { + final MdnsSocketClient client = (MdnsSocketClient) requestSender; + InetAddress mdnsAddress = MdnsConstants.getMdnsIPv4Address(); + if (client.isOnIPv6OnlyNetwork()) { + mdnsAddress = MdnsConstants.getMdnsIPv6Address(); + } + + sendPacketTo(client, new InetSocketAddress(mdnsAddress, MdnsConstants.MDNS_PORT)); + for (Integer emulatorPort : castShellEmulatorMdnsPorts) { + sendPacketTo(client, new InetSocketAddress(mdnsAddress, emulatorPort)); + } + } else { + throw new IOException("Unknown socket client type: " + requestSender.getClass()); + } + return Pair.create(transactionId, subtypes); + } catch (IOException e) { + LOGGER.e(String.format("Failed to create mDNS packet for subtype: %s.", + TextUtils.join(",", subtypes)), e); + return null; + } + } + + private void writeQuestion(String[] labels, int type) throws IOException { + packetWriter.writeLabels(labels); + packetWriter.writeUInt16(type); + packetWriter.writeUInt16( + MdnsConstants.QCLASS_INTERNET + | (expectUnicastResponse ? MdnsConstants.QCLASS_UNICAST : 0)); + } + + private void sendPacketTo(MdnsSocketClient requestSender, InetSocketAddress address) + throws IOException { + DatagramPacket packet = packetWriter.getPacket(address); + if (expectUnicastResponse) { + requestSender.sendUnicastPacket(packet); + } else { + requestSender.sendMulticastPacket(packet); + } + } + + private void sendPacketFromNetwork(MdnsSocketClientBase requestSender, + InetSocketAddress address, Network network) + throws IOException { + DatagramPacket packet = packetWriter.getPacket(address); + if (expectUnicastResponse) { + requestSender.sendUnicastPacket(packet, network); + } else { + requestSender.sendMulticastPacket(packet, network); + } + } + + private void sendPacketToIpv4AndIpv6(MdnsSocketClientBase requestSender, int port, + Network network) { + try { + sendPacketFromNetwork(requestSender, + new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), port), network); + } catch (IOException e) { + Log.i(TAG, "Can't send packet to IPv4", e); + } + try { + sendPacketFromNetwork(requestSender, + new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), port), network); + } catch (IOException e) { + Log.i(TAG, "Can't send packet to IPv6", e); + } + } +} \ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/ExecutorProvider.java b/service-t/src/com/android/server/connectivity/mdns/ExecutorProvider.java similarity index 100% rename from service/mdns/com/android/server/connectivity/mdns/ExecutorProvider.java rename to service-t/src/com/android/server/connectivity/mdns/ExecutorProvider.java
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java new file mode 100644 index 0000000..5f27b6a --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
@@ -0,0 +1,528 @@ +/* + * 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.server.connectivity.mdns.MdnsRecord.MAX_LABEL_LENGTH; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.LinkAddress; +import android.net.Network; +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.os.Looper; +import android.util.ArrayMap; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.SharedLog; +import com.android.server.connectivity.mdns.util.MdnsUtils; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiPredicate; +import java.util.function.Consumer; + +/** + * MdnsAdvertiser manages advertising services per {@link com.android.server.NsdService} requests. + * + * All methods except the constructor must be called on the looper thread. + */ +public class MdnsAdvertiser { + private static final String TAG = MdnsAdvertiser.class.getSimpleName(); + static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); + + // Top-level domain for link-local queries, as per RFC6762 3. + private static final String LOCAL_TLD = "local"; + + + private final Looper mLooper; + private final AdvertiserCallback mCb; + + // Max-sized buffers to be used as temporary buffer to read/build packets. May be used by + // multiple components, but only for self-contained operations in the looper thread, so not + // concurrently. + // TODO: set according to MTU. 1300 should fit for ethernet MTU 1500 with some overhead. + private final byte[] mPacketCreationBuffer = new byte[1300]; + + private final MdnsSocketProvider mSocketProvider; + private final ArrayMap<Network, InterfaceAdvertiserRequest> mAdvertiserRequests = + new ArrayMap<>(); + private final ArrayMap<MdnsInterfaceSocket, MdnsInterfaceAdvertiser> mAllAdvertisers = + new ArrayMap<>(); + private final SparseArray<Registration> mRegistrations = new SparseArray<>(); + private final Dependencies mDeps; + + private String[] mDeviceHostName; + @NonNull private final SharedLog mSharedLog; + + /** + * Dependencies for {@link MdnsAdvertiser}, useful for testing. + */ + @VisibleForTesting + public static class Dependencies { + /** + * @see MdnsInterfaceAdvertiser + */ + public MdnsInterfaceAdvertiser makeAdvertiser(@NonNull MdnsInterfaceSocket socket, + @NonNull List<LinkAddress> initialAddresses, + @NonNull Looper looper, @NonNull byte[] packetCreationBuffer, + @NonNull MdnsInterfaceAdvertiser.Callback cb, + @NonNull String[] deviceHostName, + @NonNull SharedLog sharedLog) { + // Note NetworkInterface is final and not mockable + return new MdnsInterfaceAdvertiser(socket, initialAddresses, looper, + packetCreationBuffer, cb, deviceHostName, sharedLog); + } + + /** + * Generates a unique hostname to be used by the device. + */ + @NonNull + public String[] generateHostname() { + // Generate a very-probably-unique hostname. This allows minimizing possible conflicts + // to the point that probing for it is no longer necessary (as per RFC6762 8.1 last + // paragraph), and does not leak more information than what could already be obtained by + // looking at the mDNS packets source address. + // This differs from historical behavior that just used "Android.local" for many + // devices, creating a lot of conflicts. + // Having a different hostname per interface is an acceptable option as per RFC6762 14. + // This hostname will change every time the interface is reconnected, so this does not + // allow tracking the device. + // TODO: consider deriving a hostname from other sources, such as the IPv6 addresses + // (reusing the same privacy-protecting mechanics). + return new String[] { + "Android_" + UUID.randomUUID().toString().replace("-", ""), LOCAL_TLD }; + } + } + + private final MdnsInterfaceAdvertiser.Callback mInterfaceAdvertiserCb = + new MdnsInterfaceAdvertiser.Callback() { + @Override + public void onRegisterServiceSucceeded( + @NonNull MdnsInterfaceAdvertiser advertiser, int serviceId) { + // Wait for all current interfaces to be done probing before notifying of success. + if (any(mAllAdvertisers, (k, a) -> a.isProbing(serviceId))) return; + // The service may still be unregistered/renamed if a conflict is found on a later added + // interface, or if a conflicting announcement/reply is detected (RFC6762 9.) + + final Registration registration = mRegistrations.get(serviceId); + if (registration == null) { + Log.wtf(TAG, "Register succeeded for unknown registration"); + return; + } + if (!registration.mNotifiedRegistrationSuccess) { + mCb.onRegisterServiceSucceeded(serviceId, registration.getServiceInfo()); + registration.mNotifiedRegistrationSuccess = true; + } + } + + @Override + public void onServiceConflict(@NonNull MdnsInterfaceAdvertiser advertiser, int serviceId) { + mSharedLog.i("Found conflict, restarted probing for service " + serviceId); + + final Registration registration = mRegistrations.get(serviceId); + if (registration == null) return; + if (registration.mNotifiedRegistrationSuccess) { + // TODO: consider notifying clients that the service is no longer registered with + // the old name (back to probing). The legacy implementation did not send any + // callback though; it only sent onServiceRegistered after re-probing finishes + // (with the old, conflicting, actually not used name as argument... The new + // implementation will send callbacks with the new name). + registration.mNotifiedRegistrationSuccess = false; + + // The service was done probing, just reset it to probing state (RFC6762 9.) + forAllAdvertisers(a -> a.restartProbingForConflict(serviceId)); + return; + } + + // Conflict was found during probing; rename once to find a name that has no conflict + registration.updateForConflict( + registration.makeNewServiceInfoForConflict(1 /* renameCount */), + 1 /* renameCount */); + + // Keep renaming if the new name conflicts in local registrations + updateRegistrationUntilNoConflict((net, adv) -> adv.hasRegistration(registration), + registration); + + // Update advertisers to use the new name + forAllAdvertisers(a -> a.renameServiceForConflict( + serviceId, registration.getServiceInfo())); + } + + @Override + public void onDestroyed(@NonNull MdnsInterfaceSocket socket) { + for (int i = mAdvertiserRequests.size() - 1; i >= 0; i--) { + if (mAdvertiserRequests.valueAt(i).onAdvertiserDestroyed(socket)) { + mAdvertiserRequests.removeAt(i); + } + } + mAllAdvertisers.remove(socket); + } + }; + + private boolean hasAnyConflict( + @NonNull BiPredicate<Network, InterfaceAdvertiserRequest> applicableAdvertiserFilter, + @NonNull NsdServiceInfo newInfo) { + return any(mAdvertiserRequests, (network, adv) -> + applicableAdvertiserFilter.test(network, adv) && adv.hasConflict(newInfo)); + } + + private void updateRegistrationUntilNoConflict( + @NonNull BiPredicate<Network, InterfaceAdvertiserRequest> applicableAdvertiserFilter, + @NonNull Registration registration) { + int renameCount = 0; + NsdServiceInfo newInfo = registration.getServiceInfo(); + while (hasAnyConflict(applicableAdvertiserFilter, newInfo)) { + renameCount++; + newInfo = registration.makeNewServiceInfoForConflict(renameCount); + } + registration.updateForConflict(newInfo, renameCount); + } + + /** + * A request for a {@link MdnsInterfaceAdvertiser}. + * + * This class tracks services to be advertised on all sockets provided via a registered + * {@link MdnsSocketProvider.SocketCallback}. + */ + private class InterfaceAdvertiserRequest implements MdnsSocketProvider.SocketCallback { + /** Registrations to add to newer MdnsInterfaceAdvertisers when sockets are created. */ + @NonNull + private final SparseArray<Registration> mPendingRegistrations = new SparseArray<>(); + @NonNull + private final ArrayMap<MdnsInterfaceSocket, MdnsInterfaceAdvertiser> mAdvertisers = + new ArrayMap<>(); + + InterfaceAdvertiserRequest(@Nullable Network requestedNetwork) { + mSocketProvider.requestSocket(requestedNetwork, this); + } + + /** + * Called when an advertiser was destroyed, after all services were unregistered and it sent + * exit announcements, or the interface is gone. + * + * @return true if this {@link InterfaceAdvertiserRequest} should now be deleted. + */ + boolean onAdvertiserDestroyed(@NonNull MdnsInterfaceSocket socket) { + mAdvertisers.remove(socket); + if (mAdvertisers.size() == 0 && mPendingRegistrations.size() == 0) { + // No advertiser is using sockets from this request anymore (in particular for exit + // announcements), and there is no registration so newer sockets will not be + // necessary, so the request can be unregistered. + mSocketProvider.unrequestSocket(this); + return true; + } + return false; + } + + /** + * Return whether this {@link InterfaceAdvertiserRequest} has the given registration. + */ + boolean hasRegistration(@NonNull Registration registration) { + return mPendingRegistrations.indexOfValue(registration) >= 0; + } + + /** + * Return whether using the proposed new {@link NsdServiceInfo} to add a registration would + * cause a conflict in this {@link InterfaceAdvertiserRequest}. + */ + boolean hasConflict(@NonNull NsdServiceInfo newInfo) { + return getConflictingService(newInfo) >= 0; + } + + /** + * Get the ID of a conflicting service, or -1 if none. + */ + int getConflictingService(@NonNull NsdServiceInfo info) { + for (int i = 0; i < mPendingRegistrations.size(); i++) { + final NsdServiceInfo other = mPendingRegistrations.valueAt(i).getServiceInfo(); + if (MdnsUtils.equalsIgnoreDnsCase(info.getServiceName(), other.getServiceName()) + && MdnsUtils.equalsIgnoreDnsCase(info.getServiceType(), + other.getServiceType())) { + return mPendingRegistrations.keyAt(i); + } + } + return -1; + } + + /** + * Add a service. + * + * Conflicts must be checked via {@link #getConflictingService} before attempting to add. + */ + void addService(int id, Registration registration) { + mPendingRegistrations.put(id, registration); + for (int i = 0; i < mAdvertisers.size(); i++) { + try { + mAdvertisers.valueAt(i).addService( + id, registration.getServiceInfo(), registration.getSubtype()); + } catch (NameConflictException e) { + Log.wtf(TAG, "Name conflict adding services that should have unique names", e); + } + } + } + + void removeService(int id) { + mPendingRegistrations.remove(id); + for (int i = 0; i < mAdvertisers.size(); i++) { + mAdvertisers.valueAt(i).removeService(id); + } + } + + @Override + public void onSocketCreated(@NonNull Network network, + @NonNull MdnsInterfaceSocket socket, + @NonNull List<LinkAddress> addresses) { + MdnsInterfaceAdvertiser advertiser = mAllAdvertisers.get(socket); + if (advertiser == null) { + advertiser = mDeps.makeAdvertiser(socket, addresses, mLooper, mPacketCreationBuffer, + mInterfaceAdvertiserCb, mDeviceHostName, + mSharedLog.forSubComponent(socket.getInterface().getName())); + mAllAdvertisers.put(socket, advertiser); + advertiser.start(); + } + mAdvertisers.put(socket, advertiser); + for (int i = 0; i < mPendingRegistrations.size(); i++) { + final Registration registration = mPendingRegistrations.valueAt(i); + try { + advertiser.addService(mPendingRegistrations.keyAt(i), + registration.getServiceInfo(), registration.getSubtype()); + } catch (NameConflictException e) { + Log.wtf(TAG, "Name conflict adding services that should have unique names", e); + } + } + } + + @Override + public void onInterfaceDestroyed(@NonNull Network network, + @NonNull MdnsInterfaceSocket socket) { + final MdnsInterfaceAdvertiser advertiser = mAdvertisers.get(socket); + if (advertiser != null) advertiser.destroyNow(); + } + + @Override + public void onAddressesChanged(@NonNull Network network, + @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) { + final MdnsInterfaceAdvertiser advertiser = mAdvertisers.get(socket); + if (advertiser != null) advertiser.updateAddresses(addresses); + } + } + + private static class Registration { + @NonNull + final String mOriginalName; + boolean mNotifiedRegistrationSuccess; + private int mConflictCount; + @NonNull + private NsdServiceInfo mServiceInfo; + @Nullable + private final String mSubtype; + + private Registration(@NonNull NsdServiceInfo serviceInfo, @Nullable String subtype) { + this.mOriginalName = serviceInfo.getServiceName(); + this.mServiceInfo = serviceInfo; + this.mSubtype = subtype; + } + + /** + * Update the registration to use a different service name, after a conflict was found. + * + * @param newInfo New service info to use. + * @param renameCount How many renames were done before reaching the current name. + */ + private void updateForConflict(@NonNull NsdServiceInfo newInfo, int renameCount) { + mConflictCount += renameCount; + mServiceInfo = newInfo; + } + + /** + * Make a new service name for the registration, after a conflict was found. + * + * If a name conflict was found during probing or because different advertising requests + * used the same name, the registration is attempted again with a new name (here using + * a number suffix, (1), (2) etc). Registration success is notified once probing succeeds + * with a new name. This matches legacy behavior based on mdnsresponder, and appendix D of + * RFC6763. + * + * @param renameCount How much to increase the number suffix for this conflict. + */ + @NonNull + public NsdServiceInfo makeNewServiceInfoForConflict(int renameCount) { + // In case of conflict choose a different service name. After the first conflict use + // "Name (2)", then "Name (3)" etc. + // TODO: use a hidden method in NsdServiceInfo once MdnsAdvertiser is moved to service-t + final NsdServiceInfo newInfo = new NsdServiceInfo(); + newInfo.setServiceName(getUpdatedServiceName(renameCount)); + newInfo.setServiceType(mServiceInfo.getServiceType()); + for (Map.Entry<String, byte[]> attr : mServiceInfo.getAttributes().entrySet()) { + newInfo.setAttribute(attr.getKey(), + attr.getValue() == null ? null : new String(attr.getValue())); + } + newInfo.setHost(mServiceInfo.getHost()); + newInfo.setPort(mServiceInfo.getPort()); + newInfo.setNetwork(mServiceInfo.getNetwork()); + // interfaceIndex is not set when registering + return newInfo; + } + + private String getUpdatedServiceName(int renameCount) { + final String suffix = " (" + (mConflictCount + renameCount + 1) + ")"; + final String truncatedServiceName = MdnsUtils.truncateServiceName(mOriginalName, + MAX_LABEL_LENGTH - suffix.length()); + return truncatedServiceName + suffix; + } + + @NonNull + public NsdServiceInfo getServiceInfo() { + return mServiceInfo; + } + + @Nullable + public String getSubtype() { + return mSubtype; + } + } + + /** + * Callbacks for advertising services. + * + * Every method is called on the MdnsAdvertiser looper thread. + */ + public interface AdvertiserCallback { + /** + * Called when a service was successfully registered, after probing. + * + * @param serviceId ID of the service provided when registering. + * @param registeredInfo Registered info, which may be different from the requested info, + * after probing and possibly choosing alternative service names. + */ + void onRegisterServiceSucceeded(int serviceId, NsdServiceInfo registeredInfo); + + /** + * Called when service registration failed. + * + * @param serviceId ID of the service provided when registering. + * @param errorCode One of {@code NsdManager.FAILURE_*} + */ + void onRegisterServiceFailed(int serviceId, int errorCode); + + // Unregistration is notified immediately as success in NsdService so no callback is needed + // here. + } + + public MdnsAdvertiser(@NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider, + @NonNull AdvertiserCallback cb, @NonNull SharedLog sharedLog) { + this(looper, socketProvider, cb, new Dependencies(), sharedLog); + } + + @VisibleForTesting + MdnsAdvertiser(@NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider, + @NonNull AdvertiserCallback cb, @NonNull Dependencies deps, + @NonNull SharedLog sharedLog) { + mLooper = looper; + mCb = cb; + mSocketProvider = socketProvider; + mDeps = deps; + mDeviceHostName = deps.generateHostname(); + mSharedLog = sharedLog; + } + + private void checkThread() { + if (Thread.currentThread() != mLooper.getThread()) { + throw new IllegalStateException("This must be called on the looper thread"); + } + } + + /** + * Add a service to advertise. + * @param id A unique ID for the service. + * @param service The service info to advertise. + * @param subtype An optional subtype to advertise the service with. + */ + public void addService(int id, NsdServiceInfo service, @Nullable String subtype) { + checkThread(); + if (mRegistrations.get(id) != null) { + Log.e(TAG, "Adding duplicate registration for " + service); + // TODO (b/264986328): add a more specific error code + mCb.onRegisterServiceFailed(id, NsdManager.FAILURE_INTERNAL_ERROR); + return; + } + + mSharedLog.i("Adding service " + service + " with ID " + id + " and subtype " + subtype); + + final Network network = service.getNetwork(); + final Registration registration = new Registration(service, subtype); + final BiPredicate<Network, InterfaceAdvertiserRequest> checkConflictFilter; + if (network == null) { + // If registering on all networks, no advertiser must have conflicts + checkConflictFilter = (net, adv) -> true; + } else { + // If registering on one network, the matching network advertiser and the one for all + // networks must not have conflicts + checkConflictFilter = (net, adv) -> net == null || network.equals(net); + } + + updateRegistrationUntilNoConflict(checkConflictFilter, registration); + + InterfaceAdvertiserRequest advertiser = mAdvertiserRequests.get(network); + if (advertiser == null) { + advertiser = new InterfaceAdvertiserRequest(network); + mAdvertiserRequests.put(network, advertiser); + } + advertiser.addService(id, registration); + mRegistrations.put(id, registration); + } + + /** + * Remove a previously added service. + * @param id ID used when registering. + */ + public void removeService(int id) { + checkThread(); + if (!mRegistrations.contains(id)) return; + mSharedLog.i("Removing service with ID " + id); + for (int i = mAdvertiserRequests.size() - 1; i >= 0; i--) { + final InterfaceAdvertiserRequest advertiser = mAdvertiserRequests.valueAt(i); + advertiser.removeService(id); + } + mRegistrations.remove(id); + // Regenerates host name when registrations removed. + if (mRegistrations.size() == 0) { + mDeviceHostName = mDeps.generateHostname(); + } + } + + private static <K, V> boolean any(@NonNull ArrayMap<K, V> map, + @NonNull BiPredicate<K, V> predicate) { + for (int i = 0; i < map.size(); i++) { + if (predicate.test(map.keyAt(i), map.valueAt(i))) { + return true; + } + } + return false; + } + + private void forAllAdvertisers(@NonNull Consumer<MdnsInterfaceAdvertiser> consumer) { + any(mAllAdvertisers, (socket, advertiser) -> { + consumer.accept(advertiser); + return false; + }); + } +}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java new file mode 100644 index 0000000..27fc945 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java
@@ -0,0 +1,122 @@ +/* + * 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 android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Looper; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Collections; +import java.util.List; + +/** + * Sends mDns announcements when a service registration changes and at regular intervals. + * + * This allows maintaining other hosts' caches up-to-date. See RFC6762 8.3. + */ +public class MdnsAnnouncer extends MdnsPacketRepeater<MdnsAnnouncer.BaseAnnouncementInfo> { + private static final long ANNOUNCEMENT_INITIAL_DELAY_MS = 1000L; + @VisibleForTesting + static final int ANNOUNCEMENT_COUNT = 8; + + // Matches delay and GoodbyeCount used by the legacy implementation + private static final long EXIT_DELAY_MS = 2000L; + private static final int EXIT_COUNT = 3; + + @NonNull + private final String mLogTag; + + /** Base class for announcement requests to send with {@link MdnsAnnouncer}. */ + public abstract static class BaseAnnouncementInfo implements MdnsPacketRepeater.Request { + private final int mServiceId; + @NonNull + private final MdnsPacket mPacket; + + protected BaseAnnouncementInfo(int serviceId, @NonNull List<MdnsRecord> announcedRecords, + @NonNull List<MdnsRecord> additionalRecords) { + mServiceId = serviceId; + final int flags = 0x8400; // Response, authoritative (rfc6762 18.4) + mPacket = new MdnsPacket(flags, + Collections.emptyList() /* questions */, + announcedRecords, + Collections.emptyList() /* authorityRecords */, + additionalRecords); + } + + public int getServiceId() { + return mServiceId; + } + + @Override + public MdnsPacket getPacket(int index) { + return mPacket; + } + } + + /** Announcement request to send with {@link MdnsAnnouncer}. */ + public static class AnnouncementInfo extends BaseAnnouncementInfo { + AnnouncementInfo(int serviceId, List<MdnsRecord> announcedRecords, + List<MdnsRecord> additionalRecords) { + super(serviceId, announcedRecords, additionalRecords); + } + + @Override + public long getDelayMs(int nextIndex) { + // Delay is doubled for each announcement + return ANNOUNCEMENT_INITIAL_DELAY_MS << (nextIndex - 1); + } + + @Override + public int getNumSends() { + return ANNOUNCEMENT_COUNT; + } + } + + /** Service exit announcement request to send with {@link MdnsAnnouncer}. */ + public static class ExitAnnouncementInfo extends BaseAnnouncementInfo { + ExitAnnouncementInfo(int serviceId, List<MdnsRecord> announcedRecords) { + super(serviceId, announcedRecords, Collections.emptyList() /* additionalRecords */); + } + + @Override + public long getDelayMs(int nextIndex) { + return EXIT_DELAY_MS; + } + + @Override + public int getNumSends() { + return EXIT_COUNT; + } + } + + public MdnsAnnouncer(@NonNull String interfaceTag, @NonNull Looper looper, + @NonNull MdnsReplySender replySender, + @Nullable PacketRepeaterCallback<BaseAnnouncementInfo> cb) { + super(looper, replySender, cb); + mLogTag = MdnsAnnouncer.class.getSimpleName() + "/" + interfaceTag; + } + + @Override + protected String getTag() { + return mLogTag; + } + + // TODO: Notify MdnsRecordRepository that the records were announced for that service ID, + // so it can update the last advertised timestamp of the associated records. +}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsAnyRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAnyRecord.java similarity index 100% rename from service/mdns/com/android/server/connectivity/mdns/MdnsAnyRecord.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsAnyRecord.java
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsConfigs.java b/service-t/src/com/android/server/connectivity/mdns/MdnsConfigs.java similarity index 100% rename from service/mdns/com/android/server/connectivity/mdns/MdnsConfigs.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsConfigs.java
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java b/service-t/src/com/android/server/connectivity/mdns/MdnsConstants.java similarity index 97% rename from service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsConstants.java index 396be5f..f0e1717 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsConstants.java
@@ -37,6 +37,7 @@ public static final int FLAGS_QUERY = 0x0000; public static final int FLAGS_RESPONSE_MASK = 0xF80F; public static final int FLAGS_RESPONSE = 0x8000; + public static final int FLAG_TRUNCATED = 0x0200; public static final int QCLASS_INTERNET = 0x0001; public static final int QCLASS_UNICAST = 0x8000; public static final String SUBTYPE_LABEL = "_sub";
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java new file mode 100644 index 0000000..0f30f10 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
@@ -0,0 +1,283 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns; + +import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread; + +import android.Manifest.permission; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.net.Network; +import android.os.Handler; +import android.os.HandlerThread; +import android.util.ArrayMap; +import android.util.Log; +import android.util.Pair; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.SharedLog; +import com.android.server.connectivity.mdns.util.MdnsUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * This class keeps tracking the set of registered {@link MdnsServiceBrowserListener} instances, and + * notify them when a mDNS service instance is found, updated, or removed? + */ +public class MdnsDiscoveryManager implements MdnsSocketClientBase.Callback { + private static final String TAG = MdnsDiscoveryManager.class.getSimpleName(); + public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); + + private final ExecutorProvider executorProvider; + private final MdnsSocketClientBase socketClient; + @NonNull private final SharedLog sharedLog; + + @NonNull private final PerNetworkServiceTypeClients perNetworkServiceTypeClients; + @NonNull private final Handler handler; + @Nullable private final HandlerThread handlerThread; + + private static class PerNetworkServiceTypeClients { + private final ArrayMap<Pair<String, Network>, MdnsServiceTypeClient> clients = + new ArrayMap<>(); + + public void put(@NonNull String serviceType, @Nullable Network network, + @NonNull MdnsServiceTypeClient client) { + final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType); + final Pair<String, Network> perNetworkServiceType = new Pair<>(dnsLowerServiceType, + network); + clients.put(perNetworkServiceType, client); + } + + @Nullable + public MdnsServiceTypeClient get(@NonNull String serviceType, @Nullable Network network) { + final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType); + final Pair<String, Network> perNetworkServiceType = new Pair<>(dnsLowerServiceType, + network); + return clients.getOrDefault(perNetworkServiceType, null); + } + + public List<MdnsServiceTypeClient> getByServiceType(@NonNull String serviceType) { + final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType); + final List<MdnsServiceTypeClient> list = new ArrayList<>(); + for (int i = 0; i < clients.size(); i++) { + final Pair<String, Network> perNetworkServiceType = clients.keyAt(i); + if (dnsLowerServiceType.equals(perNetworkServiceType.first)) { + list.add(clients.valueAt(i)); + } + } + return list; + } + + public List<MdnsServiceTypeClient> getByNetwork(@Nullable Network network) { + final List<MdnsServiceTypeClient> list = new ArrayList<>(); + for (int i = 0; i < clients.size(); i++) { + final Pair<String, Network> perNetworkServiceType = clients.keyAt(i); + final Network serviceTypeNetwork = perNetworkServiceType.second; + if (Objects.equals(network, serviceTypeNetwork)) { + list.add(clients.valueAt(i)); + } + } + return list; + } + + public void remove(@NonNull MdnsServiceTypeClient client) { + final int index = clients.indexOfValue(client); + clients.removeAt(index); + } + + public boolean isEmpty() { + return clients.isEmpty(); + } + } + + public MdnsDiscoveryManager(@NonNull ExecutorProvider executorProvider, + @NonNull MdnsSocketClientBase socketClient, @NonNull SharedLog sharedLog) { + this.executorProvider = executorProvider; + this.socketClient = socketClient; + this.sharedLog = sharedLog; + this.perNetworkServiceTypeClients = new PerNetworkServiceTypeClients(); + if (socketClient.getLooper() != null) { + this.handlerThread = null; + this.handler = new Handler(socketClient.getLooper()); + } else { + this.handlerThread = new HandlerThread(MdnsDiscoveryManager.class.getSimpleName()); + this.handlerThread.start(); + this.handler = new Handler(handlerThread.getLooper()); + } + } + + private void checkAndRunOnHandlerThread(@NonNull Runnable function) { + if (this.handlerThread == null) { + function.run(); + } else { + handler.post(function); + } + } + + /** + * Do the cleanup of the MdnsDiscoveryManager + */ + public void shutDown() { + if (this.handlerThread != null) { + this.handlerThread.quitSafely(); + } + } + + /** + * Starts (or continue) to discovery mDNS services with given {@code serviceType}, and registers + * {@code listener} for receiving mDNS service discovery responses. + * + * @param serviceType The type of the service to discover. + * @param listener The {@link MdnsServiceBrowserListener} listener. + * @param searchOptions The {@link MdnsSearchOptions} to be used for discovering {@code + * serviceType}. + */ + @RequiresPermission(permission.CHANGE_WIFI_MULTICAST_STATE) + public void registerListener( + @NonNull String serviceType, + @NonNull MdnsServiceBrowserListener listener, + @NonNull MdnsSearchOptions searchOptions) { + sharedLog.i("Registering listener for serviceType: " + serviceType); + checkAndRunOnHandlerThread(() -> + handleRegisterListener(serviceType, listener, searchOptions)); + } + + private void handleRegisterListener( + @NonNull String serviceType, + @NonNull MdnsServiceBrowserListener listener, + @NonNull MdnsSearchOptions searchOptions) { + if (perNetworkServiceTypeClients.isEmpty()) { + // First listener. Starts the socket client. + try { + socketClient.startDiscovery(); + } catch (IOException e) { + sharedLog.e("Failed to start discover.", e); + return; + } + } + // Request the network for discovery. + socketClient.notifyNetworkRequested(listener, searchOptions.getNetwork(), + new MdnsSocketClientBase.SocketCreationCallback() { + @Override + public void onSocketCreated(@Nullable Network network) { + ensureRunningOnHandlerThread(handler); + // All listeners of the same service types shares the same + // MdnsServiceTypeClient. + MdnsServiceTypeClient serviceTypeClient = + perNetworkServiceTypeClients.get(serviceType, network); + if (serviceTypeClient == null) { + serviceTypeClient = createServiceTypeClient(serviceType, network); + perNetworkServiceTypeClients.put(serviceType, network, + serviceTypeClient); + } + serviceTypeClient.startSendAndReceive(listener, searchOptions); + } + + @Override + public void onAllSocketsDestroyed(@Nullable Network network) { + ensureRunningOnHandlerThread(handler); + final MdnsServiceTypeClient serviceTypeClient = + perNetworkServiceTypeClients.get(serviceType, network); + if (serviceTypeClient == null) return; + // Notify all listeners that all services are removed from this socket. + serviceTypeClient.notifySocketDestroyed(); + perNetworkServiceTypeClients.remove(serviceTypeClient); + } + }); + } + + /** + * Unregister {@code listener} for receiving mDNS service discovery responses. IF no listener is + * registered for the given service type, stops discovery for the service type. + * + * @param serviceType The type of the service to discover. + * @param listener The {@link MdnsServiceBrowserListener} listener. + */ + @RequiresPermission(permission.CHANGE_WIFI_MULTICAST_STATE) + public void unregisterListener( + @NonNull String serviceType, @NonNull MdnsServiceBrowserListener listener) { + sharedLog.i("Unregistering listener for serviceType:" + serviceType); + checkAndRunOnHandlerThread(() -> handleUnregisterListener(serviceType, listener)); + } + + private void handleUnregisterListener( + @NonNull String serviceType, @NonNull MdnsServiceBrowserListener listener) { + final List<MdnsServiceTypeClient> serviceTypeClients = + perNetworkServiceTypeClients.getByServiceType(serviceType); + if (serviceTypeClients.isEmpty()) { + return; + } + for (int i = 0; i < serviceTypeClients.size(); i++) { + final MdnsServiceTypeClient serviceTypeClient = serviceTypeClients.get(i); + if (serviceTypeClient.stopSendAndReceive(listener)) { + // No listener is registered for the service type anymore, remove it from the list + // of the service type clients. + perNetworkServiceTypeClients.remove(serviceTypeClient); + } + } + if (perNetworkServiceTypeClients.isEmpty()) { + // No discovery request. Stops the socket client. + socketClient.stopDiscovery(); + } + // Unrequested the network. + socketClient.notifyNetworkUnrequested(listener); + } + + @Override + public void onResponseReceived(@NonNull MdnsPacket packet, + int interfaceIndex, @Nullable Network network) { + checkAndRunOnHandlerThread(() -> + handleOnResponseReceived(packet, interfaceIndex, network)); + } + + private void handleOnResponseReceived(@NonNull MdnsPacket packet, int interfaceIndex, + @Nullable Network network) { + for (MdnsServiceTypeClient serviceTypeClient + : perNetworkServiceTypeClients.getByNetwork(network)) { + serviceTypeClient.processResponse(packet, interfaceIndex, network); + } + } + + @Override + public void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode, + @Nullable Network network) { + checkAndRunOnHandlerThread(() -> + handleOnFailedToParseMdnsResponse(receivedPacketNumber, errorCode, network)); + } + + private void handleOnFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode, + @Nullable Network network) { + for (MdnsServiceTypeClient serviceTypeClient + : perNetworkServiceTypeClients.getByNetwork(network)) { + serviceTypeClient.onFailedToParseMdnsResponse(receivedPacketNumber, errorCode); + } + } + + @VisibleForTesting + MdnsServiceTypeClient createServiceTypeClient(@NonNull String serviceType, + @Nullable Network network) { + sharedLog.log("createServiceTypeClient for type:" + serviceType + ", net:" + network); + return new MdnsServiceTypeClient( + serviceType, socketClient, + executorProvider.newServiceTypeClientSchedulerExecutor(), network, + sharedLog.forSubComponent(serviceType + "-" + network)); + } +} \ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java similarity index 100% rename from service/mdns/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java new file mode 100644 index 0000000..724a704 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java
@@ -0,0 +1,349 @@ +/* + * 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 android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.LinkAddress; +import android.net.nsd.NsdServiceInfo; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.HexDump; +import com.android.net.module.util.SharedLog; +import com.android.server.connectivity.mdns.MdnsAnnouncer.BaseAnnouncementInfo; +import com.android.server.connectivity.mdns.MdnsPacketRepeater.PacketRepeaterCallback; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.List; + +/** + * A class that handles advertising services on a {@link MdnsInterfaceSocket} tied to an interface. + */ +public class MdnsInterfaceAdvertiser implements MulticastPacketReader.PacketHandler { + private static final boolean DBG = MdnsAdvertiser.DBG; + @VisibleForTesting + public static final long EXIT_ANNOUNCEMENT_DELAY_MS = 100L; + @NonNull + private final String mTag; + @NonNull + private final ProbingCallback mProbingCallback = new ProbingCallback(); + @NonNull + private final AnnouncingCallback mAnnouncingCallback = new AnnouncingCallback(); + @NonNull + private final MdnsRecordRepository mRecordRepository; + @NonNull + private final Callback mCb; + // Callbacks are on the same looper thread, but posted to the next handler loop + @NonNull + private final Handler mCbHandler; + @NonNull + private final MdnsInterfaceSocket mSocket; + @NonNull + private final MdnsAnnouncer mAnnouncer; + @NonNull + private final MdnsProber mProber; + @NonNull + private final MdnsReplySender mReplySender; + + @NonNull + private final SharedLog mSharedLog; + + /** + * Callbacks called by {@link MdnsInterfaceAdvertiser} to report status updates. + */ + interface Callback { + /** + * Called by the advertiser after it successfully registered a service, after probing. + */ + void onRegisterServiceSucceeded(@NonNull MdnsInterfaceAdvertiser advertiser, int serviceId); + + /** + * Called by the advertiser when a conflict was found, during or after probing. + * + * If a conflict is found during probing, the {@link #renameServiceForConflict} must be + * called to restart probing and attempt registration with a different name. + */ + void onServiceConflict(@NonNull MdnsInterfaceAdvertiser advertiser, int serviceId); + + /** + * Called by the advertiser when it destroyed itself. + * + * This can happen after a call to {@link #destroyNow()}, or after all services were + * unregistered and the advertiser finished sending exit announcements. + */ + void onDestroyed(@NonNull MdnsInterfaceSocket socket); + } + + /** + * Callbacks from {@link MdnsProber}. + */ + private class ProbingCallback implements + PacketRepeaterCallback<MdnsProber.ProbingInfo> { + @Override + public void onFinished(MdnsProber.ProbingInfo info) { + final MdnsAnnouncer.AnnouncementInfo announcementInfo; + mSharedLog.i("Probing finished for service " + info.getServiceId()); + mCbHandler.post(() -> mCb.onRegisterServiceSucceeded( + MdnsInterfaceAdvertiser.this, info.getServiceId())); + try { + announcementInfo = mRecordRepository.onProbingSucceeded(info); + } catch (IOException e) { + mSharedLog.e("Error building announcements", e); + return; + } + + mAnnouncer.startSending(info.getServiceId(), announcementInfo, + 0L /* initialDelayMs */); + } + } + + /** + * Callbacks from {@link MdnsAnnouncer}. + */ + private class AnnouncingCallback implements PacketRepeaterCallback<BaseAnnouncementInfo> { + @Override + public void onSent(int index, @NonNull BaseAnnouncementInfo info) { + mRecordRepository.onAdvertisementSent(info.getServiceId()); + } + + @Override + public void onFinished(@NonNull BaseAnnouncementInfo info) { + if (info instanceof MdnsAnnouncer.ExitAnnouncementInfo) { + mRecordRepository.removeService(info.getServiceId()); + + if (mRecordRepository.getServicesCount() == 0) { + destroyNow(); + } + } + } + } + + /** + * Dependencies for {@link MdnsInterfaceAdvertiser}, useful for testing. + */ + @VisibleForTesting + public static class Dependencies { + /** @see MdnsRecordRepository */ + @NonNull + public MdnsRecordRepository makeRecordRepository(@NonNull Looper looper, + @NonNull String[] deviceHostName) { + return new MdnsRecordRepository(looper, deviceHostName); + } + + /** @see MdnsReplySender */ + @NonNull + public MdnsReplySender makeReplySender(@NonNull String interfaceTag, @NonNull Looper looper, + @NonNull MdnsInterfaceSocket socket, @NonNull byte[] packetCreationBuffer) { + return new MdnsReplySender(interfaceTag, looper, socket, packetCreationBuffer); + } + + /** @see MdnsAnnouncer */ + public MdnsAnnouncer makeMdnsAnnouncer(@NonNull String interfaceTag, @NonNull Looper looper, + @NonNull MdnsReplySender replySender, + @Nullable PacketRepeaterCallback<MdnsAnnouncer.BaseAnnouncementInfo> cb) { + return new MdnsAnnouncer(interfaceTag, looper, replySender, cb); + } + + /** @see MdnsProber */ + public MdnsProber makeMdnsProber(@NonNull String interfaceTag, @NonNull Looper looper, + @NonNull MdnsReplySender replySender, + @NonNull PacketRepeaterCallback<MdnsProber.ProbingInfo> cb) { + return new MdnsProber(interfaceTag, looper, replySender, cb); + } + } + + public MdnsInterfaceAdvertiser(@NonNull MdnsInterfaceSocket socket, + @NonNull List<LinkAddress> initialAddresses, @NonNull Looper looper, + @NonNull byte[] packetCreationBuffer, @NonNull Callback cb, + @NonNull String[] deviceHostName, @NonNull SharedLog sharedLog) { + this(socket, initialAddresses, looper, packetCreationBuffer, cb, + new Dependencies(), deviceHostName, sharedLog); + } + + public MdnsInterfaceAdvertiser(@NonNull MdnsInterfaceSocket socket, + @NonNull List<LinkAddress> initialAddresses, @NonNull Looper looper, + @NonNull byte[] packetCreationBuffer, @NonNull Callback cb, @NonNull Dependencies deps, + @NonNull String[] deviceHostName, @NonNull SharedLog sharedLog) { + mTag = MdnsInterfaceAdvertiser.class.getSimpleName() + "/" + sharedLog.getTag(); + mRecordRepository = deps.makeRecordRepository(looper, deviceHostName); + mRecordRepository.updateAddresses(initialAddresses); + mSocket = socket; + mCb = cb; + mCbHandler = new Handler(looper); + mReplySender = deps.makeReplySender(sharedLog.getTag(), looper, socket, + packetCreationBuffer); + mAnnouncer = deps.makeMdnsAnnouncer(sharedLog.getTag(), looper, mReplySender, + mAnnouncingCallback); + mProber = deps.makeMdnsProber(sharedLog.getTag(), looper, mReplySender, mProbingCallback); + mSharedLog = sharedLog; + } + + /** + * Start the advertiser. + * + * The advertiser will stop itself when all services are removed and exit announcements sent, + * notifying via {@link Callback#onDestroyed}. This can also be triggered manually via + * {@link #destroyNow()}. + */ + public void start() { + mSocket.addPacketHandler(this); + } + + /** + * Start advertising a service. + * + * @throws NameConflictException There is already a service being advertised with that name. + */ + public void addService(int id, NsdServiceInfo service, @Nullable String subtype) + throws NameConflictException { + final int replacedExitingService = mRecordRepository.addService(id, service, subtype); + // Cancel announcements for the existing service. This only happens for exiting services + // (so cancelling exiting announcements), as per RecordRepository.addService. + if (replacedExitingService >= 0) { + mSharedLog.i("Service " + replacedExitingService + + " getting re-added, cancelling exit announcements"); + mAnnouncer.stop(replacedExitingService); + } + mProber.startProbing(mRecordRepository.setServiceProbing(id)); + } + + /** + * Stop advertising a service. + * + * This will trigger exit announcements for the service. + */ + public void removeService(int id) { + if (!mRecordRepository.hasActiveService(id)) return; + mProber.stop(id); + mAnnouncer.stop(id); + final MdnsAnnouncer.ExitAnnouncementInfo exitInfo = mRecordRepository.exitService(id); + if (exitInfo != null) { + // This effectively schedules destroyNow(), as it is to be called when the exit + // announcement finishes if there is no service left. + // A non-zero exit announcement delay follows legacy mdnsresponder behavior, and is + // also useful to ensure that when a host receives the exit announcement, the service + // has been unregistered on all interfaces; so an announcement sent from interface A + // that was already in-flight while unregistering won't be received after the exit on + // interface B. + mAnnouncer.startSending(id, exitInfo, EXIT_ANNOUNCEMENT_DELAY_MS); + } else { + // No exit announcement necessary: remove the service immediately. + mRecordRepository.removeService(id); + if (mRecordRepository.getServicesCount() == 0) { + destroyNow(); + } + } + } + + /** + * Update interface addresses used to advertise. + * + * This causes new address records to be announced. + */ + public void updateAddresses(@NonNull List<LinkAddress> newAddresses) { + mRecordRepository.updateAddresses(newAddresses); + // TODO: restart advertising, but figure out what exit messages need to be sent for the + // previous addresses + } + + /** + * Destroy the advertiser immediately, not sending any exit announcement. + * + * <p>Useful when the underlying network went away. This will trigger an onDestroyed callback. + */ + public void destroyNow() { + for (int serviceId : mRecordRepository.clearServices()) { + mProber.stop(serviceId); + mAnnouncer.stop(serviceId); + } + mReplySender.cancelAll(); + mSocket.removePacketHandler(this); + mCbHandler.post(() -> mCb.onDestroyed(mSocket)); + } + + /** + * Reset a service to the probing state due to a conflict found on the network. + */ + public void restartProbingForConflict(int serviceId) { + final MdnsProber.ProbingInfo probingInfo = mRecordRepository.setServiceProbing(serviceId); + if (probingInfo == null) return; + + mProber.restartForConflict(probingInfo); + } + + /** + * Rename a service following a conflict found on the network, and restart probing. + * + * If the service was not registered on this {@link MdnsInterfaceAdvertiser}, this is a no-op. + */ + public void renameServiceForConflict(int serviceId, NsdServiceInfo newInfo) { + final MdnsProber.ProbingInfo probingInfo = mRecordRepository.renameServiceForConflict( + serviceId, newInfo); + if (probingInfo == null) return; + + mProber.restartForConflict(probingInfo); + } + + /** + * Indicates whether probing is in progress for the given service on this interface. + * + * Also returns false if the specified service is not registered. + */ + public boolean isProbing(int serviceId) { + return mRecordRepository.isProbing(serviceId); + } + + @Override + public void handlePacket(byte[] recvbuf, int length, InetSocketAddress src) { + final MdnsPacket packet; + try { + packet = MdnsPacket.parse(new MdnsPacketReader(recvbuf, length)); + } catch (MdnsPacket.ParseException e) { + Log.e(mTag, "Error parsing mDNS packet", e); + if (DBG) { + Log.v( + mTag, "Packet: " + HexDump.toHexString(recvbuf, 0, length)); + } + return; + } + + if (DBG) { + Log.v(mTag, + "Parsed packet with " + packet.questions.size() + " questions, " + + packet.answers.size() + " answers, " + + packet.authorityRecords.size() + " authority, " + + packet.additionalRecords.size() + " additional from " + src); + } + + for (int conflictServiceId : mRecordRepository.getConflictingServices(packet)) { + mCbHandler.post(() -> mCb.onServiceConflict(this, conflictServiceId)); + } + + // Even in case of conflict, add replies for other services. But in general conflicts would + // happen when the incoming packet has answer records (not a question), so there will be no + // answer. One exception is simultaneous probe tiebreaking (rfc6762 8.2), in which case the + // conflicting service is still probing and won't reply either. + final MdnsRecordRepository.ReplyInfo answers = mRecordRepository.getReply(packet, src); + + if (answers == null) return; + mReplySender.queueReply(answers); + } +}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsInterfaceSocket.java b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceSocket.java similarity index 66% rename from service/mdns/com/android/server/connectivity/mdns/MdnsInterfaceSocket.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceSocket.java index 6090415..119c7a8 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsInterfaceSocket.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceSocket.java
@@ -22,10 +22,15 @@ import android.annotation.NonNull; import android.net.LinkAddress; import android.net.util.SocketUtils; +import android.os.Handler; +import android.os.Looper; import android.os.ParcelFileDescriptor; import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; import android.util.Log; +import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetSocketAddress; @@ -41,15 +46,19 @@ * otherwise. * * @see MulticastSocket for javadoc of each public method. + * @see MulticastSocket for javadoc of each public method. */ public class MdnsInterfaceSocket { private static final String TAG = MdnsInterfaceSocket.class.getSimpleName(); @NonNull private final MulticastSocket mMulticastSocket; @NonNull private final NetworkInterface mNetworkInterface; + @NonNull private final MulticastPacketReader mPacketReader; + @NonNull private final ParcelFileDescriptor mFileDescriptor; private boolean mJoinedIpv4 = false; private boolean mJoinedIpv6 = false; - public MdnsInterfaceSocket(@NonNull NetworkInterface networkInterface, int port) + public MdnsInterfaceSocket(@NonNull NetworkInterface networkInterface, int port, + @NonNull Looper looper, @NonNull byte[] packetReadBuffer) throws IOException { mNetworkInterface = networkInterface; mMulticastSocket = new MulticastSocket(port); @@ -58,11 +67,19 @@ mMulticastSocket.setNetworkInterface(networkInterface); // Bind socket to the interface for receiving from that interface only. - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(mMulticastSocket)) { - SocketUtils.bindSocketToInterface(pfd.getFileDescriptor(), mNetworkInterface.getName()); + mFileDescriptor = ParcelFileDescriptor.fromDatagramSocket(mMulticastSocket); + try { + final FileDescriptor fd = mFileDescriptor.getFileDescriptor(); + final int flags = Os.fcntlInt(fd, OsConstants.F_GETFL, 0); + Os.fcntlInt(fd, OsConstants.F_SETFL, flags | OsConstants.SOCK_NONBLOCK); + SocketUtils.bindSocketToInterface(fd, mNetworkInterface.getName()); } catch (ErrnoException e) { throw new IOException("Error setting socket options", e); } + + mPacketReader = new MulticastPacketReader(networkInterface.getName(), mFileDescriptor, + new Handler(looper), packetReadBuffer); + mPacketReader.start(); } /** @@ -74,23 +91,14 @@ mMulticastSocket.send(packet); } - /** - * Receives a datagram packet from this socket. - * - * <p>This method could be used on any thread. - */ - public void receive(@NonNull DatagramPacket packet) throws IOException { - mMulticastSocket.receive(packet); - } - - private boolean hasIpv4Address(List<LinkAddress> addresses) { + private static boolean hasIpv4Address(@NonNull List<LinkAddress> addresses) { for (LinkAddress address : addresses) { if (address.isIpv4()) return true; } return false; } - private boolean hasIpv6Address(List<LinkAddress> addresses) { + private static boolean hasIpv6Address(@NonNull List<LinkAddress> addresses) { for (LinkAddress address : addresses) { if (address.isIpv6()) return true; } @@ -103,7 +111,7 @@ maybeJoinIpv6(addresses); } - private boolean joinGroup(InetSocketAddress multicastAddress) { + private boolean joinGroup(@NonNull InetSocketAddress multicastAddress) { try { mMulticastSocket.joinGroup(multicastAddress, mNetworkInterface); return true; @@ -114,7 +122,7 @@ } } - private void maybeJoinIpv4(List<LinkAddress> addresses) { + private void maybeJoinIpv4(@NonNull List<LinkAddress> addresses) { final boolean hasAddr = hasIpv4Address(addresses); if (!mJoinedIpv4 && hasAddr) { mJoinedIpv4 = joinGroup(MULTICAST_IPV4_ADDRESS); @@ -124,7 +132,7 @@ } } - private void maybeJoinIpv6(List<LinkAddress> addresses) { + private void maybeJoinIpv6(@NonNull List<LinkAddress> addresses) { final boolean hasAddr = hasIpv6Address(addresses); if (!mJoinedIpv6 && hasAddr) { mJoinedIpv6 = joinGroup(MULTICAST_IPV6_ADDRESS); @@ -134,33 +142,40 @@ } } - /*** Destroy this socket by leaving all joined multicast groups and closing this socket. */ + /*** Destroy the socket */ public void destroy() { - if (mJoinedIpv4) { - try { - mMulticastSocket.leaveGroup(MULTICAST_IPV4_ADDRESS, mNetworkInterface); - } catch (IOException e) { - Log.e(TAG, "Error leaving IPv4 group for " + mNetworkInterface, e); - } - } - if (mJoinedIpv6) { - try { - mMulticastSocket.leaveGroup(MULTICAST_IPV6_ADDRESS, mNetworkInterface); - } catch (IOException e) { - Log.e(TAG, "Error leaving IPv4 group for " + mNetworkInterface, e); - } + mPacketReader.stop(); + try { + mFileDescriptor.close(); + } catch (IOException e) { + Log.e(TAG, "Close file descriptor failed."); } mMulticastSocket.close(); } /** - * Returns the index of the network interface that this socket is bound to. If the interface - * cannot be determined, returns -1. + * Add a handler to receive callbacks when reads the packet from socket. If the handler is + * already set, this is a no-op. + */ + public void addPacketHandler(@NonNull MulticastPacketReader.PacketHandler handler) { + mPacketReader.addPacketHandler(handler); + } + + /** + * Remove a handler added via {@link #addPacketHandler}. If the handler is not present, this is + * a no-op. + */ + public void removePacketHandler(@NonNull MulticastPacketReader.PacketHandler handler) { + mPacketReader.removePacketHandler(handler); + } + + /** + * Returns the network interface that this socket is bound to. * * <p>This method could be used on any thread. */ - public int getInterfaceIndex() { - return mNetworkInterface.getIndex(); + public NetworkInterface getInterface() { + return mNetworkInterface; } /*** Returns whether this socket has joined IPv4 group */
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java new file mode 100644 index 0000000..d9bfb26 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
@@ -0,0 +1,277 @@ +/* + * 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.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.LinkAddress; +import android.net.Network; +import android.os.Handler; +import android.os.Looper; +import android.util.ArrayMap; +import android.util.Log; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Objects; + +/** + * The {@link MdnsMultinetworkSocketClient} manages the multinetwork socket for mDns + * + * * <p>This class is not thread safe. + */ +public class MdnsMultinetworkSocketClient implements MdnsSocketClientBase { + private static final String TAG = MdnsMultinetworkSocketClient.class.getSimpleName(); + private static final boolean DBG = MdnsDiscoveryManager.DBG; + + @NonNull private final Handler mHandler; + @NonNull private final MdnsSocketProvider mSocketProvider; + + private final ArrayMap<MdnsServiceBrowserListener, InterfaceSocketCallback> mRequestedNetworks = + new ArrayMap<>(); + private final ArrayMap<MdnsInterfaceSocket, ReadPacketHandler> mSocketPacketHandlers = + new ArrayMap<>(); + private MdnsSocketClientBase.Callback mCallback = null; + private int mReceivedPacketNumber = 0; + + public MdnsMultinetworkSocketClient(@NonNull Looper looper, + @NonNull MdnsSocketProvider provider) { + mHandler = new Handler(looper); + mSocketProvider = provider; + } + + private class InterfaceSocketCallback implements MdnsSocketProvider.SocketCallback { + @NonNull + private final SocketCreationCallback mSocketCreationCallback; + @NonNull + private final ArrayMap<MdnsInterfaceSocket, Network> mActiveNetworkSockets = + new ArrayMap<>(); + + InterfaceSocketCallback(SocketCreationCallback socketCreationCallback) { + mSocketCreationCallback = socketCreationCallback; + } + + @Override + public void onSocketCreated(@Nullable Network network, + @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) { + // The socket may be already created by other request before, try to get the stored + // ReadPacketHandler. + ReadPacketHandler handler = mSocketPacketHandlers.get(socket); + if (handler == null) { + // First request to create this socket. Initial a ReadPacketHandler for this socket. + handler = new ReadPacketHandler(network, socket.getInterface().getIndex()); + mSocketPacketHandlers.put(socket, handler); + } + socket.addPacketHandler(handler); + mActiveNetworkSockets.put(socket, network); + mSocketCreationCallback.onSocketCreated(network); + } + + @Override + public void onInterfaceDestroyed(@Nullable Network network, + @NonNull MdnsInterfaceSocket socket) { + notifySocketDestroyed(socket); + maybeCleanupPacketHandler(socket); + } + + private void notifySocketDestroyed(@NonNull MdnsInterfaceSocket socket) { + final Network network = mActiveNetworkSockets.remove(socket); + if (!isAnySocketActive(network)) { + mSocketCreationCallback.onAllSocketsDestroyed(network); + } + } + + void onNetworkUnrequested() { + for (int i = mActiveNetworkSockets.size() - 1; i >= 0; i--) { + // Iterate from the end so the socket can be removed + final MdnsInterfaceSocket socket = mActiveNetworkSockets.keyAt(i); + notifySocketDestroyed(socket); + maybeCleanupPacketHandler(socket); + } + } + } + + private boolean isSocketActive(@NonNull MdnsInterfaceSocket socket) { + for (int i = 0; i < mRequestedNetworks.size(); i++) { + final InterfaceSocketCallback isc = mRequestedNetworks.valueAt(i); + if (isc.mActiveNetworkSockets.containsKey(socket)) { + return true; + } + } + return false; + } + + private boolean isAnySocketActive(@Nullable Network network) { + for (int i = 0; i < mRequestedNetworks.size(); i++) { + final InterfaceSocketCallback isc = mRequestedNetworks.valueAt(i); + if (isc.mActiveNetworkSockets.containsValue(network)) { + return true; + } + } + return false; + } + + private ArrayMap<MdnsInterfaceSocket, Network> getActiveSockets() { + final ArrayMap<MdnsInterfaceSocket, Network> sockets = new ArrayMap<>(); + for (int i = 0; i < mRequestedNetworks.size(); i++) { + final InterfaceSocketCallback isc = mRequestedNetworks.valueAt(i); + sockets.putAll(isc.mActiveNetworkSockets); + } + return sockets; + } + + private void maybeCleanupPacketHandler(@NonNull MdnsInterfaceSocket socket) { + if (isSocketActive(socket)) return; + mSocketPacketHandlers.remove(socket); + } + + private class ReadPacketHandler implements MulticastPacketReader.PacketHandler { + private final Network mNetwork; + private final int mInterfaceIndex; + + ReadPacketHandler(@NonNull Network network, int interfaceIndex) { + mNetwork = network; + mInterfaceIndex = interfaceIndex; + } + + @Override + public void handlePacket(byte[] recvbuf, int length, InetSocketAddress src) { + processResponsePacket(recvbuf, length, mInterfaceIndex, mNetwork); + } + } + + /*** Set callback for receiving mDns response */ + @Override + public void setCallback(@Nullable MdnsSocketClientBase.Callback callback) { + ensureRunningOnHandlerThread(mHandler); + mCallback = callback; + } + + /*** + * Notify that the given network is requested for mdns discovery / resolution + * + * @param listener the listener for discovery. + * @param network the target network for discovery. Null means discovery on all possible + * interfaces. + * @param socketCreationCallback the callback to notify socket creation. + */ + @Override + public void notifyNetworkRequested(@NonNull MdnsServiceBrowserListener listener, + @Nullable Network network, @NonNull SocketCreationCallback socketCreationCallback) { + ensureRunningOnHandlerThread(mHandler); + InterfaceSocketCallback callback = mRequestedNetworks.get(listener); + if (callback != null) { + throw new IllegalArgumentException("Can not register duplicated listener"); + } + + if (DBG) Log.d(TAG, "notifyNetworkRequested: network=" + network); + callback = new InterfaceSocketCallback(socketCreationCallback); + mRequestedNetworks.put(listener, callback); + mSocketProvider.requestSocket(network, callback); + } + + /*** Notify that the network is unrequested */ + @Override + public void notifyNetworkUnrequested(@NonNull MdnsServiceBrowserListener listener) { + ensureRunningOnHandlerThread(mHandler); + final InterfaceSocketCallback callback = mRequestedNetworks.get(listener); + if (callback == null) { + Log.e(TAG, "Can not be unrequested with unknown listener=" + listener); + return; + } + callback.onNetworkUnrequested(); + // onNetworkUnrequested does cleanups based on mRequestedNetworks, only remove afterwards + mRequestedNetworks.remove(listener); + mSocketProvider.unrequestSocket(callback); + } + + @Override + public Looper getLooper() { + return mHandler.getLooper(); + } + + private void sendMdnsPacket(@NonNull DatagramPacket packet, @Nullable Network targetNetwork) { + final boolean isIpv6 = ((InetSocketAddress) packet.getSocketAddress()).getAddress() + instanceof Inet6Address; + final boolean isIpv4 = ((InetSocketAddress) packet.getSocketAddress()).getAddress() + instanceof Inet4Address; + final ArrayMap<MdnsInterfaceSocket, Network> activeSockets = getActiveSockets(); + for (int i = 0; i < activeSockets.size(); i++) { + final MdnsInterfaceSocket socket = activeSockets.keyAt(i); + final Network network = activeSockets.valueAt(i); + // Check ip capability and network before sending packet + if (((isIpv6 && socket.hasJoinedIpv6()) || (isIpv4 && socket.hasJoinedIpv4())) + // Contrary to MdnsUtils.isNetworkMatched, only send packets targeting + // the null network to interfaces that have the null network (tethering + // downstream interfaces). + && Objects.equals(network, targetNetwork)) { + try { + socket.send(packet); + } catch (IOException e) { + Log.e(TAG, "Failed to send a mDNS packet.", e); + } + } + } + } + + private void processResponsePacket(byte[] recvbuf, int length, int interfaceIndex, + @NonNull Network network) { + int packetNumber = ++mReceivedPacketNumber; + + final MdnsPacket response; + try { + response = MdnsResponseDecoder.parseResponse(recvbuf, length); + } catch (MdnsPacket.ParseException e) { + if (e.code != MdnsResponseErrorCode.ERROR_NOT_RESPONSE_MESSAGE) { + Log.e(TAG, e.getMessage(), e); + if (mCallback != null) { + mCallback.onFailedToParseMdnsResponse(packetNumber, e.code, network); + } + } + return; + } + + if (mCallback != null) { + mCallback.onResponseReceived(response, interfaceIndex, network); + } + } + + /** + * Sends a mDNS request packet via given network that asks for multicast response. Null network + * means sending packet via all networks. + */ + @Override + public void sendMulticastPacket(@NonNull DatagramPacket packet, @Nullable Network network) { + mHandler.post(() -> sendMdnsPacket(packet, network)); + } + + /** + * Sends a mDNS request packet via given network that asks for unicast response. Null network + * means sending packet via all networks. + */ + @Override + public void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network) { + // TODO: Separate unicast packet. + mHandler.post(() -> sendMdnsPacket(packet, network)); + } +}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsNsecRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java similarity index 81% rename from service/mdns/com/android/server/connectivity/mdns/MdnsNsecRecord.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java index 57c3c03..1239180 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsNsecRecord.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java
@@ -17,12 +17,15 @@ package com.android.server.connectivity.mdns; import android.net.DnsResolver; +import android.text.TextUtils; import com.android.net.module.util.CollectionUtils; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Objects; /** * A mDNS "NSEC" record, used in particular for negative responses (RFC6762 6.1). @@ -96,8 +99,9 @@ @Override protected void writeData(MdnsPacketWriter writer) throws IOException { - // No compression as per RFC3845 2.1.1 - writer.writeLabelsNoCompression(mNextDomain); + // Standard NSEC records should use no compression for the Next Domain Name field as per + // RFC3845 2.1.1, but for mDNS RFC6762 18.14 specifies that compression should be used. + writer.writeLabels(mNextDomain); // type bitmaps: RFC3845 2.1.2 int typesBlockStart = 0; @@ -139,4 +143,32 @@ writer.writeUInt8(bytesInBlock); writer.writeBytes(bytes); } + + @Override + public String toString() { + return "NSEC: NextDomain: " + TextUtils.join(".", mNextDomain) + + " Types " + Arrays.toString(mTypes); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), + Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(mNextDomain)), + Arrays.hashCode(mTypes)); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof MdnsNsecRecord)) { + return false; + } + + return super.equals(other) + && MdnsUtils.equalsDnsLabelIgnoreDnsCase(mNextDomain, + ((MdnsNsecRecord) other).mNextDomain) + && Arrays.equals(mTypes, ((MdnsNsecRecord) other).mTypes); + } }
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsPacket.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPacket.java new file mode 100644 index 0000000..27002b9 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPacket.java
@@ -0,0 +1,231 @@ +/* + * 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 android.annotation.NonNull; +import android.annotation.Nullable; +import android.util.Log; + +import java.io.EOFException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class holding data that can be included in a mDNS packet. + */ +public class MdnsPacket { + private static final String TAG = MdnsPacket.class.getSimpleName(); + + public final int flags; + @NonNull + public final List<MdnsRecord> questions; + @NonNull + public final List<MdnsRecord> answers; + @NonNull + public final List<MdnsRecord> authorityRecords; + @NonNull + public final List<MdnsRecord> additionalRecords; + + MdnsPacket(int flags, + @NonNull List<MdnsRecord> questions, + @NonNull List<MdnsRecord> answers, + @NonNull List<MdnsRecord> authorityRecords, + @NonNull List<MdnsRecord> additionalRecords) { + this.flags = flags; + this.questions = Collections.unmodifiableList(questions); + this.answers = Collections.unmodifiableList(answers); + this.authorityRecords = Collections.unmodifiableList(authorityRecords); + this.additionalRecords = Collections.unmodifiableList(additionalRecords); + } + + /** + * Exception thrown on parse errors. + */ + public static class ParseException extends IOException { + public final int code; + + public ParseException(int code, @NonNull String message, @Nullable Throwable cause) { + super(message, cause); + this.code = code; + } + } + + /** + * Parse the packet in the provided {@link MdnsPacketReader}. + */ + @NonNull + public static MdnsPacket parse(@NonNull MdnsPacketReader reader) throws ParseException { + final int flags; + try { + reader.readUInt16(); // transaction ID (not used) + flags = reader.readUInt16(); + } catch (EOFException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_END_OF_FILE, + "Reached the end of the mDNS response unexpectedly.", e); + } + return parseRecordsSection(reader, flags); + } + + /** + * Parse the records section of a mDNS packet in the provided {@link MdnsPacketReader}. + * + * The records section starts with the questions count, just after the packet flags. + */ + public static MdnsPacket parseRecordsSection(@NonNull MdnsPacketReader reader, int flags) + throws ParseException { + try { + final int numQuestions = reader.readUInt16(); + final int numAnswers = reader.readUInt16(); + final int numAuthority = reader.readUInt16(); + final int numAdditional = reader.readUInt16(); + + final ArrayList<MdnsRecord> questions = parseRecords(reader, numQuestions, true); + final ArrayList<MdnsRecord> answers = parseRecords(reader, numAnswers, false); + final ArrayList<MdnsRecord> authority = parseRecords(reader, numAuthority, false); + final ArrayList<MdnsRecord> additional = parseRecords(reader, numAdditional, false); + + return new MdnsPacket(flags, questions, answers, authority, additional); + } catch (EOFException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_END_OF_FILE, + "Reached the end of the mDNS response unexpectedly.", e); + } + } + + private static ArrayList<MdnsRecord> parseRecords(@NonNull MdnsPacketReader reader, int count, + boolean isQuestion) + throws ParseException { + final ArrayList<MdnsRecord> records = new ArrayList<>(count); + for (int i = 0; i < count; ++i) { + final MdnsRecord record = parseRecord(reader, isQuestion); + if (record != null) { + records.add(record); + } + } + return records; + } + + @Nullable + private static MdnsRecord parseRecord(@NonNull MdnsPacketReader reader, boolean isQuestion) + throws ParseException { + String[] name; + try { + name = reader.readLabels(); + } catch (IOException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_READING_RECORD_NAME, + "Failed to read labels from mDNS response.", e); + } + + final int type; + try { + type = reader.readUInt16(); + } catch (EOFException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_END_OF_FILE, + "Reached the end of the mDNS response unexpectedly.", e); + } + + switch (type) { + case MdnsRecord.TYPE_A: { + try { + return new MdnsInetAddressRecord(name, MdnsRecord.TYPE_A, reader, isQuestion); + } catch (IOException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_READING_A_RDATA, + "Failed to read A record from mDNS response.", e); + } + } + + case MdnsRecord.TYPE_AAAA: { + try { + return new MdnsInetAddressRecord(name, + MdnsRecord.TYPE_AAAA, reader, isQuestion); + } catch (IOException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_READING_AAAA_RDATA, + "Failed to read AAAA record from mDNS response.", e); + } + } + + case MdnsRecord.TYPE_PTR: { + try { + return new MdnsPointerRecord(name, reader, isQuestion); + } catch (IOException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_READING_PTR_RDATA, + "Failed to read PTR record from mDNS response.", e); + } + } + + case MdnsRecord.TYPE_SRV: { + try { + return new MdnsServiceRecord(name, reader, isQuestion); + } catch (IOException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_READING_SRV_RDATA, + "Failed to read SRV record from mDNS response.", e); + } + } + + case MdnsRecord.TYPE_TXT: { + try { + return new MdnsTextRecord(name, reader, isQuestion); + } catch (IOException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_READING_TXT_RDATA, + "Failed to read TXT record from mDNS response.", e); + } + } + + case MdnsRecord.TYPE_NSEC: { + try { + return new MdnsNsecRecord(name, reader, isQuestion); + } catch (IOException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_READING_NSEC_RDATA, + "Failed to read NSEC record from mDNS response.", e); + } + } + + case MdnsRecord.TYPE_ANY: { + try { + return new MdnsAnyRecord(name, reader); + } catch (IOException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_READING_ANY_RDATA, + "Failed to read TYPE_ANY record from mDNS response.", e); + } + } + + default: { + try { + if (MdnsAdvertiser.DBG) { + Log.i(TAG, "Skipping parsing of record of unhandled type " + type); + } + skipMdnsRecord(reader, isQuestion); + return null; + } catch (IOException e) { + throw new ParseException(MdnsResponseErrorCode.ERROR_SKIPPING_UNKNOWN_RECORD, + "Failed to skip mDNS record.", e); + } + } + } + } + + private static void skipMdnsRecord(@NonNull MdnsPacketReader reader, boolean isQuestion) + throws IOException { + reader.skip(2); // Skip the class + if (isQuestion) return; + // Skip TTL and data + reader.skip(4); + int dataLength = reader.readUInt16(); + reader.skip(dataLength); + } +}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsPacketReader.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketReader.java similarity index 97% rename from service/mdns/com/android/server/connectivity/mdns/MdnsPacketReader.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsPacketReader.java index 856a2cd..aa38844 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsPacketReader.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketReader.java
@@ -38,8 +38,13 @@ /** Constructs a reader for the given packet. */ public MdnsPacketReader(DatagramPacket packet) { - buf = packet.getData(); - count = packet.getLength(); + this(packet.getData(), packet.getLength()); + } + + /** Constructs a reader for the given packet. */ + public MdnsPacketReader(byte[] buffer, int length) { + buf = buffer; + count = length; pos = 0; limit = -1; labelDictionary = new SparseArray<>(16);
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsPacketRepeater.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java similarity index 88% rename from service/mdns/com/android/server/connectivity/mdns/MdnsPacketRepeater.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java index 015dbd8..4c385da 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsPacketRepeater.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java
@@ -16,6 +16,9 @@ package com.android.server.connectivity.mdns; +import static com.android.server.connectivity.mdns.MdnsRecordRepository.IPV4_ADDR; +import static com.android.server.connectivity.mdns.MdnsRecordRepository.IPV6_ADDR; + import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; @@ -24,7 +27,7 @@ import android.util.Log; import java.io.IOException; -import java.net.SocketAddress; +import java.net.InetSocketAddress; /** * A class used to send several packets at given time intervals. @@ -32,6 +35,10 @@ */ public abstract class MdnsPacketRepeater<T extends MdnsPacketRepeater.Request> { private static final boolean DBG = MdnsAdvertiser.DBG; + private static final InetSocketAddress[] ALL_ADDRS = new InetSocketAddress[] { + IPV4_ADDR, IPV6_ADDR + }; + @NonNull private final MdnsReplySender mReplySender; @NonNull @@ -70,12 +77,6 @@ MdnsPacket getPacket(int index); /** - * Get a set of destinations for the packet for one iteration. - */ - @NonNull - Iterable<SocketAddress> getDestinations(int index); - - /** * Get the delay in milliseconds until the next packet transmission. */ long getDelayMs(int nextIndex); @@ -110,12 +111,13 @@ } final MdnsPacket packet = request.getPacket(index); - final Iterable<SocketAddress> destinations = request.getDestinations(index); if (DBG) { - Log.v(getTag(), "Sending packets to " + destinations + " for iteration " - + index + " out of " + request.getNumSends()); + Log.v(getTag(), "Sending packets for iteration " + index + " out of " + + request.getNumSends() + " for ID " + msg.what); } - for (SocketAddress destination : destinations) { + // Send to both v4 and v6 addresses; the reply sender will take care of ignoring the + // send when the socket has not joined the relevant group. + for (InetSocketAddress destination : ALL_ADDRS) { try { mReplySender.sendNow(packet, destination); } catch (IOException e) {
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsPacketWriter.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java similarity index 86% rename from service/mdns/com/android/server/connectivity/mdns/MdnsPacketWriter.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java index 1f22fa9..6879a64 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsPacketWriter.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java
@@ -17,11 +17,11 @@ package com.android.server.connectivity.mdns; import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.net.DatagramPacket; import java.net.SocketAddress; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -180,7 +180,7 @@ int existingOffset = entry.getKey(); String[] existingLabels = entry.getValue(); - if (Arrays.equals(existingLabels, labels)) { + if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(existingLabels, labels)) { writePointer(existingOffset); return; } else if (MdnsRecord.labelsAreSuffix(existingLabels, labels)) { @@ -192,22 +192,31 @@ } } + final int[] offsets; if (suffixLength > 0) { - for (int i = 0; i < (labels.length - suffixLength); ++i) { - writeString(labels[i]); - } + offsets = writePartialLabelsNoCompression(labels, labels.length - suffixLength); writePointer(suffixPointer); } else { - int[] offsets = writeLabelsNoCompression(labels); - - // Add entries to the label dictionary for each suffix of the label list, including - // the whole list itself. - for (int i = 0, len = labels.length; i < labels.length; ++i, --len) { - String[] value = new String[len]; - System.arraycopy(labels, i, value, 0, len); - labelDictionary.put(offsets[i], value); - } + offsets = writeLabelsNoCompression(labels); } + + // Add entries to the label dictionary for each suffix of the label list, including + // the whole list itself. + // Do not replace the last suffixLength suffixes that already have dictionary entries. + for (int i = 0, len = labels.length; i < labels.length - suffixLength; ++i, --len) { + String[] value = new String[len]; + System.arraycopy(labels, i, value, 0, len); + labelDictionary.put(offsets[i], value); + } + } + + private int[] writePartialLabelsNoCompression(String[] labels, int count) throws IOException { + int[] offsets = new int[count]; + for (int i = 0; i < count; ++i) { + offsets[i] = getWritePosition(); + writeString(labels[i]); + } + return offsets; } /** @@ -216,11 +225,7 @@ * @return The offsets where each label was written to. */ public int[] writeLabelsNoCompression(String[] labels) throws IOException { - int[] offsets = new int[labels.length]; - for (int i = 0; i < labels.length; ++i) { - offsets[i] = getWritePosition(); - writeString(labels[i]); - } + final int[] offsets = writePartialLabelsNoCompression(labels, labels.length); writeUInt8(0); // NUL terminator return offsets; } @@ -246,4 +251,4 @@ public DatagramPacket getPacket(SocketAddress destAddress) throws IOException { return new DatagramPacket(data, pos, destAddress); } -} \ No newline at end of file +}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java similarity index 85% rename from service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java index 2c7b26b..c88ead0 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java
@@ -19,6 +19,7 @@ import android.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.util.Arrays; @@ -60,7 +61,8 @@ } public boolean hasSubtype() { - return (name != null) && (name.length > 2) && name[1].equals(MdnsConstants.SUBTYPE_LABEL); + return (name != null) && (name.length > 2) && MdnsUtils.equalsIgnoreDnsCase(name[1], + MdnsConstants.SUBTYPE_LABEL); } public String getSubtype() { @@ -74,7 +76,7 @@ @Override public int hashCode() { - return (super.hashCode() * 31) + Arrays.hashCode(pointer); + return (super.hashCode() * 31) + Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(pointer)); } @Override @@ -86,6 +88,7 @@ return false; } - return super.equals(other) && Arrays.equals(pointer, ((MdnsPointerRecord) other).pointer); + return super.equals(other) && MdnsUtils.equalsDnsLabelIgnoreDnsCase(pointer, + ((MdnsPointerRecord) other).pointer); } } \ No newline at end of file
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java b/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java new file mode 100644 index 0000000..ecf846e --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java
@@ -0,0 +1,158 @@ +/* + * 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 android.annotation.NonNull; +import android.os.Looper; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.CollectionUtils; +import com.android.server.connectivity.mdns.util.MdnsUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Sends mDns probe requests to verify service records are unique on the network. + * + * TODO: implement receiving replies and handling conflicts. + */ +public class MdnsProber extends MdnsPacketRepeater<MdnsProber.ProbingInfo> { + private static final long CONFLICT_RETRY_DELAY_MS = 5_000L; + @NonNull + private final String mLogTag; + + public MdnsProber(@NonNull String interfaceTag, @NonNull Looper looper, + @NonNull MdnsReplySender replySender, + @NonNull PacketRepeaterCallback<ProbingInfo> cb) { + super(looper, replySender, cb); + mLogTag = MdnsProber.class.getSimpleName() + "/" + interfaceTag; + } + + /** Probing request to send with {@link MdnsProber}. */ + public static class ProbingInfo implements Request { + + private final int mServiceId; + @NonNull + private final MdnsPacket mPacket; + + /** + * Create a new ProbingInfo + * @param serviceId Service to probe for. + * @param probeRecords Records to be probed for uniqueness. + */ + ProbingInfo(int serviceId, @NonNull List<MdnsRecord> probeRecords) { + mServiceId = serviceId; + mPacket = makePacket(probeRecords); + } + + public int getServiceId() { + return mServiceId; + } + + @NonNull + @Override + public MdnsPacket getPacket(int index) { + return mPacket; + } + + @Override + public long getDelayMs(int nextIndex) { + // As per https://datatracker.ietf.org/doc/html/rfc6762#section-8.1 + return 250L; + } + + @Override + public int getNumSends() { + // 3 packets as per https://datatracker.ietf.org/doc/html/rfc6762#section-8.1 + return 3; + } + + private static MdnsPacket makePacket(@NonNull List<MdnsRecord> records) { + final ArrayList<MdnsRecord> questions = new ArrayList<>(records.size()); + for (final MdnsRecord record : records) { + if (containsName(questions, record.getName())) { + // Already added this name + continue; + } + + // TODO: legacy Android mDNS used to send the first probe (only) as unicast, even + // though https://datatracker.ietf.org/doc/html/rfc6762#section-8.1 says they + // SHOULD all be. rfc6762 15.1 says that if the port is shared with another + // responder unicast questions should not be used, and the legacy mdnsresponder may + // be running, so not using unicast at all may be better. Consider using legacy + // behavior if this causes problems. + questions.add(new MdnsAnyRecord(record.getName(), false /* unicast */)); + } + + return new MdnsPacket( + MdnsConstants.FLAGS_QUERY, + questions, + Collections.emptyList() /* answers */, + records /* authorityRecords */, + Collections.emptyList() /* additionalRecords */); + } + + /** + * Return whether the specified name is present in the list of records. + */ + private static boolean containsName(@NonNull List<MdnsRecord> records, + @NonNull String[] name) { + return CollectionUtils.any(records, + r -> MdnsUtils.equalsDnsLabelIgnoreDnsCase(name, r.getName())); + } + } + + @NonNull + @Override + protected String getTag() { + return mLogTag; + } + + @VisibleForTesting + protected long getInitialDelay() { + // First wait for a random time in 0-250ms + // as per https://datatracker.ietf.org/doc/html/rfc6762#section-8.1 + return (long) (Math.random() * 250); + } + + /** + * Start sending packets for probing. + */ + public void startProbing(@NonNull ProbingInfo info) { + startProbing(info, getInitialDelay()); + } + + private void startProbing(@NonNull ProbingInfo info, long delay) { + startSending(info.getServiceId(), info, delay); + } + + /** + * Restart probing with new service info as a conflict was found. + */ + public void restartForConflict(@NonNull ProbingInfo newInfo) { + stop(newInfo.getServiceId()); + + /* RFC 6762 8.1: "If fifteen conflicts occur within any ten-second period, then the host + MUST wait at least five seconds before each successive additional probe attempt. [...] + For very simple devices, a valid way to comply with this requirement is to always wait + five seconds after any failed probe attempt before trying again. */ + // TODO: count 15 conflicts in 10s instead of waiting for 5s every time + startProbing(newInfo, CONFLICT_RETRY_DELAY_MS); + } +}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java similarity index 91% rename from service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java index 10b8825..28bd1b4 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java
@@ -24,6 +24,7 @@ import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.util.Arrays; @@ -45,6 +46,9 @@ private static final int FLAG_CACHE_FLUSH = 0x8000; public static final long RECEIPT_TIME_NOT_SENT = 0L; + public static final int CLASS_ANY = 0x00ff; + /** Max label length as per RFC 1034/1035 */ + public static final int MAX_LABEL_LENGTH = 63; /** Status indicating that the record is current. */ public static final int STATUS_OK = 0; @@ -133,7 +137,7 @@ } for (int i = 0; i < list1.length; ++i) { - if (!list1[i].equals(list2[i + offset])) { + if (!MdnsUtils.equalsIgnoreDnsCase(list1[i], list2[i + offset])) { return false; } } @@ -201,6 +205,17 @@ protected abstract void readData(MdnsPacketReader reader) throws IOException; /** + * Write the first fields of the record, which are common fields for questions and answers. + * + * @param writer The writer to use. + */ + public final void writeHeaderFields(MdnsPacketWriter writer) throws IOException { + writer.writeLabels(name); + writer.writeUInt16(type); + writer.writeUInt16(cls); + } + + /** * Writes the record to a packet. * * @param writer The writer to use. @@ -208,9 +223,7 @@ */ @VisibleForTesting public final void write(MdnsPacketWriter writer, long now) throws IOException { - writer.writeLabels(name); - writer.writeUInt16(type); - writer.writeUInt16(cls); + writeHeaderFields(writer); writer.writeUInt32(MILLISECONDS.toSeconds(getRemainingTTL(now))); @@ -259,12 +272,13 @@ MdnsRecord otherRecord = (MdnsRecord) other; - return Arrays.equals(name, otherRecord.name) && (type == otherRecord.type); + return MdnsUtils.equalsDnsLabelIgnoreDnsCase(name, otherRecord.name) && (type + == otherRecord.type); } @Override public int hashCode() { - return Objects.hash(Arrays.hashCode(name), type); + return Objects.hash(Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(name)), type); } /** @@ -285,7 +299,7 @@ public Key(int recordType, String[] recordName) { this.recordType = recordType; - this.recordName = recordName; + this.recordName = MdnsUtils.toDnsLabelsLowerCase(recordName); } @Override @@ -308,4 +322,4 @@ return (recordType * 31) + Arrays.hashCode(recordName); } } -} \ No newline at end of file +}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java new file mode 100644 index 0000000..1375279 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
@@ -0,0 +1,903 @@ +/* + * 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 android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.TargetApi; +import android.net.LinkAddress; +import android.net.nsd.NsdServiceInfo; +import android.os.Build; +import android.os.Looper; +import android.os.SystemClock; +import android.util.ArraySet; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.CollectionUtils; +import com.android.net.module.util.HexDump; +import com.android.server.connectivity.mdns.util.MdnsUtils; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.TimeUnit; + +/** + * A repository of records advertised through {@link MdnsInterfaceAdvertiser}. + * + * Must be used on a consistent looper thread. + */ +@TargetApi(Build.VERSION_CODES.TIRAMISU) // Allow calling T+ APIs; this is only loaded on T+ +public class MdnsRecordRepository { + // RFC6762 p.15 + private static final long MIN_MULTICAST_REPLY_INTERVAL_MS = 1_000L; + + // TTLs as per RFC6762 10. + // TTL for records with a host name as the resource record's name (e.g., A, AAAA, HINFO) or a + // host name contained within the resource record's rdata (e.g., SRV, reverse mapping PTR + // record) + private static final long NAME_RECORDS_TTL_MILLIS = TimeUnit.SECONDS.toMillis(120); + // TTL for other records + private static final long NON_NAME_RECORDS_TTL_MILLIS = TimeUnit.MINUTES.toMillis(75); + + // Top-level domain for link-local queries, as per RFC6762 3. + private static final String LOCAL_TLD = "local"; + // Subtype separator as per RFC6763 7.1 (_printer._sub._http._tcp.local) + private static final String SUBTYPE_SEPARATOR = "_sub"; + + // Service type for service enumeration (RFC6763 9.) + private static final String[] DNS_SD_SERVICE_TYPE = + new String[] { "_services", "_dns-sd", "_udp", LOCAL_TLD }; + + public static final InetSocketAddress IPV6_ADDR = new InetSocketAddress( + MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT); + public static final InetSocketAddress IPV4_ADDR = new InetSocketAddress( + MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT); + + @NonNull + private final Random mDelayGenerator = new Random(); + // Map of service unique ID -> records for service + @NonNull + private final SparseArray<ServiceRegistration> mServices = new SparseArray<>(); + @NonNull + private final List<RecordInfo<?>> mGeneralRecords = new ArrayList<>(); + @NonNull + private final Looper mLooper; + @NonNull + private final String[] mDeviceHostname; + + public MdnsRecordRepository(@NonNull Looper looper, @NonNull String[] deviceHostname) { + this(looper, new Dependencies(), deviceHostname); + } + + @VisibleForTesting + public MdnsRecordRepository(@NonNull Looper looper, @NonNull Dependencies deps, + @NonNull String[] deviceHostname) { + mDeviceHostname = deviceHostname; + mLooper = looper; + } + + /** + * Dependencies to use with {@link MdnsRecordRepository}, useful for testing. + */ + @VisibleForTesting + public static class Dependencies { + + /** + * @see NetworkInterface#getInetAddresses(). + */ + @NonNull + public Enumeration<InetAddress> getInterfaceInetAddresses(@NonNull NetworkInterface iface) { + return iface.getInetAddresses(); + } + } + + private static class RecordInfo<T extends MdnsRecord> { + public final T record; + public final NsdServiceInfo serviceInfo; + + /** + * Whether the name of this record is expected to be fully owned by the service or may be + * advertised by other hosts as well (shared). + */ + public final boolean isSharedName; + + /** + * Whether probing is still in progress for the record. + */ + public boolean isProbing; + + /** + * Last time (as per SystemClock.elapsedRealtime) when advertised via multicast, 0 if never + */ + public long lastAdvertisedTimeMs; + + /** + * Last time (as per SystemClock.elapsedRealtime) when sent via unicast or multicast, + * 0 if never + */ + public long lastSentTimeMs; + + RecordInfo(NsdServiceInfo serviceInfo, T record, boolean sharedName, + boolean probing) { + this.serviceInfo = serviceInfo; + this.record = record; + this.isSharedName = sharedName; + this.isProbing = probing; + } + } + + private static class ServiceRegistration { + @NonNull + public final List<RecordInfo<?>> allRecords; + @NonNull + public final List<RecordInfo<MdnsPointerRecord>> ptrRecords; + @NonNull + public final RecordInfo<MdnsServiceRecord> srvRecord; + @NonNull + public final RecordInfo<MdnsTextRecord> txtRecord; + @NonNull + public final NsdServiceInfo serviceInfo; + @Nullable + public final String subtype; + + /** + * Whether the service is sending exit announcements and will be destroyed soon. + */ + public boolean exiting = false; + + /** + * Create a ServiceRegistration for dns-sd service registration (RFC6763). + * + * @param deviceHostname Hostname of the device (for the interface used) + * @param serviceInfo Service to advertise + */ + ServiceRegistration(@NonNull String[] deviceHostname, @NonNull NsdServiceInfo serviceInfo, + @Nullable String subtype) { + this.serviceInfo = serviceInfo; + this.subtype = subtype; + + final String[] serviceType = splitServiceType(serviceInfo); + final String[] serviceName = splitFullyQualifiedName(serviceInfo, serviceType); + + // Service PTR record + final RecordInfo<MdnsPointerRecord> ptrRecord = new RecordInfo<>( + serviceInfo, + new MdnsPointerRecord( + serviceType, + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + NON_NAME_RECORDS_TTL_MILLIS, + serviceName), + true /* sharedName */, true /* probing */); + + if (subtype == null) { + this.ptrRecords = Collections.singletonList(ptrRecord); + } else { + final String[] subtypeName = new String[serviceType.length + 2]; + System.arraycopy(serviceType, 0, subtypeName, 2, serviceType.length); + subtypeName[0] = subtype; + subtypeName[1] = SUBTYPE_SEPARATOR; + final RecordInfo<MdnsPointerRecord> subtypeRecord = new RecordInfo<>( + serviceInfo, + new MdnsPointerRecord( + subtypeName, + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + NON_NAME_RECORDS_TTL_MILLIS, + serviceName), + true /* sharedName */, true /* probing */); + + this.ptrRecords = List.of(ptrRecord, subtypeRecord); + } + + srvRecord = new RecordInfo<>( + serviceInfo, + new MdnsServiceRecord(serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + NAME_RECORDS_TTL_MILLIS, 0 /* servicePriority */, 0 /* serviceWeight */, + serviceInfo.getPort(), + deviceHostname), + false /* sharedName */, true /* probing */); + + txtRecord = new RecordInfo<>( + serviceInfo, + new MdnsTextRecord(serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, // Service name is verified unique after probing + NON_NAME_RECORDS_TTL_MILLIS, + attrsToTextEntries(serviceInfo.getAttributes())), + false /* sharedName */, true /* probing */); + + final ArrayList<RecordInfo<?>> allRecords = new ArrayList<>(5); + allRecords.addAll(ptrRecords); + allRecords.add(srvRecord); + allRecords.add(txtRecord); + // Service type enumeration record (RFC6763 9.) + allRecords.add(new RecordInfo<>( + serviceInfo, + new MdnsPointerRecord( + DNS_SD_SERVICE_TYPE, + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + NON_NAME_RECORDS_TTL_MILLIS, + serviceType), + true /* sharedName */, true /* probing */)); + + this.allRecords = Collections.unmodifiableList(allRecords); + } + + void setProbing(boolean probing) { + for (RecordInfo<?> info : allRecords) { + info.isProbing = probing; + } + } + } + + /** + * Inform the repository of the latest interface addresses. + */ + public void updateAddresses(@NonNull List<LinkAddress> newAddresses) { + mGeneralRecords.clear(); + for (LinkAddress addr : newAddresses) { + final String[] revDnsAddr = getReverseDnsAddress(addr.getAddress()); + mGeneralRecords.add(new RecordInfo<>( + null /* serviceInfo */, + new MdnsPointerRecord( + revDnsAddr, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + NAME_RECORDS_TTL_MILLIS, + mDeviceHostname), + false /* sharedName */, false /* probing */)); + + mGeneralRecords.add(new RecordInfo<>( + null /* serviceInfo */, + new MdnsInetAddressRecord( + mDeviceHostname, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + NAME_RECORDS_TTL_MILLIS, + addr.getAddress()), + false /* sharedName */, false /* probing */)); + } + } + + /** + * Add a service to the repository. + * + * This may remove/replace any existing service that used the name added but is exiting. + * @param serviceId A unique service ID. + * @param serviceInfo Service info to add. + * @return If the added service replaced another with a matching name (which was exiting), the + * ID of the replaced service. + * @throws NameConflictException There is already a (non-exiting) service using the name. + */ + public int addService(int serviceId, NsdServiceInfo serviceInfo, @Nullable String subtype) + throws NameConflictException { + if (mServices.contains(serviceId)) { + throw new IllegalArgumentException( + "Service ID must not be reused across registrations: " + serviceId); + } + + final int existing = getServiceByName(serviceInfo.getServiceName()); + // It's OK to re-add a service that is exiting + if (existing >= 0 && !mServices.get(existing).exiting) { + throw new NameConflictException(existing); + } + + final ServiceRegistration registration = new ServiceRegistration( + mDeviceHostname, serviceInfo, subtype); + mServices.put(serviceId, registration); + + // Remove existing exiting service + mServices.remove(existing); + return existing; + } + + /** + * @return The ID of the service identified by its name, or -1 if none. + */ + private int getServiceByName(@NonNull String serviceName) { + for (int i = 0; i < mServices.size(); i++) { + final ServiceRegistration registration = mServices.valueAt(i); + if (MdnsUtils.equalsIgnoreDnsCase(serviceName, + registration.serviceInfo.getServiceName())) { + return mServices.keyAt(i); + } + } + return -1; + } + + private MdnsProber.ProbingInfo makeProbingInfo(int serviceId, + @NonNull MdnsServiceRecord srvRecord) { + final List<MdnsRecord> probingRecords = new ArrayList<>(); + // Probe with cacheFlush cleared; it is set when announcing, as it was verified unique: + // RFC6762 10.2 + probingRecords.add(new MdnsServiceRecord(srvRecord.getName(), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + srvRecord.getTtl(), + srvRecord.getServicePriority(), srvRecord.getServiceWeight(), + srvRecord.getServicePort(), + srvRecord.getServiceHost())); + + return new MdnsProber.ProbingInfo(serviceId, probingRecords); + } + + private static List<MdnsServiceInfo.TextEntry> attrsToTextEntries(Map<String, byte[]> attrs) { + final List<MdnsServiceInfo.TextEntry> out = new ArrayList<>(attrs.size()); + for (Map.Entry<String, byte[]> attr : attrs.entrySet()) { + out.add(new MdnsServiceInfo.TextEntry(attr.getKey(), attr.getValue())); + } + return out; + } + + /** + * Mark a service in the repository as exiting. + * @param id ID of the service, used at registration time. + * @return The exit announcement to indicate the service was removed, or null if not necessary. + */ + @Nullable + public MdnsAnnouncer.ExitAnnouncementInfo exitService(int id) { + final ServiceRegistration registration = mServices.get(id); + if (registration == null) return null; + if (registration.exiting) return null; + + // Send exit (TTL 0) for the PTR records, if at least one was sent (in particular don't send + // if still probing) + if (CollectionUtils.all(registration.ptrRecords, r -> r.lastSentTimeMs == 0L)) { + return null; + } + + registration.exiting = true; + final List<MdnsRecord> expiredRecords = CollectionUtils.map(registration.ptrRecords, + r -> new MdnsPointerRecord( + r.record.getName(), + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 0L /* ttlMillis */, + r.record.getPointer())); + + // Exit should be skipped if the record is still advertised by another service, but that + // would be a conflict (2 service registrations with the same service name), so it would + // not have been allowed by the repository. + return new MdnsAnnouncer.ExitAnnouncementInfo(id, expiredRecords); + } + + public void removeService(int id) { + mServices.remove(id); + } + + /** + * @return The number of services currently held in the repository, including exiting services. + */ + public int getServicesCount() { + return mServices.size(); + } + + /** + * Remove all services from the repository + * @return IDs of the removed services + */ + @NonNull + public int[] clearServices() { + final int[] ret = new int[mServices.size()]; + for (int i = 0; i < mServices.size(); i++) { + ret[i] = mServices.keyAt(i); + } + mServices.clear(); + return ret; + } + + /** + * Info about a reply to be sent. + */ + public static class ReplyInfo { + @NonNull + public final List<MdnsRecord> answers; + @NonNull + public final List<MdnsRecord> additionalAnswers; + public final long sendDelayMs; + @NonNull + public final InetSocketAddress destination; + + public ReplyInfo( + @NonNull List<MdnsRecord> answers, + @NonNull List<MdnsRecord> additionalAnswers, + long sendDelayMs, + @NonNull InetSocketAddress destination) { + this.answers = answers; + this.additionalAnswers = additionalAnswers; + this.sendDelayMs = sendDelayMs; + this.destination = destination; + } + + @Override + public String toString() { + return "{ReplyInfo to " + destination + ", answers: " + answers.size() + + ", additionalAnswers: " + additionalAnswers.size() + + ", sendDelayMs " + sendDelayMs + "}"; + } + } + + /** + * Get the reply to send to an incoming packet. + * + * @param packet The incoming packet. + * @param src The source address of the incoming packet. + */ + @Nullable + public ReplyInfo getReply(MdnsPacket packet, InetSocketAddress src) { + final long now = SystemClock.elapsedRealtime(); + final boolean replyUnicast = (packet.flags & MdnsConstants.QCLASS_UNICAST) != 0; + final ArrayList<MdnsRecord> additionalAnswerRecords = new ArrayList<>(); + final ArrayList<RecordInfo<?>> answerInfo = new ArrayList<>(); + for (MdnsRecord question : packet.questions) { + // Add answers from general records + addReplyFromService(question, mGeneralRecords, null /* servicePtrRecord */, + null /* serviceSrvRecord */, null /* serviceTxtRecord */, replyUnicast, now, + answerInfo, additionalAnswerRecords); + + // Add answers from each service + for (int i = 0; i < mServices.size(); i++) { + final ServiceRegistration registration = mServices.valueAt(i); + if (registration.exiting) continue; + addReplyFromService(question, registration.allRecords, registration.ptrRecords, + registration.srvRecord, registration.txtRecord, replyUnicast, now, + answerInfo, additionalAnswerRecords); + } + } + + if (answerInfo.size() == 0 && additionalAnswerRecords.size() == 0) { + return null; + } + + // Determine the send delay + final long delayMs; + if ((packet.flags & MdnsConstants.FLAG_TRUNCATED) != 0) { + // RFC 6762 6.: 400-500ms delay if TC bit is set + delayMs = 400L + mDelayGenerator.nextInt(100); + } else if (packet.questions.size() > 1 + || CollectionUtils.any(answerInfo, a -> a.isSharedName)) { + // 20-120ms if there may be responses from other hosts (not a fully owned + // name) (RFC 6762 6.), or if there are multiple questions (6.3). + // TODO: this should be 0 if this is a probe query ("can be distinguished from a + // normal query by the fact that a probe query contains a proposed record in the + // Authority Section that answers the question" in 6.), and the reply is for a fully + // owned record. + delayMs = 20L + mDelayGenerator.nextInt(100); + } else { + delayMs = 0L; + } + + // Determine the send destination + final InetSocketAddress dest; + if (replyUnicast) { + dest = src; + } else if (src.getAddress() instanceof Inet4Address) { + dest = IPV4_ADDR; + } else { + dest = IPV6_ADDR; + } + + // Build the list of answer records from their RecordInfo + final ArrayList<MdnsRecord> answerRecords = new ArrayList<>(answerInfo.size()); + for (RecordInfo<?> info : answerInfo) { + // TODO: consider actual packet send delay after response aggregation + info.lastSentTimeMs = now + delayMs; + if (!replyUnicast) { + info.lastAdvertisedTimeMs = info.lastSentTimeMs; + } + answerRecords.add(info.record); + } + + return new ReplyInfo(answerRecords, additionalAnswerRecords, delayMs, dest); + } + + /** + * Add answers and additional answers for a question, from a ServiceRegistration. + */ + private void addReplyFromService(@NonNull MdnsRecord question, + @NonNull List<RecordInfo<?>> serviceRecords, + @Nullable List<RecordInfo<MdnsPointerRecord>> servicePtrRecords, + @Nullable RecordInfo<MdnsServiceRecord> serviceSrvRecord, + @Nullable RecordInfo<MdnsTextRecord> serviceTxtRecord, + boolean replyUnicast, long now, @NonNull List<RecordInfo<?>> answerInfo, + @NonNull List<MdnsRecord> additionalAnswerRecords) { + boolean hasDnsSdPtrRecordAnswer = false; + boolean hasDnsSdSrvRecordAnswer = false; + boolean hasFullyOwnedNameMatch = false; + boolean hasKnownAnswer = false; + + final int answersStartIndex = answerInfo.size(); + for (RecordInfo<?> info : serviceRecords) { + if (info.isProbing) continue; + + /* RFC6762 6.: the record name must match the question name, the record rrtype + must match the question qtype unless the qtype is "ANY" (255) or the rrtype is + "CNAME" (5), and the record rrclass must match the question qclass unless the + qclass is "ANY" (255) */ + if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(info.record.getName(), question.getName())) { + continue; + } + hasFullyOwnedNameMatch |= !info.isSharedName; + + // The repository does not store CNAME records + if (question.getType() != MdnsRecord.TYPE_ANY + && question.getType() != info.record.getType()) { + continue; + } + if (question.getRecordClass() != MdnsRecord.CLASS_ANY + && question.getRecordClass() != info.record.getRecordClass()) { + continue; + } + + hasKnownAnswer = true; + hasDnsSdPtrRecordAnswer |= (servicePtrRecords != null + && CollectionUtils.any(servicePtrRecords, r -> info == r)); + hasDnsSdSrvRecordAnswer |= (info == serviceSrvRecord); + + // TODO: responses to probe queries should bypass this check and only ensure the + // reply is sent 250ms after the last sent time (RFC 6762 p.15) + if (!replyUnicast && info.lastAdvertisedTimeMs > 0L + && now - info.lastAdvertisedTimeMs < MIN_MULTICAST_REPLY_INTERVAL_MS) { + continue; + } + + // TODO: Don't reply if in known answers of the querier (7.1) if TTL is > half + + answerInfo.add(info); + } + + // RFC6762 6.1: + // "Any time a responder receives a query for a name for which it has verified exclusive + // ownership, for a type for which that name has no records, the responder MUST [...] + // respond asserting the nonexistence of that record" + if (hasFullyOwnedNameMatch && !hasKnownAnswer) { + additionalAnswerRecords.add(new MdnsNsecRecord( + question.getName(), + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + // TODO: RFC6762 6.1: "In general, the TTL given for an NSEC record SHOULD + // be the same as the TTL that the record would have had, had it existed." + NAME_RECORDS_TTL_MILLIS, + question.getName(), + new int[] { question.getType() })); + } + + // No more records to add if no answer + if (answerInfo.size() == answersStartIndex) return; + + final List<RecordInfo<?>> additionalAnswerInfo = new ArrayList<>(); + // RFC6763 12.1: if including PTR record, include the SRV and TXT records it names + if (hasDnsSdPtrRecordAnswer) { + if (serviceTxtRecord != null) { + additionalAnswerInfo.add(serviceTxtRecord); + } + if (serviceSrvRecord != null) { + additionalAnswerInfo.add(serviceSrvRecord); + } + } + + // RFC6763 12.1&.2: if including PTR or SRV record, include the address records it names + if (hasDnsSdPtrRecordAnswer || hasDnsSdSrvRecordAnswer) { + for (RecordInfo<?> record : mGeneralRecords) { + if (record.record instanceof MdnsInetAddressRecord) { + additionalAnswerInfo.add(record); + } + } + } + + for (RecordInfo<?> info : additionalAnswerInfo) { + additionalAnswerRecords.add(info.record); + } + + // RFC6762 6.1: negative responses + addNsecRecordsForUniqueNames(additionalAnswerRecords, + answerInfo.listIterator(answersStartIndex), + additionalAnswerInfo.listIterator()); + } + + /** + * Add NSEC records indicating that the response records are unique. + * + * Following RFC6762 6.1: + * "On receipt of a question for a particular name, rrtype, and rrclass, for which a responder + * does have one or more unique answers, the responder MAY also include an NSEC record in the + * Additional Record Section indicating the nonexistence of other rrtypes for that name and + * rrclass." + * @param destinationList List to add the NSEC records to. + * @param answerRecords Lists of answered records based on which to add NSEC records (typically + * answer and additionalAnswer sections) + */ + @SafeVarargs + private static void addNsecRecordsForUniqueNames( + List<MdnsRecord> destinationList, + Iterator<RecordInfo<?>>... answerRecords) { + // Group unique records by name. Use a TreeMap with comparator as arrays don't implement + // equals / hashCode. + final Map<String[], List<MdnsRecord>> nsecByName = new TreeMap<>(Arrays::compare); + // But keep the list of names in added order, otherwise records would be sorted in + // alphabetical order instead of the order of the original records, which would look like + // inconsistent behavior depending on service name. + final List<String[]> namesInAddedOrder = new ArrayList<>(); + for (Iterator<RecordInfo<?>> answers : answerRecords) { + addNonSharedRecordsToMap(answers, nsecByName, namesInAddedOrder); + } + + for (String[] nsecName : namesInAddedOrder) { + final List<MdnsRecord> entryRecords = nsecByName.get(nsecName); + long minTtl = Long.MAX_VALUE; + final Set<Integer> types = new ArraySet<>(entryRecords.size()); + for (MdnsRecord record : entryRecords) { + if (minTtl > record.getTtl()) minTtl = record.getTtl(); + types.add(record.getType()); + } + + destinationList.add(new MdnsNsecRecord( + nsecName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + minTtl, + nsecName, + CollectionUtils.toIntArray(types))); + } + } + + /** + * Add non-shared records to a map listing them by record name, and to a list of names that + * remembers the adding order. + * + * In the destination map records are grouped by name; so the map has one key per record name, + * and the values are the lists of different records that share the same name. + * @param records Records to scan. + * @param dest Map to add the records to. + * @param namesInAddedOrder List of names to add the names in order, keeping the first + * occurrence of each name. + */ + private static void addNonSharedRecordsToMap( + Iterator<RecordInfo<?>> records, + Map<String[], List<MdnsRecord>> dest, + List<String[]> namesInAddedOrder) { + while (records.hasNext()) { + final RecordInfo<?> record = records.next(); + if (record.isSharedName) continue; + final List<MdnsRecord> recordsForName = dest.computeIfAbsent(record.record.name, + key -> { + namesInAddedOrder.add(key); + return new ArrayList<>(); + }); + recordsForName.add(record.record); + } + } + + /** + * Called to indicate that probing succeeded for a service. + * @param probeSuccessInfo The successful probing info. + * @return The {@link MdnsAnnouncer.AnnouncementInfo} to send, now that probing has succeeded. + */ + public MdnsAnnouncer.AnnouncementInfo onProbingSucceeded( + MdnsProber.ProbingInfo probeSuccessInfo) + throws IOException { + + final ServiceRegistration registration = mServices.get(probeSuccessInfo.getServiceId()); + if (registration == null) throw new IOException( + "Service is not registered: " + probeSuccessInfo.getServiceId()); + registration.setProbing(false); + + final ArrayList<MdnsRecord> answers = new ArrayList<>(); + final ArrayList<MdnsRecord> additionalAnswers = new ArrayList<>(); + + // Interface address records in general records + for (RecordInfo<?> record : mGeneralRecords) { + answers.add(record.record); + } + + // All service records + for (RecordInfo<?> info : registration.allRecords) { + answers.add(info.record); + } + + addNsecRecordsForUniqueNames(additionalAnswers, + mGeneralRecords.iterator(), registration.allRecords.iterator()); + + return new MdnsAnnouncer.AnnouncementInfo(probeSuccessInfo.getServiceId(), + answers, additionalAnswers); + } + + /** + * Get the service IDs of services conflicting with a received packet. + */ + public Set<Integer> getConflictingServices(MdnsPacket packet) { + // Avoid allocating a new set for each incoming packet: use an empty set by default. + Set<Integer> conflicting = Collections.emptySet(); + for (MdnsRecord record : packet.answers) { + for (int i = 0; i < mServices.size(); i++) { + final ServiceRegistration registration = mServices.valueAt(i); + if (registration.exiting) continue; + + // Only look for conflicts in service name, as a different service name can be used + // if there is a conflict, but there is nothing actionable if any other conflict + // happens. In fact probing is only done for the service name in the SRV record. + // This means only SRV and TXT records need to be checked. + final RecordInfo<MdnsServiceRecord> srvRecord = registration.srvRecord; + if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(record.getName(), + srvRecord.record.getName())) { + continue; + } + + // As per RFC6762 9., it's fine if the "conflict" is an identical record with same + // data. + if (record instanceof MdnsServiceRecord) { + final MdnsServiceRecord local = srvRecord.record; + final MdnsServiceRecord other = (MdnsServiceRecord) record; + // Note "equals" does not consider TTL or receipt time, as intended here + if (Objects.equals(local, other)) { + continue; + } + } + + if (record instanceof MdnsTextRecord) { + final MdnsTextRecord local = registration.txtRecord.record; + final MdnsTextRecord other = (MdnsTextRecord) record; + if (Objects.equals(local, other)) { + continue; + } + } + + if (conflicting.size() == 0) { + // Conflict was found: use a mutable set + conflicting = new ArraySet<>(); + } + final int serviceId = mServices.keyAt(i); + conflicting.add(serviceId); + } + } + + return conflicting; + } + + /** + * (Re)set a service to the probing state. + * @return The {@link MdnsProber.ProbingInfo} to send for probing. + */ + @Nullable + public MdnsProber.ProbingInfo setServiceProbing(int serviceId) { + final ServiceRegistration registration = mServices.get(serviceId); + if (registration == null) return null; + + registration.setProbing(true); + return makeProbingInfo(serviceId, registration.srvRecord.record); + } + + /** + * Indicates whether a given service is in probing state. + */ + public boolean isProbing(int serviceId) { + final ServiceRegistration registration = mServices.get(serviceId); + if (registration == null) return false; + + return registration.srvRecord.isProbing; + } + + /** + * Return whether the repository has an active (non-exiting) service for the given ID. + */ + public boolean hasActiveService(int serviceId) { + final ServiceRegistration registration = mServices.get(serviceId); + if (registration == null) return false; + + return !registration.exiting; + } + + /** + * Rename a service to the newly provided info, following a conflict. + * + * If the specified service does not exist, this returns null. + */ + @Nullable + public MdnsProber.ProbingInfo renameServiceForConflict(int serviceId, NsdServiceInfo newInfo) { + final ServiceRegistration existing = mServices.get(serviceId); + if (existing == null) return null; + + final ServiceRegistration newService = new ServiceRegistration( + mDeviceHostname, newInfo, existing.subtype); + mServices.put(serviceId, newService); + return makeProbingInfo(serviceId, newService.srvRecord.record); + } + + /** + * Called when {@link MdnsAdvertiser} sent an advertisement for the given service. + */ + public void onAdvertisementSent(int serviceId) { + final ServiceRegistration registration = mServices.get(serviceId); + if (registration == null) return; + + final long now = SystemClock.elapsedRealtime(); + for (RecordInfo<?> record : registration.allRecords) { + record.lastSentTimeMs = now; + record.lastAdvertisedTimeMs = now; + } + } + + /** + * Compute: + * 2001:db8::1 --> 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa + * + * Or: + * 192.0.2.123 --> 123.2.0.192.in-addr.arpa + */ + @VisibleForTesting + public static String[] getReverseDnsAddress(@NonNull InetAddress addr) { + // xxx.xxx.xxx.xxx.in-addr.arpa (up to 28 characters) + // or 32 hex characters separated by dots + .ip6.arpa + final byte[] addrBytes = addr.getAddress(); + final List<String> out = new ArrayList<>(); + if (addr instanceof Inet4Address) { + for (int i = addrBytes.length - 1; i >= 0; i--) { + out.add(String.valueOf(Byte.toUnsignedInt(addrBytes[i]))); + } + out.add("in-addr"); + } else { + final String hexAddr = HexDump.toHexString(addrBytes); + + for (int i = hexAddr.length() - 1; i >= 0; i--) { + out.add(String.valueOf(hexAddr.charAt(i))); + } + out.add("ip6"); + } + out.add("arpa"); + + return out.toArray(new String[0]); + } + + private static String[] splitFullyQualifiedName( + @NonNull NsdServiceInfo info, @NonNull String[] serviceType) { + final String[] split = new String[serviceType.length + 1]; + split[0] = info.getServiceName(); + System.arraycopy(serviceType, 0, split, 1, serviceType.length); + + return split; + } + + private static String[] splitServiceType(@NonNull NsdServiceInfo info) { + // String.split(pattern, 0) removes trailing empty strings, which would appear when + // splitting "domain.name." (with a dot a the end), so this is what is needed here. + final String[] split = info.getServiceType().split("\\.", 0); + final String[] type = new String[split.length + 1]; + System.arraycopy(split, 0, type, 0, split.length); + type[split.length] = LOCAL_TLD; + + return type; + } +}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java b/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java new file mode 100644 index 0000000..8bc598d --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java
@@ -0,0 +1,153 @@ +/* + * 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.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread; + +import android.annotation.NonNull; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import com.android.server.connectivity.mdns.MdnsRecordRepository.ReplyInfo; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetSocketAddress; +import java.net.MulticastSocket; +import java.util.Collections; + +/** + * A class that handles sending mDNS replies to a {@link MulticastSocket}, possibly queueing them + * to be sent after some delay. + * + * TODO: implement sending after a delay, combining queued replies and duplicate answer suppression + */ +public class MdnsReplySender { + private static final boolean DBG = MdnsAdvertiser.DBG; + private static final int MSG_SEND = 1; + + private final String mLogTag; + @NonNull + private final MdnsInterfaceSocket mSocket; + @NonNull + private final Handler mHandler; + @NonNull + private final byte[] mPacketCreationBuffer; + + public MdnsReplySender(@NonNull String interfaceTag, @NonNull Looper looper, + @NonNull MdnsInterfaceSocket socket, @NonNull byte[] packetCreationBuffer) { + mHandler = new SendHandler(looper); + mLogTag = MdnsReplySender.class.getSimpleName() + "/" + interfaceTag; + mSocket = socket; + mPacketCreationBuffer = packetCreationBuffer; + } + + /** + * Queue a reply to be sent when its send delay expires. + */ + public void queueReply(@NonNull ReplyInfo reply) { + ensureRunningOnHandlerThread(mHandler); + // TODO: implement response aggregation (RFC 6762 6.4) + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SEND, reply), reply.sendDelayMs); + + if (DBG) { + Log.v(mLogTag, "Scheduling " + reply); + } + } + + /** + * Send a packet immediately. + * + * Must be called on the looper thread used by the {@link MdnsReplySender}. + */ + public void sendNow(@NonNull MdnsPacket packet, @NonNull InetSocketAddress destination) + throws IOException { + ensureRunningOnHandlerThread(mHandler); + if (!((destination.getAddress() instanceof Inet6Address && mSocket.hasJoinedIpv6()) + || (destination.getAddress() instanceof Inet4Address && mSocket.hasJoinedIpv4()))) { + // Skip sending if the socket has not joined the v4/v6 group (there was no address) + return; + } + + // TODO: support packets over size (send in multiple packets with TC bit set) + final MdnsPacketWriter writer = new MdnsPacketWriter(mPacketCreationBuffer); + + writer.writeUInt16(0); // Transaction ID (advertisement: 0) + writer.writeUInt16(packet.flags); // Response, authoritative (rfc6762 18.4) + writer.writeUInt16(packet.questions.size()); // questions count + writer.writeUInt16(packet.answers.size()); // answers count + writer.writeUInt16(packet.authorityRecords.size()); // authority entries count + writer.writeUInt16(packet.additionalRecords.size()); // additional records count + + for (MdnsRecord record : packet.questions) { + // Questions do not have TTL or data + record.writeHeaderFields(writer); + } + for (MdnsRecord record : packet.answers) { + record.write(writer, 0L); + } + for (MdnsRecord record : packet.authorityRecords) { + record.write(writer, 0L); + } + for (MdnsRecord record : packet.additionalRecords) { + record.write(writer, 0L); + } + + final int len = writer.getWritePosition(); + final byte[] outBuffer = new byte[len]; + System.arraycopy(mPacketCreationBuffer, 0, outBuffer, 0, len); + + mSocket.send(new DatagramPacket(outBuffer, 0, len, destination)); + } + + /** + * Cancel all pending sends. + */ + public void cancelAll() { + ensureRunningOnHandlerThread(mHandler); + mHandler.removeMessages(MSG_SEND); + } + + private class SendHandler extends Handler { + SendHandler(@NonNull Looper looper) { + super(looper); + } + + @Override + public void handleMessage(@NonNull Message msg) { + final ReplyInfo replyInfo = (ReplyInfo) msg.obj; + if (DBG) Log.v(mLogTag, "Sending " + replyInfo); + + final int flags = 0x8400; // Response, authoritative (rfc6762 18.4) + final MdnsPacket packet = new MdnsPacket(flags, + Collections.emptyList() /* questions */, + replyInfo.answers, + Collections.emptyList() /* authorityRecords */, + replyInfo.additionalAnswers); + + try { + sendNow(packet, replyInfo.destination); + } catch (IOException e) { + Log.e(mLogTag, "Error sending MDNS response", e); + } + } + } +}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java new file mode 100644 index 0000000..28aa640 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java
@@ -0,0 +1,410 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Network; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.connectivity.mdns.util.MdnsUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +/** An mDNS response. */ +public class MdnsResponse { + private final List<MdnsRecord> records; + private final List<MdnsPointerRecord> pointerRecords; + private MdnsServiceRecord serviceRecord; + private MdnsTextRecord textRecord; + @NonNull private List<MdnsInetAddressRecord> inet4AddressRecords; + @NonNull private List<MdnsInetAddressRecord> inet6AddressRecords; + private long lastUpdateTime; + private final int interfaceIndex; + @Nullable private final Network network; + @NonNull private final String[] serviceName; + + /** Constructs a new, empty response. */ + public MdnsResponse(long now, @NonNull String[] serviceName, int interfaceIndex, + @Nullable Network network) { + lastUpdateTime = now; + records = new LinkedList<>(); + pointerRecords = new LinkedList<>(); + inet4AddressRecords = new ArrayList<>(); + inet6AddressRecords = new ArrayList<>(); + this.interfaceIndex = interfaceIndex; + this.network = network; + this.serviceName = serviceName; + } + + public MdnsResponse(@NonNull MdnsResponse base) { + records = new ArrayList<>(base.records); + pointerRecords = new ArrayList<>(base.pointerRecords); + serviceRecord = base.serviceRecord; + textRecord = base.textRecord; + inet4AddressRecords = new ArrayList<>(base.inet4AddressRecords); + inet6AddressRecords = new ArrayList<>(base.inet6AddressRecords); + lastUpdateTime = base.lastUpdateTime; + serviceName = base.serviceName; + interfaceIndex = base.interfaceIndex; + network = base.network; + } + + /** + * Compare records for equality, including their TTL. + * + * MdnsRecord#equals ignores TTL and receiptTimeMillis, but methods in this class need to update + * records when the TTL changes (especially for goodbye announcements). + */ + private boolean recordsAreSame(MdnsRecord a, MdnsRecord b) { + if (!Objects.equals(a, b)) return false; + return a == null || a.getTtl() == b.getTtl(); + } + + private <T extends MdnsRecord> boolean addOrReplaceRecord(@NonNull T record, + @NonNull List<T> recordsList) { + final int existing = recordsList.indexOf(record); + if (existing >= 0) { + if (recordsAreSame(record, recordsList.get(existing))) { + return false; + } + final MdnsRecord existedRecord = recordsList.remove(existing); + records.remove(existedRecord); + } + recordsList.add(record); + records.add(record); + return true; + } + + /** + * Adds a pointer record. + * + * @return <code>true</code> if the record was added, or <code>false</code> if a matching + * pointer record is already present in the response with the same TTL. + */ + public synchronized boolean addPointerRecord(MdnsPointerRecord pointerRecord) { + if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceName, pointerRecord.getPointer())) { + throw new IllegalArgumentException( + "Pointer records for different service names cannot be added"); + } + return addOrReplaceRecord(pointerRecord, pointerRecords); + } + + /** Gets the pointer records. */ + public synchronized List<MdnsPointerRecord> getPointerRecords() { + // Returns a shallow copy. + return new LinkedList<>(pointerRecords); + } + + public synchronized boolean hasPointerRecords() { + return !pointerRecords.isEmpty(); + } + + @VisibleForTesting + synchronized void clearPointerRecords() { + pointerRecords.clear(); + } + + public synchronized boolean hasSubtypes() { + for (MdnsPointerRecord pointerRecord : pointerRecords) { + if (pointerRecord.hasSubtype()) { + return true; + } + } + return false; + } + + @Nullable + public synchronized List<String> getSubtypes() { + List<String> subtypes = null; + for (MdnsPointerRecord pointerRecord : pointerRecords) { + String pointerRecordSubtype = pointerRecord.getSubtype(); + if (pointerRecordSubtype != null) { + if (subtypes == null) { + subtypes = new LinkedList<>(); + } + subtypes.add(pointerRecordSubtype); + } + } + + return subtypes; + } + + @VisibleForTesting + public synchronized void removeSubtypes() { + Iterator<MdnsPointerRecord> iter = pointerRecords.iterator(); + while (iter.hasNext()) { + MdnsPointerRecord pointerRecord = iter.next(); + if (pointerRecord.hasSubtype()) { + iter.remove(); + } + } + } + + /** Sets the service record. */ + public synchronized boolean setServiceRecord(MdnsServiceRecord serviceRecord) { + if (recordsAreSame(this.serviceRecord, serviceRecord)) { + return false; + } + if (this.serviceRecord != null) { + records.remove(this.serviceRecord); + } + this.serviceRecord = serviceRecord; + if (this.serviceRecord != null) { + records.add(this.serviceRecord); + } + return true; + } + + /** Gets the service record. */ + public synchronized MdnsServiceRecord getServiceRecord() { + return serviceRecord; + } + + public synchronized boolean hasServiceRecord() { + return serviceRecord != null; + } + + /** Sets the text record. */ + public synchronized boolean setTextRecord(MdnsTextRecord textRecord) { + if (recordsAreSame(this.textRecord, textRecord)) { + return false; + } + if (this.textRecord != null) { + records.remove(this.textRecord); + } + this.textRecord = textRecord; + if (this.textRecord != null) { + records.add(this.textRecord); + } + return true; + } + + /** Gets the text record. */ + public synchronized MdnsTextRecord getTextRecord() { + return textRecord; + } + + public synchronized boolean hasTextRecord() { + return textRecord != null; + } + + /** Add the IPv4 address record. */ + public synchronized boolean addInet4AddressRecord( + @NonNull MdnsInetAddressRecord newInet4AddressRecord) { + return addOrReplaceRecord(newInet4AddressRecord, inet4AddressRecords); + } + + /** Gets the IPv4 address records. */ + @NonNull + public synchronized List<MdnsInetAddressRecord> getInet4AddressRecords() { + return Collections.unmodifiableList(inet4AddressRecords); + } + + /** Return the first IPv4 address record or null if no record. */ + @Nullable + public synchronized MdnsInetAddressRecord getInet4AddressRecord() { + return inet4AddressRecords.isEmpty() ? null : inet4AddressRecords.get(0); + } + + /** Check whether response has IPv4 address record */ + public synchronized boolean hasInet4AddressRecord() { + return !inet4AddressRecords.isEmpty(); + } + + /** Clear all IPv4 address records */ + synchronized void clearInet4AddressRecords() { + for (MdnsInetAddressRecord record : inet4AddressRecords) { + records.remove(record); + } + inet4AddressRecords.clear(); + } + + /** Sets the IPv6 address records. */ + public synchronized boolean addInet6AddressRecord( + @NonNull MdnsInetAddressRecord newInet6AddressRecord) { + return addOrReplaceRecord(newInet6AddressRecord, inet6AddressRecords); + } + + /** + * 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 int getInterfaceIndex() { + return interfaceIndex; + } + + /** + * Returns the network at which this response was received, or null if the network is unknown. + */ + @Nullable + public Network getNetwork() { + return network; + } + + /** Gets all IPv6 address records. */ + public synchronized List<MdnsInetAddressRecord> getInet6AddressRecords() { + return Collections.unmodifiableList(inet6AddressRecords); + } + + /** Return the first IPv6 address record or null if no record. */ + @Nullable + public synchronized MdnsInetAddressRecord getInet6AddressRecord() { + return inet6AddressRecords.isEmpty() ? null : inet6AddressRecords.get(0); + } + + /** Check whether response has IPv6 address record */ + public synchronized boolean hasInet6AddressRecord() { + return !inet6AddressRecords.isEmpty(); + } + + /** Clear all IPv6 address records */ + synchronized void clearInet6AddressRecords() { + for (MdnsInetAddressRecord record : inet6AddressRecords) { + records.remove(record); + } + inet6AddressRecords.clear(); + } + + /** Gets all of the records. */ + public synchronized List<MdnsRecord> getRecords() { + return new LinkedList<>(records); + } + + /** + * Drop address records if they are for a hostname that does not match the service record. + * + * @return True if the records were dropped. + */ + public synchronized boolean dropUnmatchedAddressRecords() { + if (this.serviceRecord == null) return false; + boolean dropAddressRecords = false; + + for (MdnsInetAddressRecord inetAddressRecord : getInet4AddressRecords()) { + if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase( + this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) { + dropAddressRecords = true; + } + } + for (MdnsInetAddressRecord inetAddressRecord : getInet6AddressRecords()) { + if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase( + this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) { + dropAddressRecords = true; + } + } + + if (dropAddressRecords) { + clearInet4AddressRecords(); + clearInet6AddressRecords(); + return true; + } + return false; + } + + /** + * Tests if the response is complete. A response is considered complete if it contains SRV, + * TXT, and A (for IPv4) or AAAA (for IPv6) records. The service type->name mapping is always + * known when constructing a MdnsResponse, so this may return true when there is no PTR record. + */ + public synchronized boolean isComplete() { + return (serviceRecord != null) + && (textRecord != null) + && (!inet4AddressRecords.isEmpty() || !inet6AddressRecords.isEmpty()); + } + + /** + * Returns the key for this response. The key uniquely identifies the response by its service + * name. + */ + @Nullable + public String getServiceInstanceName() { + return serviceName.length > 0 ? serviceName[0] : null; + } + + @NonNull + public String[] getServiceName() { + return serviceName; + } + + /** + * Tests if this response is a goodbye message. This will be true if a service record is present + * and any of the records have a TTL of 0. + */ + public synchronized boolean isGoodbye() { + if (getServiceInstanceName() != null) { + for (MdnsRecord record : records) { + // Expiring PTR records with subtypes just signal a change in known supported + // criteria, not the device itself going offline, so ignore those. + if ((record instanceof MdnsPointerRecord) + && ((MdnsPointerRecord) record).hasSubtype()) { + continue; + } + + if (record.getTtl() == 0) { + return true; + } + } + } + return false; + } + + /** + * Writes the response to a packet. + * + * @param writer The writer to use. + * @param now The current time. This is used to write updated TTLs that reflect the remaining + * TTL + * since the response was received. + * @return The number of records that were written. + * @throws IOException If an error occurred while writing (typically indicating overflow). + */ + public synchronized int write(MdnsPacketWriter writer, long now) throws IOException { + int count = 0; + for (MdnsPointerRecord pointerRecord : pointerRecords) { + pointerRecord.write(writer, now); + ++count; + } + + if (serviceRecord != null) { + serviceRecord.write(writer, now); + ++count; + } + + if (textRecord != null) { + textRecord.write(writer, now); + ++count; + } + + for (MdnsInetAddressRecord inetAddressRecord : inet4AddressRecords) { + inetAddressRecord.write(writer, now); + ++count; + } + + for (MdnsInetAddressRecord inetAddressRecord : inet6AddressRecords) { + inetAddressRecord.write(writer, now); + ++count; + } + + return count; + } +}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java new file mode 100644 index 0000000..77b5c58 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
@@ -0,0 +1,312 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Network; +import android.os.SystemClock; +import android.util.ArraySet; + +import com.android.server.connectivity.mdns.util.MdnsLogger; +import com.android.server.connectivity.mdns.util.MdnsUtils; + +import java.io.EOFException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** A class that decodes mDNS responses from UDP packets. */ +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 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. */ + public MdnsResponseDecoder(@NonNull Clock clock, @Nullable String[] serviceType) { + this.clock = clock; + this.serviceType = serviceType; + } + + private static MdnsResponse findResponseWithPointer( + List<MdnsResponse> responses, String[] pointer) { + if (responses != null) { + for (MdnsResponse response : responses) { + if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(response.getServiceName(), pointer)) { + return response; + } + } + } + return null; + } + + private static MdnsResponse findResponseWithHostName( + List<MdnsResponse> responses, String[] hostName) { + if (responses != null) { + for (MdnsResponse response : responses) { + MdnsServiceRecord serviceRecord = response.getServiceRecord(); + if (serviceRecord == null) { + continue; + } + if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceRecord.getServiceHost(), + hostName)) { + return response; + } + } + } + return null; + } + + /** + * Decodes all mDNS responses for the desired service type from a packet. The class does not + * check the responses for completeness; the caller should do that. + * + * @param recvbuf The received data buffer to read from. + * @param length The length of received data buffer. + * @return A decoded {@link MdnsPacket}. + * @throws MdnsPacket.ParseException if a response packet could not be parsed. + */ + @NonNull + public static MdnsPacket parseResponse(@NonNull byte[] recvbuf, int length) + throws MdnsPacket.ParseException { + MdnsPacketReader reader = new MdnsPacketReader(recvbuf, length); + + final MdnsPacket mdnsPacket; + try { + reader.readUInt16(); // transaction ID (not used) + int flags = reader.readUInt16(); + if ((flags & MdnsConstants.FLAGS_RESPONSE_MASK) != MdnsConstants.FLAGS_RESPONSE) { + throw new MdnsPacket.ParseException( + MdnsResponseErrorCode.ERROR_NOT_RESPONSE_MESSAGE, "Not a response", null); + } + + mdnsPacket = MdnsPacket.parseRecordsSection(reader, flags); + if (mdnsPacket.answers.size() < 1) { + throw new MdnsPacket.ParseException( + MdnsResponseErrorCode.ERROR_NO_ANSWERS, "Response has no answers", + null); + } + return mdnsPacket; + } catch (EOFException e) { + throw new MdnsPacket.ParseException(MdnsResponseErrorCode.ERROR_END_OF_FILE, + "Reached the end of the mDNS response unexpectedly.", e); + } + } + + /** + * Augments a list of {@link MdnsResponse} with records from a packet. The class does not check + * the resulting responses for completeness; the caller should do that. + * + * @param mdnsPacket the response packet with the new records + * @param existingResponses list of existing responses. Will not be modified. + * @param interfaceIndex the network interface index (or + * {@link MdnsSocket#INTERFACE_INDEX_UNSPECIFIED} if not known) at which the packet was received + * @param network the network at which the packet was received, or null if it is unknown. + * @return The set of response instances that were modified or newly added. + */ + public ArraySet<MdnsResponse> augmentResponses(@NonNull MdnsPacket mdnsPacket, + @NonNull Collection<MdnsResponse> existingResponses, int interfaceIndex, + @Nullable Network network) { + final ArrayList<MdnsRecord> records = new ArrayList<>( + mdnsPacket.questions.size() + mdnsPacket.answers.size() + + mdnsPacket.authorityRecords.size() + mdnsPacket.additionalRecords.size()); + records.addAll(mdnsPacket.answers); + records.addAll(mdnsPacket.authorityRecords); + records.addAll(mdnsPacket.additionalRecords); + + final ArraySet<MdnsResponse> modified = new ArraySet<>(); + final ArrayList<MdnsResponse> responses = new ArrayList<>(existingResponses.size()); + for (MdnsResponse existing : existingResponses) { + responses.add(new MdnsResponse(existing)); + } + // The response records are structured in a hierarchy, where some records reference + // others, as follows: + // + // PTR + // / \ + // / \ + // TXT SRV + // / \ + // / \ + // A AAAA + // + // But the order in which these records appear in the response packet is completely + // arbitrary. This means that we need to rescan the record list to construct each level of + // this hierarchy. + // + // PTR: service type -> service instance name + // + // SRV: service instance name -> host name (priority, weight) + // + // TXT: service instance name -> machine readable txt entries. + // + // A: host name -> IP address + + // Loop 1: find PTR records, which identify distinct service instances. + long now = SystemClock.elapsedRealtime(); + for (MdnsRecord record : records) { + if (record instanceof MdnsPointerRecord) { + String[] name = record.getName(); + if ((serviceType == null) || MdnsUtils.typeEqualsOrIsSubtype( + serviceType, name)) { + MdnsPointerRecord pointerRecord = (MdnsPointerRecord) record; + // Group PTR records that refer to the same service instance name into a single + // response. + MdnsResponse response = findResponseWithPointer(responses, + pointerRecord.getPointer()); + if (response == null) { + response = new MdnsResponse(now, pointerRecord.getPointer(), interfaceIndex, + network); + responses.add(response); + } + + if (response.addPointerRecord((MdnsPointerRecord) record)) { + modified.add(response); + } + } + } + } + + // Loop 2: find SRV and TXT records, which reference the pointer in the PTR record. + for (MdnsRecord record : records) { + if (record instanceof MdnsServiceRecord) { + MdnsServiceRecord serviceRecord = (MdnsServiceRecord) record; + MdnsResponse response = findResponseWithPointer(responses, serviceRecord.getName()); + if (response != null && response.setServiceRecord(serviceRecord)) { + response.dropUnmatchedAddressRecords(); + modified.add(response); + } + } else if (record instanceof MdnsTextRecord) { + MdnsTextRecord textRecord = (MdnsTextRecord) record; + MdnsResponse response = findResponseWithPointer(responses, textRecord.getName()); + if (response != null && response.setTextRecord(textRecord)) { + modified.add(response); + } + } + } + + // Loop 3-1: find A and AAAA records and clear addresses if the cache-flush bit set, which + // reference the host name in the SRV record. + final List<MdnsInetAddressRecord> inetRecords = new ArrayList<>(); + for (MdnsRecord record : records) { + if (record instanceof MdnsInetAddressRecord) { + MdnsInetAddressRecord inetRecord = (MdnsInetAddressRecord) record; + inetRecords.add(inetRecord); + if (allowMultipleSrvRecordsPerHost) { + List<MdnsResponse> matchingResponses = + findResponsesWithHostName(responses, inetRecord.getName()); + for (MdnsResponse response : matchingResponses) { + // Per RFC6762 10.2, clear all address records if the cache-flush bit set. + // This bit, the cache-flush bit, tells neighboring hosts + // that this is not a shared record type. Instead of merging this new + // record additively into the cache in addition to any previous records with + // the same name, rrtype, and rrclass. + // TODO: All old records with that name, rrtype, and rrclass that were + // received more than one second ago are declared invalid, and marked + // to expire from the cache in one second. + if (inetRecord.getCacheFlush()) { + response.clearInet4AddressRecords(); + response.clearInet6AddressRecords(); + } + } + } else { + MdnsResponse response = + findResponseWithHostName(responses, inetRecord.getName()); + if (response != null) { + // Per RFC6762 10.2, clear all address records if the cache-flush bit set. + // This bit, the cache-flush bit, tells neighboring hosts + // that this is not a shared record type. Instead of merging this new + // record additively into the cache in addition to any previous records with + // the same name, rrtype, and rrclass. + // TODO: All old records with that name, rrtype, and rrclass that were + // received more than one second ago are declared invalid, and marked + // to expire from the cache in one second. + if (inetRecord.getCacheFlush()) { + response.clearInet4AddressRecords(); + response.clearInet6AddressRecords(); + } + } + } + } + } + + // Loop 3-2: Assign addresses, which reference the host name in the SRV record. + for (MdnsInetAddressRecord inetRecord : inetRecords) { + if (allowMultipleSrvRecordsPerHost) { + List<MdnsResponse> matchingResponses = + findResponsesWithHostName(responses, inetRecord.getName()); + for (MdnsResponse response : matchingResponses) { + if (assignInetRecord(response, inetRecord)) { + modified.add(response); + } + } + } else { + MdnsResponse response = + findResponseWithHostName(responses, inetRecord.getName()); + if (response != null) { + if (assignInetRecord(response, inetRecord)) { + modified.add(response); + } + } + } + } + + return modified; + } + + private static boolean assignInetRecord( + MdnsResponse response, MdnsInetAddressRecord inetRecord) { + if (inetRecord.getInet4Address() != null) { + return response.addInet4AddressRecord(inetRecord); + } else if (inetRecord.getInet6Address() != null) { + return response.addInet6AddressRecord(inetRecord); + } + return false; + } + + 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 (MdnsUtils.equalsDnsLabelIgnoreDnsCase(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(); + } + } +} \ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsResponseErrorCode.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseErrorCode.java similarity index 92% rename from service/mdns/com/android/server/connectivity/mdns/MdnsResponseErrorCode.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsResponseErrorCode.java index fcf9058..73a7e3a 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsResponseErrorCode.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseErrorCode.java
@@ -35,4 +35,6 @@ public static final int ERROR_READING_TXT_RDATA = 10; public static final int ERROR_SKIPPING_UNKNOWN_RECORD = 11; public static final int ERROR_END_OF_FILE = 12; + public static final int ERROR_READING_NSEC_RDATA = 13; + public static final int ERROR_READING_ANY_RDATA = 14; } \ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsSearchOptions.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSearchOptions.java similarity index 85% rename from service/mdns/com/android/server/connectivity/mdns/MdnsSearchOptions.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsSearchOptions.java index 583c4a9..3da6bd0 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsSearchOptions.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSearchOptions.java
@@ -46,7 +46,8 @@ public MdnsSearchOptions createFromParcel(Parcel source) { return new MdnsSearchOptions(source.createStringArrayList(), source.readBoolean(), source.readBoolean(), - source.readParcelable(null)); + source.readParcelable(null), + source.readString()); } @Override @@ -56,6 +57,8 @@ }; private static MdnsSearchOptions defaultOptions; private final List<String> subtypes; + @Nullable + private final String resolveInstanceName; private final boolean isPassiveMode; private final boolean removeExpiredService; @@ -64,7 +67,7 @@ /** Parcelable constructs for a {@link MdnsSearchOptions}. */ MdnsSearchOptions(List<String> subtypes, boolean isPassiveMode, boolean removeExpiredService, - @Nullable Network network) { + @Nullable Network network, @Nullable String resolveInstanceName) { this.subtypes = new ArrayList<>(); if (subtypes != null) { this.subtypes.addAll(subtypes); @@ -72,6 +75,7 @@ this.isPassiveMode = isPassiveMode; this.removeExpiredService = removeExpiredService; mNetwork = network; + this.resolveInstanceName = resolveInstanceName; } /** Returns a {@link Builder} for {@link MdnsSearchOptions}. */ @@ -115,6 +119,15 @@ return mNetwork; } + /** + * If non-null, queries should try to resolve all records of this specific service, rather than + * discovering all services. + */ + @Nullable + public String getResolveInstanceName() { + return resolveInstanceName; + } + @Override public int describeContents() { return 0; @@ -126,6 +139,7 @@ out.writeBoolean(isPassiveMode); out.writeBoolean(removeExpiredService); out.writeParcelable(mNetwork, 0); + out.writeString(resolveInstanceName); } /** A builder to create {@link MdnsSearchOptions}. */ @@ -134,6 +148,7 @@ private boolean isPassiveMode = true; private boolean removeExpiredService; private Network mNetwork; + private String resolveInstanceName; private Builder() { subtypes = new ArraySet<>(); @@ -194,10 +209,22 @@ return this; } + /** + * Set the instance name to resolve. + * + * If non-null, queries should try to resolve all records of this specific service, + * rather than discovering all services. + * @param name The instance name. + */ + public Builder setResolveInstanceName(String name) { + resolveInstanceName = name; + return this; + } + /** Builds a {@link MdnsSearchOptions} with the arguments supplied to this builder. */ public MdnsSearchOptions build() { return new MdnsSearchOptions(new ArrayList<>(subtypes), isPassiveMode, - removeExpiredService, mNetwork); + removeExpiredService, mNetwork, resolveInstanceName); } } } \ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceBrowserListener.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceBrowserListener.java similarity index 100% rename from service/mdns/com/android/server/connectivity/mdns/MdnsServiceBrowserListener.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsServiceBrowserListener.java
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceCache.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceCache.java new file mode 100644 index 0000000..cd0be67 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceCache.java
@@ -0,0 +1,178 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns; + +import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread; +import static com.android.server.connectivity.mdns.util.MdnsUtils.equalsIgnoreDnsCase; +import static com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLowerCase; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Network; +import android.os.Handler; +import android.os.Looper; +import android.util.ArrayMap; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +/** + * The {@link MdnsServiceCache} manages the service which discovers from each socket and cache these + * services to reduce duplicated queries. + * + * <p>This class is not thread safe, it is intended to be used only from the looper thread. + * However, the constructor is an exception, as it is called on another thread; + * therefore for thread safety all members of this class MUST either be final or initialized + * to their default value (0, false or null). + */ +public class MdnsServiceCache { + private static class CacheKey { + @NonNull final String mLowercaseServiceType; + @Nullable final Network mNetwork; + + CacheKey(@NonNull String serviceType, @Nullable Network network) { + mLowercaseServiceType = toDnsLowerCase(serviceType); + mNetwork = network; + } + + @Override public int hashCode() { + return Objects.hash(mLowercaseServiceType, mNetwork); + } + + @Override public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof CacheKey)) { + return false; + } + return Objects.equals(mLowercaseServiceType, ((CacheKey) other).mLowercaseServiceType) + && Objects.equals(mNetwork, ((CacheKey) other).mNetwork); + } + } + /** + * A map of cached services. Key is composed of service name, type and network. Value is the + * service which use the service type to discover from each socket. + */ + @NonNull + private final ArrayMap<CacheKey, List<MdnsResponse>> mCachedServices = new ArrayMap<>(); + @NonNull + private final Handler mHandler; + + public MdnsServiceCache(@NonNull Looper looper) { + mHandler = new Handler(looper); + } + + /** + * Get the cache services which are queried from given service type and network. + * + * @param serviceType the target service type. + * @param network the target network + * @return the set of services which matches the given service type. + */ + @NonNull + public List<MdnsResponse> getCachedServices(@NonNull String serviceType, + @Nullable Network network) { + ensureRunningOnHandlerThread(mHandler); + final CacheKey key = new CacheKey(serviceType, network); + return mCachedServices.containsKey(key) + ? Collections.unmodifiableList(new ArrayList<>(mCachedServices.get(key))) + : Collections.emptyList(); + } + + private MdnsResponse findMatchedResponse(@NonNull List<MdnsResponse> responses, + @NonNull String serviceName) { + for (MdnsResponse response : responses) { + if (equalsIgnoreDnsCase(serviceName, response.getServiceInstanceName())) { + return response; + } + } + return null; + } + + /** + * Get the cache service. + * + * @param serviceName the target service name. + * @param serviceType the target service type. + * @param network the target network + * @return the service which matches given conditions. + */ + @Nullable + public MdnsResponse getCachedService(@NonNull String serviceName, + @NonNull String serviceType, @Nullable Network network) { + ensureRunningOnHandlerThread(mHandler); + final List<MdnsResponse> responses = + mCachedServices.get(new CacheKey(serviceType, network)); + if (responses == null) { + return null; + } + final MdnsResponse response = findMatchedResponse(responses, serviceName); + return response != null ? new MdnsResponse(response) : null; + } + + /** + * Add or update a service. + * + * @param serviceType the service type. + * @param network the target network + * @param response the response of the discovered service. + */ + public void addOrUpdateService(@NonNull String serviceType, @Nullable Network network, + @NonNull MdnsResponse response) { + ensureRunningOnHandlerThread(mHandler); + final List<MdnsResponse> responses = mCachedServices.computeIfAbsent( + new CacheKey(serviceType, network), key -> new ArrayList<>()); + // Remove existing service if present. + final MdnsResponse existing = + findMatchedResponse(responses, response.getServiceInstanceName()); + responses.remove(existing); + responses.add(response); + } + + /** + * Remove a service which matches the given service name, type and network. + * + * @param serviceName the target service name. + * @param serviceType the target service type. + * @param network the target network. + */ + @Nullable + public MdnsResponse removeService(@NonNull String serviceName, @NonNull String serviceType, + @Nullable Network network) { + ensureRunningOnHandlerThread(mHandler); + final List<MdnsResponse> responses = + mCachedServices.get(new CacheKey(serviceType, network)); + if (responses == null) { + return null; + } + final Iterator<MdnsResponse> iterator = responses.iterator(); + while (iterator.hasNext()) { + final MdnsResponse response = iterator.next(); + if (equalsIgnoreDnsCase(serviceName, response.getServiceInstanceName())) { + iterator.remove(); + return response; + } + } + return null; + } + + // TODO: check ttl expiration for each service and notify to the clients. +}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceInfo.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceInfo.java similarity index 85% rename from service/mdns/com/android/server/connectivity/mdns/MdnsServiceInfo.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsServiceInfo.java index 938fc3f..78df6df 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceInfo.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceInfo.java
@@ -31,10 +31,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.TreeMap; /** * A class representing a discovered mDNS service instance. @@ -57,8 +57,8 @@ source.createStringArrayList(), source.createStringArray(), source.readInt(), - source.readString(), - source.readString(), + source.createStringArrayList(), + source.createStringArrayList(), source.createStringArrayList(), source.createTypedArrayList(TextEntry.CREATOR), source.readInt(), @@ -76,10 +76,10 @@ private final List<String> subtypes; private final String[] hostName; private final int port; - @Nullable - private final String ipv4Address; - @Nullable - private final String ipv6Address; + @NonNull + private final List<String> ipv4Addresses; + @NonNull + private final List<String> ipv6Addresses; final List<String> textStrings; @Nullable final List<TextEntry> textEntries; @@ -105,8 +105,8 @@ subtypes, hostName, port, - ipv4Address, - ipv6Address, + List.of(ipv4Address), + List.of(ipv6Address), textStrings, /* textEntries= */ null, /* interfaceIndex= */ INTERFACE_INDEX_UNSPECIFIED, @@ -130,8 +130,8 @@ subtypes, hostName, port, - ipv4Address, - ipv6Address, + List.of(ipv4Address), + List.of(ipv6Address), textStrings, textEntries, /* interfaceIndex= */ INTERFACE_INDEX_UNSPECIFIED, @@ -160,8 +160,8 @@ subtypes, hostName, port, - ipv4Address, - ipv6Address, + List.of(ipv4Address), + List.of(ipv6Address), textStrings, textEntries, interfaceIndex, @@ -179,8 +179,8 @@ @Nullable List<String> subtypes, String[] hostName, int port, - @Nullable String ipv4Address, - @Nullable String ipv6Address, + @NonNull List<String> ipv4Addresses, + @NonNull List<String> ipv6Addresses, @Nullable List<String> textStrings, @Nullable List<TextEntry> textEntries, int interfaceIndex, @@ -193,8 +193,8 @@ } this.hostName = hostName; this.port = port; - this.ipv4Address = ipv4Address; - this.ipv6Address = ipv6Address; + this.ipv4Addresses = new ArrayList<>(ipv4Addresses); + this.ipv6Addresses = new ArrayList<>(ipv6Addresses); this.textStrings = new ArrayList<>(); if (textStrings != null) { this.textStrings.addAll(textStrings); @@ -205,17 +205,14 @@ // compatibility. We should prefer only {@code textEntries} if it's not null. List<TextEntry> entries = (this.textEntries != null) ? this.textEntries : parseTextStrings(this.textStrings); - Map<String, byte[]> attributes = new HashMap<>(entries.size()); + // The map of attributes is case-insensitive. + final Map<String, byte[]> attributes = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); for (TextEntry entry : entries) { - String key = entry.getKey().toLowerCase(Locale.ENGLISH); - // Per https://datatracker.ietf.org/doc/html/rfc6763#section-6.4, only the first entry // of the same key should be accepted: // If a client receives a TXT record containing the same key more than once, then the // client MUST silently ignore all but the first occurrence of that attribute. - if (!attributes.containsKey(key)) { - attributes.put(key, entry.getValue()); - } + attributes.putIfAbsent(entry.getKey(), entry.getValue()); } this.attributes = Collections.unmodifiableMap(attributes); this.interfaceIndex = interfaceIndex; @@ -263,16 +260,41 @@ return port; } - /** Returns the IPV4 address of this service instance. */ + /** Returns the IPV4 addresses of this service instance. */ + @NonNull + public List<String> getIpv4Addresses() { + return Collections.unmodifiableList(ipv4Addresses); + } + + /** + * Returns the first IPV4 address of this service instance. + * + * @deprecated Use {@link #getIpv4Addresses()} to get the entire list of IPV4 + * addresses for + * the host. + */ @Nullable + @Deprecated public String getIpv4Address() { - return ipv4Address; + return ipv4Addresses.isEmpty() ? null : ipv4Addresses.get(0); } /** Returns the IPV6 address of this service instance. */ + @NonNull + public List<String> getIpv6Addresses() { + return Collections.unmodifiableList(ipv6Addresses); + } + + /** + * Returns the first IPV6 address of this service instance. + * + * @deprecated Use {@link #getIpv6Addresses()} to get the entire list of IPV6 addresses for + * the host. + */ @Nullable + @Deprecated public String getIpv6Address() { - return ipv6Address; + return ipv6Addresses.isEmpty() ? null : ipv6Addresses.get(0); } /** @@ -311,12 +333,12 @@ */ @Nullable public byte[] getAttributeAsBytes(@NonNull String key) { - return attributes.get(key.toLowerCase(Locale.ENGLISH)); + return attributes.get(key); } /** Returns an immutable map of all attributes. */ public Map<String, String> getAttributes() { - Map<String, String> map = new HashMap<>(attributes.size()); + Map<String, String> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); for (Map.Entry<String, byte[]> kv : attributes.entrySet()) { final byte[] value = kv.getValue(); map.put(kv.getKey(), value == null ? null : new String(value, UTF_8)); @@ -336,8 +358,8 @@ out.writeStringList(subtypes); out.writeStringArray(hostName); out.writeInt(port); - out.writeString(ipv4Address); - out.writeString(ipv6Address); + out.writeStringList(ipv4Addresses); + out.writeStringList(ipv6Addresses); out.writeStringList(textStrings); out.writeTypedList(textEntries); out.writeInt(interfaceIndex); @@ -346,13 +368,16 @@ @Override public String toString() { - return String.format( - Locale.ROOT, - "Name: %s, subtypes: %s, ip: %s, port: %d", - serviceInstanceName, - TextUtils.join(",", subtypes), - ipv4Address, - port); + return "Name: " + serviceInstanceName + + ", type: " + TextUtils.join(".", serviceType) + + ", subtypes: " + TextUtils.join(",", subtypes) + + ", ip: " + ipv4Addresses + + ", ipv6: " + ipv6Addresses + + ", port: " + port + + ", interfaceIndex: " + interfaceIndex + + ", network: " + network + + ", textStrings: " + textStrings + + ", textEntries: " + textEntries; }
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java similarity index 94% rename from service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java index ebd8b77..f851b35 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java
@@ -19,6 +19,7 @@ import android.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.util.Arrays; @@ -142,7 +143,8 @@ @Override public int hashCode() { return (super.hashCode() * 31) - + Objects.hash(servicePriority, serviceWeight, Arrays.hashCode(serviceHost), + + Objects.hash(servicePriority, serviceWeight, + Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(serviceHost)), servicePort); } @@ -159,7 +161,7 @@ return super.equals(other) && (servicePriority == otherRecord.servicePriority) && (serviceWeight == otherRecord.serviceWeight) - && Arrays.equals(serviceHost, otherRecord.serviceHost) + && MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceHost, otherRecord.serviceHost) && (servicePort == otherRecord.servicePort); } }
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java new file mode 100644 index 0000000..c2c0db2 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -0,0 +1,612 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Network; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Pair; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.CollectionUtils; +import com.android.net.module.util.SharedLog; +import com.android.server.connectivity.mdns.util.MdnsUtils; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; + +/** + * Instance of this class sends and receives mDNS packets of a given service type and invoke + * registered {@link MdnsServiceBrowserListener} instances. + */ +public class MdnsServiceTypeClient { + + private static final int DEFAULT_MTU = 1500; + + private final String serviceType; + private final String[] serviceTypeLabels; + private final MdnsSocketClientBase socketClient; + private final MdnsResponseDecoder responseDecoder; + private final ScheduledExecutorService executor; + @Nullable private final Network network; + @NonNull private final SharedLog sharedLog; + private final Object lock = new Object(); + private final ArrayMap<MdnsServiceBrowserListener, MdnsSearchOptions> listeners = + new ArrayMap<>(); + private final Map<String, MdnsResponse> instanceNameToResponse = new HashMap<>(); + private final boolean removeServiceAfterTtlExpires = + MdnsConfigs.removeServiceAfterTtlExpires(); + private final boolean allowSearchOptionsToRemoveExpiredService = + MdnsConfigs.allowSearchOptionsToRemoveExpiredService(); + + private final MdnsResponseDecoder.Clock clock; + + @Nullable private MdnsSearchOptions searchOptions; + + // The session ID increases when startSendAndReceive() is called where we schedule a + // QueryTask for + // new subtypes. It stays the same between packets for same subtypes. + private long currentSessionId = 0; + + @GuardedBy("lock") + @Nullable + private Future<?> requestTaskFuture; + + /** + * Constructor of {@link MdnsServiceTypeClient}. + * + * @param socketClient Sends and receives mDNS packet. + * @param executor A {@link ScheduledExecutorService} used to schedule query tasks. + */ + public MdnsServiceTypeClient( + @NonNull String serviceType, + @NonNull MdnsSocketClientBase socketClient, + @NonNull ScheduledExecutorService executor, + @Nullable Network network, + @NonNull SharedLog sharedLog) { + this(serviceType, socketClient, executor, new MdnsResponseDecoder.Clock(), network, + sharedLog); + } + + @VisibleForTesting + public MdnsServiceTypeClient( + @NonNull String serviceType, + @NonNull MdnsSocketClientBase socketClient, + @NonNull ScheduledExecutorService executor, + @NonNull MdnsResponseDecoder.Clock clock, + @Nullable Network network, + @NonNull SharedLog sharedLog) { + this.serviceType = serviceType; + this.socketClient = socketClient; + this.executor = executor; + this.serviceTypeLabels = TextUtils.split(serviceType, "\\."); + this.responseDecoder = new MdnsResponseDecoder(clock, serviceTypeLabels); + this.clock = clock; + this.network = network; + this.sharedLog = sharedLog; + } + + private static MdnsServiceInfo buildMdnsServiceInfoFromResponse( + @NonNull MdnsResponse response, @NonNull String[] serviceTypeLabels) { + String[] hostName = null; + int port = 0; + if (response.hasServiceRecord()) { + hostName = response.getServiceRecord().getServiceHost(); + port = response.getServiceRecord().getServicePort(); + } + + final List<String> ipv4Addresses = new ArrayList<>(); + final List<String> ipv6Addresses = new ArrayList<>(); + if (response.hasInet4AddressRecord()) { + for (MdnsInetAddressRecord inetAddressRecord : response.getInet4AddressRecords()) { + final Inet4Address inet4Address = inetAddressRecord.getInet4Address(); + ipv4Addresses.add((inet4Address == null) ? null : inet4Address.getHostAddress()); + } + } + if (response.hasInet6AddressRecord()) { + for (MdnsInetAddressRecord inetAddressRecord : response.getInet6AddressRecords()) { + final Inet6Address inet6Address = inetAddressRecord.getInet6Address(); + ipv6Addresses.add((inet6Address == null) ? null : inet6Address.getHostAddress()); + } + } + String serviceInstanceName = response.getServiceInstanceName(); + if (serviceInstanceName == null) { + throw new IllegalStateException( + "mDNS response must have non-null service instance name"); + } + List<String> textStrings = null; + List<MdnsServiceInfo.TextEntry> textEntries = null; + if (response.hasTextRecord()) { + textStrings = response.getTextRecord().getStrings(); + textEntries = response.getTextRecord().getEntries(); + } + // TODO: Throw an error message if response doesn't have Inet6 or Inet4 address. + return new MdnsServiceInfo( + serviceInstanceName, + serviceTypeLabels, + response.getSubtypes(), + hostName, + port, + ipv4Addresses, + ipv6Addresses, + textStrings, + textEntries, + response.getInterfaceIndex(), + response.getNetwork()); + } + + /** + * Registers {@code listener} for receiving discovery event of mDNS service instances, and + * starts + * (or continue) to send mDNS queries periodically. + * + * @param listener The {@link MdnsServiceBrowserListener} to register. + * @param searchOptions {@link MdnsSearchOptions} contains the list of subtypes to discover. + */ + public void startSendAndReceive( + @NonNull MdnsServiceBrowserListener listener, + @NonNull MdnsSearchOptions searchOptions) { + synchronized (lock) { + this.searchOptions = searchOptions; + boolean hadReply = false; + if (listeners.put(listener, searchOptions) == null) { + for (MdnsResponse existingResponse : instanceNameToResponse.values()) { + if (!responseMatchesOptions(existingResponse, searchOptions)) continue; + final MdnsServiceInfo info = + buildMdnsServiceInfoFromResponse(existingResponse, serviceTypeLabels); + listener.onServiceNameDiscovered(info); + if (existingResponse.isComplete()) { + listener.onServiceFound(info); + hadReply = true; + } + } + } + // Cancel the next scheduled periodical task. + if (requestTaskFuture != null) { + requestTaskFuture.cancel(true); + } + // Keep tracking the ScheduledFuture for the task so we can cancel it if caller is not + // interested anymore. + final QueryTaskConfig taskConfig = new QueryTaskConfig( + searchOptions.getSubtypes(), + searchOptions.isPassiveMode(), + ++currentSessionId, + network); + if (hadReply) { + requestTaskFuture = scheduleNextRunLocked(taskConfig); + } else { + requestTaskFuture = executor.submit(new QueryTask(taskConfig)); + } + } + } + + private boolean responseMatchesOptions(@NonNull MdnsResponse response, + @NonNull MdnsSearchOptions options) { + final boolean matchesInstanceName = options.getResolveInstanceName() == null + // DNS is case-insensitive, so ignore case in the comparison + || MdnsUtils.equalsIgnoreDnsCase(options.getResolveInstanceName(), + response.getServiceInstanceName()); + + // If discovery is requiring some subtypes, the response must have one that matches a + // requested one. + final List<String> responseSubtypes = response.getSubtypes() == null + ? Collections.emptyList() : response.getSubtypes(); + final boolean matchesSubtype = options.getSubtypes().size() == 0 + || CollectionUtils.any(options.getSubtypes(), requiredSub -> + CollectionUtils.any(responseSubtypes, actualSub -> + MdnsUtils.equalsIgnoreDnsCase( + MdnsConstants.SUBTYPE_PREFIX + requiredSub, actualSub))); + + return matchesInstanceName && matchesSubtype; + } + + /** + * Unregisters {@code listener} from receiving discovery event of mDNS service instances. + * + * @param listener The {@link MdnsServiceBrowserListener} to unregister. + * @return {@code true} if no listener is registered with this client after unregistering {@code + * listener}. Otherwise returns {@code false}. + */ + public boolean stopSendAndReceive(@NonNull MdnsServiceBrowserListener listener) { + synchronized (lock) { + if (listeners.remove(listener) == null) { + return listeners.isEmpty(); + } + if (listeners.isEmpty() && requestTaskFuture != null) { + requestTaskFuture.cancel(true); + requestTaskFuture = null; + } + return listeners.isEmpty(); + } + } + + public String[] getServiceTypeLabels() { + return serviceTypeLabels; + } + + /** + * Process an incoming response packet. + */ + public synchronized void processResponse(@NonNull MdnsPacket packet, int interfaceIndex, + Network network) { + synchronized (lock) { + // Augment the list of current known responses, and generated responses for resolve + // requests if there is no known response + final List<MdnsResponse> currentList = new ArrayList<>(instanceNameToResponse.values()); + currentList.addAll(makeResponsesForResolveIfUnknown(interfaceIndex, network)); + final ArraySet<MdnsResponse> modifiedResponses = responseDecoder.augmentResponses( + packet, currentList, interfaceIndex, network); + + for (MdnsResponse modified : modifiedResponses) { + if (modified.isGoodbye()) { + onGoodbyeReceived(modified.getServiceInstanceName()); + } else { + onResponseModified(modified); + } + } + } + } + + public synchronized void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode) { + for (int i = 0; i < listeners.size(); i++) { + listeners.keyAt(i).onFailedToParseMdnsResponse(receivedPacketNumber, errorCode); + } + } + + /** Notify all services are removed because the socket is destroyed. */ + public void notifySocketDestroyed() { + synchronized (lock) { + for (MdnsResponse response : instanceNameToResponse.values()) { + final String name = response.getServiceInstanceName(); + if (name == null) continue; + for (int i = 0; i < listeners.size(); i++) { + if (!responseMatchesOptions(response, listeners.valueAt(i))) continue; + final MdnsServiceBrowserListener listener = listeners.keyAt(i); + final MdnsServiceInfo serviceInfo = + buildMdnsServiceInfoFromResponse(response, serviceTypeLabels); + if (response.isComplete()) { + sharedLog.log("Socket destroyed. onServiceRemoved: " + name); + listener.onServiceRemoved(serviceInfo); + } + sharedLog.log("Socket destroyed. onServiceNameRemoved: " + name); + listener.onServiceNameRemoved(serviceInfo); + } + } + + if (requestTaskFuture != null) { + requestTaskFuture.cancel(true); + requestTaskFuture = null; + } + } + } + + private void onResponseModified(@NonNull MdnsResponse response) { + final String serviceInstanceName = response.getServiceInstanceName(); + final MdnsResponse currentResponse = + instanceNameToResponse.get(serviceInstanceName); + + boolean newServiceFound = false; + boolean serviceBecomesComplete = false; + if (currentResponse == null) { + newServiceFound = true; + if (serviceInstanceName != null) { + instanceNameToResponse.put(serviceInstanceName, response); + } + } else { + boolean before = currentResponse.isComplete(); + instanceNameToResponse.put(serviceInstanceName, response); + boolean after = response.isComplete(); + serviceBecomesComplete = !before && after; + } + MdnsServiceInfo serviceInfo = + buildMdnsServiceInfoFromResponse(response, serviceTypeLabels); + + for (int i = 0; i < listeners.size(); i++) { + if (!responseMatchesOptions(response, listeners.valueAt(i))) continue; + final MdnsServiceBrowserListener listener = listeners.keyAt(i); + if (newServiceFound) { + sharedLog.log("onServiceNameDiscovered: " + serviceInfo); + listener.onServiceNameDiscovered(serviceInfo); + } + + if (response.isComplete()) { + if (newServiceFound || serviceBecomesComplete) { + sharedLog.log("onServiceFound: " + serviceInfo); + listener.onServiceFound(serviceInfo); + } else { + sharedLog.log("onServiceUpdated: " + serviceInfo); + listener.onServiceUpdated(serviceInfo); + } + } + } + } + + private void onGoodbyeReceived(@Nullable String serviceInstanceName) { + final MdnsResponse response = instanceNameToResponse.remove(serviceInstanceName); + if (response == null) { + return; + } + for (int i = 0; i < listeners.size(); i++) { + if (!responseMatchesOptions(response, listeners.valueAt(i))) continue; + final MdnsServiceBrowserListener listener = listeners.keyAt(i); + final MdnsServiceInfo serviceInfo = + buildMdnsServiceInfoFromResponse(response, serviceTypeLabels); + if (response.isComplete()) { + sharedLog.log("onServiceRemoved: " + serviceInfo); + listener.onServiceRemoved(serviceInfo); + } + sharedLog.log("onServiceNameRemoved: " + serviceInfo); + listener.onServiceNameRemoved(serviceInfo); + } + } + + private boolean shouldRemoveServiceAfterTtlExpires() { + if (removeServiceAfterTtlExpires) { + return true; + } + return allowSearchOptionsToRemoveExpiredService + && searchOptions != null + && searchOptions.removeExpiredService(); + } + + @VisibleForTesting + MdnsPacketWriter createMdnsPacketWriter() { + return new MdnsPacketWriter(DEFAULT_MTU); + } + + // A configuration for the PeriodicalQueryTask that contains parameters to build a query packet. + // Call to getConfigForNextRun returns a config that can be used to build the next query task. + @VisibleForTesting + static class QueryTaskConfig { + + private static final int INITIAL_TIME_BETWEEN_BURSTS_MS = + (int) MdnsConfigs.initialTimeBetweenBurstsMs(); + private static final int TIME_BETWEEN_BURSTS_MS = (int) MdnsConfigs.timeBetweenBurstsMs(); + private static final int QUERIES_PER_BURST = (int) MdnsConfigs.queriesPerBurst(); + private static final int TIME_BETWEEN_QUERIES_IN_BURST_MS = + (int) MdnsConfigs.timeBetweenQueriesInBurstMs(); + private static final int QUERIES_PER_BURST_PASSIVE_MODE = + (int) MdnsConfigs.queriesPerBurstPassive(); + private static final int UNSIGNED_SHORT_MAX_VALUE = 65536; + // The following fields are used by QueryTask so we need to test them. + @VisibleForTesting + final List<String> subtypes; + private final boolean alwaysAskForUnicastResponse = + MdnsConfigs.alwaysAskForUnicastResponseInEachBurst(); + private final boolean usePassiveMode; + private final long sessionId; + @VisibleForTesting + int transactionId; + @VisibleForTesting + boolean expectUnicastResponse; + private int queriesPerBurst; + private int timeBetweenBurstsInMs; + private int burstCounter; + private int timeToRunNextTaskInMs; + private boolean isFirstBurst; + @Nullable private final Network network; + + QueryTaskConfig(@NonNull Collection<String> subtypes, boolean usePassiveMode, + long sessionId, @Nullable Network network) { + this.usePassiveMode = usePassiveMode; + this.subtypes = new ArrayList<>(subtypes); + this.queriesPerBurst = QUERIES_PER_BURST; + this.burstCounter = 0; + this.transactionId = 1; + this.expectUnicastResponse = true; + this.isFirstBurst = true; + this.sessionId = sessionId; + // Config the scan frequency based on the scan mode. + if (this.usePassiveMode) { + // In passive scan mode, sends a single burst of QUERIES_PER_BURST queries, and then + // in each TIME_BETWEEN_BURSTS interval, sends QUERIES_PER_BURST_PASSIVE_MODE + // queries. + this.timeBetweenBurstsInMs = TIME_BETWEEN_BURSTS_MS; + } else { + // In active scan mode, sends a burst of QUERIES_PER_BURST queries, + // TIME_BETWEEN_QUERIES_IN_BURST_MS apart, then waits for the scan interval, and + // then repeats. The scan interval starts as INITIAL_TIME_BETWEEN_BURSTS_MS and + // doubles until it maxes out at TIME_BETWEEN_BURSTS_MS. + this.timeBetweenBurstsInMs = INITIAL_TIME_BETWEEN_BURSTS_MS; + } + this.network = network; + } + + QueryTaskConfig getConfigForNextRun() { + if (++transactionId > UNSIGNED_SHORT_MAX_VALUE) { + transactionId = 1; + } + // Only the first query expects uni-cast response. + expectUnicastResponse = false; + if (++burstCounter == queriesPerBurst) { + burstCounter = 0; + + if (alwaysAskForUnicastResponse) { + expectUnicastResponse = true; + } + // In passive scan mode, sends a single burst of QUERIES_PER_BURST queries, and + // then in each TIME_BETWEEN_BURSTS interval, sends QUERIES_PER_BURST_PASSIVE_MODE + // queries. + if (isFirstBurst) { + isFirstBurst = false; + if (usePassiveMode) { + queriesPerBurst = QUERIES_PER_BURST_PASSIVE_MODE; + } + } + // In active scan mode, sends a burst of QUERIES_PER_BURST queries, + // TIME_BETWEEN_QUERIES_IN_BURST_MS apart, then waits for the scan interval, and + // then repeats. The scan interval starts as INITIAL_TIME_BETWEEN_BURSTS_MS and + // doubles until it maxes out at TIME_BETWEEN_BURSTS_MS. + timeToRunNextTaskInMs = timeBetweenBurstsInMs; + if (timeBetweenBurstsInMs < TIME_BETWEEN_BURSTS_MS) { + timeBetweenBurstsInMs = Math.min(timeBetweenBurstsInMs * 2, + TIME_BETWEEN_BURSTS_MS); + } + } else { + timeToRunNextTaskInMs = TIME_BETWEEN_QUERIES_IN_BURST_MS; + } + return this; + } + } + + private List<MdnsResponse> makeResponsesForResolveIfUnknown(int interfaceIndex, + @NonNull Network network) { + final List<MdnsResponse> resolveResponses = new ArrayList<>(); + for (int i = 0; i < listeners.size(); i++) { + final String resolveName = listeners.valueAt(i).getResolveInstanceName(); + if (resolveName == null) { + continue; + } + MdnsResponse knownResponse = instanceNameToResponse.get(resolveName); + if (knownResponse == null) { + final ArrayList<String> instanceFullName = new ArrayList<>( + serviceTypeLabels.length + 1); + instanceFullName.add(resolveName); + instanceFullName.addAll(Arrays.asList(serviceTypeLabels)); + knownResponse = new MdnsResponse( + 0L /* lastUpdateTime */, instanceFullName.toArray(new String[0]), + interfaceIndex, network); + } + resolveResponses.add(knownResponse); + } + return resolveResponses; + } + + // A FutureTask that enqueues a single query, and schedule a new FutureTask for the next task. + private class QueryTask implements Runnable { + + private final QueryTaskConfig config; + + QueryTask(@NonNull QueryTaskConfig config) { + this.config = config; + } + + @Override + public void run() { + final List<MdnsResponse> servicesToResolve; + final boolean sendDiscoveryQueries; + synchronized (lock) { + // The listener is requesting to resolve a service that has no info in + // cache. Use the provided name to generate a minimal response, so other records are + // queried to complete it. + // Only the names are used to know which queries to send, other parameters like + // interfaceIndex do not matter. + servicesToResolve = makeResponsesForResolveIfUnknown( + 0 /* interfaceIndex */, config.network); + sendDiscoveryQueries = servicesToResolve.size() < listeners.size(); + } + Pair<Integer, List<String>> result; + try { + result = + new EnqueueMdnsQueryCallable( + socketClient, + createMdnsPacketWriter(), + serviceType, + config.subtypes, + config.expectUnicastResponse, + config.transactionId, + config.network, + sendDiscoveryQueries, + servicesToResolve) + .call(); + } catch (RuntimeException e) { + sharedLog.e(String.format("Failed to run EnqueueMdnsQueryCallable for subtype: %s", + TextUtils.join(",", config.subtypes)), e); + result = null; + } + synchronized (lock) { + if (MdnsConfigs.useSessionIdToScheduleMdnsTask()) { + // In case that the task is not canceled successfully, use session ID to check + // if this task should continue to schedule more. + if (config.sessionId != currentSessionId) { + return; + } + } + + if (MdnsConfigs.shouldCancelScanTaskWhenFutureIsNull()) { + if (requestTaskFuture == null) { + // If requestTaskFuture is set to null, the task is cancelled. We can't use + // isCancelled() here because this QueryTask is different from the future + // that is returned from executor.schedule(). See b/71646910. + return; + } + } + if ((result != null)) { + for (int i = 0; i < listeners.size(); i++) { + listeners.keyAt(i).onDiscoveryQuerySent(result.second, result.first); + } + } + if (shouldRemoveServiceAfterTtlExpires()) { + Iterator<MdnsResponse> iter = instanceNameToResponse.values().iterator(); + while (iter.hasNext()) { + MdnsResponse existingResponse = iter.next(); + if (existingResponse.hasServiceRecord() + && existingResponse + .getServiceRecord() + .getRemainingTTL(clock.elapsedRealtime()) + == 0) { + iter.remove(); + for (int i = 0; i < listeners.size(); i++) { + if (!responseMatchesOptions(existingResponse, + listeners.valueAt(i))) { + continue; + } + final MdnsServiceBrowserListener listener = listeners.keyAt(i); + if (existingResponse.getServiceInstanceName() != null) { + final MdnsServiceInfo serviceInfo = + buildMdnsServiceInfoFromResponse( + existingResponse, serviceTypeLabels); + if (existingResponse.isComplete()) { + sharedLog.log("TTL expired. onServiceRemoved: " + + serviceInfo); + listener.onServiceRemoved(serviceInfo); + } + sharedLog.log("TTL expired. onServiceNameRemoved: " + + serviceInfo); + listener.onServiceNameRemoved(serviceInfo); + } + } + } + } + } + requestTaskFuture = scheduleNextRunLocked(this.config); + } + } + } + + @NonNull + private Future<?> scheduleNextRunLocked(@NonNull QueryTaskConfig lastRunConfig) { + QueryTaskConfig config = lastRunConfig.getConfigForNextRun(); + return executor.schedule(new QueryTask(config), config.timeToRunNextTaskInMs, MILLISECONDS); + } +} \ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java similarity index 97% rename from service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java index 64c4495..5fd1354 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java
@@ -40,9 +40,9 @@ private static final MdnsLogger LOGGER = new MdnsLogger("MdnsSocket"); static final int INTERFACE_INDEX_UNSPECIFIED = -1; - protected static final InetSocketAddress MULTICAST_IPV4_ADDRESS = + public static final InetSocketAddress MULTICAST_IPV4_ADDRESS = new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT); - protected static final InetSocketAddress MULTICAST_IPV6_ADDRESS = + public static final InetSocketAddress MULTICAST_IPV6_ADDRESS = new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT); private final MulticastNetworkInterfaceProvider multicastNetworkInterfaceProvider; private final MulticastSocket multicastSocket;
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java similarity index 91% rename from service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java index 6a321d1..1144d16 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java
@@ -33,7 +33,6 @@ import java.net.DatagramPacket; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Timer; @@ -47,7 +46,7 @@ * * <p>See https://tools.ietf.org/html/rfc6763 (namely sections 4 and 5). */ -public class MdnsSocketClient { +public class MdnsSocketClient implements MdnsSocketClientBase { private static final String TAG = "MdnsClient"; // TODO: The following values are copied from cast module. We need to think about the @@ -71,7 +70,6 @@ private final Context context; private final byte[] multicastReceiverBuffer = new byte[RECEIVER_BUFFER_SIZE]; @Nullable private final byte[] unicastReceiverBuffer; - private final MdnsResponseDecoder responseDecoder; private final MulticastLock multicastLock; private final boolean useSeparateSocketForUnicast = MdnsConfigs.useSeparateSocketToSendUnicastQuery(); @@ -108,7 +106,6 @@ public MdnsSocketClient(@NonNull Context context, @NonNull MulticastLock multicastLock) { this.context = context; this.multicastLock = multicastLock; - responseDecoder = new MdnsResponseDecoder(new MdnsResponseDecoder.Clock(), null); if (useSeparateSocketForUnicast) { unicastReceiverBuffer = new byte[RECEIVER_BUFFER_SIZE]; } else { @@ -116,11 +113,13 @@ } } + @Override public synchronized void setCallback(@Nullable Callback callback) { this.callback = callback; } @RequiresPermission(permission.CHANGE_WIFI_MULTICAST_STATE) + @Override public synchronized void startDiscovery() throws IOException { if (multicastSocket != null) { LOGGER.w("Discovery is already in progress."); @@ -160,6 +159,7 @@ } @RequiresPermission(permission.CHANGE_WIFI_MULTICAST_STATE) + @Override public void stopDiscovery() { LOGGER.log("Stop discovery."); if (multicastSocket == null && unicastSocket == null) { @@ -208,6 +208,36 @@ } } + @Override + public void sendMulticastPacket(@NonNull DatagramPacket packet, @Nullable Network network) { + if (network != null) { + throw new IllegalArgumentException("This socket client does not support sending to " + + "specific networks"); + } + sendMulticastPacket(packet); + } + + @Override + public void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network) { + if (network != null) { + throw new IllegalArgumentException("This socket client does not support sending to " + + "specific networks"); + } + sendUnicastPacket(packet); + } + + @Override + public void notifyNetworkRequested( + @NonNull MdnsServiceBrowserListener listener, + @Nullable Network network, + @NonNull SocketCreationCallback socketCreationCallback) { + if (network != null) { + throw new IllegalArgumentException("This socket client does not support requesting " + + "specific networks"); + } + socketCreationCallback.onSocketCreated(null); + } + private void sendMdnsPacket(DatagramPacket packet, Queue<DatagramPacket> packetQueueToUse) { if (shouldStopSocketLoop && !MdnsConfigs.allowAddMdnsPacketAfterDiscoveryStops()) { LOGGER.w("sendMdnsPacket() is called after discovery already stopped"); @@ -414,37 +444,27 @@ int interfaceIndex, @Nullable Network network) { int packetNumber = ++receivedPacketNumber; - List<MdnsResponse> responses = new LinkedList<>(); - int errorCode = responseDecoder.decode(packet, responses, interfaceIndex, network); - if (errorCode == MdnsResponseDecoder.SUCCESS) { - if (responseType.equals(MULTICAST_TYPE)) { - receivedMulticastResponse = true; - if (cannotReceiveMulticastResponse.getAndSet(false)) { - // If we are already in the bad state, receiving a multicast response means - // we are recovered. - LOGGER.e( - "Recovered from the state where the phone can't receive any multicast" - + " response"); - } - } else { - receivedUnicastResponse = true; - } - for (MdnsResponse response : responses) { - String serviceInstanceName = response.getServiceInstanceName(); - LOGGER.log("mDNS %s response received: %s at ifIndex %d", responseType, - serviceInstanceName, interfaceIndex); - if (callback != null) { - callback.onResponseReceived(response); - } - } - } else if (errorCode != MdnsResponseErrorCode.ERROR_NOT_RESPONSE_MESSAGE) { + final MdnsPacket response; + try { + response = MdnsResponseDecoder.parseResponse(packet.getData(), packet.getLength()); + } catch (MdnsPacket.ParseException e) { LOGGER.w(String.format("Error while decoding %s packet (%d): %d", - responseType, packetNumber, errorCode)); + responseType, packetNumber, e.code)); if (callback != null) { - callback.onFailedToParseMdnsResponse(packetNumber, errorCode); + callback.onFailedToParseMdnsResponse(packetNumber, e.code, network); } + return e.code; } - return errorCode; + + if (response == null) { + return MdnsResponseErrorCode.ERROR_NOT_RESPONSE_MESSAGE; + } + + if (callback != null) { + callback.onResponseReceived(response, interfaceIndex, network); + } + + return MdnsResponseErrorCode.SUCCESS; } @VisibleForTesting @@ -512,11 +532,4 @@ public boolean isOnIPv6OnlyNetwork() { return multicastSocket != null && multicastSocket.isOnIPv6OnlyNetwork(); } - - /** Callback for {@link MdnsSocketClient}. */ - public interface Callback { - void onResponseReceived(@NonNull MdnsResponse response); - - void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode); - } } \ No newline at end of file
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java new file mode 100644 index 0000000..deadc58 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java
@@ -0,0 +1,89 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Network; +import android.os.Looper; + +import java.io.IOException; +import java.net.DatagramPacket; + +/** + * Base class for multicast socket client. + * + * @hide + */ +public interface MdnsSocketClientBase { + /*** Start mDns discovery on given network. */ + default void startDiscovery() throws IOException { } + + /*** Stop mDns discovery. */ + default void stopDiscovery() { } + + /*** Set callback for receiving mDns response */ + void setCallback(@Nullable Callback callback); + + /** + * Send a mDNS request packet via given network that asks for multicast response. + * + * <p>The socket client may use a null network to identify some or all interfaces, in which case + * passing null sends the packet to these. + */ + void sendMulticastPacket(@NonNull DatagramPacket packet, @Nullable Network network); + + /** + * Send a mDNS request packet via given network that asks for unicast response. + * + * <p>The socket client may use a null network to identify some or all interfaces, in which case + * passing null sends the packet to these. + */ + void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network); + + /*** Notify that the given network is requested for mdns discovery / resolution */ + void notifyNetworkRequested(@NonNull MdnsServiceBrowserListener listener, + @Nullable Network network, @NonNull SocketCreationCallback socketCreationCallback); + + /*** Notify that the network is unrequested */ + default void notifyNetworkUnrequested(@NonNull MdnsServiceBrowserListener listener) { } + + /*** Gets looper that used by the socket client */ + default Looper getLooper() { + return null; + } + + /*** Callback for mdns response */ + interface Callback { + /*** Receive a mdns response */ + void onResponseReceived(@NonNull MdnsPacket packet, int interfaceIndex, + @Nullable Network network); + + /*** Parse a mdns response failed */ + void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode, + @Nullable Network network); + } + + /*** Callback for requested socket creation */ + interface SocketCreationCallback { + /*** Notify requested socket is created */ + void onSocketCreated(@Nullable Network network); + + /*** Notify requested socket is destroyed */ + void onAllSocketsDestroyed(@Nullable Network network); + } +}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java new file mode 100644 index 0000000..2fa1ae4 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
@@ -0,0 +1,671 @@ +/* + * 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 android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread; +import static com.android.server.connectivity.mdns.util.MdnsUtils.isNetworkMatched; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.TetheringManager; +import android.net.TetheringManager.TetheringEventCallback; +import android.os.Handler; +import android.os.Looper; +import android.util.ArrayMap; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.CollectionUtils; +import com.android.net.module.util.LinkPropertiesUtils.CompareResult; +import com.android.net.module.util.SharedLog; + +import java.io.IOException; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.List; + +/** + * The {@link MdnsSocketProvider} manages the multiple sockets for mDns. + * + * <p>This class is not thread safe, it is intended to be used only from the looper thread. + * However, the constructor is an exception, as it is called on another thread; + * therefore for thread safety all members of this class MUST either be final or initialized + * to their default value (0, false or null). + * + */ +public class MdnsSocketProvider { + private static final String TAG = MdnsSocketProvider.class.getSimpleName(); + private static final boolean DBG = MdnsDiscoveryManager.DBG; + // This buffer size matches what MdnsSocketClient uses currently. + // But 1440 should generally be enough because of standard Ethernet. + // Note: mdnsresponder mDNSEmbeddedAPI.h uses 8940 for Ethernet jumbo frames. + private static final int READ_BUFFER_SIZE = 2048; + private static final int IFACE_IDX_NOT_EXIST = -1; + @NonNull private final Context mContext; + @NonNull private final Looper mLooper; + @NonNull private final Handler mHandler; + @NonNull private final Dependencies mDependencies; + @NonNull private final NetworkCallback mNetworkCallback; + @NonNull private final TetheringEventCallback mTetheringEventCallback; + @NonNull private final AbstractSocketNetlink mSocketNetlinkMonitor; + @NonNull private final SharedLog mSharedLog; + private final ArrayMap<Network, SocketInfo> mNetworkSockets = new ArrayMap<>(); + private final ArrayMap<String, SocketInfo> mTetherInterfaceSockets = new ArrayMap<>(); + private final ArrayMap<Network, LinkProperties> mActiveNetworksLinkProperties = + new ArrayMap<>(); + private final ArrayMap<Network, int[]> mActiveNetworksTransports = new ArrayMap<>(); + private final ArrayMap<SocketCallback, Network> mCallbacksToRequestedNetworks = + new ArrayMap<>(); + private final List<String> mLocalOnlyInterfaces = new ArrayList<>(); + private final List<String> mTetheredInterfaces = new ArrayList<>(); + // mIfaceIdxToLinkProperties should not be cleared in maybeStopMonitoringSockets() because + // the netlink monitor is never stop and the old states must be kept. + private final SparseArray<LinkProperties> mIfaceIdxToLinkProperties = new SparseArray<>(); + private final byte[] mPacketReadBuffer = new byte[READ_BUFFER_SIZE]; + private boolean mMonitoringSockets = false; + private boolean mRequestStop = false; + + public MdnsSocketProvider(@NonNull Context context, @NonNull Looper looper, + @NonNull SharedLog sharedLog) { + this(context, looper, new Dependencies(), sharedLog); + } + + MdnsSocketProvider(@NonNull Context context, @NonNull Looper looper, + @NonNull Dependencies deps, @NonNull SharedLog sharedLog) { + mContext = context; + mLooper = looper; + mHandler = new Handler(looper); + mDependencies = deps; + mSharedLog = sharedLog; + mNetworkCallback = new NetworkCallback() { + @Override + public void onLost(Network network) { + mActiveNetworksLinkProperties.remove(network); + mActiveNetworksTransports.remove(network); + removeNetworkSocket(network); + } + + @Override + public void onCapabilitiesChanged(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities) { + mActiveNetworksTransports.put(network, networkCapabilities.getTransportTypes()); + } + + @Override + public void onLinkPropertiesChanged(Network network, LinkProperties lp) { + handleLinkPropertiesChanged(network, lp); + } + }; + mTetheringEventCallback = new TetheringEventCallback() { + @Override + public void onLocalOnlyInterfacesChanged(@NonNull List<String> interfaces) { + handleTetherInterfacesChanged(mLocalOnlyInterfaces, interfaces); + } + + @Override + public void onTetheredInterfacesChanged(@NonNull List<String> interfaces) { + handleTetherInterfacesChanged(mTetheredInterfaces, interfaces); + } + }; + + mSocketNetlinkMonitor = mDependencies.createSocketNetlinkMonitor(mHandler, + mSharedLog.forSubComponent("NetlinkMonitor"), new NetLinkMessageProcessor()); + } + + /** + * Dependencies of MdnsSocketProvider, for injection in tests. + */ + @VisibleForTesting + public static class Dependencies { + /*** Get network interface by given interface name */ + public NetworkInterfaceWrapper getNetworkInterfaceByName(@NonNull String interfaceName) + throws SocketException { + final NetworkInterface ni = NetworkInterface.getByName(interfaceName); + return ni == null ? null : new NetworkInterfaceWrapper(ni); + } + + /*** Create a MdnsInterfaceSocket */ + public MdnsInterfaceSocket createMdnsInterfaceSocket( + @NonNull NetworkInterface networkInterface, int port, @NonNull Looper looper, + @NonNull byte[] packetReadBuffer) throws IOException { + return new MdnsInterfaceSocket(networkInterface, port, looper, packetReadBuffer); + } + + /*** Get network interface by given interface name */ + public int getNetworkInterfaceIndexByName(@NonNull final String ifaceName) { + final NetworkInterface iface; + try { + iface = NetworkInterface.getByName(ifaceName); + } catch (SocketException e) { + Log.e(TAG, "Error querying interface", e); + return IFACE_IDX_NOT_EXIST; + } + if (iface == null) { + Log.e(TAG, "Interface not found: " + ifaceName); + return IFACE_IDX_NOT_EXIST; + } + return iface.getIndex(); + } + /*** Creates a SocketNetlinkMonitor */ + public AbstractSocketNetlink createSocketNetlinkMonitor(@NonNull final Handler handler, + @NonNull final SharedLog log, + @NonNull final NetLinkMonitorCallBack cb) { + return SocketNetLinkMonitorFactory.createNetLinkMonitor(handler, log, cb); + } + } + /** + * The callback interface for the netlink monitor messages. + */ + public interface NetLinkMonitorCallBack { + /** + * Handles the interface address add or update. + */ + void addOrUpdateInterfaceAddress(int ifaceIdx, @NonNull LinkAddress newAddress); + + + /** + * Handles the interface address delete. + */ + void deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress); + } + private class NetLinkMessageProcessor implements NetLinkMonitorCallBack { + + @Override + public void addOrUpdateInterfaceAddress(int ifaceIdx, + @NonNull final LinkAddress newAddress) { + + LinkProperties linkProperties; + linkProperties = mIfaceIdxToLinkProperties.get(ifaceIdx); + if (linkProperties == null) { + linkProperties = new LinkProperties(); + mIfaceIdxToLinkProperties.put(ifaceIdx, linkProperties); + } + boolean updated = linkProperties.addLinkAddress(newAddress); + + if (!updated) { + return; + } + maybeUpdateTetheringSocketAddress(ifaceIdx, linkProperties.getLinkAddresses()); + } + + @Override + public void deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress) { + LinkProperties linkProperties; + boolean updated = false; + linkProperties = mIfaceIdxToLinkProperties.get(ifaceIdx); + if (linkProperties != null) { + updated = linkProperties.removeLinkAddress(deleteAddress); + if (linkProperties.getLinkAddresses().isEmpty()) { + mIfaceIdxToLinkProperties.remove(ifaceIdx); + } + } + + if (linkProperties == null || !updated) { + return; + } + maybeUpdateTetheringSocketAddress(ifaceIdx, linkProperties.getLinkAddresses()); + + } + } + /*** Data class for storing socket related info */ + private static class SocketInfo { + final MdnsInterfaceSocket mSocket; + final List<LinkAddress> mAddresses; + + SocketInfo(MdnsInterfaceSocket socket, List<LinkAddress> addresses) { + mSocket = socket; + mAddresses = new ArrayList<>(addresses); + } + } + + /*** Start monitoring sockets by listening callbacks for sockets creation or removal */ + public void startMonitoringSockets() { + ensureRunningOnHandlerThread(mHandler); + mRequestStop = false; // Reset stop request flag. + if (mMonitoringSockets) { + Log.d(TAG, "Already monitoring sockets."); + return; + } + mSharedLog.i("Start monitoring sockets."); + mContext.getSystemService(ConnectivityManager.class).registerNetworkCallback( + new NetworkRequest.Builder().clearCapabilities().build(), + mNetworkCallback, mHandler); + + final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); + tetheringManager.registerTetheringEventCallback(mHandler::post, mTetheringEventCallback); + + if (mSocketNetlinkMonitor.isSupported()) { + mHandler.post(mSocketNetlinkMonitor::startMonitoring); + } + mMonitoringSockets = true; + } + /** + * Start netlink monitor. + */ + public void startNetLinkMonitor() { + ensureRunningOnHandlerThread(mHandler); + if (mSocketNetlinkMonitor.isSupported()) { + mSocketNetlinkMonitor.startMonitoring(); + } + } + + private void maybeStopMonitoringSockets() { + if (!mMonitoringSockets) return; // Already unregistered. + if (!mRequestStop) return; // No stop request. + + // Only unregister the network callback if there is no socket request. + if (mCallbacksToRequestedNetworks.isEmpty()) { + mSharedLog.i("Stop monitoring sockets."); + mContext.getSystemService(ConnectivityManager.class) + .unregisterNetworkCallback(mNetworkCallback); + + final TetheringManager tetheringManager = mContext.getSystemService( + TetheringManager.class); + tetheringManager.unregisterTetheringEventCallback(mTetheringEventCallback); + // Clear all saved status. + mActiveNetworksLinkProperties.clear(); + mNetworkSockets.clear(); + mTetherInterfaceSockets.clear(); + mLocalOnlyInterfaces.clear(); + mTetheredInterfaces.clear(); + mMonitoringSockets = false; + } + // The netlink monitor is not stopped here because the MdnsSocketProvider need to listen + // to all the netlink updates when the system is up and running. + } + + /*** Request to stop monitoring sockets and unregister callbacks */ + public void requestStopWhenInactive() { + ensureRunningOnHandlerThread(mHandler); + if (!mMonitoringSockets) { + Log.d(TAG, "Monitoring sockets hasn't been started."); + return; + } + mRequestStop = true; + maybeStopMonitoringSockets(); + } + + private boolean matchRequestedNetwork(Network network) { + return hasAllNetworksRequest() + || mCallbacksToRequestedNetworks.containsValue(network); + } + + private boolean hasAllNetworksRequest() { + return mCallbacksToRequestedNetworks.containsValue(null); + } + + private void handleLinkPropertiesChanged(Network network, LinkProperties lp) { + mActiveNetworksLinkProperties.put(network, lp); + if (!matchRequestedNetwork(network)) { + if (DBG) { + Log.d(TAG, "Ignore LinkProperties change. There is no request for the" + + " Network:" + network); + } + return; + } + + final NetworkAsKey networkKey = new NetworkAsKey(network); + final SocketInfo socketInfo = mNetworkSockets.get(network); + if (socketInfo == null) { + createSocket(networkKey, lp); + } else { + updateSocketInfoAddress(network, socketInfo, lp.getLinkAddresses()); + } + } + private void maybeUpdateTetheringSocketAddress(int ifaceIndex, + @NonNull final List<LinkAddress> updatedAddresses) { + for (int i = 0; i < mTetherInterfaceSockets.size(); ++i) { + String tetheringInterfaceName = mTetherInterfaceSockets.keyAt(i); + if (mDependencies.getNetworkInterfaceIndexByName(tetheringInterfaceName) + == ifaceIndex) { + updateSocketInfoAddress(null /* network */, + mTetherInterfaceSockets.valueAt(i), updatedAddresses); + return; + } + } + } + + private void updateSocketInfoAddress(@Nullable final Network network, + @NonNull final SocketInfo socketInfo, + @NonNull final List<LinkAddress> addresses) { + // Update the addresses of this socket. + socketInfo.mAddresses.clear(); + socketInfo.mAddresses.addAll(addresses); + // Try to join the group again. + socketInfo.mSocket.joinGroup(addresses); + + notifyAddressesChanged(network, socketInfo.mSocket, addresses); + } + private LinkProperties createLPForTetheredInterface(@NonNull final String interfaceName, + int ifaceIndex) { + final LinkProperties linkProperties = + new LinkProperties(mIfaceIdxToLinkProperties.get(ifaceIndex)); + linkProperties.setInterfaceName(interfaceName); + return linkProperties; + } + + private void handleTetherInterfacesChanged(List<String> current, List<String> updated) { + if (!hasAllNetworksRequest()) { + // Currently, the network for tethering can not be requested, so the sockets for + // tethering are only created if there is a request for all networks (interfaces). + // Therefore, this change can skip if there is no such request. + if (DBG) { + Log.d(TAG, "Ignore tether interfaces change. There is no request for all" + + " networks."); + } + return; + } + + final CompareResult<String> interfaceDiff = new CompareResult<>( + current, updated); + for (String name : interfaceDiff.added) { + int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(name); + createSocket(LOCAL_NET, createLPForTetheredInterface(name, ifaceIndex)); + } + for (String name : interfaceDiff.removed) { + removeTetherInterfaceSocket(name); + } + current.clear(); + current.addAll(updated); + } + + private void createSocket(NetworkKey networkKey, LinkProperties lp) { + final String interfaceName = lp.getInterfaceName(); + if (interfaceName == null) { + Log.e(TAG, "Can not create socket with null interface name."); + return; + } + + try { + final NetworkInterfaceWrapper networkInterface = + mDependencies.getNetworkInterfaceByName(interfaceName); + // There are no transports for tethered interfaces. Other interfaces should always + // have transports since LinkProperties updates are always sent after + // NetworkCapabilities updates. + final int[] transports; + if (networkKey == LOCAL_NET) { + transports = new int[0]; + } else { + transports = mActiveNetworksTransports.get(((NetworkAsKey) networkKey).mNetwork); + if (transports == null) { + Log.wtf(TAG, "transports is missing for key: " + networkKey); + } + } + if (networkInterface == null || !isMdnsCapableInterface(networkInterface, transports)) { + return; + } + + mSharedLog.log("Create socket on net:" + networkKey + ", ifName:" + interfaceName); + final MdnsInterfaceSocket socket = mDependencies.createMdnsInterfaceSocket( + networkInterface.getNetworkInterface(), MdnsConstants.MDNS_PORT, mLooper, + mPacketReadBuffer); + final List<LinkAddress> addresses = lp.getLinkAddresses(); + if (networkKey == LOCAL_NET) { + mTetherInterfaceSockets.put(interfaceName, new SocketInfo(socket, addresses)); + } else { + mNetworkSockets.put(((NetworkAsKey) networkKey).mNetwork, + new SocketInfo(socket, addresses)); + } + // Try to join IPv4/IPv6 group. + socket.joinGroup(addresses); + + // Notify the listeners which need this socket. + if (networkKey == LOCAL_NET) { + notifySocketCreated(null /* network */, socket, addresses); + } else { + notifySocketCreated(((NetworkAsKey) networkKey).mNetwork, socket, addresses); + } + } catch (IOException e) { + mSharedLog.e("Create socket failed ifName:" + interfaceName, e); + } + } + + private boolean isMdnsCapableInterface( + @NonNull NetworkInterfaceWrapper iface, @NonNull int[] transports) { + try { + // Never try mDNS on cellular, or on interfaces with incompatible flags + if (CollectionUtils.contains(transports, TRANSPORT_CELLULAR) + || iface.isLoopback() + || iface.isPointToPoint() + || iface.isVirtual() + || !iface.isUp()) { + return false; + } + + // Otherwise, always try mDNS on non-VPN Wifi. + if (!CollectionUtils.contains(transports, TRANSPORT_VPN) + && CollectionUtils.contains(transports, TRANSPORT_WIFI)) { + return true; + } + + // For other transports, or no transports (tethering downstreams), do mDNS based on the + // interface flags. This is not always reliable (for example some Wifi interfaces may + // not have the MULTICAST flag even though they can do mDNS, and some cellular + // interfaces may have the BROADCAST or MULTICAST flags), so checks are done based on + // transports above in priority. + return iface.supportsMulticast(); + } catch (SocketException e) { + mSharedLog.e("Error checking interface flags", e); + return false; + } + } + + private void removeNetworkSocket(Network network) { + final SocketInfo socketInfo = mNetworkSockets.remove(network); + if (socketInfo == null) return; + + socketInfo.mSocket.destroy(); + notifyInterfaceDestroyed(network, socketInfo.mSocket); + mSharedLog.log("Remove socket on net:" + network); + } + + private void removeTetherInterfaceSocket(String interfaceName) { + final SocketInfo socketInfo = mTetherInterfaceSockets.remove(interfaceName); + if (socketInfo == null) return; + socketInfo.mSocket.destroy(); + notifyInterfaceDestroyed(null /* network */, socketInfo.mSocket); + mSharedLog.log("Remove socket on ifName:" + interfaceName); + } + + private void notifySocketCreated(Network network, MdnsInterfaceSocket socket, + List<LinkAddress> addresses) { + for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) { + final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i); + if (isNetworkMatched(requestedNetwork, network)) { + mCallbacksToRequestedNetworks.keyAt(i).onSocketCreated(network, socket, addresses); + } + } + } + + private void notifyInterfaceDestroyed(Network network, MdnsInterfaceSocket socket) { + for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) { + final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i); + if (isNetworkMatched(requestedNetwork, network)) { + mCallbacksToRequestedNetworks.keyAt(i).onInterfaceDestroyed(network, socket); + } + } + } + + private void notifyAddressesChanged(Network network, MdnsInterfaceSocket socket, + List<LinkAddress> addresses) { + for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) { + final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i); + if (isNetworkMatched(requestedNetwork, network)) { + mCallbacksToRequestedNetworks.keyAt(i) + .onAddressesChanged(network, socket, addresses); + } + } + } + + private void retrieveAndNotifySocketFromNetwork(Network network, SocketCallback cb) { + final SocketInfo socketInfo = mNetworkSockets.get(network); + if (socketInfo == null) { + final LinkProperties lp = mActiveNetworksLinkProperties.get(network); + if (lp == null) { + // The requested network is not existed. Maybe wait for LinkProperties change later. + if (DBG) Log.d(TAG, "There is no LinkProperties for this network:" + network); + return; + } + createSocket(new NetworkAsKey(network), lp); + } else { + // Notify the socket for requested network. + cb.onSocketCreated(network, socketInfo.mSocket, socketInfo.mAddresses); + } + } + + private void retrieveAndNotifySocketFromInterface(String interfaceName, SocketCallback cb) { + final SocketInfo socketInfo = mTetherInterfaceSockets.get(interfaceName); + if (socketInfo == null) { + int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(interfaceName); + createSocket( + LOCAL_NET, + createLPForTetheredInterface(interfaceName, ifaceIndex)); + } else { + // Notify the socket for requested network. + cb.onSocketCreated( + null /* network */, socketInfo.mSocket, socketInfo.mAddresses); + } + } + + /** + * Request a socket for given network. + * + * @param network the required network for a socket. Null means create sockets on all possible + * networks (interfaces). + * @param cb the callback to listen the socket creation. + */ + public void requestSocket(@Nullable Network network, @NonNull SocketCallback cb) { + ensureRunningOnHandlerThread(mHandler); + mSharedLog.log("requestSocket for net:" + network); + mCallbacksToRequestedNetworks.put(cb, network); + if (network == null) { + // Does not specify a required network, create sockets for all possible + // networks (interfaces). + for (int i = 0; i < mActiveNetworksLinkProperties.size(); i++) { + retrieveAndNotifySocketFromNetwork(mActiveNetworksLinkProperties.keyAt(i), cb); + } + + for (String localInterface : mLocalOnlyInterfaces) { + retrieveAndNotifySocketFromInterface(localInterface, cb); + } + + for (String tetheredInterface : mTetheredInterfaces) { + retrieveAndNotifySocketFromInterface(tetheredInterface, cb); + } + } else { + retrieveAndNotifySocketFromNetwork(network, cb); + } + } + + /*** Unrequest the socket */ + public void unrequestSocket(@NonNull SocketCallback cb) { + ensureRunningOnHandlerThread(mHandler); + mSharedLog.log("unrequestSocket"); + mCallbacksToRequestedNetworks.remove(cb); + if (hasAllNetworksRequest()) { + // Still has a request for all networks (interfaces). + return; + } + + // Check if remaining requests are matched any of sockets. + for (int i = mNetworkSockets.size() - 1; i >= 0; i--) { + final Network network = mNetworkSockets.keyAt(i); + if (matchRequestedNetwork(network)) continue; + final SocketInfo info = mNetworkSockets.removeAt(i); + info.mSocket.destroy(); + mSharedLog.log("Remove socket on net:" + network + " after unrequestSocket"); + } + + // Remove all sockets for tethering interface because these sockets do not have associated + // networks, and they should invoke by a request for all networks (interfaces). If there is + // no such request, the sockets for tethering interface should be removed. + for (int i = mTetherInterfaceSockets.size() - 1; i >= 0; i--) { + final SocketInfo info = mTetherInterfaceSockets.valueAt(i); + info.mSocket.destroy(); + mSharedLog.log("Remove socket on ifName:" + mTetherInterfaceSockets.keyAt(i) + + " after unrequestSocket"); + } + mTetherInterfaceSockets.clear(); + + // Try to unregister network callback. + maybeStopMonitoringSockets(); + } + + + /*** Callbacks for listening socket changes */ + public interface SocketCallback { + /*** Notify the socket is created */ + default void onSocketCreated(@Nullable Network network, @NonNull MdnsInterfaceSocket socket, + @NonNull List<LinkAddress> addresses) {} + /*** Notify the interface is destroyed */ + default void onInterfaceDestroyed(@Nullable Network network, + @NonNull MdnsInterfaceSocket socket) {} + /*** Notify the addresses is changed on the network */ + default void onAddressesChanged(@Nullable Network network, + @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) {} + } + + private interface NetworkKey { + } + + private static final NetworkKey LOCAL_NET = new NetworkKey() { + @Override + public String toString() { + return "NetworkKey:LOCAL_NET"; + } + }; + + private static class NetworkAsKey implements NetworkKey { + private final Network mNetwork; + + NetworkAsKey(Network network) { + this.mNetwork = network; + } + + @Override + public int hashCode() { + return mNetwork.hashCode(); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof NetworkAsKey)) { + return false; + } + return mNetwork.equals(((NetworkAsKey) other).mNetwork); + } + + @Override + public String toString() { + return "NetworkAsKey{ network=" + mNetwork + " }"; + } + } +}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsTextRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsTextRecord.java similarity index 100% rename from service/mdns/com/android/server/connectivity/mdns/MdnsTextRecord.java rename to service-t/src/com/android/server/connectivity/mdns/MdnsTextRecord.java
diff --git a/service/mdns/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java b/service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java similarity index 98% rename from service/mdns/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java rename to service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java index ade7b95..f248c98 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java +++ b/service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java
@@ -148,7 +148,7 @@ } /*** Check whether given network interface can support mdns */ - public static boolean canScanOnInterface(@Nullable NetworkInterfaceWrapper networkInterface) { + private static boolean canScanOnInterface(@Nullable NetworkInterfaceWrapper networkInterface) { try { if ((networkInterface == null) || networkInterface.isLoopback()
diff --git a/service-t/src/com/android/server/connectivity/mdns/MulticastPacketReader.java b/service-t/src/com/android/server/connectivity/mdns/MulticastPacketReader.java new file mode 100644 index 0000000..63119ac --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/MulticastPacketReader.java
@@ -0,0 +1,123 @@ +/* + * 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.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread; + +import android.annotation.NonNull; +import android.os.Handler; +import android.os.ParcelFileDescriptor; +import android.system.Os; +import android.util.ArraySet; + +import com.android.net.module.util.FdEventsReader; + +import java.io.FileDescriptor; +import java.net.InetSocketAddress; +import java.util.Set; + +/** Simple reader for mDNS packets. */ +public class MulticastPacketReader extends FdEventsReader<MulticastPacketReader.RecvBuffer> { + @NonNull + private final String mLogTag; + @NonNull + private final ParcelFileDescriptor mSocket; + @NonNull + private final Handler mHandler; + @NonNull + private final Set<PacketHandler> mPacketHandlers = new ArraySet<>(); + + interface PacketHandler { + void handlePacket(byte[] recvbuf, int length, InetSocketAddress src); + } + + public static final class RecvBuffer { + final byte[] data; + final InetSocketAddress src; + + private RecvBuffer(byte[] data, InetSocketAddress src) { + this.data = data; + this.src = src; + } + } + + /** + * Create a new {@link MulticastPacketReader}. + * @param socket Socket to read from. This will *not* be closed when the reader terminates. + * @param buffer Buffer to read packets into. Will only be used from the handler thread. + * @param port the port number for the socket + */ + protected MulticastPacketReader(@NonNull String interfaceTag, + @NonNull ParcelFileDescriptor socket, @NonNull Handler handler, + @NonNull byte[] buffer) { + // Set the port to zero as placeholder as the recvfrom() call will fill the actual port + // value later. + super(handler, new RecvBuffer(buffer, new InetSocketAddress(0 /* port */))); + mLogTag = MulticastPacketReader.class.getSimpleName() + "/" + interfaceTag; + mSocket = socket; + mHandler = handler; + } + + @Override + protected int recvBufSize(@NonNull RecvBuffer buffer) { + return buffer.data.length; + } + + @Override + protected FileDescriptor createFd() { + // Keep a reference to the PFD as it would close the fd in its finalizer otherwise + return mSocket.getFileDescriptor(); + } + + @Override + protected void onStop() { + // Do nothing (do not close the FD) + } + + @Override + protected int readPacket(@NonNull FileDescriptor fd, @NonNull RecvBuffer buffer) + throws Exception { + return Os.recvfrom( + fd, buffer.data, 0, buffer.data.length, 0 /* flags */, buffer.src); + } + + @Override + protected void handlePacket(@NonNull RecvBuffer recvbuf, int length) { + for (PacketHandler handler : mPacketHandlers) { + handler.handlePacket(recvbuf.data, length, recvbuf.src); + } + } + + /** + * Add a packet handler to deal with received packets. If the handler is already set, + * this is a no-op. + */ + public void addPacketHandler(@NonNull PacketHandler handler) { + ensureRunningOnHandlerThread(mHandler); + mPacketHandlers.add(handler); + } + + /** + * Remove a packet handler added via {@link #addPacketHandler}. If the handler was not set, + * this is a no-op. + */ + public void removePacketHandler(@NonNull PacketHandler handler) { + ensureRunningOnHandlerThread(mHandler); + mPacketHandlers.remove(handler); + } +} +
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/NameConflictException.java similarity index 64% rename from service/mdns/com/android/server/connectivity/mdns/MdnsAdvertiser.java rename to service-t/src/com/android/server/connectivity/mdns/NameConflictException.java index dee78fd..c123d02 100644 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsAdvertiser.java +++ b/service-t/src/com/android/server/connectivity/mdns/NameConflictException.java
@@ -16,14 +16,15 @@ package com.android.server.connectivity.mdns; -import android.util.Log; - /** - * MdnsAdvertiser manages advertising services per {@link com.android.server.NsdService} requests. - * - * TODO: implement + * An exception thrown when a service name conflicts with an existing service. */ -public class MdnsAdvertiser { - private static final String TAG = MdnsAdvertiser.class.getSimpleName(); - public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); +public class NameConflictException extends Exception { + /** + * ID of the existing service that conflicted. + */ + public final int conflictingServiceId; + public NameConflictException(int conflictingServiceId) { + this.conflictingServiceId = conflictingServiceId; + } }
diff --git a/service/mdns/com/android/server/connectivity/mdns/NetworkInterfaceWrapper.java b/service-t/src/com/android/server/connectivity/mdns/NetworkInterfaceWrapper.java similarity index 100% rename from service/mdns/com/android/server/connectivity/mdns/NetworkInterfaceWrapper.java rename to service-t/src/com/android/server/connectivity/mdns/NetworkInterfaceWrapper.java
diff --git a/service-t/src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java b/service-t/src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java new file mode 100644 index 0000000..6bc7941 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java
@@ -0,0 +1,41 @@ +/* + * 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 android.annotation.NonNull; +import android.os.Handler; + +import com.android.net.module.util.SharedLog; +import com.android.server.connectivity.mdns.internal.SocketNetlinkMonitor; + +/** + * The factory class for creating the netlink monitor. + */ +public class SocketNetLinkMonitorFactory { + + /** + * Creates a new netlink monitor. + */ + public static AbstractSocketNetlink createNetLinkMonitor(@NonNull final Handler handler, + @NonNull SharedLog log, @NonNull MdnsSocketProvider.NetLinkMonitorCallBack cb) { + return new SocketNetlinkMonitor(handler, log, cb); + } + + private SocketNetLinkMonitorFactory() { + } + +}
diff --git a/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java b/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java new file mode 100644 index 0000000..451909c --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java
@@ -0,0 +1,92 @@ +/* + * 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.internal; + +import android.annotation.NonNull; +import android.net.LinkAddress; +import android.os.Handler; +import android.system.OsConstants; +import android.util.Log; + +import com.android.net.module.util.SharedLog; +import com.android.net.module.util.ip.NetlinkMonitor; +import com.android.net.module.util.netlink.NetlinkConstants; +import com.android.net.module.util.netlink.NetlinkMessage; +import com.android.net.module.util.netlink.RtNetlinkAddressMessage; +import com.android.net.module.util.netlink.StructIfaddrMsg; +import com.android.server.connectivity.mdns.AbstractSocketNetlink; +import com.android.server.connectivity.mdns.MdnsSocketProvider; + +/** + * The netlink monitor for MdnsSocketProvider. + */ +public class SocketNetlinkMonitor extends NetlinkMonitor implements AbstractSocketNetlink { + + public static final String TAG = SocketNetlinkMonitor.class.getSimpleName(); + + @NonNull + private final MdnsSocketProvider.NetLinkMonitorCallBack mCb; + public SocketNetlinkMonitor(@NonNull final Handler handler, + @NonNull SharedLog log, + @NonNull final MdnsSocketProvider.NetLinkMonitorCallBack cb) { + super(handler, log, TAG, OsConstants.NETLINK_ROUTE, + NetlinkConstants.RTMGRP_IPV4_IFADDR | NetlinkConstants.RTMGRP_IPV6_IFADDR); + mCb = cb; + } + @Override + public void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) { + if (nlMsg instanceof RtNetlinkAddressMessage) { + processRtNetlinkAddressMessage((RtNetlinkAddressMessage) nlMsg); + } + } + + /** + * Process the RTM_NEWADDR and RTM_DELADDR netlink message. + */ + private void processRtNetlinkAddressMessage(RtNetlinkAddressMessage msg) { + final StructIfaddrMsg ifaddrMsg = msg.getIfaddrHeader(); + final LinkAddress la = new LinkAddress(msg.getIpAddress(), ifaddrMsg.prefixLen, + msg.getFlags(), ifaddrMsg.scope); + switch (msg.getHeader().nlmsg_type) { + case NetlinkConstants.RTM_NEWADDR: + if (la.isPreferred()) { + mCb.addOrUpdateInterfaceAddress(ifaddrMsg.index, la); + } + break; + case NetlinkConstants.RTM_DELADDR: + mCb.deleteInterfaceAddress(ifaddrMsg.index, la); + break; + default: + Log.e(TAG, "Unknown rtnetlink address msg type " + msg.getHeader().nlmsg_type); + } + } + + @Override + public boolean isSupported() { + return true; + } + + @Override + public void startMonitoring() { + this.start(); + } + + @Override + public void stopMonitoring() { + this.stop(); + } +}
diff --git a/service/mdns/com/android/server/connectivity/mdns/util/MdnsLogger.java b/service-t/src/com/android/server/connectivity/mdns/util/MdnsLogger.java similarity index 100% rename from service/mdns/com/android/server/connectivity/mdns/util/MdnsLogger.java rename to service-t/src/com/android/server/connectivity/mdns/util/MdnsLogger.java
diff --git a/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java new file mode 100644 index 0000000..bc94869 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
@@ -0,0 +1,155 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Network; +import android.os.Handler; + +import com.android.server.connectivity.mdns.MdnsConstants; +import com.android.server.connectivity.mdns.MdnsRecord; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; + +/** + * Mdns utility functions. + */ +public class MdnsUtils { + + private MdnsUtils() { } + + /** + * Convert the string to DNS case-insensitive lowercase + * + * Per rfc6762#page-46, accented characters are not defined to be automatically equivalent to + * their unaccented counterparts. So the "DNS lowercase" should be if character is A-Z then they + * transform into a-z. Otherwise, they are kept as-is. + */ + public static String toDnsLowerCase(@NonNull String string) { + final char[] outChars = new char[string.length()]; + for (int i = 0; i < string.length(); i++) { + outChars[i] = toDnsLowerCase(string.charAt(i)); + } + return new String(outChars); + } + + /** + * Convert the array of labels to DNS case-insensitive lowercase. + */ + public static String[] toDnsLabelsLowerCase(@NonNull String[] labels) { + final String[] outStrings = new String[labels.length]; + for (int i = 0; i < labels.length; ++i) { + outStrings[i] = toDnsLowerCase(labels[i]); + } + return outStrings; + } + + /** + * Compare two strings by DNS case-insensitive lowercase. + */ + public static boolean equalsIgnoreDnsCase(@NonNull String a, @NonNull String b) { + if (a.length() != b.length()) return false; + for (int i = 0; i < a.length(); i++) { + if (toDnsLowerCase(a.charAt(i)) != toDnsLowerCase(b.charAt(i))) { + return false; + } + } + return true; + } + + /** + * Compare two set of DNS labels by DNS case-insensitive lowercase. + */ + public static boolean equalsDnsLabelIgnoreDnsCase(@NonNull String[] a, @NonNull String[] b) { + if (a == b) { + return true; + } + int length = a.length; + if (b.length != length) { + return false; + } + for (int i = 0; i < length; i++) { + if (!equalsIgnoreDnsCase(a[i], b[i])) { + return false; + } + } + return true; + } + + /** + * Compare labels a equals b or a is suffix of b. + * + * @param a the type or subtype. + * @param b the base type + */ + public static boolean typeEqualsOrIsSubtype(@NonNull String[] a, + @NonNull String[] b) { + return MdnsUtils.equalsDnsLabelIgnoreDnsCase(a, b) + || ((b.length == (a.length + 2)) + && MdnsUtils.equalsIgnoreDnsCase(b[1], MdnsConstants.SUBTYPE_LABEL) + && MdnsRecord.labelsAreSuffix(a, b)); + } + + private static char toDnsLowerCase(char a) { + return a >= 'A' && a <= 'Z' ? (char) (a + ('a' - 'A')) : a; + } + + /*** Ensure that current running thread is same as given handler thread */ + public static void ensureRunningOnHandlerThread(@NonNull Handler handler) { + if (!isRunningOnHandlerThread(handler)) { + throw new IllegalStateException( + "Not running on Handler thread: " + Thread.currentThread().getName()); + } + } + + /*** Check that current running thread is same as given handler thread */ + public static boolean isRunningOnHandlerThread(@NonNull Handler handler) { + if (handler.getLooper().getThread() == Thread.currentThread()) { + return true; + } + return false; + } + + /*** Check whether the target network is matched current network */ + public static boolean isNetworkMatched(@Nullable Network targetNetwork, + @Nullable Network currentNetwork) { + return targetNetwork == null || targetNetwork.equals(currentNetwork); + } + + /** + * Truncate a service name to up to maxLength UTF-8 bytes. + */ + public static String truncateServiceName(@NonNull String originalName, int maxLength) { + // UTF-8 is at most 4 bytes per character; return early in the common case where + // the name can't possibly be over the limit given its string length. + if (originalName.length() <= maxLength / 4) return originalName; + + final Charset utf8 = StandardCharsets.UTF_8; + final CharsetEncoder encoder = utf8.newEncoder(); + final ByteBuffer out = ByteBuffer.allocate(maxLength); + // encode will write as many characters as possible to the out buffer, and just + // return an overflow code if there were too many characters (no need to check the + // return code here, this method truncates the name on purpose). + encoder.encode(CharBuffer.wrap(originalName), out, true /* endOfInput */); + return new String(out.array(), 0, out.position(), utf8); + } +} \ No newline at end of file
diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 0605abe..6776920 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
@@ -20,7 +20,6 @@ import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; -import android.net.ConnectivityResources; import android.net.EthernetManager; import android.net.EthernetNetworkSpecifier; import android.net.IpConfiguration; @@ -50,6 +49,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.net.module.util.InterfaceParams; +import com.android.server.connectivity.ConnectivityResources; import java.io.FileDescriptor; import java.util.Objects; @@ -469,9 +469,7 @@ // TODO: Update this logic to only do a restart if required. Although a restart may // be required due to the capabilities or ipConfiguration values, not all // capabilities changes require a restart. - if (mIpClient != null) { - restart(); - } + maybeRestart(); } boolean isRestricted() { @@ -491,10 +489,19 @@ mDeps.makeIpClient(mContext, name, mIpClientCallback); mIpClientCallback.awaitIpClientStart(); + if (mIpConfig.getProxySettings() == ProxySettings.STATIC + || mIpConfig.getProxySettings() == ProxySettings.PAC) { + mIpClient.setHttpProxy(mIpConfig.getHttpProxy()); + } + if (sTcpBufferSizes == null) { sTcpBufferSizes = mDeps.getTcpBufferSizesFromResource(mContext); } - provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes); + if (!TextUtils.isEmpty(sTcpBufferSizes)) { + mIpClient.setTcpBufferSizes(sTcpBufferSizes); + } + + mIpClient.startProvisioning(createProvisioningConfiguration(mIpConfig)); } void onIpLayerStarted(@NonNull final LinkProperties linkProperties) { @@ -540,7 +547,7 @@ // Send a callback in case a provisioning request was in progress. return; } - restart(); + maybeRestart(); } private void ensureRunningOnEthernetHandlerThread() { @@ -573,7 +580,7 @@ // If there is a better network, that will become default and apps // will be able to use internet. If ethernet gets connected again, // and has backhaul connectivity, it will become default. - restart(); + maybeRestart(); } /** Returns true if state has been modified */ @@ -635,20 +642,6 @@ mRequestIds.clear(); } - private static void provisionIpClient(@NonNull final IpClientManager ipClient, - @NonNull final IpConfiguration config, @NonNull final String tcpBufferSizes) { - if (config.getProxySettings() == ProxySettings.STATIC || - config.getProxySettings() == ProxySettings.PAC) { - ipClient.setHttpProxy(config.getHttpProxy()); - } - - if (!TextUtils.isEmpty(tcpBufferSizes)) { - ipClient.setTcpBufferSizes(tcpBufferSizes); - } - - ipClient.startProvisioning(createProvisioningConfiguration(config)); - } - private static ProvisioningConfiguration createProvisioningConfiguration( @NonNull final IpConfiguration config) { if (config.getIpAssignment() == IpAssignment.STATIC) { @@ -661,8 +654,16 @@ .build(); } - void restart() { - if (DBG) Log.d(TAG, "reconnecting Ethernet"); + void maybeRestart() { + if (mIpClient == null) { + // If maybeRestart() is called from a provisioning failure, it is + // possible that link disappeared in the meantime. In that + // case, stop() has already been called and IpClient should not + // get restarted to prevent a provisioning failure loop. + Log.i(TAG, String.format("maybeRestart() called on stopped interface %s", name)); + return; + } + if (DBG) Log.d(TAG, "restart IpClient"); stop(); start(); }
diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index f6a55c8..e7af569 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
@@ -92,7 +92,7 @@ @Override public String[] getAvailableInterfaces() throws RemoteException { PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); - return mTracker.getInterfaces(checkUseRestrictedNetworksPermission()); + return mTracker.getClientModeInterfaces(checkUseRestrictedNetworksPermission()); } /**
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 852cf42..1f22b02 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -25,7 +25,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.net.ConnectivityResources; import android.net.EthernetManager; import android.net.IEthernetServiceListener; import android.net.INetd; @@ -57,6 +56,7 @@ import com.android.net.module.util.netlink.NetlinkMessage; import com.android.net.module.util.netlink.RtNetlinkLinkMessage; import com.android.net.module.util.netlink.StructIfinfoMsg; +import com.android.server.connectivity.ConnectivityResources; import java.io.FileDescriptor; import java.net.InetAddress; @@ -385,7 +385,7 @@ return mFactory.hasInterface(iface); } - String[] getInterfaces(boolean includeRestricted) { + String[] getClientModeInterfaces(boolean includeRestricted) { return mFactory.getAvailableInterfaces(includeRestricted); } @@ -428,9 +428,12 @@ // Remote process has already died return; } - for (String iface : getInterfaces(canUseRestrictedNetworks)) { + for (String iface : getClientModeInterfaces(canUseRestrictedNetworks)) { unicastInterfaceStateChange(listener, iface); } + if (mTetheringInterfaceMode == INTERFACE_MODE_SERVER) { + unicastInterfaceStateChange(listener, mTetheringInterface); + } unicastEthernetStateChange(listener, mEthernetState); });
diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java index 8161f50..5f66f47 100644 --- a/service-t/src/com/android/server/net/NetworkStatsFactory.java +++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java
@@ -34,8 +34,6 @@ import java.io.IOException; import java.net.ProtocolException; -import java.util.Arrays; -import java.util.HashSet; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -86,12 +84,9 @@ * are expected to monotonically increase since device boot. */ @NonNull - public NetworkStats getNetworkStatsDetail(int limitUid, @Nullable String[] limitIfaces, - int limitTag) throws IOException { + public NetworkStats getNetworkStatsDetail() throws IOException { final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0); - // TODO: remove both path and useBpfStats arguments. - // The path is never used if useBpfStats is true. - final int ret = nativeReadNetworkStatsDetail(stats, limitUid, limitIfaces, limitTag); + final int ret = nativeReadNetworkStatsDetail(stats); if (ret != 0) { throw new IOException("Failed to parse network stats"); } @@ -147,36 +142,6 @@ } /** - * Get a set of interfaces containing specified ifaces and stacked interfaces. - * - * <p>The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces - * on which the specified ones are stacked. Stacked interfaces are those noted with - * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method - * is called are guaranteed to be included. - */ - public String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) { - if (requiredIfaces == NetworkStats.INTERFACES_ALL) { - return null; - } - - HashSet<String> relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces)); - // ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse - // elements as they existed upon construction exactly once, and may - // (but are not guaranteed to) reflect any modifications subsequent to construction". - // This is enough here. - for (Map.Entry<String, String> entry : mStackedIfaces.entrySet()) { - if (relatedIfaces.contains(entry.getKey())) { - relatedIfaces.add(entry.getValue()); - } else if (relatedIfaces.contains(entry.getValue())) { - relatedIfaces.add(entry.getKey()); - } - } - - String[] outArray = new String[relatedIfaces.size()]; - return relatedIfaces.toArray(outArray); - } - - /** * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) */ @@ -200,16 +165,6 @@ } /** - * Parse and return interface-level summary {@link NetworkStats} measured - * using {@code /proc/net/dev} style hooks, which may include non IP layer - * traffic. Values monotonically increase since device boot, and may include - * details about inactive interfaces. - */ - public NetworkStats readNetworkStatsSummaryDev() throws IOException { - return mDeps.getNetworkStatsDev(); - } - - /** * Parse and return interface-level summary {@link NetworkStats}. Designed * to return only IP layer traffic. Values monotonically increase since * device boot, and may include details about inactive interfaces. @@ -255,8 +210,7 @@ requestSwapActiveStatsMapLocked(); // Stats are always read from the inactive map, so they must be read after the // swap - final NetworkStats stats = mDeps.getNetworkStatsDetail( - UID_ALL, INTERFACES_ALL, TAG_ALL); + final NetworkStats stats = mDeps.getNetworkStatsDetail(); // BPF stats are incremental; fold into mPersistSnapshot. mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime()); mPersistSnapshot.combineAllValues(stats); @@ -343,8 +297,7 @@ * are expected to monotonically increase since device boot. */ @VisibleForTesting - public static native int nativeReadNetworkStatsDetail(NetworkStats stats, int limitUid, - String[] limitIfaces, int limitTag); + public static native int nativeReadNetworkStatsDetail(NetworkStats stats); @VisibleForTesting public static native int nativeReadNetworkStatsDev(NetworkStats stats);
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index cf53002..e7ef510 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -46,6 +46,7 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.MATCH_MOBILE; +import static android.net.NetworkTemplate.MATCH_TEST; import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; @@ -69,6 +70,7 @@ import android.annotation.Nullable; import android.annotation.TargetApi; import android.app.AlarmManager; +import android.app.BroadcastOptions; import android.app.PendingIntent; import android.app.usage.NetworkStatsManager; import android.content.ApexEnvironment; @@ -82,7 +84,6 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.net.ConnectivityManager; -import android.net.ConnectivityResources; import android.net.DataUsageRequest; import android.net.INetd; import android.net.INetworkStatsService; @@ -105,6 +106,7 @@ import android.net.TetherStatsParcel; import android.net.TetheringManager; import android.net.TrafficStats; +import android.net.TransportInfo; import android.net.UnderlyingNetworkInfo; import android.net.Uri; import android.net.netstats.IUsageCallback; @@ -112,8 +114,10 @@ import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; +import android.net.wifi.WifiInfo; import android.os.Binder; import android.os.Build; +import android.os.Bundle; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; @@ -149,6 +153,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FileRotator; +import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.BaseNetdUnsolicitedEventListener; import com.android.net.module.util.BestClock; import com.android.net.module.util.BinderUtils; @@ -166,7 +171,11 @@ import com.android.net.module.util.Struct.U8; import com.android.net.module.util.bpf.CookieTagMapKey; import com.android.net.module.util.bpf.CookieTagMapValue; +import com.android.networkstack.apishim.BroadcastOptionsShimImpl; +import com.android.networkstack.apishim.ConstantsShim; +import com.android.networkstack.apishim.common.UnsupportedApiLevelException; import com.android.server.BpfNetMaps; +import com.android.server.connectivity.ConnectivityResources; import java.io.File; import java.io.FileDescriptor; @@ -333,13 +342,11 @@ } } - Config getDevConfig(); Config getXtConfig(); Config getUidConfig(); Config getUidTagConfig(); long getGlobalAlertBytes(long def); - long getDevPersistBytes(long def); long getXtPersistBytes(long def); long getUidPersistBytes(long def); long getUidTagPersistBytes(long def); @@ -389,8 +396,6 @@ private final Semaphore mStatsProviderSem = new Semaphore(0, true); @GuardedBy("mStatsLock") - private NetworkStatsRecorder mDevRecorder; - @GuardedBy("mStatsLock") private NetworkStatsRecorder mXtRecorder; @GuardedBy("mStatsLock") private NetworkStatsRecorder mUidRecorder; @@ -526,8 +531,24 @@ case MSG_BROADCAST_NETWORK_STATS_UPDATED: { final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + Bundle opts = null; + if (SdkLevel.isAtLeastU()) { + try { + // This allows us to discard older broadcasts still waiting to + // be delivered. + opts = BroadcastOptionsShimImpl.newInstance( + BroadcastOptions.makeBasic()) + .setDeliveryGroupPolicy( + ConstantsShim.DELIVERY_GROUP_POLICY_MOST_RECENT) + .setDeferralPolicy( + ConstantsShim.DEFERRAL_POLICY_UNTIL_ACTIVE) + .toBundle(); + } catch (UnsupportedApiLevelException e) { + Log.wtf(TAG, "Using unsupported API" + e); + } + } mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL, - READ_NETWORK_USAGE_HISTORY); + READ_NETWORK_USAGE_HISTORY, opts); break; } } @@ -844,8 +865,6 @@ mSystemReady = true; // create data recorders along with historical rotators - mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false, mStatsDir, - true /* wipeOnError */); mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false, mStatsDir, true /* wipeOnError */); mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false, mStatsDir, @@ -928,7 +947,11 @@ @GuardedBy("mStatsLock") private void shutdownLocked() { final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); - tetheringManager.unregisterTetheringEventCallback(mTetherListener); + try { + tetheringManager.unregisterTetheringEventCallback(mTetherListener); + } catch (IllegalStateException e) { + Log.i(TAG, "shutdownLocked: error when unregister tethering, ignored. e=" + e); + } mContext.unregisterReceiver(mPollReceiver); mContext.unregisterReceiver(mRemovedReceiver); mContext.unregisterReceiver(mUserReceiver); @@ -943,7 +966,6 @@ final long currentTime = mClock.millis(); // persist any pending stats - mDevRecorder.forcePersistLocked(currentTime); mXtRecorder.forcePersistLocked(currentTime); mUidRecorder.forcePersistLocked(currentTime); mUidTagRecorder.forcePersistLocked(currentTime); @@ -1010,8 +1032,17 @@ Log.i(TAG, "Starting import : attempts " + attempts + "/" + targetAttempts); } + // Still create a legacy dev recorder locally but the service doesn't really use it. + // This is for backward compatibility where the OEMs might call readPlatformCollection to + // perform proprietary operations and relying on the side-effects to complete the follow-up + // import process. + final NetworkStatsSettings.Config devConfig = + new NetworkStatsSettings.Config(HOUR_IN_MILLIS, + 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); + final NetworkStatsRecorder devRecorder = buildRecorder(PREFIX_DEV, devConfig, + false, mStatsDir, true /* wipeOnError */); final MigrationInfo[] migrations = new MigrationInfo[]{ - new MigrationInfo(mDevRecorder), new MigrationInfo(mXtRecorder), + new MigrationInfo(devRecorder), new MigrationInfo(mXtRecorder), new MigrationInfo(mUidRecorder), new MigrationInfo(mUidTagRecorder) }; @@ -1021,9 +1052,10 @@ final File legacyBaseDir = mDeps.getLegacyStatsDir(); // Set wipeOnError flag false so the recorder won't damage persistent data if reads // failed and calling deleteAll. + // Set DEV legacy recorder as null since the DEV recorder has been removed. + // Thus it doesn't need to build DEV legacy recorder for comparing with imported data. legacyRecorders = new NetworkStatsRecorder[]{ - buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false, legacyBaseDir, - false /* wipeOnError */), + null /* dev Recorder */, buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false, legacyBaseDir, false /* wipeOnError */), buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false, legacyBaseDir, @@ -1040,7 +1072,6 @@ // commit any data to disk until all are read. for (int i = 0; i < migrations.length; i++) { final MigrationInfo migration = migrations[i]; - // Read the collection from platform code, and set fallbacks counter if throws // for better debugging. try { @@ -1074,6 +1105,7 @@ // Find the latest end time. for (final MigrationInfo migration : migrations) { + if (PREFIX_DEV.equals(migration.recorder.getCookie())) continue; final long migrationEnd = migration.collection.getEndMillis(); if (migrationEnd > migrationEndTime) migrationEndTime = migrationEnd; } @@ -1090,7 +1122,8 @@ for (final MigrationInfo migration : migrations) { migration.imported = true; migration.recorder.removeDataBefore(migrationEndTime); - if (migration.collection.isEmpty()) continue; + if (migration.collection.isEmpty() + || PREFIX_DEV.equals(migration.recorder.getCookie())) continue; migration.recorder.importCollectionLocked(migration.collection); } @@ -1113,6 +1146,7 @@ if (migrationEndTime > Long.MIN_VALUE) { try { for (final MigrationInfo migration : migrations) { + if (PREFIX_DEV.equals(migration.recorder.getCookie())) continue; if (migration.imported) { migration.recorder.removeDataBefore(migrationEndTime); } @@ -1123,6 +1157,7 @@ // framework will reboot, and if there are remaining tries, the migration // process will retry, which is fine because it's idempotent. for (final MigrationInfo migration : migrations) { + if (PREFIX_DEV.equals(migration.recorder.getCookie())) continue; migration.recorder.recoverAndDeleteData(); } } @@ -1176,11 +1211,14 @@ /** * Compare imported data with the data returned by legacy recorders. * - * @return true if the data matches, false if the data does not match or throw with exceptions. + * @return true if the data matches or if {@code legacyRecorder} is null, false if the data + * does not match or throw with exceptions. */ private boolean compareImportedToLegacyStats(@NonNull MigrationInfo migration, - @NonNull NetworkStatsRecorder legacyRecorder) { + @Nullable NetworkStatsRecorder legacyRecorder) { final NetworkStatsCollection legacyStats; + // Skip the recorder that doesn't need to be compared. + if (legacyRecorder == null) return true; try { legacyStats = legacyRecorder.getOrLoadCompleteLocked(); } catch (Throwable e) { @@ -1545,7 +1583,9 @@ // For a template with wifi network keys, it is possible for a malicious // client to track the user locations via querying data usage. Thus, enforce // fine location permission check. - if (!template.getWifiNetworkKeys().isEmpty()) { + // For a template with MATCH_TEST, since the wifi network key is just a placeholder + // to identify a specific test network, it is not related to track user location. + if (!template.getWifiNetworkKeys().isEmpty() && template.getMatchRule() != MATCH_TEST) { final boolean canAccessFineLocation = mLocationPermissionChecker .checkCallersLocationPermission(callingPackage, null /* featureId */, @@ -1699,11 +1739,7 @@ PermissionUtils.enforceNetworkStackPermission(mContext); try { final String[] ifaceArray = getAllIfacesSinceBoot(transport); - // TODO(b/215633405) : mMobileIfaces and mWifiIfaces already contain the stacked - // interfaces, so this is not useful, remove it. - final String[] ifacesToQuery = - mStatsFactory.augmentWithStackedInterfaces(ifaceArray); - final NetworkStats stats = getNetworkStatsUidDetail(ifacesToQuery); + final NetworkStats stats = getNetworkStatsUidDetail(ifaceArray); // Clear the interfaces of the stats before returning, so callers won't get this // information. This is because no caller needs this information for now, and it // makes it easier to change the implementation later by using the histories in the @@ -1834,7 +1870,6 @@ updatePersistThresholdsLocked(); - mDevRecorder.maybePersistLocked(currentTime); mXtRecorder.maybePersistLocked(currentTime); mUidRecorder.maybePersistLocked(currentTime); mUidTagRecorder.maybePersistLocked(currentTime); @@ -1950,7 +1985,6 @@ */ @GuardedBy("mStatsLock") private void updatePersistThresholdsLocked() { - mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold)); mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold)); mUidRecorder.setPersistThreshold(mSettings.getUidPersistBytes(mPersistThreshold)); mUidTagRecorder.setPersistThreshold(mSettings.getUidTagPersistBytes(mPersistThreshold)); @@ -2097,6 +2131,14 @@ final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, isDefault, ratType); + // If WifiInfo contains a null network key then this identity should not be added into + // the network identity set. See b/266598304. + final TransportInfo transportInfo = snapshot.getNetworkCapabilities() + .getTransportInfo(); + if (transportInfo instanceof WifiInfo) { + final WifiInfo info = (WifiInfo) transportInfo; + if (info.getNetworkKey() == null) continue; + } // Traffic occurring on the base interface is always counted for // both total usage and UID details. final String baseIface = snapshot.getLinkProperties().getInterfaceName(); @@ -2230,30 +2272,23 @@ @GuardedBy("mStatsLock") private void recordSnapshotLocked(long currentTime) throws RemoteException { // snapshot and record current counters; read UID stats first to - // avoid over counting dev stats. + // avoid over counting xt stats. Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotUid"); final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotXt"); final NetworkStats xtSnapshot = readNetworkStatsSummaryXt(); Trace.traceEnd(TRACE_TAG_NETWORK); - Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotDev"); - final NetworkStats devSnapshot = readNetworkStatsSummaryDev(); - Trace.traceEnd(TRACE_TAG_NETWORK); - // Snapshot for dev/xt stats from all custom stats providers. Counts per-interface data - // from stats providers that isn't already counted by dev and XT stats. + // Snapshot for xt stats from all custom stats providers. Counts per-interface data + // from stats providers that isn't already counted by XT stats. Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotStatsProvider"); final NetworkStats providersnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE); Trace.traceEnd(TRACE_TAG_NETWORK); xtSnapshot.combineAllValues(providersnapshot); - devSnapshot.combineAllValues(providersnapshot); - // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic + // For xt, we pass a null VPN array because usage is aggregated by UID, so VPN traffic // can't be reattributed to responsible apps. - Trace.traceBegin(TRACE_TAG_NETWORK, "recordDev"); - mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); - Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "recordXt"); mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); @@ -2333,13 +2368,11 @@ // persist any pending data depending on requested flags Trace.traceBegin(TRACE_TAG_NETWORK, "[persisting]"); if (persistForce) { - mDevRecorder.forcePersistLocked(currentTime); mXtRecorder.forcePersistLocked(currentTime); mUidRecorder.forcePersistLocked(currentTime); mUidTagRecorder.forcePersistLocked(currentTime); } else { if (persistNetwork) { - mDevRecorder.maybePersistLocked(currentTime); mXtRecorder.maybePersistLocked(currentTime); } if (persistUid) { @@ -2396,33 +2429,49 @@ final long currentTime = mClock.millis(); NetworkTemplate template; - NetworkStats.Entry devTotal; NetworkStats.Entry xtTotal; NetworkStats.Entry uidTotal; // collect mobile sample template = new NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES).build(); - devTotal = mDevRecorder.getTotalSinceBootLocked(template); xtTotal = mXtRecorder.getTotalSinceBootLocked(template); uidTotal = mUidRecorder.getTotalSinceBootLocked(template); - EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE, - devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, - xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, - uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - currentTime); + if (SdkLevel.isAtLeastU()) { + EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE, + xtTotal.rxBytes, xtTotal.txBytes, xtTotal.rxPackets, xtTotal.txPackets, + uidTotal.rxBytes, uidTotal.txBytes, uidTotal.rxPackets, uidTotal.txPackets, + currentTime); + } else { + // To keep the format of event log, here replaces the value of DevRecorder with the + // value of XtRecorder because they have the same content in old design. + EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE, + xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, + xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, + uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, + currentTime); + } // collect wifi sample template = new NetworkTemplate.Builder(MATCH_WIFI).build(); - devTotal = mDevRecorder.getTotalSinceBootLocked(template); xtTotal = mXtRecorder.getTotalSinceBootLocked(template); uidTotal = mUidRecorder.getTotalSinceBootLocked(template); - EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE, - devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, - xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, - uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - currentTime); + if (SdkLevel.isAtLeastU()) { + EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE, + xtTotal.rxBytes, xtTotal.txBytes, xtTotal.rxPackets, xtTotal.txPackets, + uidTotal.rxBytes, uidTotal.txBytes, uidTotal.rxPackets, uidTotal.txPackets, + currentTime); + } else { + // To keep the format of event log, here replaces the value of DevRecorder with the + // value of XtRecorder because they have the same content in old design. + EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE, + xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, + xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, + uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, + currentTime); + + } } // deleteKernelTagData can ignore ENOENT; otherwise we should log an error @@ -2721,7 +2770,12 @@ pw.println("Dev stats:"); pw.increaseIndent(); - mDevRecorder.dumpLocked(pw, fullHistory); + pw.println("Pending bytes: "); + if (fullHistory) { + pw.println("Complete history:"); + } else { + pw.println("History since boot:"); + } pw.decreaseIndent(); pw.println("Xt stats:"); @@ -2781,7 +2835,6 @@ mActiveIfaces); dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces); - mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); mUidTagRecorder.dumpDebugLocked(proto, @@ -2797,7 +2850,7 @@ return; } if (map.isEmpty()) { - pw.println("No entries"); + pw.println(""); return; } // If there is a concurrent entry deletion, value could be null. http://b/220084230. @@ -2916,14 +2969,6 @@ }); } - private NetworkStats readNetworkStatsSummaryDev() { - try { - return mStatsFactory.readNetworkStatsSummaryDev(); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - private NetworkStats readNetworkStatsSummaryXt() { try { return mStatsFactory.readNetworkStatsSummaryXt(); @@ -3232,12 +3277,8 @@ return false; } @Override - public Config getDevConfig() { - return new Config(HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); - } - @Override public Config getXtConfig() { - return getDevConfig(); + return new Config(HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); } @Override public Config getUidConfig() { @@ -3248,10 +3289,6 @@ return new Config(2 * HOUR_IN_MILLIS, 5 * DAY_IN_MILLIS, 15 * DAY_IN_MILLIS); } @Override - public long getDevPersistBytes(long def) { - return def; - } - @Override public long getXtPersistBytes(long def) { return def; } @@ -3268,4 +3305,7 @@ private static native long nativeGetTotalStat(int type); private static native long nativeGetIfaceStat(String iface, int type); private static native long nativeGetUidStat(int uid, int type); + + /** Initializes and registers the Perfetto Network Trace data source */ + public static native void nativeInitNetworkTracing(); }
diff --git a/service/Android.bp b/service/Android.bp index 98bbbac..e1376a1 100644 --- a/service/Android.bp +++ b/service/Android.bp
@@ -138,6 +138,14 @@ name: "service-connectivity-pre-jarjar", sdk_version: "system_server_current", min_sdk_version: "30", + // NetworkStackApiShimSettingsForCurrentBranch provides the latest available shims depending on + // the branch to "service-connectivity". + // There are Tethering.apk and TetheringNext.apk variants for the tethering APEX, + // which use NetworkStackApiStableShims and NetworkStackApiCurrentShims respectively. + // Note that there can be no service-connectivity-next because it would need to be configured in + // default_art_config.mk which doesn't support conditionals, hence this scheme of using a + // variable here. + defaults: ["NetworkStackApiShimSettingsForCurrentBranch"], srcs: [ "src/**/*.java", ":framework-connectivity-shared-srcs", @@ -157,7 +165,9 @@ // against the implementation because the two libraries are in the same // APEX. "framework-connectivity-t.stubs.module_lib", - "framework-tethering", + // TODO: figure out why just using "framework-tethering" uses the stubs, even though both + // service-connectivity and framework-tethering are in the same APEX. + "framework-tethering.impl", "framework-wifi", "unsupportedappusage", "ServiceConnectivityResources", @@ -166,9 +176,10 @@ static_libs: [ // Do not add libs here if they are already included // in framework-connectivity + "androidx.annotation_annotation", "connectivity-net-module-utils-bpf", "connectivity_native_aidl_interface-lateststable-java", - "dnsresolver_aidl_interface-V9-java", + "dnsresolver_aidl_interface-V11-java", "modules-utils-shell-command-handler", "net-utils-device-common", "net-utils-device-common-bpf", @@ -180,7 +191,6 @@ "PlatformProperties", "service-connectivity-protos", "service-connectivity-stats-protos", - "NetworkStackApiStableShims", ], apex_available: [ "com.android.tethering", @@ -192,26 +202,6 @@ ], } -// TODO: Remove this temporary library and put code into module when test coverage is enough. -java_library { - name: "service-mdns", - sdk_version: "system_server_current", - min_sdk_version: "30", - srcs: [ - "mdns/**/*.java", - ], - libs: [ - "framework-annotations-lib", - "framework-connectivity-pre-jarjar", - "framework-tethering", - "framework-wifi", - "service-connectivity-pre-jarjar", - ], - visibility: [ - "//packages/modules/Connectivity/tests:__subpackages__", - ], -} - java_library { name: "service-connectivity-protos", sdk_version: "system_current", @@ -258,7 +248,7 @@ "framework-annotations-lib", "framework-connectivity.impl", "framework-connectivity-t.impl", - "framework-tethering", + "framework-tethering.impl", "framework-wifi", "libprotobuf-java-nano", ],
diff --git a/service/ServiceConnectivityResources/res/values-eu/strings.xml b/service/ServiceConnectivityResources/res/values-eu/strings.xml index 9b39fd3..13f9eb4 100644 --- a/service/ServiceConnectivityResources/res/values-eu/strings.xml +++ b/service/ServiceConnectivityResources/res/values-eu/strings.xml
@@ -36,7 +36,7 @@ <item msgid="3004933964374161223">"datu-konexioa"</item> <item msgid="5624324321165953608">"Wifia"</item> <item msgid="5667906231066981731">"Bluetootha"</item> - <item msgid="346574747471703768">"Ethernet-a"</item> + <item msgid="346574747471703768">"Etherneta"</item> <item msgid="5734728378097476003">"VPNa"</item> </string-array> <string name="network_switch_type_name_unknown" msgid="5116448402191972082">"sare mota ezezaguna"</string>
diff --git a/service/ServiceConnectivityResources/res/values-mcc310-mnc590/config.xml b/service/ServiceConnectivityResources/res/values-mcc310-mnc590/config.xml new file mode 120000 index 0000000..2b8e406 --- /dev/null +++ b/service/ServiceConnectivityResources/res/values-mcc310-mnc590/config.xml
@@ -0,0 +1 @@ +../values-mcc310-mnc004/config.xml \ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc310-mnc599/config.xml b/service/ServiceConnectivityResources/res/values-mcc310-mnc599/config.xml new file mode 120000 index 0000000..2b8e406 --- /dev/null +++ b/service/ServiceConnectivityResources/res/values-mcc310-mnc599/config.xml
@@ -0,0 +1 @@ +../values-mcc310-mnc004/config.xml \ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc311-mnc270/config.xml b/service/ServiceConnectivityResources/res/values-mcc311-mnc270/config.xml new file mode 120000 index 0000000..2b8e406 --- /dev/null +++ b/service/ServiceConnectivityResources/res/values-mcc311-mnc270/config.xml
@@ -0,0 +1 @@ +../values-mcc310-mnc004/config.xml \ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc311-mnc280/config.xml b/service/ServiceConnectivityResources/res/values-mcc311-mnc280/config.xml new file mode 120000 index 0000000..2b8e406 --- /dev/null +++ b/service/ServiceConnectivityResources/res/values-mcc311-mnc280/config.xml
@@ -0,0 +1 @@ +../values-mcc310-mnc004/config.xml \ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml b/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml deleted file mode 100644 index 7e7025f..0000000 --- a/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml +++ /dev/null
@@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2021 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<!-- Configuration values for ConnectivityService - DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources - Overlay package following the overlayable.xml configuration in the same directory: - https://source.android.com/devices/architecture/rros --> -<resources> - <!-- Whether the device should automatically switch away from Wi-Fi networks that lose - Internet access. Actual device behaviour is controlled by - Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. --> - <integer translatable="false" name="config_networkAvoidBadWifi">0</integer> -</resources> \ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml b/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml new file mode 120000 index 0000000..2b8e406 --- /dev/null +++ b/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
@@ -0,0 +1 @@ +../values-mcc310-mnc004/config.xml \ No newline at end of file
diff --git a/service/jarjar-excludes.txt b/service/jarjar-excludes.txt index b0d6763..7bd3862 100644 --- a/service/jarjar-excludes.txt +++ b/service/jarjar-excludes.txt
@@ -1,9 +1,3 @@ # Classes loaded by SystemServer via their hardcoded name, so they can't be jarjared com\.android\.server\.ConnectivityServiceInitializer(\$.+)? com\.android\.server\.NetworkStatsServiceInitializer(\$.+)? - -# Do not jarjar com.android.server, as several unit tests fail because they lose -# package-private visibility between jarjared and non-jarjared classes. -# TODO: fix the tests and also jarjar com.android.server, or at least only exclude a package that -# is specific to the module like com.android.server.connectivity -com\.android\.server\..+
diff --git a/service/jni/com_android_server_BpfNetMaps.cpp b/service/jni/com_android_server_BpfNetMaps.cpp index 799ac5c..9ced44e 100644 --- a/service/jni/com_android_server_BpfNetMaps.cpp +++ b/service/jni/com_android_server_BpfNetMaps.cpp
@@ -18,7 +18,8 @@ #include "TrafficController.h" -#include <bpf_shared.h> +#include "netd.h" + #include <jni.h> #include <log/log.h> #include <nativehelper/JNIHelp.h> @@ -53,6 +54,10 @@ if (!isOk(status)) { uid_t uid = getuid(); ALOGE("BpfNetMaps jni init failure as uid=%d", uid); + // We probably only ever get called from system_server (ie. AID_SYSTEM) + // or from tests, and never from network_stack (ie. AID_NETWORK_STACK). + // However, if we ever do add calls from production network_stack code + // we do want to make sure this initializes correctly. // TODO: Fix tests to not use this jni lib, so we can unconditionally abort() if (uid == AID_SYSTEM || uid == AID_NETWORK_STACK) abort(); } @@ -235,7 +240,7 @@ // clang-format on int register_com_android_server_BpfNetMaps(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/server/BpfNetMaps", + return jniRegisterNativeMethods(env, "android/net/connectivity/com/android/server/BpfNetMaps", gMethods, NELEM(gMethods)); }
diff --git a/service/jni/com_android_server_TestNetworkService.cpp b/service/jni/com_android_server_TestNetworkService.cpp index bd74d54..08d31a3 100644 --- a/service/jni/com_android_server_TestNetworkService.cpp +++ b/service/jni/com_android_server_TestNetworkService.cpp
@@ -38,9 +38,14 @@ #include "jni.h" #include <android-base/stringprintf.h> #include <android-base/unique_fd.h> +#include <bpf/KernelUtils.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedUtfChars.h> +#ifndef IFF_NO_CARRIER +#define IFF_NO_CARRIER 0x0040 +#endif + namespace android { //------------------------------------------------------------------------------ @@ -66,17 +71,21 @@ // Allocate interface. ifr.ifr_flags = (isTun ? IFF_TUN : IFF_TAP) | IFF_NO_PI; + if (!hasCarrier) { + // Using IFF_NO_CARRIER is supported starting in kernel version >= 6.0 + // Up until then, unsupported flags are ignored. + if (!bpf::isAtLeastKernelVersion(6, 0, 0)) { + throwException(env, EOPNOTSUPP, "IFF_NO_CARRIER not supported", ifr.ifr_name); + return -1; + } + ifr.ifr_flags |= IFF_NO_CARRIER; + } strlcpy(ifr.ifr_name, iface, IFNAMSIZ); if (ioctl(tun.get(), TUNSETIFF, &ifr)) { throwException(env, errno, "allocating", ifr.ifr_name); return -1; } - if (!hasCarrier) { - // disable carrier before setting IFF_UP - setTunTapCarrierEnabledImpl(env, iface, tun.get(), hasCarrier); - } - // Mark some TAP interfaces as supporting multicast if (setIffMulticast && !isTun) { base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0)); @@ -151,8 +160,9 @@ }; int register_com_android_server_TestNetworkService(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/server/TestNetworkService", gMethods, - NELEM(gMethods)); + return jniRegisterNativeMethods(env, + "android/net/connectivity/com/android/server/TestNetworkService", gMethods, + NELEM(gMethods)); } }; // namespace android
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp index 5cd6e5d..c125bd6 100644 --- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp +++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -19,27 +19,29 @@ #include <errno.h> #include <fcntl.h> #include <inttypes.h> +#include <linux/if_packet.h> #include <linux/if_tun.h> #include <linux/ioctl.h> #include <log/log.h> #include <nativehelper/JNIHelp.h> #include <net/if.h> #include <spawn.h> +#include <sys/stat.h> +#include <sys/types.h> #include <sys/wait.h> +#include <sys/xattr.h> #include <string> +#include <unistd.h> +#include <android-modules-utils/sdk_level.h> #include <bpf/BpfMap.h> #include <bpf/BpfUtils.h> -#include <bpf_shared.h> #include <netjniutils/netjniutils.h> #include <private/android_filesystem_config.h> #include "libclat/clatutils.h" #include "nativehelper/scoped_utf_chars.h" -// Sync from system/netd/include/netid_client.h -#define MARK_UNSET 0u - // Sync from system/netd/server/NetdConstants.h #define __INT_STRLEN(i) sizeof(#i) #define _INT_STRLEN(i) __INT_STRLEN(i) @@ -48,14 +50,97 @@ #define DEVICEPREFIX "v4-" namespace android { -static const char* kClatdPath = "/apex/com.android.tethering/bin/for-system/clatd"; + +static bool fatal = false; + +#define ALOGF(s ...) do { ALOGE(s); fatal = true; } while(0) + +enum verify { VERIFY_DIR, VERIFY_BIN, VERIFY_PROG, VERIFY_MAP_RO, VERIFY_MAP_RW }; + +static void verifyPerms(const char * const path, + const mode_t mode, const uid_t uid, const gid_t gid, + const char * const ctxt, + const verify vtype) { + struct stat s = {}; + + if (lstat(path, &s)) ALOGF("lstat '%s' errno=%d", path, errno); + if (s.st_mode != mode) ALOGF("'%s' mode is 0%o != 0%o", path, s.st_mode, mode); + if (s.st_uid != uid) ALOGF("'%s' uid is %d != %d", path, s.st_uid, uid); + if (s.st_gid != gid) ALOGF("'%s' gid is %d != %d", path, s.st_gid, gid); + + char b[255] = {}; + int v = lgetxattr(path, "security.selinux", &b, sizeof(b)); + if (v < 0) ALOGF("lgetxattr '%s' errno=%d", path, errno); + if (strncmp(ctxt, b, sizeof(b))) ALOGF("context of '%s' is '%s' != '%s'", path, b, ctxt); + + int fd = -1; + + switch (vtype) { + case VERIFY_DIR: return; + case VERIFY_BIN: return; + case VERIFY_PROG: fd = bpf::retrieveProgram(path); break; + case VERIFY_MAP_RO: fd = bpf::mapRetrieveRO(path); break; + case VERIFY_MAP_RW: fd = bpf::mapRetrieveRW(path); break; + } + + if (fd < 0) ALOGF("bpf_obj_get '%s' failed, errno=%d", path, errno); + + if (fd >= 0) close(fd); +} + +#undef ALOGF + +static const char* kClatdDir = "/apex/com.android.tethering/bin/for-system"; +static const char* kClatdBin = "/apex/com.android.tethering/bin/for-system/clatd"; + +#define V(path, md, uid, gid, ctx, vtype) \ + verifyPerms((path), (md), AID_ ## uid, AID_ ## gid, "u:object_r:" ctx ":s0", VERIFY_ ## vtype) + +static void verifyClatPerms() { + // We might run as part of tests instead of as part of system server + if (getuid() != AID_SYSTEM) return; + + // First verify the clatd directory and binary, + // since this is built into the apex file system image, + // failures here are 99% likely to be build problems. + V(kClatdDir, S_IFDIR|0750, ROOT, SYSTEM, "system_file", DIR); + V(kClatdBin, S_IFREG|S_ISUID|S_ISGID|0755, CLAT, CLAT, "clatd_exec", BIN); + + // Move on to verifying that the bpf programs and maps are as expected. + // This relies on the kernel and bpfloader. + + // Clat BPF was only mainlined during T. + if (!modules::sdklevel::IsAtLeastT()) return; + + V("/sys/fs/bpf", S_IFDIR|S_ISVTX|0777, ROOT, ROOT, "fs_bpf", DIR); + V("/sys/fs/bpf/net_shared", S_IFDIR|S_ISVTX|0777, ROOT, ROOT, "fs_bpf_net_shared", DIR); + + // pre-U we do not have selinux privs to getattr on bpf maps/progs + // so while the below *should* be as listed, we have no way to actually verify + if (!modules::sdklevel::IsAtLeastU()) return; + +#define V2(path, md, vtype) \ + V("/sys/fs/bpf/net_shared/" path, (md), ROOT, SYSTEM, "fs_bpf_net_shared", vtype) + + V2("prog_clatd_schedcls_egress4_clat_rawip", S_IFREG|0440, PROG); + V2("prog_clatd_schedcls_ingress6_clat_rawip", S_IFREG|0440, PROG); + V2("prog_clatd_schedcls_ingress6_clat_ether", S_IFREG|0440, PROG); + V2("map_clatd_clat_egress4_map", S_IFREG|0660, MAP_RW); + V2("map_clatd_clat_ingress6_map", S_IFREG|0660, MAP_RW); + +#undef V2 + + if (fatal) abort(); +} + +#undef V static void throwIOException(JNIEnv* env, const char* msg, int error) { jniThrowExceptionFmt(env, "java/io/IOException", "%s: %s", msg, strerror(error)); } jstring com_android_server_connectivity_ClatCoordinator_selectIpv4Address(JNIEnv* env, - jobject clazz, + jclass clazz, jstring v4addr, jint prefixlen) { ScopedUtfChars address(env, v4addr); @@ -87,7 +172,7 @@ // 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, jclass clazz, jstring ifaceStr, jstring v4Str, jstring prefix64Str, jint mark) { ScopedUtfChars iface(env, ifaceStr); ScopedUtfChars addr4(env, v4Str); @@ -128,7 +213,7 @@ } static jint com_android_server_connectivity_ClatCoordinator_createTunInterface(JNIEnv* env, - jobject clazz, + jclass clazz, jstring tuniface) { ScopedUtfChars v4interface(env, tuniface); @@ -141,7 +226,7 @@ } struct ifreq ifr = { - .ifr_flags = IFF_TUN, + .ifr_flags = static_cast<short>(IFF_TUN | IFF_TUN_EXCL), }; strlcpy(ifr.ifr_name, v4interface.c_str(), sizeof(ifr.ifr_name)); @@ -155,7 +240,7 @@ return fd; } -static jint com_android_server_connectivity_ClatCoordinator_detectMtu(JNIEnv* env, jobject clazz, +static jint com_android_server_connectivity_ClatCoordinator_detectMtu(JNIEnv* env, jclass clazz, jstring platSubnet, jint plat_suffix, jint mark) { ScopedUtfChars platSubnetStr(env, platSubnet); @@ -177,19 +262,32 @@ } static jint com_android_server_connectivity_ClatCoordinator_openPacketSocket(JNIEnv* env, - jobject clazz) { + jclass clazz) { // Will eventually be bound to htons(ETH_P_IPV6) protocol, // but only after appropriate bpf filter is attached. - int sock = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + const int sock = socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC, 0); if (sock < 0) { throwIOException(env, "packet socket failed", errno); return -1; } + const int on = 1; + // enable tpacket_auxdata cmsg delivery, which includes L2 header length + if (setsockopt(sock, SOL_PACKET, PACKET_AUXDATA, &on, sizeof(on))) { + throwIOException(env, "packet socket auxdata enablement failed", errno); + close(sock); + return -1; + } + // needed for virtio_net_hdr prepending, which includes checksum metadata + if (setsockopt(sock, SOL_PACKET, PACKET_VNET_HDR, &on, sizeof(on))) { + throwIOException(env, "packet socket vnet_hdr enablement failed", errno); + close(sock); + return -1; + } return sock; } static jint com_android_server_connectivity_ClatCoordinator_openRawSocket6(JNIEnv* env, - jobject clazz, + jclass clazz, jint mark) { int sock = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_RAW); if (sock < 0) { @@ -198,7 +296,7 @@ } // TODO: check the mark validation - if (mark != MARK_UNSET && setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) { + if (setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) { throwIOException(env, "could not set mark on raw socket", errno); close(sock); return -1; @@ -208,7 +306,7 @@ } static void com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt( - JNIEnv* env, jobject clazz, jobject javaFd, jstring addr6, jint ifindex) { + JNIEnv* env, jclass clazz, jobject javaFd, jstring addr6, jint ifindex) { int sock = netjniutils::GetNativeFileDescriptor(env, javaFd); if (sock < 0) { jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor"); @@ -234,7 +332,7 @@ } static void com_android_server_connectivity_ClatCoordinator_configurePacketSocket( - JNIEnv* env, jobject clazz, jobject javaFd, jstring addr6, jint ifindex) { + JNIEnv* env, jclass clazz, jobject javaFd, jstring addr6, jint ifindex) { ScopedUtfChars addrStr(env, addr6); int sock = netjniutils::GetNativeFileDescriptor(env, javaFd); @@ -258,7 +356,7 @@ } static jint com_android_server_connectivity_ClatCoordinator_startClatd( - JNIEnv* env, jobject clazz, jobject tunJavaFd, jobject readSockJavaFd, + JNIEnv* env, jclass clazz, jobject tunJavaFd, jobject readSockJavaFd, jobject writeSockJavaFd, jstring iface, jstring pfx96, jstring v4, jstring v6) { ScopedUtfChars ifaceStr(env, iface); ScopedUtfChars pfx96Str(env, pfx96); @@ -355,7 +453,7 @@ // 5. actually perform vfork/dup2/execve pid_t pid; - if (int ret = posix_spawn(&pid, kClatdPath, &fa, &attr, (char* const*)args, nullptr)) { + if (int ret = posix_spawn(&pid, kClatdBin, &fa, &attr, (char* const*)args, nullptr)) { posix_spawnattr_destroy(&attr); posix_spawn_file_actions_destroy(&fa); throwIOException(env, "posix_spawn failed", ret); @@ -374,11 +472,15 @@ static constexpr int WAITPID_ATTEMPTS = 50; static constexpr int WAITPID_RETRY_INTERVAL_US = 100000; -static void stopClatdProcess(int pid) { - int err = kill(pid, SIGTERM); - if (err) { - err = errno; +static void com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv* env, jclass clazz, + jint pid) { + if (pid <= 0) { + jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid pid"); + return; } + + int err = kill(pid, SIGTERM); + if (err) err = errno; if (err == ESRCH) { ALOGE("clatd child process %d unexpectedly disappeared", pid); return; @@ -395,7 +497,9 @@ if (ret == 0) { ALOGE("Failed to SIGTERM clatd pid=%d, try SIGKILL", pid); // TODO: fix that kill failed or waitpid doesn't return. - kill(pid, SIGKILL); + if (kill(pid, SIGKILL)) { + ALOGE("Failed to SIGKILL clatd pid=%d: %s", pid, strerror(errno)); + } ret = waitpid(pid, &status, 0); } if (ret == -1) { @@ -405,25 +509,8 @@ } } -static void com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv* env, jobject clazz, - jstring iface, jstring pfx96, - jstring v4, jstring v6, - jint pid) { - ScopedUtfChars ifaceStr(env, iface); - ScopedUtfChars pfx96Str(env, pfx96); - ScopedUtfChars v4Str(env, v4); - ScopedUtfChars v6Str(env, v6); - - if (pid <= 0) { - jniThrowExceptionFmt(env, "java/io/IOException", "Invalid pid"); - return; - } - - stopClatdProcess(pid); -} - static jlong com_android_server_connectivity_ClatCoordinator_getSocketCookie( - JNIEnv* env, jobject clazz, jobject sockJavaFd) { + JNIEnv* env, jclass clazz, jobject sockJavaFd) { int sockFd = netjniutils::GetNativeFileDescriptor(env, sockJavaFd); if (sockFd < 0) { jniThrowExceptionFmt(env, "java/io/IOException", "Invalid socket file descriptor"); @@ -431,7 +518,7 @@ } uint64_t sock_cookie = bpf::getSocketCookie(sockFd); - if (sock_cookie == bpf::NONEXISTENT_COOKIE) { + if (!sock_cookie) { throwIOException(env, "get socket cookie failed", errno); return -1; } @@ -466,16 +553,17 @@ "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/lang/" "String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", (void*)com_android_server_connectivity_ClatCoordinator_startClatd}, - {"native_stopClatd", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V", + {"native_stopClatd", "(I)V", (void*)com_android_server_connectivity_ClatCoordinator_stopClatd}, {"native_getSocketCookie", "(Ljava/io/FileDescriptor;)J", (void*)com_android_server_connectivity_ClatCoordinator_getSocketCookie}, }; int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/server/connectivity/ClatCoordinator", - gMethods, NELEM(gMethods)); + verifyClatPerms(); + return jniRegisterNativeMethods(env, + "android/net/connectivity/com/android/server/connectivity/ClatCoordinator", + gMethods, NELEM(gMethods)); } }; // namespace android
diff --git a/service/jni/onload.cpp b/service/jni/onload.cpp index 3d15d43..ed74430 100644 --- a/service/jni/onload.cpp +++ b/service/jni/onload.cpp
@@ -22,8 +22,8 @@ namespace android { int register_com_android_server_TestNetworkService(JNIEnv* env); -int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env); int register_com_android_server_BpfNetMaps(JNIEnv* env); +int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env); int register_android_server_net_NetworkStatsFactory(JNIEnv* env); int register_android_server_net_NetworkStatsService(JNIEnv* env); @@ -38,15 +38,15 @@ return JNI_ERR; } - if (register_com_android_server_connectivity_ClatCoordinator(env) < 0) { - return JNI_ERR; - } - - if (register_com_android_server_BpfNetMaps(env) < 0) { - return JNI_ERR; - } - if (android::modules::sdklevel::IsAtLeastT()) { + if (register_com_android_server_BpfNetMaps(env) < 0) { + return JNI_ERR; + } + + if (register_com_android_server_connectivity_ClatCoordinator(env) < 0) { + return JNI_ERR; + } + if (register_android_server_net_NetworkStatsFactory(env) < 0) { return JNI_ERR; }
diff --git a/service/libconnectivity/src/connectivity_native.cpp b/service/libconnectivity/src/connectivity_native.cpp index 49622ae..f39bb0a 100644 --- a/service/libconnectivity/src/connectivity_native.cpp +++ b/service/libconnectivity/src/connectivity_native.cpp
@@ -24,8 +24,8 @@ static std::shared_ptr<IConnectivityNative> getBinder() { - static ndk::SpAIBinder sBinder = ndk::SpAIBinder(reinterpret_cast<AIBinder*>( - AServiceManager_getService("connectivity_native"))); + ndk::SpAIBinder sBinder = ndk::SpAIBinder(reinterpret_cast<AIBinder*>( + AServiceManager_checkService("connectivity_native"))); return aidl::android::net::connectivity::aidl::IConnectivityNative::fromBinder(sBinder); } @@ -47,24 +47,36 @@ int AConnectivityNative_blockPortForBind(in_port_t port) { if (!android::modules::sdklevel::IsAtLeastU()) return ENOSYS; std::shared_ptr<IConnectivityNative> c = getBinder(); + if (!c) { + return EAGAIN; + } return getErrno(c->blockPortForBind(port)); } int AConnectivityNative_unblockPortForBind(in_port_t port) { if (!android::modules::sdklevel::IsAtLeastU()) return ENOSYS; std::shared_ptr<IConnectivityNative> c = getBinder(); + if (!c) { + return EAGAIN; + } return getErrno(c->unblockPortForBind(port)); } int AConnectivityNative_unblockAllPortsForBind() { if (!android::modules::sdklevel::IsAtLeastU()) return ENOSYS; std::shared_ptr<IConnectivityNative> c = getBinder(); + if (!c) { + return EAGAIN; + } return getErrno(c->unblockAllPortsForBind()); } int AConnectivityNative_getPortsBlockedForBind(in_port_t *ports, size_t *count) { if (!android::modules::sdklevel::IsAtLeastU()) return ENOSYS; std::shared_ptr<IConnectivityNative> c = getBinder(); + if (!c) { + return EAGAIN; + } std::vector<int32_t> actualBlockedPorts; int err = getErrno(c->getPortsBlockedForBind(&actualBlockedPorts)); if (err) {
diff --git a/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java b/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java deleted file mode 100644 index f7871f3..0000000 --- a/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java +++ /dev/null
@@ -1,157 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.connectivity.mdns; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.text.TextUtils; -import android.util.Pair; - -import com.android.server.connectivity.mdns.util.MdnsLogger; - -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.net.DatagramPacket; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Callable; - -/** - * A {@link Callable} that builds and enqueues a mDNS query to send over the multicast socket. If a - * query is built and enqueued successfully, then call to {@link #call()} returns the transaction ID - * 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}. - */ -public class EnqueueMdnsQueryCallable implements Callable<Pair<Integer, List<String>>> { - - private static final String TAG = "MdnsQueryCallable"; - private static final MdnsLogger LOGGER = new MdnsLogger(TAG); - private static final List<Integer> castShellEmulatorMdnsPorts; - - static { - castShellEmulatorMdnsPorts = new ArrayList<>(); - String[] stringPorts = MdnsConfigs.castShellEmulatorMdnsPorts(); - - for (String port : stringPorts) { - try { - castShellEmulatorMdnsPorts.add(Integer.parseInt(port)); - } catch (NumberFormatException e) { - // Ignore. - } - } - } - - private final WeakReference<MdnsSocketClient> weakRequestSender; - private final MdnsPacketWriter packetWriter; - private final String[] serviceTypeLabels; - private final List<String> subtypes; - private final boolean expectUnicastResponse; - private final int transactionId; - - EnqueueMdnsQueryCallable( - @NonNull MdnsSocketClient requestSender, - @NonNull MdnsPacketWriter packetWriter, - @NonNull String serviceType, - @NonNull Collection<String> subtypes, - boolean expectUnicastResponse, - int transactionId) { - weakRequestSender = new WeakReference<>(requestSender); - this.packetWriter = packetWriter; - serviceTypeLabels = TextUtils.split(serviceType, "\\."); - this.subtypes = new ArrayList<>(subtypes); - this.expectUnicastResponse = expectUnicastResponse; - 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(); - if (requestSender == null) { - return null; - } - - int numQuestions = 1; - if (!subtypes.isEmpty()) { - numQuestions += subtypes.size(); - } - - // Header. - packetWriter.writeUInt16(transactionId); // transaction ID - packetWriter.writeUInt16(MdnsConstants.FLAGS_QUERY); // flags - packetWriter.writeUInt16(numQuestions); // number of questions - packetWriter.writeUInt16(0); // number of answers (not yet known; will be written later) - packetWriter.writeUInt16(0); // number of authority entries - packetWriter.writeUInt16(0); // number of additional records - - // Question(s). There will be one question for each (fqdn+subtype, recordType) - // combination, - // as well as one for each (fqdn, recordType) combination. - - for (String subtype : subtypes) { - String[] labels = new String[serviceTypeLabels.length + 2]; - labels[0] = MdnsConstants.SUBTYPE_PREFIX + subtype; - labels[1] = MdnsConstants.SUBTYPE_LABEL; - System.arraycopy(serviceTypeLabels, 0, labels, 2, serviceTypeLabels.length); - - packetWriter.writeLabels(labels); - packetWriter.writeUInt16(MdnsRecord.TYPE_PTR); - packetWriter.writeUInt16( - MdnsConstants.QCLASS_INTERNET - | (expectUnicastResponse ? MdnsConstants.QCLASS_UNICAST : 0)); - } - - packetWriter.writeLabels(serviceTypeLabels); - packetWriter.writeUInt16(MdnsRecord.TYPE_PTR); - packetWriter.writeUInt16( - MdnsConstants.QCLASS_INTERNET - | (expectUnicastResponse ? MdnsConstants.QCLASS_UNICAST : 0)); - - InetAddress mdnsAddress = MdnsConstants.getMdnsIPv4Address(); - if (requestSender.isOnIPv6OnlyNetwork()) { - mdnsAddress = MdnsConstants.getMdnsIPv6Address(); - } - - sendPacketTo(requestSender, - new InetSocketAddress(mdnsAddress, MdnsConstants.MDNS_PORT)); - for (Integer emulatorPort : castShellEmulatorMdnsPorts) { - sendPacketTo(requestSender, new InetSocketAddress(mdnsAddress, emulatorPort)); - } - return Pair.create(transactionId, subtypes); - } catch (IOException e) { - LOGGER.e(String.format("Failed to create mDNS packet for subtype: %s.", - TextUtils.join(",", subtypes)), e); - return null; - } - } - - private void sendPacketTo(MdnsSocketClient requestSender, InetSocketAddress address) - throws IOException { - DatagramPacket packet = packetWriter.getPacket(address); - if (expectUnicastResponse) { - requestSender.sendUnicastPacket(packet); - } else { - requestSender.sendMulticastPacket(packet); - } - } -} \ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java b/service/mdns/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java deleted file mode 100644 index 0f3c23a..0000000 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java +++ /dev/null
@@ -1,148 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.connectivity.mdns; - -import android.Manifest.permission; -import android.annotation.NonNull; -import android.annotation.RequiresPermission; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.server.connectivity.mdns.util.MdnsLogger; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Map; - -/** - * This class keeps tracking the set of registered {@link MdnsServiceBrowserListener} instances, and - * notify them when a mDNS service instance is found, updated, or removed? - */ -public class MdnsDiscoveryManager implements MdnsSocketClient.Callback { - private static final String TAG = MdnsDiscoveryManager.class.getSimpleName(); - public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); - private static final MdnsLogger LOGGER = new MdnsLogger("MdnsDiscoveryManager"); - - private final ExecutorProvider executorProvider; - private final MdnsSocketClient socketClient; - - private final Map<String, MdnsServiceTypeClient> serviceTypeClients = new ArrayMap<>(); - - public MdnsDiscoveryManager( - @NonNull ExecutorProvider executorProvider, @NonNull MdnsSocketClient socketClient) { - this.executorProvider = executorProvider; - this.socketClient = socketClient; - } - - /** - * Starts (or continue) to discovery mDNS services with given {@code serviceType}, and registers - * {@code listener} for receiving mDNS service discovery responses. - * - * @param serviceType The type of the service to discover. - * @param listener The {@link MdnsServiceBrowserListener} listener. - * @param searchOptions The {@link MdnsSearchOptions} to be used for discovering {@code - * serviceType}. - */ - @RequiresPermission(permission.CHANGE_WIFI_MULTICAST_STATE) - public synchronized void registerListener( - @NonNull String serviceType, - @NonNull MdnsServiceBrowserListener listener, - @NonNull MdnsSearchOptions searchOptions) { - LOGGER.log( - "Registering listener for subtypes: %s", - TextUtils.join(",", searchOptions.getSubtypes())); - if (serviceTypeClients.isEmpty()) { - // First listener. Starts the socket client. - try { - socketClient.startDiscovery(); - } catch (IOException e) { - LOGGER.e("Failed to start discover.", e); - return; - } - } - // All listeners of the same service types shares the same MdnsServiceTypeClient. - MdnsServiceTypeClient serviceTypeClient = serviceTypeClients.get(serviceType); - if (serviceTypeClient == null) { - serviceTypeClient = createServiceTypeClient(serviceType); - serviceTypeClients.put(serviceType, serviceTypeClient); - } - serviceTypeClient.startSendAndReceive(listener, searchOptions); - } - - /** - * Unregister {@code listener} for receiving mDNS service discovery responses. IF no listener is - * registered for the given service type, stops discovery for the service type. - * - * @param serviceType The type of the service to discover. - * @param listener The {@link MdnsServiceBrowserListener} listener. - */ - @RequiresPermission(permission.CHANGE_WIFI_MULTICAST_STATE) - public synchronized void unregisterListener( - @NonNull String serviceType, @NonNull MdnsServiceBrowserListener listener) { - LOGGER.log("Unregistering listener for service type: %s", serviceType); - MdnsServiceTypeClient serviceTypeClient = serviceTypeClients.get(serviceType); - if (serviceTypeClient == null) { - return; - } - if (serviceTypeClient.stopSendAndReceive(listener)) { - // No listener is registered for the service type anymore, remove it from the list of - // the - // service type clients. - serviceTypeClients.remove(serviceType); - if (serviceTypeClients.isEmpty()) { - // No discovery request. Stops the socket client. - socketClient.stopDiscovery(); - } - } - } - - @Override - public synchronized void onResponseReceived(@NonNull MdnsResponse response) { - String[] name = - response.getPointerRecords().isEmpty() - ? null - : response.getPointerRecords().get(0).getName(); - if (name != null) { - for (MdnsServiceTypeClient serviceTypeClient : serviceTypeClients.values()) { - String[] serviceType = serviceTypeClient.getServiceTypeLabels(); - if ((Arrays.equals(name, serviceType) - || ((name.length == (serviceType.length + 2)) - && name[1].equals(MdnsConstants.SUBTYPE_LABEL) - && MdnsRecord.labelsAreSuffix(serviceType, name)))) { - serviceTypeClient.processResponse(response); - return; - } - } - } - } - - @Override - public synchronized void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode) { - for (MdnsServiceTypeClient serviceTypeClient : serviceTypeClients.values()) { - serviceTypeClient.onFailedToParseMdnsResponse(receivedPacketNumber, errorCode); - } - } - - @VisibleForTesting - MdnsServiceTypeClient createServiceTypeClient(@NonNull String serviceType) { - return new MdnsServiceTypeClient( - serviceType, socketClient, - executorProvider.newServiceTypeClientSchedulerExecutor()); - } -} \ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsPacket.java b/service/mdns/com/android/server/connectivity/mdns/MdnsPacket.java deleted file mode 100644 index eae084a..0000000 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsPacket.java +++ /dev/null
@@ -1,43 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.connectivity.mdns; - -import java.util.Collections; -import java.util.List; - -/** - * A class holding data that can be included in a mDNS packet. - */ -public class MdnsPacket { - public final int flags; - public final List<MdnsRecord> questions; - public final List<MdnsRecord> answers; - public final List<MdnsRecord> authorityRecords; - public final List<MdnsRecord> additionalRecords; - - MdnsPacket(int flags, - List<MdnsRecord> questions, - List<MdnsRecord> answers, - List<MdnsRecord> authorityRecords, - List<MdnsRecord> additionalRecords) { - this.flags = flags; - this.questions = Collections.unmodifiableList(questions); - this.answers = Collections.unmodifiableList(answers); - this.authorityRecords = Collections.unmodifiableList(authorityRecords); - this.additionalRecords = Collections.unmodifiableList(additionalRecords); - } -}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsReplySender.java b/service/mdns/com/android/server/connectivity/mdns/MdnsReplySender.java deleted file mode 100644 index 2acd789..0000000 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsReplySender.java +++ /dev/null
@@ -1,88 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.connectivity.mdns; - -import android.annotation.NonNull; -import android.os.Looper; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.MulticastSocket; -import java.net.SocketAddress; - -/** - * A class that handles sending mDNS replies to a {@link MulticastSocket}, possibly queueing them - * to be sent after some delay. - * - * TODO: implement sending after a delay, combining queued replies and duplicate answer suppression - */ -public class MdnsReplySender { - @NonNull - private final MulticastSocket mSocket; - @NonNull - private final Looper mLooper; - @NonNull - private final byte[] mPacketCreationBuffer; - - public MdnsReplySender(@NonNull Looper looper, - @NonNull MulticastSocket socket, @NonNull byte[] packetCreationBuffer) { - mLooper = looper; - mSocket = socket; - mPacketCreationBuffer = packetCreationBuffer; - } - - /** - * Send a packet immediately. - * - * Must be called on the looper thread used by the {@link MdnsReplySender}. - */ - public void sendNow(@NonNull MdnsPacket packet, @NonNull SocketAddress destination) - throws IOException { - if (Thread.currentThread() != mLooper.getThread()) { - throw new IllegalStateException("sendNow must be called in the handler thread"); - } - - // TODO: support packets over size (send in multiple packets with TC bit set) - final MdnsPacketWriter writer = new MdnsPacketWriter(mPacketCreationBuffer); - - writer.writeUInt16(0); // Transaction ID (advertisement: 0) - writer.writeUInt16(packet.flags); // Response, authoritative (rfc6762 18.4) - writer.writeUInt16(packet.questions.size()); // questions count - writer.writeUInt16(packet.answers.size()); // answers count - writer.writeUInt16(packet.authorityRecords.size()); // authority entries count - writer.writeUInt16(packet.additionalRecords.size()); // additional records count - - for (MdnsRecord record : packet.questions) { - record.write(writer, 0L); - } - for (MdnsRecord record : packet.answers) { - record.write(writer, 0L); - } - for (MdnsRecord record : packet.authorityRecords) { - record.write(writer, 0L); - } - for (MdnsRecord record : packet.additionalRecords) { - record.write(writer, 0L); - } - - final int len = writer.getWritePosition(); - final byte[] outBuffer = new byte[len]; - System.arraycopy(mPacketCreationBuffer, 0, outBuffer, 0, len); - - mSocket.send(new DatagramPacket(outBuffer, 0, len, destination)); - } -}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java b/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java deleted file mode 100644 index 3a41978..0000000 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java +++ /dev/null
@@ -1,403 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.connectivity.mdns; - -import android.annotation.Nullable; -import android.net.Network; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -/** An mDNS response. */ -public class MdnsResponse { - private final List<MdnsRecord> records; - private final List<MdnsPointerRecord> pointerRecords; - private MdnsServiceRecord serviceRecord; - private MdnsTextRecord textRecord; - private MdnsInetAddressRecord inet4AddressRecord; - private MdnsInetAddressRecord inet6AddressRecord; - private long lastUpdateTime; - private final int interfaceIndex; - @Nullable private final Network network; - - /** Constructs a new, empty response. */ - public MdnsResponse(long now, int interfaceIndex, @Nullable Network network) { - lastUpdateTime = now; - records = new LinkedList<>(); - pointerRecords = new LinkedList<>(); - this.interfaceIndex = interfaceIndex; - this.network = network; - } - - // This generic typed helper compares records for equality. - // Returns True if records are the same. - private <T> boolean recordsAreSame(T a, T b) { - return ((a == null) && (b == null)) || ((a != null) && (b != null) && a.equals(b)); - } - - /** - * Adds a pointer record. - * - * @return <code>true</code> if the record was added, or <code>false</code> if a matching - * pointer - * record is already present in the response. - */ - public synchronized boolean addPointerRecord(MdnsPointerRecord pointerRecord) { - if (!pointerRecords.contains(pointerRecord)) { - pointerRecords.add(pointerRecord); - records.add(pointerRecord); - return true; - } - - return false; - } - - /** Gets the pointer records. */ - public synchronized List<MdnsPointerRecord> getPointerRecords() { - // Returns a shallow copy. - return new LinkedList<>(pointerRecords); - } - - public synchronized boolean hasPointerRecords() { - return !pointerRecords.isEmpty(); - } - - @VisibleForTesting - synchronized void clearPointerRecords() { - pointerRecords.clear(); - } - - public synchronized boolean hasSubtypes() { - for (MdnsPointerRecord pointerRecord : pointerRecords) { - if (pointerRecord.hasSubtype()) { - return true; - } - } - return false; - } - - @Nullable - public synchronized List<String> getSubtypes() { - List<String> subtypes = null; - for (MdnsPointerRecord pointerRecord : pointerRecords) { - String pointerRecordSubtype = pointerRecord.getSubtype(); - if (pointerRecordSubtype != null) { - if (subtypes == null) { - subtypes = new LinkedList<>(); - } - subtypes.add(pointerRecordSubtype); - } - } - - return subtypes; - } - - @VisibleForTesting - public synchronized void removeSubtypes() { - Iterator<MdnsPointerRecord> iter = pointerRecords.iterator(); - while (iter.hasNext()) { - MdnsPointerRecord pointerRecord = iter.next(); - if (pointerRecord.hasSubtype()) { - iter.remove(); - } - } - } - - /** Sets the service record. */ - public synchronized boolean setServiceRecord(MdnsServiceRecord serviceRecord) { - if (recordsAreSame(this.serviceRecord, serviceRecord)) { - return false; - } - if (this.serviceRecord != null) { - records.remove(this.serviceRecord); - } - this.serviceRecord = serviceRecord; - if (this.serviceRecord != null) { - records.add(this.serviceRecord); - } - return true; - } - - /** Gets the service record. */ - public synchronized MdnsServiceRecord getServiceRecord() { - return serviceRecord; - } - - public synchronized boolean hasServiceRecord() { - return serviceRecord != null; - } - - /** Sets the text record. */ - public synchronized boolean setTextRecord(MdnsTextRecord textRecord) { - if (recordsAreSame(this.textRecord, textRecord)) { - return false; - } - if (this.textRecord != null) { - records.remove(this.textRecord); - } - this.textRecord = textRecord; - if (this.textRecord != null) { - records.add(this.textRecord); - } - return true; - } - - /** Gets the text record. */ - public synchronized MdnsTextRecord getTextRecord() { - return textRecord; - } - - public synchronized boolean hasTextRecord() { - return textRecord != null; - } - - /** Sets the IPv4 address record. */ - public synchronized boolean setInet4AddressRecord( - @Nullable MdnsInetAddressRecord newInet4AddressRecord) { - if (recordsAreSame(this.inet4AddressRecord, newInet4AddressRecord)) { - return false; - } - if (this.inet4AddressRecord != null) { - records.remove(this.inet4AddressRecord); - } - if (newInet4AddressRecord != null && newInet4AddressRecord.getInet4Address() != null) { - this.inet4AddressRecord = newInet4AddressRecord; - records.add(this.inet4AddressRecord); - } - return true; - } - - /** Gets the IPv4 address record. */ - public synchronized MdnsInetAddressRecord getInet4AddressRecord() { - return inet4AddressRecord; - } - - public synchronized boolean hasInet4AddressRecord() { - return inet4AddressRecord != null; - } - - /** Sets the IPv6 address record. */ - public synchronized boolean setInet6AddressRecord( - @Nullable MdnsInetAddressRecord newInet6AddressRecord) { - if (recordsAreSame(this.inet6AddressRecord, newInet6AddressRecord)) { - return false; - } - if (this.inet6AddressRecord != null) { - records.remove(this.inet6AddressRecord); - } - if (newInet6AddressRecord != null && newInet6AddressRecord.getInet6Address() != null) { - this.inet6AddressRecord = newInet6AddressRecord; - records.add(this.inet6AddressRecord); - } - return true; - } - - /** - * 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 int getInterfaceIndex() { - return interfaceIndex; - } - - /** - * Returns the network at which this response was received, or null if the network is unknown. - */ - @Nullable - public Network getNetwork() { - return network; - } - - /** Gets the IPv6 address record. */ - public synchronized MdnsInetAddressRecord getInet6AddressRecord() { - return inet6AddressRecord; - } - - public synchronized boolean hasInet6AddressRecord() { - return inet6AddressRecord != null; - } - - /** Gets all of the records. */ - public synchronized List<MdnsRecord> getRecords() { - return new LinkedList<>(records); - } - - /** - * Merges any records that are present in another response into this one. - * - * @return <code>true</code> if any records were added or updated. - */ - public synchronized boolean mergeRecordsFrom(MdnsResponse other) { - lastUpdateTime = other.lastUpdateTime; - - boolean updated = false; - - List<MdnsPointerRecord> pointerRecords = other.getPointerRecords(); - if (pointerRecords != null) { - for (MdnsPointerRecord pointerRecord : pointerRecords) { - if (addPointerRecord(pointerRecord)) { - updated = true; - } - } - } - - MdnsServiceRecord serviceRecord = other.getServiceRecord(); - if (serviceRecord != null) { - if (setServiceRecord(serviceRecord)) { - updated = true; - } - } - - MdnsTextRecord textRecord = other.getTextRecord(); - if (textRecord != null) { - if (setTextRecord(textRecord)) { - updated = true; - } - } - - MdnsInetAddressRecord otherInet4AddressRecord = other.getInet4AddressRecord(); - if (otherInet4AddressRecord != null && otherInet4AddressRecord.getInet4Address() != null) { - if (setInet4AddressRecord(otherInet4AddressRecord)) { - updated = true; - } - } - - MdnsInetAddressRecord otherInet6AddressRecord = other.getInet6AddressRecord(); - if (otherInet6AddressRecord != null && otherInet6AddressRecord.getInet6Address() != null) { - if (setInet6AddressRecord(otherInet6AddressRecord)) { - updated = true; - } - } - - // If the hostname in the service record no longer matches the hostname in either of the - // address records, then drop the address records. - if (this.serviceRecord != null) { - boolean dropAddressRecords = false; - - if (this.inet4AddressRecord != null) { - if (!Arrays.equals( - this.serviceRecord.getServiceHost(), this.inet4AddressRecord.getName())) { - dropAddressRecords = true; - } - } - if (this.inet6AddressRecord != null) { - if (!Arrays.equals( - this.serviceRecord.getServiceHost(), this.inet6AddressRecord.getName())) { - dropAddressRecords = true; - } - } - - if (dropAddressRecords) { - setInet4AddressRecord(null); - setInet6AddressRecord(null); - updated = true; - } - } - - return updated; - } - - /** - * Tests if the response is complete. A response is considered complete if it contains PTR, SRV, - * TXT, and A (for IPv4) or AAAA (for IPv6) records. - */ - public synchronized boolean isComplete() { - return !pointerRecords.isEmpty() - && (serviceRecord != null) - && (textRecord != null) - && (inet4AddressRecord != null || inet6AddressRecord != null); - } - - /** - * Returns the key for this response. The key uniquely identifies the response by its service - * name. - */ - public synchronized String getServiceInstanceName() { - if (pointerRecords.isEmpty()) { - return null; - } - String[] pointers = pointerRecords.get(0).getPointer(); - return ((pointers != null) && (pointers.length > 0)) ? pointers[0] : null; - } - - /** - * Tests if this response is a goodbye message. This will be true if a service record is present - * and any of the records have a TTL of 0. - */ - public synchronized boolean isGoodbye() { - if (getServiceInstanceName() != null) { - for (MdnsRecord record : records) { - // Expiring PTR records with subtypes just signal a change in known supported - // criteria, not the device itself going offline, so ignore those. - if ((record instanceof MdnsPointerRecord) - && ((MdnsPointerRecord) record).hasSubtype()) { - continue; - } - - if (record.getTtl() == 0) { - return true; - } - } - } - return false; - } - - /** - * Writes the response to a packet. - * - * @param writer The writer to use. - * @param now The current time. This is used to write updated TTLs that reflect the remaining - * TTL - * since the response was received. - * @return The number of records that were written. - * @throws IOException If an error occurred while writing (typically indicating overflow). - */ - public synchronized int write(MdnsPacketWriter writer, long now) throws IOException { - int count = 0; - for (MdnsPointerRecord pointerRecord : pointerRecords) { - pointerRecord.write(writer, now); - ++count; - } - - if (serviceRecord != null) { - serviceRecord.write(writer, now); - ++count; - } - - if (textRecord != null) { - textRecord.write(writer, now); - ++count; - } - - if (inet4AddressRecord != null) { - inet4AddressRecord.write(writer, now); - ++count; - } - - if (inet6AddressRecord != null) { - inet6AddressRecord.write(writer, now); - ++count; - } - - return count; - } -}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java b/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java deleted file mode 100644 index 7cf84f6..0000000 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java +++ /dev/null
@@ -1,343 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.connectivity.mdns; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.Network; -import android.os.SystemClock; - -import com.android.server.connectivity.mdns.util.MdnsLogger; - -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. */ -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 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. */ - public MdnsResponseDecoder(@NonNull Clock clock, @Nullable String[] serviceType) { - this.clock = clock; - this.serviceType = serviceType; - } - - private static void skipMdnsRecord(MdnsPacketReader reader) throws IOException { - reader.skip(2 + 4); // skip the class and TTL - int dataLength = reader.readUInt16(); - reader.skip(dataLength); - } - - private static MdnsResponse findResponseWithPointer( - List<MdnsResponse> responses, String[] pointer) { - if (responses != null) { - for (MdnsResponse response : responses) { - List<MdnsPointerRecord> pointerRecords = response.getPointerRecords(); - if (pointerRecords == null) { - continue; - } - for (MdnsPointerRecord pointerRecord : pointerRecords) { - if (Arrays.equals(pointerRecord.getPointer(), pointer)) { - return response; - } - } - } - } - return null; - } - - private static MdnsResponse findResponseWithHostName( - List<MdnsResponse> responses, String[] hostName) { - if (responses != null) { - for (MdnsResponse response : responses) { - MdnsServiceRecord serviceRecord = response.getServiceRecord(); - if (serviceRecord == null) { - continue; - } - if (Arrays.equals(serviceRecord.getServiceHost(), hostName)) { - return response; - } - } - } - return null; - } - - /** - * Decodes all mDNS responses for the desired service type from a packet. The class does not - * check - * 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 - * @param network the network at which the packet was received, or null if it is unknown. - * @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, - int interfaceIndex, @Nullable Network network) { - MdnsPacketReader reader = new MdnsPacketReader(packet); - - List<MdnsRecord> records; - try { - reader.readUInt16(); // transaction ID (not used) - int flags = reader.readUInt16(); - if ((flags & MdnsConstants.FLAGS_RESPONSE_MASK) != MdnsConstants.FLAGS_RESPONSE) { - return MdnsResponseErrorCode.ERROR_NOT_RESPONSE_MESSAGE; - } - - int numQuestions = reader.readUInt16(); - int numAnswers = reader.readUInt16(); - int numAuthority = reader.readUInt16(); - int numRecords = reader.readUInt16(); - - LOGGER.log(String.format( - "num questions: %d, num answers: %d, num authority: %d, num records: %d", - numQuestions, numAnswers, numAuthority, numRecords)); - - if (numAnswers < 1) { - return MdnsResponseErrorCode.ERROR_NO_ANSWERS; - } - - records = new LinkedList<>(); - - for (int i = 0; i < (numAnswers + numAuthority + numRecords); ++i) { - String[] name; - try { - name = reader.readLabels(); - } catch (IOException e) { - LOGGER.e("Failed to read labels from mDNS response.", e); - return MdnsResponseErrorCode.ERROR_READING_RECORD_NAME; - } - int type = reader.readUInt16(); - - switch (type) { - case MdnsRecord.TYPE_A: { - try { - records.add(new MdnsInetAddressRecord(name, MdnsRecord.TYPE_A, reader)); - } catch (IOException e) { - LOGGER.e("Failed to read A record from mDNS response.", e); - return MdnsResponseErrorCode.ERROR_READING_A_RDATA; - } - break; - } - - case MdnsRecord.TYPE_AAAA: { - try { - // AAAA should only contain the IPv6 address. - MdnsInetAddressRecord record = - new MdnsInetAddressRecord(name, MdnsRecord.TYPE_AAAA, reader); - if (record.getInet6Address() != null) { - records.add(record); - } - } catch (IOException e) { - LOGGER.e("Failed to read AAAA record from mDNS response.", e); - return MdnsResponseErrorCode.ERROR_READING_AAAA_RDATA; - } - break; - } - - case MdnsRecord.TYPE_PTR: { - try { - records.add(new MdnsPointerRecord(name, reader)); - } catch (IOException e) { - LOGGER.e("Failed to read PTR record from mDNS response.", e); - return MdnsResponseErrorCode.ERROR_READING_PTR_RDATA; - } - break; - } - - case MdnsRecord.TYPE_SRV: { - if (name.length == 4) { - try { - records.add(new MdnsServiceRecord(name, reader)); - } catch (IOException e) { - LOGGER.e("Failed to read SRV record from mDNS response.", e); - return MdnsResponseErrorCode.ERROR_READING_SRV_RDATA; - } - } else { - try { - skipMdnsRecord(reader); - } catch (IOException e) { - LOGGER.e("Failed to skip SVR record from mDNS response.", e); - return MdnsResponseErrorCode.ERROR_SKIPPING_SRV_RDATA; - } - } - break; - } - - case MdnsRecord.TYPE_TXT: { - try { - records.add(new MdnsTextRecord(name, reader)); - } catch (IOException e) { - LOGGER.e("Failed to read TXT record from mDNS response.", e); - return MdnsResponseErrorCode.ERROR_READING_TXT_RDATA; - } - break; - } - - default: { - try { - skipMdnsRecord(reader); - } catch (IOException e) { - LOGGER.e("Failed to skip mDNS record.", e); - return MdnsResponseErrorCode.ERROR_SKIPPING_UNKNOWN_RECORD; - } - } - } - } - } catch (EOFException e) { - LOGGER.e("Reached the end of the mDNS response unexpectedly.", e); - return MdnsResponseErrorCode.ERROR_END_OF_FILE; - } - - // The response records are structured in a hierarchy, where some records reference - // others, as follows: - // - // PTR - // / \ - // / \ - // TXT SRV - // / \ - // / \ - // A AAAA - // - // But the order in which these records appear in the response packet is completely - // arbitrary. This means that we need to rescan the record list to construct each level of - // this hierarchy. - // - // PTR: service type -> service instance name - // - // SRV: service instance name -> host name (priority, weight) - // - // TXT: service instance name -> machine readable txt entries. - // - // A: host name -> IP address - - // Loop 1: find PTR records, which identify distinct service instances. - long now = SystemClock.elapsedRealtime(); - for (MdnsRecord record : records) { - if (record instanceof MdnsPointerRecord) { - String[] name = record.getName(); - if ((serviceType == null) - || Arrays.equals(name, serviceType) - || ((name.length == (serviceType.length + 2)) - && name[1].equals(MdnsConstants.SUBTYPE_LABEL) - && MdnsRecord.labelsAreSuffix(serviceType, name))) { - MdnsPointerRecord pointerRecord = (MdnsPointerRecord) record; - // Group PTR records that refer to the same service instance name into a single - // response. - MdnsResponse response = findResponseWithPointer(responses, - pointerRecord.getPointer()); - if (response == null) { - response = new MdnsResponse(now, interfaceIndex, network); - responses.add(response); - } - // Set interface index earlier because some responses have PTR record only. - // Need to know every response is getting from which interface. - response.addPointerRecord((MdnsPointerRecord) record); - } - } - } - - // Loop 2: find SRV and TXT records, which reference the pointer in the PTR record. - for (MdnsRecord record : records) { - if (record instanceof MdnsServiceRecord) { - MdnsServiceRecord serviceRecord = (MdnsServiceRecord) record; - MdnsResponse response = findResponseWithPointer(responses, serviceRecord.getName()); - if (response != null) { - response.setServiceRecord(serviceRecord); - } - } else if (record instanceof MdnsTextRecord) { - MdnsTextRecord textRecord = (MdnsTextRecord) record; - MdnsResponse response = findResponseWithPointer(responses, textRecord.getName()); - if (response != null) { - response.setTextRecord(textRecord); - } - } - } - - // Loop 3: find A and AAAA records, which reference the host name in the SRV record. - for (MdnsRecord record : records) { - if (record instanceof MdnsInetAddressRecord) { - MdnsInetAddressRecord inetRecord = (MdnsInetAddressRecord) record; - if (allowMultipleSrvRecordsPerHost) { - List<MdnsResponse> matchingResponses = - findResponsesWithHostName(responses, inetRecord.getName()); - for (MdnsResponse response : matchingResponses) { - assignInetRecord(response, inetRecord); - } - } else { - MdnsResponse response = - findResponseWithHostName(responses, inetRecord.getName()); - if (response != null) { - assignInetRecord(response, inetRecord); - } - } - } - } - - return SUCCESS; - } - - private static void assignInetRecord(MdnsResponse response, MdnsInetAddressRecord inetRecord) { - if (inetRecord.getInet4Address() != null) { - response.setInet4AddressRecord(inetRecord); - } else if (inetRecord.getInet6Address() != null) { - response.setInet6AddressRecord(inetRecord); - } - } - - 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(); - } - } -} \ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java deleted file mode 100644 index 538f376..0000000 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java +++ /dev/null
@@ -1,470 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.connectivity.mdns; - -import static java.util.concurrent.TimeUnit.MILLISECONDS; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.SystemClock; -import android.text.TextUtils; -import android.util.ArraySet; -import android.util.Pair; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.server.connectivity.mdns.util.MdnsLogger; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; - -/** - * Instance of this class sends and receives mDNS packets of a given service type and invoke - * registered {@link MdnsServiceBrowserListener} instances. - */ -public class MdnsServiceTypeClient { - - private static final int DEFAULT_MTU = 1500; - private static final MdnsLogger LOGGER = new MdnsLogger("MdnsServiceTypeClient"); - - private final String serviceType; - private final String[] serviceTypeLabels; - private final MdnsSocketClient socketClient; - private final ScheduledExecutorService executor; - private final Object lock = new Object(); - private final Set<MdnsServiceBrowserListener> listeners = new ArraySet<>(); - private final Map<String, MdnsResponse> instanceNameToResponse = new HashMap<>(); - private final boolean removeServiceAfterTtlExpires = - MdnsConfigs.removeServiceAfterTtlExpires(); - private final boolean allowSearchOptionsToRemoveExpiredService = - MdnsConfigs.allowSearchOptionsToRemoveExpiredService(); - - @Nullable private MdnsSearchOptions searchOptions; - - // The session ID increases when startSendAndReceive() is called where we schedule a - // QueryTask for - // new subtypes. It stays the same between packets for same subtypes. - private long currentSessionId = 0; - - @GuardedBy("lock") - @Nullable - private Future<?> requestTaskFuture; - - /** - * Constructor of {@link MdnsServiceTypeClient}. - * - * @param socketClient Sends and receives mDNS packet. - * @param executor A {@link ScheduledExecutorService} used to schedule query tasks. - */ - public MdnsServiceTypeClient( - @NonNull String serviceType, - @NonNull MdnsSocketClient socketClient, - @NonNull ScheduledExecutorService executor) { - this.serviceType = serviceType; - this.socketClient = socketClient; - this.executor = executor; - serviceTypeLabels = TextUtils.split(serviceType, "\\."); - } - - private static MdnsServiceInfo buildMdnsServiceInfoFromResponse( - @NonNull MdnsResponse response, @NonNull String[] serviceTypeLabels) { - String[] hostName = null; - int port = 0; - if (response.hasServiceRecord()) { - hostName = response.getServiceRecord().getServiceHost(); - port = response.getServiceRecord().getServicePort(); - } - - String ipv4Address = null; - String ipv6Address = null; - if (response.hasInet4AddressRecord()) { - Inet4Address inet4Address = response.getInet4AddressRecord().getInet4Address(); - ipv4Address = (inet4Address == null) ? null : inet4Address.getHostAddress(); - } - if (response.hasInet6AddressRecord()) { - Inet6Address inet6Address = response.getInet6AddressRecord().getInet6Address(); - ipv6Address = (inet6Address == null) ? null : inet6Address.getHostAddress(); - } - String serviceInstanceName = response.getServiceInstanceName(); - if (serviceInstanceName == null) { - throw new IllegalStateException( - "mDNS response must have non-null service instance name"); - } - List<String> textStrings = null; - List<MdnsServiceInfo.TextEntry> textEntries = null; - if (response.hasTextRecord()) { - textStrings = response.getTextRecord().getStrings(); - textEntries = response.getTextRecord().getEntries(); - } - // TODO: Throw an error message if response doesn't have Inet6 or Inet4 address. - return new MdnsServiceInfo( - serviceInstanceName, - serviceTypeLabels, - response.getSubtypes(), - hostName, - port, - ipv4Address, - ipv6Address, - textStrings, - textEntries, - response.getInterfaceIndex(), - response.getNetwork()); - } - - /** - * Registers {@code listener} for receiving discovery event of mDNS service instances, and - * starts - * (or continue) to send mDNS queries periodically. - * - * @param listener The {@link MdnsServiceBrowserListener} to register. - * @param searchOptions {@link MdnsSearchOptions} contains the list of subtypes to discover. - */ - public void startSendAndReceive( - @NonNull MdnsServiceBrowserListener listener, - @NonNull MdnsSearchOptions searchOptions) { - synchronized (lock) { - this.searchOptions = searchOptions; - if (listeners.add(listener)) { - for (MdnsResponse existingResponse : instanceNameToResponse.values()) { - final MdnsServiceInfo info = - buildMdnsServiceInfoFromResponse(existingResponse, serviceTypeLabels); - listener.onServiceNameDiscovered(info); - if (existingResponse.isComplete()) { - listener.onServiceFound(info); - } - } - } - // Cancel the next scheduled periodical task. - if (requestTaskFuture != null) { - requestTaskFuture.cancel(true); - } - // Keep tracking the ScheduledFuture for the task so we can cancel it if caller is not - // interested anymore. - requestTaskFuture = - executor.submit( - new QueryTask( - new QueryTaskConfig( - searchOptions.getSubtypes(), - searchOptions.isPassiveMode(), - ++currentSessionId))); - } - } - - /** - * Unregisters {@code listener} from receiving discovery event of mDNS service instances. - * - * @param listener The {@link MdnsServiceBrowserListener} to unregister. - * @return {@code true} if no listener is registered with this client after unregistering {@code - * listener}. Otherwise returns {@code false}. - */ - public boolean stopSendAndReceive(@NonNull MdnsServiceBrowserListener listener) { - synchronized (lock) { - listeners.remove(listener); - if (listeners.isEmpty() && requestTaskFuture != null) { - requestTaskFuture.cancel(true); - requestTaskFuture = null; - } - return listeners.isEmpty(); - } - } - - public String[] getServiceTypeLabels() { - return serviceTypeLabels; - } - - public synchronized void processResponse(@NonNull MdnsResponse response) { - if (shouldRemoveServiceAfterTtlExpires()) { - // Because {@link QueryTask} and {@link processResponse} are running in different - // threads. We need to synchronize {@link lock} to protect - // {@link instanceNameToResponse} won’t be modified at the same time. - synchronized (lock) { - if (response.isGoodbye()) { - onGoodbyeReceived(response.getServiceInstanceName()); - } else { - onResponseReceived(response); - } - } - } else { - if (response.isGoodbye()) { - onGoodbyeReceived(response.getServiceInstanceName()); - } else { - onResponseReceived(response); - } - } - } - - public synchronized void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode) { - for (MdnsServiceBrowserListener listener : listeners) { - listener.onFailedToParseMdnsResponse(receivedPacketNumber, errorCode); - } - } - - private void onResponseReceived(@NonNull MdnsResponse response) { - MdnsResponse currentResponse; - currentResponse = instanceNameToResponse.get(response.getServiceInstanceName()); - - boolean newServiceFound = false; - boolean existingServiceChanged = false; - boolean serviceBecomesComplete = false; - if (currentResponse == null) { - newServiceFound = true; - currentResponse = response; - String serviceInstanceName = response.getServiceInstanceName(); - if (serviceInstanceName != null) { - instanceNameToResponse.put(serviceInstanceName, currentResponse); - } - } else { - boolean before = currentResponse.isComplete(); - existingServiceChanged = currentResponse.mergeRecordsFrom(response); - boolean after = currentResponse.isComplete(); - serviceBecomesComplete = !before && after; - } - if (!newServiceFound && !existingServiceChanged) { - return; - } - MdnsServiceInfo serviceInfo = - buildMdnsServiceInfoFromResponse(currentResponse, serviceTypeLabels); - - for (MdnsServiceBrowserListener listener : listeners) { - if (newServiceFound) { - listener.onServiceNameDiscovered(serviceInfo); - } - - if (currentResponse.isComplete()) { - if (newServiceFound || serviceBecomesComplete) { - listener.onServiceFound(serviceInfo); - } else { - listener.onServiceUpdated(serviceInfo); - } - } - } - } - - private void onGoodbyeReceived(@Nullable String serviceInstanceName) { - final MdnsResponse response = instanceNameToResponse.remove(serviceInstanceName); - if (response == null) { - return; - } - for (MdnsServiceBrowserListener listener : listeners) { - final MdnsServiceInfo serviceInfo = - buildMdnsServiceInfoFromResponse(response, serviceTypeLabels); - if (response.isComplete()) { - listener.onServiceRemoved(serviceInfo); - } - listener.onServiceNameRemoved(serviceInfo); - } - } - - private boolean shouldRemoveServiceAfterTtlExpires() { - if (removeServiceAfterTtlExpires) { - return true; - } - return allowSearchOptionsToRemoveExpiredService - && searchOptions != null - && searchOptions.removeExpiredService(); - } - - @VisibleForTesting - MdnsPacketWriter createMdnsPacketWriter() { - return new MdnsPacketWriter(DEFAULT_MTU); - } - - // A configuration for the PeriodicalQueryTask that contains parameters to build a query packet. - // Call to getConfigForNextRun returns a config that can be used to build the next query task. - @VisibleForTesting - static class QueryTaskConfig { - - private static final int INITIAL_TIME_BETWEEN_BURSTS_MS = - (int) MdnsConfigs.initialTimeBetweenBurstsMs(); - private static final int TIME_BETWEEN_BURSTS_MS = (int) MdnsConfigs.timeBetweenBurstsMs(); - private static final int QUERIES_PER_BURST = (int) MdnsConfigs.queriesPerBurst(); - private static final int TIME_BETWEEN_QUERIES_IN_BURST_MS = - (int) MdnsConfigs.timeBetweenQueriesInBurstMs(); - private static final int QUERIES_PER_BURST_PASSIVE_MODE = - (int) MdnsConfigs.queriesPerBurstPassive(); - private static final int UNSIGNED_SHORT_MAX_VALUE = 65536; - // The following fields are used by QueryTask so we need to test them. - @VisibleForTesting - final List<String> subtypes; - private final boolean alwaysAskForUnicastResponse = - MdnsConfigs.alwaysAskForUnicastResponseInEachBurst(); - private final boolean usePassiveMode; - private final long sessionId; - @VisibleForTesting - int transactionId; - @VisibleForTesting - boolean expectUnicastResponse; - private int queriesPerBurst; - private int timeBetweenBurstsInMs; - private int burstCounter; - private int timeToRunNextTaskInMs; - private boolean isFirstBurst; - - QueryTaskConfig(@NonNull Collection<String> subtypes, boolean usePassiveMode, - long sessionId) { - this.usePassiveMode = usePassiveMode; - this.subtypes = new ArrayList<>(subtypes); - this.queriesPerBurst = QUERIES_PER_BURST; - this.burstCounter = 0; - this.transactionId = 1; - this.expectUnicastResponse = true; - this.isFirstBurst = true; - this.sessionId = sessionId; - // Config the scan frequency based on the scan mode. - if (this.usePassiveMode) { - // In passive scan mode, sends a single burst of QUERIES_PER_BURST queries, and then - // in each TIME_BETWEEN_BURSTS interval, sends QUERIES_PER_BURST_PASSIVE_MODE - // queries. - this.timeBetweenBurstsInMs = TIME_BETWEEN_BURSTS_MS; - } else { - // In active scan mode, sends a burst of QUERIES_PER_BURST queries, - // TIME_BETWEEN_QUERIES_IN_BURST_MS apart, then waits for the scan interval, and - // then repeats. The scan interval starts as INITIAL_TIME_BETWEEN_BURSTS_MS and - // doubles until it maxes out at TIME_BETWEEN_BURSTS_MS. - this.timeBetweenBurstsInMs = INITIAL_TIME_BETWEEN_BURSTS_MS; - } - } - - QueryTaskConfig getConfigForNextRun() { - if (++transactionId > UNSIGNED_SHORT_MAX_VALUE) { - transactionId = 1; - } - // Only the first query expects uni-cast response. - expectUnicastResponse = false; - if (++burstCounter == queriesPerBurst) { - burstCounter = 0; - - if (alwaysAskForUnicastResponse) { - expectUnicastResponse = true; - } - // In passive scan mode, sends a single burst of QUERIES_PER_BURST queries, and - // then in each TIME_BETWEEN_BURSTS interval, sends QUERIES_PER_BURST_PASSIVE_MODE - // queries. - if (isFirstBurst) { - isFirstBurst = false; - if (usePassiveMode) { - queriesPerBurst = QUERIES_PER_BURST_PASSIVE_MODE; - } - } - // In active scan mode, sends a burst of QUERIES_PER_BURST queries, - // TIME_BETWEEN_QUERIES_IN_BURST_MS apart, then waits for the scan interval, and - // then repeats. The scan interval starts as INITIAL_TIME_BETWEEN_BURSTS_MS and - // doubles until it maxes out at TIME_BETWEEN_BURSTS_MS. - timeToRunNextTaskInMs = timeBetweenBurstsInMs; - if (timeBetweenBurstsInMs < TIME_BETWEEN_BURSTS_MS) { - timeBetweenBurstsInMs = Math.min(timeBetweenBurstsInMs * 2, - TIME_BETWEEN_BURSTS_MS); - } - } else { - timeToRunNextTaskInMs = TIME_BETWEEN_QUERIES_IN_BURST_MS; - } - return this; - } - } - - // A FutureTask that enqueues a single query, and schedule a new FutureTask for the next task. - private class QueryTask implements Runnable { - - private final QueryTaskConfig config; - - QueryTask(@NonNull QueryTaskConfig config) { - this.config = config; - } - - @Override - public void run() { - Pair<Integer, List<String>> result; - try { - result = - new EnqueueMdnsQueryCallable( - socketClient, - createMdnsPacketWriter(), - serviceType, - config.subtypes, - config.expectUnicastResponse, - config.transactionId) - .call(); - } catch (RuntimeException e) { - LOGGER.e(String.format("Failed to run EnqueueMdnsQueryCallable for subtype: %s", - TextUtils.join(",", config.subtypes)), e); - result = null; - } - synchronized (lock) { - if (MdnsConfigs.useSessionIdToScheduleMdnsTask()) { - // In case that the task is not canceled successfully, use session ID to check - // if this task should continue to schedule more. - if (config.sessionId != currentSessionId) { - return; - } - } - - if (MdnsConfigs.shouldCancelScanTaskWhenFutureIsNull()) { - if (requestTaskFuture == null) { - // If requestTaskFuture is set to null, the task is cancelled. We can't use - // isCancelled() here because this QueryTask is different from the future - // that is returned from executor.schedule(). See b/71646910. - return; - } - } - if ((result != null)) { - for (MdnsServiceBrowserListener listener : listeners) { - listener.onDiscoveryQuerySent(result.second, result.first); - } - } - if (shouldRemoveServiceAfterTtlExpires()) { - Iterator<MdnsResponse> iter = instanceNameToResponse.values().iterator(); - while (iter.hasNext()) { - MdnsResponse existingResponse = iter.next(); - if (existingResponse.hasServiceRecord() - && existingResponse - .getServiceRecord() - .getRemainingTTL(SystemClock.elapsedRealtime()) - == 0) { - iter.remove(); - for (MdnsServiceBrowserListener listener : listeners) { - String serviceInstanceName = - existingResponse.getServiceInstanceName(); - if (serviceInstanceName != null) { - final MdnsServiceInfo serviceInfo = - buildMdnsServiceInfoFromResponse( - existingResponse, serviceTypeLabels); - if (existingResponse.isComplete()) { - listener.onServiceRemoved(serviceInfo); - } - listener.onServiceNameRemoved(serviceInfo); - } - } - } - } - } - QueryTaskConfig config = this.config.getConfigForNextRun(); - requestTaskFuture = - executor.schedule( - new QueryTask(config), config.timeToRunNextTaskInMs, MILLISECONDS); - } - } - } -} \ No newline at end of file
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsSocketProvider.java b/service/mdns/com/android/server/connectivity/mdns/MdnsSocketProvider.java deleted file mode 100644 index b8c324e..0000000 --- a/service/mdns/com/android/server/connectivity/mdns/MdnsSocketProvider.java +++ /dev/null
@@ -1,460 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.connectivity.mdns; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.INetd; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.Network; -import android.net.NetworkRequest; -import android.net.TetheringManager; -import android.net.TetheringManager.TetheringEventCallback; -import android.os.Handler; -import android.os.Looper; -import android.system.OsConstants; -import android.util.ArrayMap; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.LinkPropertiesUtils.CompareResult; -import com.android.net.module.util.ip.NetlinkMonitor; -import com.android.net.module.util.netlink.NetlinkConstants; -import com.android.net.module.util.netlink.NetlinkMessage; -import com.android.server.connectivity.mdns.util.MdnsLogger; - -import java.io.IOException; -import java.net.InterfaceAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.List; - -/** - * The {@link MdnsSocketProvider} manages the multiple sockets for mDns. - * - * <p>This class is not thread safe, it is intended to be used only from the looper thread. - * However, the constructor is an exception, as it is called on another thread; - * therefore for thread safety all members of this class MUST either be final or initialized - * to their default value (0, false or null). - * - */ -public class MdnsSocketProvider { - private static final String TAG = MdnsSocketProvider.class.getSimpleName(); - private static final boolean DBG = MdnsDiscoveryManager.DBG; - private static final MdnsLogger LOGGER = new MdnsLogger(TAG); - @NonNull private final Context mContext; - @NonNull private final Handler mHandler; - @NonNull private final Dependencies mDependencies; - @NonNull private final NetworkCallback mNetworkCallback; - @NonNull private final TetheringEventCallback mTetheringEventCallback; - @NonNull private final NetlinkMonitor mNetlinkMonitor; - private final ArrayMap<Network, SocketInfo> mNetworkSockets = new ArrayMap<>(); - private final ArrayMap<String, SocketInfo> mTetherInterfaceSockets = new ArrayMap<>(); - private final ArrayMap<Network, LinkProperties> mActiveNetworksLinkProperties = - new ArrayMap<>(); - private final ArrayMap<SocketCallback, Network> mCallbacksToRequestedNetworks = - new ArrayMap<>(); - private final List<String> mLocalOnlyInterfaces = new ArrayList<>(); - private final List<String> mTetheredInterfaces = new ArrayList<>(); - private boolean mMonitoringSockets = false; - - public MdnsSocketProvider(@NonNull Context context, @NonNull Looper looper) { - this(context, looper, new Dependencies()); - } - - MdnsSocketProvider(@NonNull Context context, @NonNull Looper looper, - @NonNull Dependencies deps) { - mContext = context; - mHandler = new Handler(looper); - mDependencies = deps; - mNetworkCallback = new NetworkCallback() { - @Override - public void onLost(Network network) { - mActiveNetworksLinkProperties.remove(network); - removeSocket(network, null /* interfaceName */); - } - - @Override - public void onLinkPropertiesChanged(Network network, LinkProperties lp) { - handleLinkPropertiesChanged(network, lp); - } - }; - mTetheringEventCallback = new TetheringEventCallback() { - @Override - public void onLocalOnlyInterfacesChanged(@NonNull List<String> interfaces) { - handleTetherInterfacesChanged(mLocalOnlyInterfaces, interfaces); - } - - @Override - public void onTetheredInterfacesChanged(@NonNull List<String> interfaces) { - handleTetherInterfacesChanged(mTetheredInterfaces, interfaces); - } - }; - - mNetlinkMonitor = new SocketNetlinkMonitor(mHandler); - } - - /** - * Dependencies of MdnsSocketProvider, for injection in tests. - */ - @VisibleForTesting - public static class Dependencies { - /*** Get network interface by given interface name */ - public NetworkInterfaceWrapper getNetworkInterfaceByName(String interfaceName) - throws SocketException { - final NetworkInterface ni = NetworkInterface.getByName(interfaceName); - return ni == null ? null : new NetworkInterfaceWrapper(ni); - } - - /*** Check whether given network interface can support mdns */ - public boolean canScanOnInterface(NetworkInterfaceWrapper networkInterface) { - return MulticastNetworkInterfaceProvider.canScanOnInterface(networkInterface); - } - - /*** Create a MdnsInterfaceSocket */ - public MdnsInterfaceSocket createMdnsInterfaceSocket(NetworkInterface networkInterface, - int port) throws IOException { - return new MdnsInterfaceSocket(networkInterface, port); - } - } - - /*** Data class for storing socket related info */ - private static class SocketInfo { - final MdnsInterfaceSocket mSocket; - final List<LinkAddress> mAddresses = new ArrayList<>(); - - SocketInfo(MdnsInterfaceSocket socket, List<LinkAddress> addresses) { - mSocket = socket; - mAddresses.addAll(addresses); - } - } - - private static class SocketNetlinkMonitor extends NetlinkMonitor { - SocketNetlinkMonitor(Handler handler) { - super(handler, LOGGER.mLog, TAG, OsConstants.NETLINK_ROUTE, - NetlinkConstants.RTMGRP_IPV4_IFADDR | NetlinkConstants.RTMGRP_IPV6_IFADDR); - } - - @Override - public void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) { - // TODO: Handle netlink message. - } - } - - private void ensureRunningOnHandlerThread() { - if (mHandler.getLooper().getThread() != Thread.currentThread()) { - throw new IllegalStateException( - "Not running on Handler thread: " + Thread.currentThread().getName()); - } - } - - /*** Start monitoring sockets by listening callbacks for sockets creation or removal */ - public void startMonitoringSockets() { - ensureRunningOnHandlerThread(); - if (mMonitoringSockets) { - Log.d(TAG, "Already monitoring sockets."); - return; - } - if (DBG) Log.d(TAG, "Start monitoring sockets."); - mContext.getSystemService(ConnectivityManager.class).registerNetworkCallback( - new NetworkRequest.Builder().clearCapabilities().build(), - mNetworkCallback, mHandler); - - final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); - tetheringManager.registerTetheringEventCallback(mHandler::post, mTetheringEventCallback); - - mHandler.post(mNetlinkMonitor::start); - mMonitoringSockets = true; - } - - /*** Stop monitoring sockets and unregister callbacks */ - public void stopMonitoringSockets() { - ensureRunningOnHandlerThread(); - if (!mMonitoringSockets) { - Log.d(TAG, "Monitoring sockets hasn't been started."); - return; - } - if (DBG) Log.d(TAG, "Stop monitoring sockets."); - mContext.getSystemService(ConnectivityManager.class) - .unregisterNetworkCallback(mNetworkCallback); - - final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); - tetheringManager.unregisterTetheringEventCallback(mTetheringEventCallback); - - mHandler.post(mNetlinkMonitor::stop); - mMonitoringSockets = false; - } - - private static boolean isNetworkMatched(@Nullable Network targetNetwork, - @NonNull Network currentNetwork) { - return targetNetwork == null || targetNetwork.equals(currentNetwork); - } - - private boolean matchRequestedNetwork(Network network) { - for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) { - final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i); - if (isNetworkMatched(requestedNetwork, network)) { - return true; - } - } - return false; - } - - private boolean hasAllNetworksRequest() { - return mCallbacksToRequestedNetworks.containsValue(null); - } - - private void handleLinkPropertiesChanged(Network network, LinkProperties lp) { - mActiveNetworksLinkProperties.put(network, lp); - if (!matchRequestedNetwork(network)) { - if (DBG) { - Log.d(TAG, "Ignore LinkProperties change. There is no request for the" - + " Network:" + network); - } - return; - } - - final SocketInfo socketInfo = mNetworkSockets.get(network); - if (socketInfo == null) { - createSocket(network, lp); - } else { - // Update the addresses of this socket. - final List<LinkAddress> addresses = lp.getLinkAddresses(); - socketInfo.mAddresses.clear(); - socketInfo.mAddresses.addAll(addresses); - // Try to join the group again. - socketInfo.mSocket.joinGroup(addresses); - - notifyAddressesChanged(network, lp); - } - } - - private static LinkProperties createLPForTetheredInterface(String interfaceName) { - final LinkProperties linkProperties = new LinkProperties(); - linkProperties.setInterfaceName(interfaceName); - // TODO: Use NetlinkMonitor to update addresses for tethering interfaces. - return linkProperties; - } - - private void handleTetherInterfacesChanged(List<String> current, List<String> updated) { - if (!hasAllNetworksRequest()) { - // Currently, the network for tethering can not be requested, so the sockets for - // tethering are only created if there is a request for all networks (interfaces). - // Therefore, this change can skip if there is no such request. - if (DBG) { - Log.d(TAG, "Ignore tether interfaces change. There is no request for all" - + " networks."); - } - return; - } - - final CompareResult<String> interfaceDiff = new CompareResult<>( - current, updated); - for (String name : interfaceDiff.added) { - createSocket(new Network(INetd.LOCAL_NET_ID), createLPForTetheredInterface(name)); - } - for (String name : interfaceDiff.removed) { - removeSocket(new Network(INetd.LOCAL_NET_ID), name); - } - current.clear(); - current.addAll(updated); - } - - private static List<LinkAddress> getLinkAddressFromNetworkInterface( - NetworkInterfaceWrapper networkInterface) { - List<LinkAddress> addresses = new ArrayList<>(); - for (InterfaceAddress address : networkInterface.getInterfaceAddresses()) { - addresses.add(new LinkAddress(address)); - } - return addresses; - } - - private void createSocket(Network network, LinkProperties lp) { - final String interfaceName = lp.getInterfaceName(); - if (interfaceName == null) { - Log.e(TAG, "Can not create socket with null interface name."); - return; - } - - try { - final NetworkInterfaceWrapper networkInterface = - mDependencies.getNetworkInterfaceByName(interfaceName); - if (networkInterface == null || !mDependencies.canScanOnInterface(networkInterface)) { - return; - } - - if (DBG) { - Log.d(TAG, "Create a socket on network:" + network - + " with interfaceName:" + interfaceName); - } - final MdnsInterfaceSocket socket = mDependencies.createMdnsInterfaceSocket( - networkInterface.getNetworkInterface(), MdnsConstants.MDNS_PORT); - final List<LinkAddress> addresses; - if (network.netId == INetd.LOCAL_NET_ID) { - addresses = getLinkAddressFromNetworkInterface(networkInterface); - mTetherInterfaceSockets.put(interfaceName, new SocketInfo(socket, addresses)); - } else { - addresses = lp.getLinkAddresses(); - mNetworkSockets.put(network, new SocketInfo(socket, addresses)); - } - // Try to join IPv4/IPv6 group. - socket.joinGroup(addresses); - - // Notify the listeners which need this socket. - notifySocketCreated(network, socket, addresses); - } catch (IOException e) { - Log.e(TAG, "Create a socket failed with interface=" + interfaceName, e); - } - } - - private void removeSocket(Network network, String interfaceName) { - final SocketInfo socketInfo = network.netId == INetd.LOCAL_NET_ID - ? mTetherInterfaceSockets.remove(interfaceName) - : mNetworkSockets.remove(network); - if (socketInfo == null) return; - - socketInfo.mSocket.destroy(); - notifyInterfaceDestroyed(network, socketInfo.mSocket); - } - - private void notifySocketCreated(Network network, MdnsInterfaceSocket socket, - List<LinkAddress> addresses) { - for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) { - final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i); - if (isNetworkMatched(requestedNetwork, network)) { - mCallbacksToRequestedNetworks.keyAt(i).onSocketCreated(network, socket, addresses); - } - } - } - - private void notifyInterfaceDestroyed(Network network, MdnsInterfaceSocket socket) { - for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) { - final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i); - if (isNetworkMatched(requestedNetwork, network)) { - mCallbacksToRequestedNetworks.keyAt(i).onInterfaceDestroyed(network, socket); - } - } - } - - private void notifyAddressesChanged(Network network, LinkProperties lp) { - for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) { - final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i); - if (isNetworkMatched(requestedNetwork, network)) { - mCallbacksToRequestedNetworks.keyAt(i) - .onAddressesChanged(network, lp.getLinkAddresses()); - } - } - } - - private void retrieveAndNotifySocketFromNetwork(Network network, SocketCallback cb) { - final SocketInfo socketInfo = mNetworkSockets.get(network); - if (socketInfo == null) { - final LinkProperties lp = mActiveNetworksLinkProperties.get(network); - if (lp == null) { - // The requested network is not existed. Maybe wait for LinkProperties change later. - if (DBG) Log.d(TAG, "There is no LinkProperties for this network:" + network); - return; - } - createSocket(network, lp); - } else { - // Notify the socket for requested network. - cb.onSocketCreated(network, socketInfo.mSocket, socketInfo.mAddresses); - } - } - - private void retrieveAndNotifySocketFromInterface(String interfaceName, SocketCallback cb) { - final SocketInfo socketInfo = mTetherInterfaceSockets.get(interfaceName); - if (socketInfo == null) { - createSocket( - new Network(INetd.LOCAL_NET_ID), createLPForTetheredInterface(interfaceName)); - } else { - // Notify the socket for requested network. - cb.onSocketCreated( - new Network(INetd.LOCAL_NET_ID), socketInfo.mSocket, socketInfo.mAddresses); - } - } - - /** - * Request a socket for given network. - * - * @param network the required network for a socket. Null means create sockets on all possible - * networks (interfaces). - * @param cb the callback to listen the socket creation. - */ - public void requestSocket(@Nullable Network network, @NonNull SocketCallback cb) { - ensureRunningOnHandlerThread(); - mCallbacksToRequestedNetworks.put(cb, network); - if (network == null) { - // Does not specify a required network, create sockets for all possible - // networks (interfaces). - for (int i = 0; i < mActiveNetworksLinkProperties.size(); i++) { - retrieveAndNotifySocketFromNetwork(mActiveNetworksLinkProperties.keyAt(i), cb); - } - - for (String localInterface : mLocalOnlyInterfaces) { - retrieveAndNotifySocketFromInterface(localInterface, cb); - } - - for (String tetheredInterface : mTetheredInterfaces) { - retrieveAndNotifySocketFromInterface(tetheredInterface, cb); - } - } else { - retrieveAndNotifySocketFromNetwork(network, cb); - } - } - - /*** Unrequest the socket */ - public void unrequestSocket(@NonNull SocketCallback cb) { - ensureRunningOnHandlerThread(); - mCallbacksToRequestedNetworks.remove(cb); - if (hasAllNetworksRequest()) { - // Still has a request for all networks (interfaces). - return; - } - - // Check if remaining requests are matched any of sockets. - for (int i = mNetworkSockets.size() - 1; i >= 0; i--) { - if (matchRequestedNetwork(mNetworkSockets.keyAt(i))) continue; - mNetworkSockets.removeAt(i).mSocket.destroy(); - } - - // Remove all sockets for tethering interface because these sockets do not have associated - // networks, and they should invoke by a request for all networks (interfaces). If there is - // no such request, the sockets for tethering interface should be removed. - for (int i = mTetherInterfaceSockets.size() - 1; i >= 0; i--) { - mTetherInterfaceSockets.removeAt(i).mSocket.destroy(); - } - } - - /*** Callbacks for listening socket changes */ - public interface SocketCallback { - /*** Notify the socket is created */ - default void onSocketCreated(@NonNull Network network, @NonNull MdnsInterfaceSocket socket, - @NonNull List<LinkAddress> addresses) {} - /*** Notify the interface is destroyed */ - default void onInterfaceDestroyed(@NonNull Network network, - @NonNull MdnsInterfaceSocket socket) {} - /*** Notify the addresses is changed on the network */ - default void onAddressesChanged(@NonNull Network network, - @NonNull List<LinkAddress> addresses) {} - } -}
diff --git a/service/native/include/TrafficController.h b/service/native/include/TrafficController.h index b44d795..cb6c836 100644 --- a/service/native/include/TrafficController.h +++ b/service/native/include/TrafficController.h
@@ -21,7 +21,7 @@ #include "android-base/thread_annotations.h" #include "bpf/BpfMap.h" -#include "bpf_shared.h" +#include "netd.h" #include "netdutils/DumpWriter.h" #include "netdutils/NetlinkListener.h" #include "netdutils/StatusOr.h"
diff --git a/service/native/libs/libclat/Android.bp b/service/native/libs/libclat/Android.bp index 54d40ac..996706e 100644 --- a/service/native/libs/libclat/Android.bp +++ b/service/native/libs/libclat/Android.bp
@@ -23,6 +23,9 @@ "clatutils.cpp", ], stl: "libc++_static", + header_libs: [ + "bpf_headers", + ], static_libs: [ "libip_checksum", ],
diff --git a/service/native/libs/libclat/clatutils.cpp b/service/native/libs/libclat/clatutils.cpp index be86612..6c5c9e3 100644 --- a/service/native/libs/libclat/clatutils.cpp +++ b/service/native/libs/libclat/clatutils.cpp
@@ -25,26 +25,19 @@ #include <string.h> #include <unistd.h> +#include <bpf/BpfClassic.h> + extern "C" { #include "checksum.h" } -// Sync from external/android-clat/clatd.h -#define MAXMTU 65536 -#define PACKETLEN (MAXMTU + sizeof(struct tun_pi)) - -// Sync from system/netd/include/netid_client.h. -#define MARK_UNSET 0u - namespace android { namespace net { namespace clat { -bool isIpv4AddressFree(in_addr_t addr) { - int s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (s == -1) { - return 0; - } +bool isIpv4AddressFree(const in_addr_t addr) { + const int s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (s == -1) return 0; // Attempt to connect to the address. If the connection succeeds and getsockname returns the // same then the address is already assigned to the system and we can't use it. @@ -54,9 +47,10 @@ .sin_addr = {addr}, }; socklen_t len = sizeof(sin); - bool inuse = connect(s, (struct sockaddr*)&sin, sizeof(sin)) == 0 && - getsockname(s, (struct sockaddr*)&sin, &len) == 0 && (size_t)len >= sizeof(sin) && - sin.sin_addr.s_addr == addr; + const bool inuse = !connect(s, (struct sockaddr*)&sin, sizeof(sin)) && + !getsockname(s, (struct sockaddr*)&sin, &len) && + len == (socklen_t)sizeof(sin) && + sin.sin_addr.s_addr == addr; close(s); return !inuse; @@ -66,36 +60,30 @@ // ip - the IP address from the configuration file // prefixlen - the length of the prefix from which addresses may be selected. // returns: the IPv4 address, or INADDR_NONE if no addresses were available -in_addr_t selectIpv4Address(const in_addr ip, int16_t prefixlen) { +in_addr_t selectIpv4Address(const in_addr ip, const int16_t prefixlen) { return selectIpv4AddressInternal(ip, prefixlen, isIpv4AddressFree); } // Only allow testing to use this function directly. Otherwise call selectIpv4Address(ip, pfxlen) // which has applied valid isIpv4AddressFree function pointer. -in_addr_t selectIpv4AddressInternal(const in_addr ip, int16_t prefixlen, - isIpv4AddrFreeFn isIpv4AddressFreeFunc) { +in_addr_t selectIpv4AddressInternal(const in_addr ip, const int16_t prefixlen, + const isIpv4AddrFreeFn isIpv4AddressFreeFunc) { // Impossible! Only test allows to apply fn. - if (isIpv4AddressFreeFunc == nullptr) { - return INADDR_NONE; - } + if (isIpv4AddressFreeFunc == nullptr) return INADDR_NONE; // Don't accept prefixes that are too large because we scan addresses one by one. - if (prefixlen < 16 || prefixlen > 32) { - return INADDR_NONE; - } + if (prefixlen < 16 || prefixlen > 32) return INADDR_NONE; // All these are in host byte order. - in_addr_t mask = 0xffffffff >> (32 - prefixlen) << (32 - prefixlen); - in_addr_t ipv4 = ntohl(ip.s_addr); - in_addr_t first_ipv4 = ipv4; - in_addr_t prefix = ipv4 & mask; + const uint32_t mask = 0xffffffff >> (32 - prefixlen) << (32 - prefixlen); + uint32_t ipv4 = ntohl(ip.s_addr); + const uint32_t first_ipv4 = ipv4; + const uint32_t prefix = ipv4 & mask; // Pick the first IPv4 address in the pool, wrapping around if necessary. // So, for example, 192.0.0.4 -> 192.0.0.5 -> 192.0.0.6 -> 192.0.0.7 -> 192.0.0.0. do { - if (isIpv4AddressFreeFunc(htonl(ipv4))) { - return htonl(ipv4); - } + if (isIpv4AddressFreeFunc(htonl(ipv4))) return htonl(ipv4); ipv4 = prefix | ((ipv4 + 1) & ~mask); } while (ipv4 != first_ipv4); @@ -103,7 +91,7 @@ } // Alters the bits in the IPv6 address to make them checksum neutral with v4 and nat64Prefix. -void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix) { +void makeChecksumNeutral(in6_addr* const v6, const in_addr v4, const in6_addr& nat64Prefix) { // Fill last 8 bytes of IPv6 address with random bits. arc4random_buf(&v6->s6_addr[8], 8); @@ -125,33 +113,35 @@ } // Picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix. -int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix, - in6_addr* v6, uint32_t mark) { - int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); +int generateIpv6Address(const char* const iface, const in_addr v4, const in6_addr& nat64Prefix, + in6_addr* const v6, const uint32_t mark) { + const int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (s == -1) return -errno; // Socket's mark affects routing decisions (network selection) // An fwmark is necessary for clat to bypass the VPN during initialization. - if ((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)); + if (setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))) { + const int err = errno; + ALOGE("setsockopt(SOL_SOCKET, SO_MARK) failed: %s", strerror(err)); close(s); - return -ret; + return -err; } - if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface) + 1) == -1) { + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface) + 1)) { + const int err = errno; + ALOGE("setsockopt(SOL_SOCKET, SO_BINDTODEVICE, '%s') failed: %s", iface, strerror(err)); close(s); - return -errno; + return -err; } sockaddr_in6 sin6 = {.sin6_family = AF_INET6, .sin6_addr = nat64Prefix}; - if (connect(s, reinterpret_cast<struct sockaddr*>(&sin6), sizeof(sin6)) == -1) { + if (connect(s, reinterpret_cast<struct sockaddr*>(&sin6), sizeof(sin6))) { close(s); return -errno; } socklen_t len = sizeof(sin6); - if (getsockname(s, reinterpret_cast<struct sockaddr*>(&sin6), &len) == -1) { + if (getsockname(s, reinterpret_cast<struct sockaddr*>(&sin6), &len)) { close(s); return -errno; } @@ -170,21 +160,22 @@ return 0; } -int detect_mtu(const struct in6_addr* plat_subnet, uint32_t plat_suffix, uint32_t mark) { +int detect_mtu(const struct in6_addr* const plat_subnet, const uint32_t plat_suffix, + const uint32_t mark) { // Create an IPv6 UDP socket. - int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); + const int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (s < 0) { - int ret = errno; - ALOGE("socket(AF_INET6, SOCK_DGRAM, 0) failed: %s", strerror(errno)); - return -ret; + const int err = errno; + ALOGE("socket(AF_INET6, SOCK_DGRAM, 0) failed: %s", strerror(err)); + return -err; } // Socket's mark affects routing decisions (network selection) - if ((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)); + if (setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))) { + const int err = errno; + ALOGE("setsockopt(SOL_SOCKET, SO_MARK) failed: %s", strerror(err)); close(s); - return -ret; + return -err; } // Try to connect udp socket to plat_subnet(96 bits):plat_suffix(32 bits) @@ -194,20 +185,20 @@ }; dst.sin6_addr.s6_addr32[3] = plat_suffix; if (connect(s, (struct sockaddr*)&dst, sizeof(dst))) { - int ret = errno; - ALOGE("connect() failed: %s", strerror(errno)); + const int err = errno; + ALOGE("connect() failed: %s", strerror(err)); close(s); - return -ret; + return -err; } // Fetch the socket's IPv6 mtu - this is effectively fetching mtu from routing table int mtu; socklen_t sz_mtu = sizeof(mtu); if (getsockopt(s, SOL_IPV6, IPV6_MTU, &mtu, &sz_mtu)) { - int ret = errno; - ALOGE("getsockopt(SOL_IPV6, IPV6_MTU) failed: %s", strerror(errno)); + const int err = errno; + ALOGE("getsockopt(SOL_IPV6, IPV6_MTU) failed: %s", strerror(err)); close(s); - return -ret; + return -err; } if (sz_mtu != sizeof(mtu)) { ALOGE("getsockopt(SOL_IPV6, IPV6_MTU) returned unexpected size: %d", sz_mtu); @@ -226,34 +217,26 @@ * ifindex - index of interface to add the filter to * returns: 0 on success, -errno on failure */ -int configure_packet_socket(int sock, in6_addr* addr, int ifindex) { - uint32_t* ipv6 = addr->s6_addr32; - +int configure_packet_socket(const int sock, const in6_addr* const addr, const int ifindex) { // clang-format off struct sock_filter filter_code[] = { - // Load the first four bytes of the IPv6 destination address (starts 24 bytes in). - // Compare it against the first four bytes of our IPv6 address, in host byte order (BPF loads - // are always in host byte order). If it matches, continue with next instruction (JMP 0). If it - // doesn't match, jump ahead to statement that returns 0 (ignore packet). Repeat for the other - // three words of the IPv6 address, and if they all match, return PACKETLEN (accept packet). - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 24), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[0]), 0, 7), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 28), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[1]), 0, 5), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 32), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[2]), 0, 3), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 36), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[3]), 0, 1), - BPF_STMT(BPF_RET | BPF_K, PACKETLEN), - BPF_STMT(BPF_RET | BPF_K, 0), + BPF_LOAD_IPV6_BE32(daddr.s6_addr32[0]), + BPF2_REJECT_IF_NOT_EQUAL(ntohl(addr->s6_addr32[0])), + BPF_LOAD_IPV6_BE32(daddr.s6_addr32[1]), + BPF2_REJECT_IF_NOT_EQUAL(ntohl(addr->s6_addr32[1])), + BPF_LOAD_IPV6_BE32(daddr.s6_addr32[2]), + BPF2_REJECT_IF_NOT_EQUAL(ntohl(addr->s6_addr32[2])), + BPF_LOAD_IPV6_BE32(daddr.s6_addr32[3]), + BPF2_REJECT_IF_NOT_EQUAL(ntohl(addr->s6_addr32[3])), + BPF_ACCEPT, }; // clang-format on struct sock_fprog filter = {sizeof(filter_code) / sizeof(filter_code[0]), filter_code}; if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) { - int res = errno; - ALOGE("attach packet filter failed: %s", strerror(errno)); - return -res; + const int err = errno; + ALOGE("attach packet filter failed: %s", strerror(err)); + return -err; } struct sockaddr_ll sll = { @@ -264,9 +247,9 @@ PACKET_OTHERHOST, // The 464xlat IPv6 address is not assigned to the kernel. }; if (bind(sock, (struct sockaddr*)&sll, sizeof(sll))) { - int res = errno; - ALOGE("binding packet socket: %s", strerror(errno)); - return -res; + const int err = errno; + ALOGE("binding packet socket: %s", strerror(err)); + return -err; } return 0;
diff --git a/service/native/libs/libclat/clatutils_test.cpp b/service/native/libs/libclat/clatutils_test.cpp index abd4e81..f4f97db 100644 --- a/service/native/libs/libclat/clatutils_test.cpp +++ b/service/native/libs/libclat/clatutils_test.cpp
@@ -165,7 +165,7 @@ TunInterface v6Iface; ASSERT_EQ(0, v6Iface.init()); - int s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IPV6)); + const int s = socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC, htons(ETH_P_IPV6)); EXPECT_LE(0, s); struct in6_addr addr6; EXPECT_EQ(1, inet_pton(AF_INET6, "2001:db8::f00", &addr6));
diff --git a/service/native/libs/libclat/include/libclat/clatutils.h b/service/native/libs/libclat/include/libclat/clatutils.h index 991b193..6e17e67 100644 --- a/service/native/libs/libclat/include/libclat/clatutils.h +++ b/service/native/libs/libclat/include/libclat/clatutils.h
@@ -20,17 +20,19 @@ namespace net { namespace clat { -bool isIpv4AddressFree(in_addr_t addr); -in_addr_t selectIpv4Address(const in_addr ip, int16_t prefixlen); -void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix); -int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix, - in6_addr* v6, uint32_t mark); -int detect_mtu(const struct in6_addr* plat_subnet, uint32_t plat_suffix, uint32_t mark); -int configure_packet_socket(int sock, in6_addr* addr, int ifindex); +bool isIpv4AddressFree(const in_addr_t addr); +in_addr_t selectIpv4Address(const in_addr ip, const int16_t prefixlen); +void makeChecksumNeutral(in6_addr* const v6, const in_addr v4, const in6_addr& nat64Prefix); +int generateIpv6Address(const char* const iface, const in_addr v4, const in6_addr& nat64Prefix, + in6_addr* const v6, const uint32_t mark); +int detect_mtu(const struct in6_addr* const plat_subnet, const uint32_t plat_suffix, + const uint32_t mark); +int configure_packet_socket(const int sock, const in6_addr* const addr, const int ifindex); // For testing -typedef bool (*isIpv4AddrFreeFn)(in_addr_t); -in_addr_t selectIpv4AddressInternal(const in_addr ip, int16_t prefixlen, isIpv4AddrFreeFn fn); +typedef bool (*isIpv4AddrFreeFn)(const in_addr_t); +in_addr_t selectIpv4AddressInternal(const in_addr ip, const int16_t prefixlen, + const isIpv4AddrFreeFn fn); } // namespace clat } // namespace net
diff --git a/service/proguard.flags b/service/proguard.flags index 864a28b..cf25f05 100644 --- a/service/proguard.flags +++ b/service/proguard.flags
@@ -7,7 +7,7 @@ *; } --keepclassmembers class com.android.server.**,android.net.**,com.android.networkstack.** { +-keepclassmembers class android.net.**,com.android.networkstack.** { static final % POLICY_*; static final % NOTIFY_TYPE_*; static final % TRANSPORT_*;
diff --git a/service/src/com/android/metrics/stats.proto b/service/src/com/android/metrics/stats.proto index 48b8316..006d20a 100644 --- a/service/src/com/android/metrics/stats.proto +++ b/service/src/com/android/metrics/stats.proto
@@ -284,3 +284,152 @@ // The latency of selection issued in milli-second optional int32 selection_issued_latency_milli = 5; } + +message NetworkSliceRequestCountSample { + // Bitfield representing the network's capability(e.g. NET_CAPABILITY_PRIORITIZE_LATENCY), + // defined in packages/modules/Connectivity/framework/src/android/net/NetworkCapabilities.java + optional int64 slice_id = 1; + + // Bitfield representing the network's enterprise capability identifier + // (e.g. NET_ENTERPRISE_ID_1), defined in + // packages/modules/Connectivity/framework/src/android/net/NetworkCapabilities.java + optional int32 enterprise_id = 2; + + // number of request for this slice + optional int32 request_count = 3; + + // number of apps with outstanding request(s) for this slice + optional int32 distinct_app_count = 4; +} + +message NetworkSliceSessionEnded { + // Bitfield representing the network's capability(e.g. NET_CAPABILITY_PRIORITIZE_LATENCY), + // defined in packages/modules/Connectivity/framework/src/android/net/NetworkCapabilities.java + optional int64 slice_id = 1; + + // Bitfield representing the network's enterprise capability identifier + // (e.g. NET_ENTERPRISE_ID_1), defined in + // packages/modules/Connectivity/framework/src/android/net/NetworkCapabilities.java + optional int32 enterprise_id = 2; + + // Number of bytes received at the device on this slice id + optional int64 rx_bytes = 3; + + // Number of bytes transmitted by the device on this slice id + optional int64 tx_bytes = 4; + + // Number of apps that have used this slice + optional int32 number_of_apps = 5; + + // How long(in seconds) this slice has been connected + optional int32 slice_connection_duration_sec = 6; +} + +message NetworkSliceDailyDataUsageReported { + // Bitfield representing the network's capability(e.g. NET_CAPABILITY_PRIORITIZE_LATENCY), + // defined in packages/modules/Connectivity/framework/src/android/net/NetworkCapabilities.java + optional int64 slice_id = 1; + + // Bitfield representing the network's enterprise capability identifier + // (e.g. NET_ENTERPRISE_ID_1), defined in + // packages/modules/Connectivity/framework/src/android/net/NetworkCapabilities.java + optional int32 enterprise_id = 2; + + // Number of bytes received at the device on this slice id + optional int64 rx_bytes = 3; + + // Number of bytes transmitted by the device on this slice id + optional int64 tx_bytes = 4; + + // Number of apps that have used this slice + optional int32 number_of_apps = 5; + + // How long(in seconds) this slice has been connected + optional int32 slice_connection_duration_sec = 6; +} + +/** + * Logs DailykeepaliveInfoReported + * + * Logs from: packages/modules/Connectivity/service/src/com/android/ + * server/connectivity/AutomaticOnOffKeepaliveTracker. + */ +message DailykeepaliveInfoReported{ + // Daily duration per number of concurrent keepalive + optional DurationPerNumOfKeepalive duration_per_num_of_keepalive = 1; + + // Daily keepalive registered/active duration on each list of keepalive session, in + // milli-seconds + optional KeepaliveLifetimePerCarrier keepalive_lifetime_per_carrier = 2; + + // Daily number of keepalive requests + optional int32 keepalive_requests = 3; + + // Daily number of automatic keepalive requests + optional int32 automatic_keepalive_requests = 4; + + // Daily number of distinct apps that requested keepalives + optional int32 distinct_user_count = 5; + + // Daily distinct apps uid list that requested keepalives + repeated int32 uid = 6; +} + +/** + * Daily duration per number of concurrent keepalive + * + * Logs from: packages/modules/Connectivity/service/src/com/android/ + * server/connectivity/AutomaticOnOffKeepaliveTracker. + */ +message DurationPerNumOfKeepalive { + repeated DurationForNumOfKeepalive duration_for_num_of_keepalive = 1; +} + +message DurationForNumOfKeepalive { + // The number of concurrent keepalives is in the device + optional int32 num_of_keepalive = 1; + + // How many milliseconds the device has keepalive registration number is num_of_keepalive + optional int32 keepalive_registered_durations_msec = 2; + + // How many milliseconds the device has keepalive active(not paused) number is num_of_keepalive + optional int32 keepalive_active_durations_msec = 3; +} + +/** + * Daily keepalive registered/active duration on each list of Keepalive session, in milli-seconds + * + * Logs from: packages/modules/Connectivity/service/src/com/android/ + * server/connectivity/AutomaticOnOffKeepaliveTracker. + */ +message KeepaliveLifetimePerCarrier { + // The number of network count on each list of carriers + repeated KeepaliveLifetimeForCarrier keepalive_lifetime_for_carrier = 1; +} + +/** + * Logs the keepalive registered/active duration in milli-seconds and carrier + * info(carrier id, transport, keepalive interval). + * + * Logs from: packages/modules/Connectivity/service/src/com/android/ + * server/connectivity/AutomaticOnOffKeepaliveTracker. + */ +message KeepaliveLifetimeForCarrier { + // The carrier ID for each keepalive, or TelephonyManager.UNKNOWN_CARRIER_ID(-1) if not cell + optional int32 carrier_id = 1; + + // The transport types of the underlying network for each keepalive. 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 = 2; + + // The keepalive interval for each keepalive + optional int32 intervals_msec = 3; + + // The lifetime of the keepalive registered today + optional int32 lifetime_msec = 4; + + // The duration for which the keepalive was active (not suspended) + optional int32 active_lifetime_msec = 5; +} +
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java index b8a8fb4..ec168dd 100644 --- a/service/src/com/android/server/BpfNetMaps.java +++ b/service/src/com/android/server/BpfNetMaps.java
@@ -139,7 +139,7 @@ @VisibleForTesting public static final long OEM_DENY_1_MATCH = (1 << 9); @VisibleForTesting public static final long OEM_DENY_2_MATCH = (1 << 10); @VisibleForTesting public static final long OEM_DENY_3_MATCH = (1 << 11); - // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/bpf_shared.h) + // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/netd.h) private static final List<Pair<Integer, String>> PERMISSION_LIST = Arrays.asList( Pair.create(PERMISSION_INTERNET, "PERMISSION_INTERNET"), @@ -279,9 +279,10 @@ private static synchronized void ensureInitialized(final Context context) { if (sInitialized) return; if (sEnableJavaBpfMap == null) { - sEnableJavaBpfMap = DeviceConfigUtils.isFeatureEnabled(context, - DeviceConfig.NAMESPACE_TETHERING, BPF_NET_MAPS_ENABLE_JAVA_BPF_MAP, - false /* defaultValue */) || SdkLevel.isAtLeastU(); + sEnableJavaBpfMap = SdkLevel.isAtLeastU() || + DeviceConfigUtils.isFeatureEnabled(context, + DeviceConfig.NAMESPACE_TETHERING, BPF_NET_MAPS_ENABLE_JAVA_BPF_MAP, + DeviceConfigUtils.TETHERING_MODULE_NAME, false /* defaultValue */); } Log.d(TAG, "BpfNetMaps is initialized with sEnableJavaBpfMap=" + sEnableJavaBpfMap); @@ -383,7 +384,6 @@ * ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed * DENYLIST means the firewall allows all by default, uids must be explicitly denyed */ - @VisibleForTesting public boolean isFirewallAllowList(final int chain) { switch (chain) { case FIREWALL_CHAIN_DOZABLE: @@ -720,6 +720,90 @@ } /** + * Get firewall rule of specified firewall chain on specified uid. + * + * @param childChain target chain + * @param uid target uid + * @return either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY + * @throws UnsupportedOperationException if called on pre-T devices. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + public int getUidRule(final int childChain, final int uid) { + throwIfPreT("isUidChainEnabled is not available on pre-T devices"); + + final long match = getMatchByFirewallChain(childChain); + final boolean isAllowList = isFirewallAllowList(childChain); + try { + final UidOwnerValue uidMatch = sUidOwnerMap.getValue(new S32(uid)); + final boolean isMatchEnabled = uidMatch != null && (uidMatch.rule & match) != 0; + return isMatchEnabled == isAllowList ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY; + } catch (ErrnoException e) { + throw new ServiceSpecificException(e.errno, + "Unable to get uid rule status: " + Os.strerror(e.errno)); + } + } + + private Set<Integer> getUidsMatchEnabled(final int childChain) throws ErrnoException { + final long match = getMatchByFirewallChain(childChain); + Set<Integer> uids = new ArraySet<>(); + synchronized (sUidOwnerMap) { + sUidOwnerMap.forEach((uid, val) -> { + if (val == null) { + Log.wtf(TAG, "sUidOwnerMap entry was deleted while holding a lock"); + } else { + if ((val.rule & match) != 0) { + uids.add(uid.val); + } + } + }); + } + return uids; + } + + /** + * Get uids that has FIREWALL_RULE_ALLOW on allowlist chain. + * Allowlist means the firewall denies all by default, uids must be explicitly allowed. + * + * Note that uids that has FIREWALL_RULE_DENY on allowlist chain can not be computed from the + * bpf map, since all the uids that does not have explicit FIREWALL_RULE_ALLOW rule in bpf map + * are determined to have FIREWALL_RULE_DENY. + * + * @param childChain target chain + * @return Set of uids + */ + public Set<Integer> getUidsWithAllowRuleOnAllowListChain(final int childChain) + throws ErrnoException { + if (!isFirewallAllowList(childChain)) { + throw new IllegalArgumentException("getUidsWithAllowRuleOnAllowListChain is called with" + + " denylist chain:" + childChain); + } + // Corresponding match is enabled for uids that has FIREWALL_RULE_ALLOW on allowlist chain. + return getUidsMatchEnabled(childChain); + } + + /** + * Get uids that has FIREWALL_RULE_DENY on denylist chain. + * Denylist means the firewall allows all by default, uids must be explicitly denyed + * + * Note that uids that has FIREWALL_RULE_ALLOW on denylist chain can not be computed from the + * bpf map, since all the uids that does not have explicit FIREWALL_RULE_DENY rule in bpf map + * are determined to have the FIREWALL_RULE_ALLOW. + * + * @param childChain target chain + * @return Set of uids + */ + public Set<Integer> getUidsWithDenyRuleOnDenyListChain(final int childChain) + throws ErrnoException { + if (isFirewallAllowList(childChain)) { + throw new IllegalArgumentException("getUidsWithDenyRuleOnDenyListChain is called with" + + " allowlist chain:" + childChain); + } + // Corresponding match is enabled for uids that has FIREWALL_RULE_DENY on denylist chain. + return getUidsMatchEnabled(childChain); + } + + /** * Add ingress interface filtering rules to a list of UIDs * * For a given uid, once a filtering rule is added, the kernel will only allow packets from the
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index a44494c..98ad861 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java
@@ -17,6 +17,7 @@ package com.android.server; import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; +import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_FROZEN; import static android.content.pm.PackageManager.FEATURE_BLUETOOTH; import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.FEATURE_WIFI; @@ -91,13 +92,14 @@ import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY; import static android.os.Process.INVALID_UID; import static android.os.Process.VPN_UID; -import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; +import static android.provider.DeviceConfig.NAMESPACE_TETHERING; import static android.system.OsConstants.ETH_P_ALL; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME; import static com.android.net.module.util.NetworkMonitorUtils.isPrivateDnsValidationRequired; +import static com.android.net.module.util.PermissionUtils.checkAnyPermissionOf; import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf; import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission; import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr; @@ -108,10 +110,13 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TargetApi; +import android.app.ActivityManager; +import android.app.ActivityManager.UidFrozenStateChangedCallback; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; +import android.app.compat.CompatChanges; import android.app.usage.NetworkStatsManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -120,6 +125,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.res.XmlResourceParser; import android.database.ContentObserver; import android.net.CaptivePortal; import android.net.CaptivePortalData; @@ -130,7 +136,6 @@ import android.net.ConnectivityManager.BlockedReason; import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager.RestrictBackgroundStatus; -import android.net.ConnectivityResources; import android.net.ConnectivitySettingsManager; import android.net.DataStallReportParcelable; import android.net.DnsResolverServiceManager; @@ -194,6 +199,7 @@ import android.net.Uri; import android.net.VpnManager; import android.net.VpnTransportInfo; +import android.net.connectivity.ConnectivityCompatChanges; import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.netd.aidl.NativeUidRangeConfig; @@ -239,9 +245,12 @@ import android.util.LocalLog; import android.util.Log; import android.util.Pair; +import android.util.Range; import android.util.SparseArray; import android.util.SparseIntArray; +import androidx.annotation.RequiresApi; + import com.android.connectivity.resources.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -262,14 +271,24 @@ import com.android.net.module.util.PermissionUtils; import com.android.net.module.util.TcUtils; import com.android.net.module.util.netlink.InetDiagMessage; +import com.android.networkstack.apishim.BroadcastOptionsShimImpl; +import com.android.networkstack.apishim.ConstantsShim; +import com.android.networkstack.apishim.common.BroadcastOptionsShim; +import com.android.networkstack.apishim.common.UnsupportedApiLevelException; +import com.android.server.connectivity.ApplicationSelfCertifiedNetworkCapabilities; import com.android.server.connectivity.AutodestructReference; +import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker; +import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker.AutomaticOnOffKeepalive; import com.android.server.connectivity.CarrierPrivilegeAuthenticator; import com.android.server.connectivity.ClatCoordinator; import com.android.server.connectivity.ConnectivityFlags; +import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; import com.android.server.connectivity.DscpPolicyTracker; import com.android.server.connectivity.FullScore; +import com.android.server.connectivity.InvalidTagException; +import com.android.server.connectivity.KeepaliveResourceUtil; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.LingerMonitor; import com.android.server.connectivity.MockableSystemProperties; @@ -279,22 +298,29 @@ import com.android.server.connectivity.NetworkNotificationManager; import com.android.server.connectivity.NetworkNotificationManager.NotificationType; import com.android.server.connectivity.NetworkOffer; +import com.android.server.connectivity.NetworkPreferenceList; import com.android.server.connectivity.NetworkRanker; import com.android.server.connectivity.PermissionMonitor; -import com.android.server.connectivity.ProfileNetworkPreferenceList; +import com.android.server.connectivity.ProfileNetworkPreferenceInfo; import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.QosCallbackTracker; import com.android.server.connectivity.UidRangeUtils; +import com.android.server.connectivity.VpnNetworkPreferenceInfo; +import com.android.server.connectivity.wear.CompanionDeviceManagerProxyService; import libcore.io.IoUtils; +import org.xmlpull.v1.XmlPullParserException; + import java.io.FileDescriptor; import java.io.IOException; +import java.io.InterruptedIOException; import java.io.PrintWriter; import java.io.Writer; import java.net.Inet4Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; @@ -369,6 +395,10 @@ private static final int DEFAULT_LINGER_DELAY_MS = 30_000; private static final int DEFAULT_NASCENT_DELAY_MS = 5_000; + // Delimiter used when creating the broadcast delivery group for sending + // CONNECTIVITY_ACTION broadcast. + private static final char DELIVERY_GROUP_KEY_DELIMITER = ';'; + // The maximum value for the blocking validation result, in milliseconds. public static final int MAX_VALIDATION_IGNORE_AFTER_ROAM_TIME_MS = 10000; @@ -394,8 +424,7 @@ private final MockableSystemProperties mSystemProperties; - @VisibleForTesting - protected final PermissionMonitor mPermissionMonitor; + private final PermissionMonitor mPermissionMonitor; @VisibleForTesting final RequestInfoPerUidCounter mNetworkRequestCounter; @@ -434,13 +463,18 @@ */ @GuardedBy("mTNSLock") private TestNetworkService mTNS; + private final CompanionDeviceManagerProxyService mCdmps; private final Object mTNSLock = new Object(); private String mCurrentTcpBufferSizes; private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames( - new Class[] { ConnectivityService.class, NetworkAgent.class, NetworkAgentInfo.class }); + new Class[] { + ConnectivityService.class, + NetworkAgent.class, + NetworkAgentInfo.class, + AutomaticOnOffKeepaliveTracker.class }); private enum ReapUnvalidatedNetworks { // Tear down networks that have no chance (e.g. even if validated) of becoming @@ -744,6 +778,22 @@ private static final int EVENT_USER_DOES_NOT_WANT = 58; /** + * Event to set VPN as preferred network for specific apps. + * obj = VpnNetworkPreferenceInfo + */ + private static final int EVENT_SET_VPN_NETWORK_PREFERENCE = 59; + + /** + * Event to use low TCP polling timer used in automatic on/off keepalive temporarily. + */ + private static final int EVENT_SET_LOW_TCP_POLLING_UNTIL = 60; + + /** + * Event to inform the ConnectivityService handler when a uid has been frozen or unfrozen. + */ + private static final int EVENT_UID_FROZEN_STATE_CHANGED = 61; + + /** * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification * should be shown. */ @@ -761,6 +811,12 @@ private static final long MAX_TEST_ALLOW_BAD_WIFI_UNTIL_MS = 5 * 60 * 1000L; /** + * The maximum alive time to decrease TCP polling timer in automatic on/off keepalive for + * testing. + */ + private static final long MAX_TEST_LOW_TCP_POLLING_UNTIL_MS = 5 * 60 * 1000L; + + /** * The priority of the tc police rate limiter -- smaller value is higher priority. * This value needs to be coordinated with PRIO_CLAT, PRIO_TETHER4, and PRIO_TETHER6. */ @@ -823,7 +879,7 @@ private final LocationPermissionChecker mLocationPermissionChecker; - private final KeepaliveTracker mKeepaliveTracker; + private final AutomaticOnOffKeepaliveTracker mKeepaliveTracker; private final QosCallbackTracker mQosCallbackTracker; private final NetworkNotificationManager mNotifier; private final LingerMonitor mLingerMonitor; @@ -869,6 +925,13 @@ // Only the handler thread is allowed to access this field. private long mIngressRateLimit = -1; + // This is the cache for the packageName -> ApplicationSelfCertifiedNetworkCapabilities. This + // value can be accessed from both handler thread and any random binder thread. Therefore, + // accessing this value requires holding a lock. The cache is the same across all the users. + @GuardedBy("mSelfCertifiedCapabilityCache") + private final Map<String, ApplicationSelfCertifiedNetworkCapabilities> + mSelfCertifiedCapabilityCache = new HashMap<>(); + /** * Implements support for the legacy "one network per network type" model. * @@ -1215,6 +1278,18 @@ return Binder.getCallingUid(); } + public boolean isAtLeastS() { + return SdkLevel.isAtLeastS(); + } + + public boolean isAtLeastT() { + return SdkLevel.isAtLeastT(); + } + + public boolean isAtLeastU() { + return SdkLevel.isAtLeastU(); + } + /** * Get system properties to use in ConnectivityService. */ @@ -1283,6 +1358,14 @@ } /** + * @see AutomaticOnOffKeepaliveTracker + */ + public AutomaticOnOffKeepaliveTracker makeAutomaticOnOffKeepaliveTracker( + @NonNull Context c, @NonNull Handler h) { + return new AutomaticOnOffKeepaliveTracker(c, h); + } + + /** * @see BatteryStatsManager */ public void reportNetworkInterfaceForTransports(Context context, String iface, @@ -1319,7 +1402,7 @@ @Nullable public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator( @NonNull final Context context, @NonNull final TelephonyManager tm) { - if (SdkLevel.isAtLeastT()) { + if (isAtLeastT()) { return new CarrierPrivilegeAuthenticator(context, tm); } else { return null; @@ -1329,9 +1412,9 @@ /** * @see DeviceConfigUtils#isFeatureEnabled */ - public boolean isFeatureEnabled(Context context, String name, boolean defaultEnabled) { - return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY, name, - TETHERING_MODULE_NAME, defaultEnabled); + public boolean isFeatureEnabled(Context context, String name) { + return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_TETHERING, name, + TETHERING_MODULE_NAME, false /* defaultValue */); } /** @@ -1401,6 +1484,77 @@ + ", ingress=true, PRIO_POLICE, ETH_P_ALL) failure: ", e); } } + + /** + * Wraps {@link BroadcastOptionsShimImpl#newInstance(BroadcastOptions)} + */ + // TODO: when available in all active branches: + // @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT) + public BroadcastOptionsShim makeBroadcastOptionsShim(BroadcastOptions options) { + return BroadcastOptionsShimImpl.newInstance(options); + } + + /** + * Wrapper method for + * {@link android.app.compat.CompatChanges#isChangeEnabled(long, String, UserHandle)}. + * + * @param changeId The ID of the compatibility change in question. + * @param packageName The package name of the app in question. + * @param user The user that the operation is done for. + * @return {@code true} if the change is enabled for the specified package. + */ + public boolean isChangeEnabled(long changeId, @NonNull final String packageName, + @NonNull final UserHandle user) { + return CompatChanges.isChangeEnabled(changeId, packageName, user); + } + + /** + * As above but with a UID. + * @see CompatChanges#isChangeEnabled(long, int) + */ + public boolean isChangeEnabled(final long changeId, final int uid) { + return CompatChanges.isChangeEnabled(changeId, uid); + } + + /** + * Call {@link InetDiagMessage#destroyLiveTcpSockets(Set, Set)} + * + * @param ranges target uid ranges + * @param exemptUids uids to skip close socket + */ + public void destroyLiveTcpSockets(@NonNull final Set<Range<Integer>> ranges, + @NonNull final Set<Integer> exemptUids) + throws SocketException, InterruptedIOException, ErrnoException { + InetDiagMessage.destroyLiveTcpSockets(ranges, exemptUids); + } + + /** + * Call {@link InetDiagMessage#destroyLiveTcpSocketsByOwnerUids(Set)} + * + * @param ownerUids target uids to close sockets + */ + public void destroyLiveTcpSocketsByOwnerUids(final Set<Integer> ownerUids) + throws SocketException, InterruptedIOException, ErrnoException { + InetDiagMessage.destroyLiveTcpSocketsByOwnerUids(ownerUids); + } + + /** + * Schedule the evaluation timeout. + * + * When a network connects, it's "not evaluated" yet. Detection events cause the network + * to be "evaluated" (typically, validation or detection of a captive portal). If none + * of these events happen, this time will run out, after which the network is considered + * "evaluated" even if nothing happened to it. Notionally that means the system gave up + * on this network and considers it won't provide connectivity. In particular, that means + * it's when the system prefers it to cell if it's wifi and configuration says it should + * prefer bad wifi to cell. + */ + public void scheduleEvaluationTimeout(@NonNull Handler handler, + @NonNull final Network network, final long delayMs) { + handler.sendMessageDelayed( + handler.obtainMessage(EVENT_INITIAL_EVALUATION_TIMEOUT, network), delayMs); + } } public ConnectivityService(Context context) { @@ -1535,7 +1689,7 @@ mSettingsObserver = new SettingsObserver(mContext, mHandler); registerSettingsCallbacks(); - mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler); + mKeepaliveTracker = mDeps.makeAutomaticOnOffKeepaliveTracker(mContext, mHandler); mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager); mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter); @@ -1576,7 +1730,7 @@ // Even if it could, running on S would at least require mocking out the BPF map, // otherwise the unit tests will fail on pre-T devices where the seccomp filter blocks // the bpf syscall. http://aosp/1907693 - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { mDscpPolicyTracker = new DscpPolicyTracker(); } } catch (ErrnoException e) { @@ -1585,6 +1739,38 @@ mIngressRateLimit = ConnectivitySettingsManager.getIngressRateLimitInBytesPerSecond( mContext); + + if (mDeps.isAtLeastT()) { + mCdmps = new CompanionDeviceManagerProxyService(context); + } else { + mCdmps = null; + } + + if (mDeps.isAtLeastU() + && mDeps.isFeatureEnabled(context, KEY_DESTROY_FROZEN_SOCKETS_VERSION)) { + final UidFrozenStateChangedCallback frozenStateChangedCallback = + new UidFrozenStateChangedCallback() { + @Override + public void onUidFrozenStateChanged(int[] uids, int[] frozenStates) { + if (uids.length != frozenStates.length) { + Log.wtf(TAG, "uids has length " + uids.length + + " but frozenStates has length " + frozenStates.length); + return; + } + + final UidFrozenStateChangedArgs args = + new UidFrozenStateChangedArgs(uids, frozenStates); + + mHandler.sendMessage( + mHandler.obtainMessage(EVENT_UID_FROZEN_STATE_CHANGED, args)); + } + }; + + final ActivityManager activityManager = + mContext.getSystemService(ActivityManager.class); + activityManager.registerUidFrozenStateChangedCallback( + (Runnable r) -> r.run(), frozenStateChangedCallback); + } } /** @@ -1616,6 +1802,17 @@ TYPE_NONE, NetworkRequest.Type.REQUEST); } + private NetworkRequest createVpnRequest() { + final NetworkCapabilities netCap = new NetworkCapabilities.Builder() + .withoutDefaultCapabilities() + .addTransportType(TRANSPORT_VPN) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .addCapability(NET_CAPABILITY_NOT_RESTRICTED) + .build(); + netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName()); + return createNetworkRequest(NetworkRequest.Type.REQUEST, netCap); + } + private NetworkRequest createDefaultInternetRequestForTransport( int transportType, NetworkRequest.Type type) { final NetworkCapabilities netCap = new NetworkCapabilities(); @@ -2228,11 +2425,12 @@ if (newNc.getNetworkSpecifier() != null) { newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact()); } - if (!checkAnyPermissionOf(callerPid, callerUid, android.Manifest.permission.NETWORK_STACK, + if (!checkAnyPermissionOf(mContext, callerPid, callerUid, + android.Manifest.permission.NETWORK_STACK, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)) { newNc.setAdministratorUids(new int[0]); } - if (!checkAnyPermissionOf( + if (!checkAnyPermissionOf(mContext, callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) { newNc.setAllowedUids(new ArraySet<>()); newNc.setSubscriptionIds(Collections.emptySet()); @@ -2501,7 +2699,8 @@ final ArrayList<NetworkStateSnapshot> result = new ArrayList<>(); for (Network network : getAllNetworks()) { final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); - if (nai != null && nai.everConnected()) { + final boolean includeNetwork = (nai != null) && nai.isCreated(); + if (includeNetwork) { // TODO (b/73321673) : NetworkStateSnapshot contains a copy of the // NetworkCapabilities, which may contain UIDs of apps to which the // network applies. Should the UIDs be cleared so as not to leak or @@ -2741,15 +2940,39 @@ setUidBlockedReasons(uid, blockedReasons); } - private boolean checkAnyPermissionOf(int pid, int uid, String... permissions) { - for (String permission : permissions) { - if (mContext.checkPermission(permission, pid, uid) == PERMISSION_GRANTED) { - return true; + static final class UidFrozenStateChangedArgs { + final int[] mUids; + final int[] mFrozenStates; + + UidFrozenStateChangedArgs(int[] uids, int[] frozenStates) { + mUids = uids; + mFrozenStates = frozenStates; + } + } + + private void handleFrozenUids(int[] uids, int[] frozenStates) { + final ArraySet<Range<Integer>> ranges = new ArraySet<>(); + + for (int i = 0; i < uids.length; i++) { + if (frozenStates[i] == UID_FROZEN_STATE_FROZEN) { + Integer uidAsInteger = Integer.valueOf(uids[i]); + ranges.add(new Range(uidAsInteger, uidAsInteger)); } } - return false; + + if (!ranges.isEmpty()) { + final Set<Integer> exemptUids = new ArraySet<>(); + try { + mDeps.destroyLiveTcpSockets(ranges, exemptUids); + } catch (Exception e) { + loge("Exception in socket destroy: " + e); + } + } } + @VisibleForTesting + static final String KEY_DESTROY_FROZEN_SOCKETS_VERSION = "destroy_frozen_sockets_version"; + private void enforceInternetPermission() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERNET, @@ -2814,9 +3037,10 @@ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); } - private void enforceSettingsOrUseRestrictedNetworksPermission() { + private void enforceSettingsOrSetupWizardOrUseRestrictedNetworksPermission() { enforceAnyPermissionOf(mContext, android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS); } @@ -2907,13 +3131,13 @@ } private boolean checkNetworkStackPermission(int pid, int uid) { - return checkAnyPermissionOf(pid, uid, + return checkAnyPermissionOf(mContext, pid, uid, android.Manifest.permission.NETWORK_STACK, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); } private boolean checkNetworkSignalStrengthWakeupPermission(int pid, int uid) { - return checkAnyPermissionOf(pid, uid, + return checkAnyPermissionOf(mContext, pid, uid, android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS); @@ -3010,6 +3234,7 @@ ConnectivityManager.EXTRA_NETWORK_INFO); final BroadcastOptions opts = BroadcastOptions.makeBasic(); opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M); + applyMostRecentPolicyForConnectivityAction(opts, ni); options = opts.toBundle(); intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); } @@ -3021,6 +3246,33 @@ } } + private void applyMostRecentPolicyForConnectivityAction(BroadcastOptions options, + NetworkInfo info) { + // Delivery group policy APIs are only available on U+. + if (!mDeps.isAtLeastU()) return; + + final BroadcastOptionsShim optsShim = mDeps.makeBroadcastOptionsShim(options); + try { + // This allows us to discard older broadcasts still waiting to be delivered + // which have the same namespace and key. + optsShim.setDeliveryGroupPolicy(ConstantsShim.DELIVERY_GROUP_POLICY_MOST_RECENT); + optsShim.setDeliveryGroupMatchingKey(ConnectivityManager.CONNECTIVITY_ACTION, + createDeliveryGroupKeyForConnectivityAction(info)); + optsShim.setDeferralPolicy(ConstantsShim.DEFERRAL_POLICY_UNTIL_ACTIVE); + } catch (UnsupportedApiLevelException e) { + Log.wtf(TAG, "Using unsupported API" + e); + } + } + + @VisibleForTesting + static String createDeliveryGroupKeyForConnectivityAction(NetworkInfo info) { + final StringBuilder sb = new StringBuilder(); + sb.append(info.getType()).append(DELIVERY_GROUP_KEY_DELIMITER); + sb.append(info.getSubtype()).append(DELIVERY_GROUP_KEY_DELIMITER); + sb.append(info.getExtraInfo()); + return sb.toString(); + } + /** * Called by SystemServer through ConnectivityManager when the system is ready. */ @@ -3075,7 +3327,7 @@ } // On T+ devices, register callback for statsd to pull NETWORK_BPF_MAP_INFO atom - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { mBpfNetMaps.setPullAtomCallback(mContext); } // Wait PermissionMonitor to finish the permission update. Then MultipathPolicyTracker won't @@ -3116,22 +3368,23 @@ private void updateMtu(@NonNull LinkProperties newLp, @Nullable LinkProperties oldLp) { final String iface = newLp.getInterfaceName(); final int mtu = newLp.getMtu(); - if (oldLp == null && mtu == 0) { + if (mtu == 0) { // Silently ignore unset MTU value. return; } - if (oldLp != null && newLp.isIdenticalMtu(oldLp)) { - if (VDBG) log("identical MTU - not setting"); + if (oldLp != null && newLp.isIdenticalMtu(oldLp) + && TextUtils.equals(oldLp.getInterfaceName(), iface)) { + if (VDBG) log("identical MTU and iface - not setting"); return; } - if (!LinkProperties.isValidMtu(mtu, newLp.hasGlobalIpv6Address())) { - if (mtu != 0) loge("Unexpected mtu value: " + mtu + ", " + iface); + // Cannot set MTU without interface name + if (TextUtils.isEmpty(iface)) { + if (VDBG) log("Setting MTU size with null iface."); return; } - // Cannot set MTU without interface name - if (TextUtils.isEmpty(iface)) { - loge("Setting MTU size with null iface."); + if (!LinkProperties.isValidMtu(mtu, newLp.hasGlobalIpv6Address())) { + loge("Unexpected mtu value: " + mtu + ", " + iface); return; } @@ -3413,7 +3666,7 @@ if (!mProfileNetworkPreferences.isEmpty()) { pw.println("Profile preferences:"); pw.increaseIndent(); - pw.println(mProfileNetworkPreferences.preferences); + pw.println(mProfileNetworkPreferences); pw.decreaseIndent(); } if (!mOemNetworkPreferences.isEmpty()) { @@ -3671,9 +3924,9 @@ break; } case NetworkAgent.EVENT_UNREGISTER_AFTER_REPLACEMENT: { - if (!nai.isCreated()) { - Log.d(TAG, "unregisterAfterReplacement on uncreated " + nai.toShortString() - + ", tearing down instead"); + if (!nai.everConnected()) { + Log.d(TAG, "unregisterAfterReplacement on never-connected " + + nai.toShortString() + ", tearing down instead"); teardownUnneededNetwork(nai); break; } @@ -4258,6 +4511,25 @@ } } + @VisibleForTesting + protected static boolean shouldCreateNetworksImmediately() { + // Before U, physical networks are only created when the agent advances to CONNECTED. + // In U and above, all networks are immediately created when the agent is registered. + return SdkLevel.isAtLeastU(); + } + + private static boolean shouldCreateNativeNetwork(@NonNull NetworkAgentInfo nai, + @NonNull NetworkInfo.State state) { + if (nai.isCreated()) return false; + if (state == NetworkInfo.State.CONNECTED) return true; + if (state != NetworkInfo.State.CONNECTING) { + // TODO: throw if no WTFs are observed in the field. + Log.wtf(TAG, "Uncreated network in invalid state: " + state); + return false; + } + return nai.isVPN() || shouldCreateNetworksImmediately(); + } + private static boolean shouldDestroyNativeNetwork(@NonNull NetworkAgentInfo nai) { return nai.isCreated() && !nai.isDestroyed(); } @@ -4265,7 +4537,7 @@ @VisibleForTesting boolean shouldIgnoreValidationFailureAfterRoam(NetworkAgentInfo nai) { // T+ devices should use unregisterAfterReplacement. - if (SdkLevel.isAtLeastT()) return false; + if (mDeps.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. @@ -4308,7 +4580,7 @@ // because they lost all their requests or because their score isn't good) // then they would disconnect organically, report their new state and then // disconnect the channel. - if (nai.networkInfo.isConnected()) { + if (nai.networkInfo.isConnected() || nai.networkInfo.isSuspended()) { nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); } @@ -4327,7 +4599,7 @@ mQosCallbackTracker.handleNetworkReleased(nai.network); for (String iface : nai.linkProperties.getAllInterfaceNames()) { // Disable wakeup packet monitoring for each interface. - wakeupModifyInterface(iface, nai.networkCapabilities, false); + wakeupModifyInterface(iface, nai, false); } nai.networkMonitor().notifyNetworkDisconnected(); mNetworkAgentInfos.remove(nai); @@ -4338,6 +4610,9 @@ mNetworkForNetId.remove(nai.network.getNetId()); } propagateUnderlyingNetworkCapabilities(nai.network); + // Update allowed network lists in netd. This should be called after removing nai + // from mNetworkAgentInfos. + updateProfileAllowedNetworks(); // Remove all previously satisfied requests. for (int i = 0; i < nai.numNetworkRequests(); i++) { final NetworkRequest request = nai.requestAt(i); @@ -4401,7 +4676,7 @@ // for an unnecessarily long time. destroyNativeNetwork(nai); } - if (!nai.isCreated() && !SdkLevel.isAtLeastT()) { + if (!nai.isCreated() && !mDeps.isAtLeastT()) { // Backwards compatibility: send onNetworkDestroyed even if network was never created. // This can never run if the code above runs because shouldDestroyNativeNetwork is // false if the network was never created. @@ -4485,7 +4760,7 @@ } private void checkNrisConsistency(final NetworkRequestInfo nri) { - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { for (final NetworkRequestInfo n : mNetworkRequests.values()) { if (n.mBinder != null && n.mBinder == nri.mBinder) { // Temporary help to debug b/194394697 ; TODO : remove this function when the @@ -4772,6 +5047,7 @@ } } } + nri.mPerUidCounter.decrementCount(nri.mUid); mNetworkRequestInfoLogs.log("RELEASE " + nri); checkNrisConsistency(nri); @@ -4876,7 +5152,7 @@ } private RequestInfoPerUidCounter getRequestCounter(NetworkRequestInfo nri) { - return checkAnyPermissionOf( + return checkAnyPermissionOf(mContext, nri.mPid, nri.mUid, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) ? mSystemNetworkRequestCounter : mNetworkRequestCounter; } @@ -4917,6 +5193,19 @@ mHandler.obtainMessage(EVENT_SET_TEST_ALLOW_BAD_WIFI_UNTIL, timeMs)); } + @Override + public void setTestLowTcpPollingTimerForKeepalive(long timeMs) { + enforceSettingsPermission(); + + if (timeMs > System.currentTimeMillis() + MAX_TEST_LOW_TCP_POLLING_UNTIL_MS) { + throw new IllegalArgumentException("Argument should not exceed " + + MAX_TEST_LOW_TCP_POLLING_UNTIL_MS + "ms from now"); + } + + mHandler.sendMessage( + mHandler.obtainMessage(EVENT_SET_LOW_TCP_POLLING_UNTIL, timeMs)); + } + private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) { if (DBG) log("handleSetAcceptUnvalidated network=" + network + " accept=" + accept + " always=" + always); @@ -5018,8 +5307,7 @@ /** Schedule evaluation timeout */ @VisibleForTesting public void scheduleEvaluationTimeout(@NonNull final Network network, final long delayMs) { - mHandler.sendMessageDelayed( - mHandler.obtainMessage(EVENT_INITIAL_EVALUATION_TIMEOUT, network), delayMs); + mDeps.scheduleEvaluationTimeout(mHandler, network, delayMs); } @Override @@ -5460,17 +5748,51 @@ handleConfigureAlwaysOnNetworks(); break; } - // Sent by KeepaliveTracker to process an app request on the state machine thread. - case NetworkAgent.CMD_START_SOCKET_KEEPALIVE: { + // Sent by AutomaticOnOffKeepaliveTracker to process an app request on the + // handler thread. + case AutomaticOnOffKeepaliveTracker.CMD_REQUEST_START_KEEPALIVE: { mKeepaliveTracker.handleStartKeepalive(msg); break; } + case AutomaticOnOffKeepaliveTracker.CMD_MONITOR_AUTOMATIC_KEEPALIVE: { + final AutomaticOnOffKeepalive ki = + mKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj); + if (null == ki) return; // The callback was unregistered before the alarm fired + + final Network underpinnedNetwork = ki.getUnderpinnedNetwork(); + final Network network = ki.getNetwork(); + boolean networkFound = false; + boolean underpinnedNetworkFound = false; + for (NetworkAgentInfo n : mNetworkAgentInfos) { + if (n.network.equals(network)) networkFound = true; + if (n.everConnected() && n.network.equals(underpinnedNetwork)) { + underpinnedNetworkFound = true; + } + } + + // If the network no longer exists, then the keepalive should have been + // cleaned up already. There is no point trying to resume keepalives. + if (!networkFound) return; + + if (underpinnedNetworkFound) { + mKeepaliveTracker.handleMonitorAutomaticKeepalive(ki, + underpinnedNetwork.netId); + } else { + // If no underpinned network, then make sure the keepalive is running. + mKeepaliveTracker.handleMaybeResumeKeepalive(ki); + } + break; + } // Sent by KeepaliveTracker to process an app request on the state machine thread. case NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE: { - NetworkAgentInfo nai = getNetworkAgentInfoForNetwork((Network) msg.obj); - int slot = msg.arg1; - int reason = msg.arg2; - mKeepaliveTracker.handleStopKeepalive(nai, slot, reason); + final AutomaticOnOffKeepalive ki = mKeepaliveTracker.getKeepaliveForBinder( + (IBinder) msg.obj); + if (ki == null) { + Log.e(TAG, "Attempt to stop an already stopped keepalive"); + return; + } + final int reason = msg.arg2; + mKeepaliveTracker.handleStopKeepalive(ki, reason); break; } case EVENT_REPORT_NETWORK_CONNECTIVITY: { @@ -5498,10 +5820,8 @@ break; } case EVENT_SET_PROFILE_NETWORK_PREFERENCE: { - final Pair<List<ProfileNetworkPreferenceList.Preference>, - IOnCompleteListener> arg = - (Pair<List<ProfileNetworkPreferenceList.Preference>, - IOnCompleteListener>) msg.obj; + final Pair<List<ProfileNetworkPreferenceInfo>, IOnCompleteListener> arg = + (Pair<List<ProfileNetworkPreferenceInfo>, IOnCompleteListener>) msg.obj; handleSetProfileNetworkPreference(arg.first, arg.second); break; } @@ -5524,6 +5844,18 @@ nai.onPreventAutomaticReconnect(); nai.disconnect(); break; + case EVENT_SET_VPN_NETWORK_PREFERENCE: + handleSetVpnNetworkPreference((VpnNetworkPreferenceInfo) msg.obj); + break; + case EVENT_SET_LOW_TCP_POLLING_UNTIL: { + final long time = ((Long) msg.obj).longValue(); + mKeepaliveTracker.handleSetTestLowTcpPollingTimer(time); + break; + } + case EVENT_UID_FROZEN_STATE_CHANGED: + UidFrozenStateChangedArgs args = (UidFrozenStateChangedArgs) msg.obj; + handleFrozenUids(args.mUids, args.mFrozenStates); + break; } } } @@ -6018,7 +6350,7 @@ + Arrays.toString(ranges) + "): netd command failed: " + e); } - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { mPermissionMonitor.updateVpnLockdownUidRanges(requireVpn, ranges); } @@ -6137,12 +6469,14 @@ if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) { handleSetOemNetworkPreference(mOemNetworkPreferences, null); } + updateProfileAllowedNetworks(); } private void onUserRemoved(@NonNull final UserHandle user) { // If there was a network preference for this user, remove it. handleSetProfileNetworkPreference( - List.of(new ProfileNetworkPreferenceList.Preference(user, null, true)), + List.of(new ProfileNetworkPreferenceInfo(user, null, true, + false /* blockingNonEnterprise */)), null /* listener */); if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) { handleSetOemNetworkPreference(mOemNetworkPreferences, null); @@ -6158,6 +6492,11 @@ if (isMappedInOemNetworkPreference(packageName)) { handleSetOemNetworkPreference(mOemNetworkPreferences, null); } + + // Invalidates cache entry when the package is updated. + synchronized (mSelfCertifiedCapabilityCache) { + mSelfCertifiedCapabilityCache.remove(packageName); + } } private final BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { @@ -6494,8 +6833,6 @@ @Override public void binderDied() { - log("ConnectivityService NetworkRequestInfo binderDied(" + - "uid/pid:" + mUid + "/" + mPid + ", " + mRequests + ", " + mBinder + ")"); // As an immutable collection, mRequests cannot change by the time the // lambda is evaluated on the handler thread so calling .get() from a binder thread // is acceptable. Use handleReleaseNetworkRequest and not directly @@ -6688,7 +7025,7 @@ enforceAccessPermission(); break; case TRACK_SYSTEM_DEFAULT: - enforceSettingsOrUseRestrictedNetworksPermission(); + enforceSettingsOrSetupWizardOrUseRestrictedNetworksPermission(); networkCapabilities = new NetworkCapabilities(defaultNc); break; case BACKGROUND_REQUEST: @@ -6786,8 +7123,72 @@ asUid, requests, nr, msgr, binder, callbackFlags, callingAttributionTag); } + private boolean shouldCheckCapabilitiesDeclaration( + @NonNull final NetworkCapabilities networkCapabilities, final int callingUid, + @NonNull final String callingPackageName) { + final UserHandle user = UserHandle.getUserHandleForUid(callingUid); + // Only run the check if the change is enabled. + if (!mDeps.isChangeEnabled( + ConnectivityCompatChanges.ENABLE_SELF_CERTIFIED_CAPABILITIES_DECLARATION, + callingPackageName, user)) { + return false; + } + + return networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + || networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY); + } + + private void enforceRequestCapabilitiesDeclaration(@NonNull final String callerPackageName, + @NonNull final NetworkCapabilities networkCapabilities) { + // This check is added to fix the linter error for "current min is 30", which is not going + // to happen because Connectivity service always run in S+. + if (!mDeps.isAtLeastS()) { + Log.wtf(TAG, "Connectivity service should always run in at least SDK S"); + return; + } + ApplicationSelfCertifiedNetworkCapabilities applicationNetworkCapabilities; + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mSelfCertifiedCapabilityCache) { + applicationNetworkCapabilities = mSelfCertifiedCapabilityCache.get( + callerPackageName); + if (applicationNetworkCapabilities == null) { + final PackageManager packageManager = mContext.getPackageManager(); + final PackageManager.Property networkSliceProperty = packageManager.getProperty( + ConstantsShim.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES, + callerPackageName + ); + final XmlResourceParser parser = packageManager + .getResourcesForApplication(callerPackageName) + .getXml(networkSliceProperty.getResourceId()); + applicationNetworkCapabilities = + ApplicationSelfCertifiedNetworkCapabilities.createFromXml(parser); + mSelfCertifiedCapabilityCache.put(callerPackageName, + applicationNetworkCapabilities); + } + + } + } catch (PackageManager.NameNotFoundException ne) { + throw new SecurityException( + "Cannot find " + ConstantsShim.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES + + " property"); + } catch (XmlPullParserException | IOException | InvalidTagException e) { + throw new SecurityException(e.getMessage()); + } finally { + Binder.restoreCallingIdentity(ident); + } + + applicationNetworkCapabilities.enforceSelfCertifiedNetworkCapabilitiesDeclared( + networkCapabilities); + } private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities, String callingPackageName, String callingAttributionTag, final int callingUid) { + if (shouldCheckCapabilitiesDeclaration(networkCapabilities, callingUid, + callingPackageName)) { + enforceRequestCapabilitiesDeclaration(callingPackageName, networkCapabilities); + } if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) == false) { // For T+ devices, callers with carrier privilege could request with CBS capabilities. if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS) @@ -7112,8 +7513,14 @@ // Current per-profile network preferences. This object follows the same threading rules as // the OEM network preferences above. @NonNull - private ProfileNetworkPreferenceList mProfileNetworkPreferences = - new ProfileNetworkPreferenceList(); + private NetworkPreferenceList<UserHandle, ProfileNetworkPreferenceInfo> + mProfileNetworkPreferences = new NetworkPreferenceList<>(); + + // Current VPN network preferences. This object follows the same threading rules as the OEM + // network preferences above. + @NonNull + private NetworkPreferenceList<String, VpnNetworkPreferenceInfo> + mVpnNetworkPreferences = new NetworkPreferenceList<>(); // A set of UIDs that should use mobile data preferentially if available. This object follows // the same threading rules as the OEM network preferences above. @@ -7539,7 +7946,7 @@ // the LinkProperties for the network are accurate. networkAgent.clatd.fixupLinkProperties(oldLp, newLp); - updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities); + updateInterfaces(newLp, oldLp, netId, networkAgent); // update filtering rules, need to happen after the interface update so netd knows about the // new interface (the interface name -> index map becomes initialized) @@ -7564,7 +7971,7 @@ if (isDefaultNetwork(networkAgent)) { handleApplyDefaultProxy(newLp.getHttpProxy()); - } else { + } else if (networkAgent.everConnected()) { updateProxy(newLp, oldLp); } @@ -7598,6 +8005,10 @@ mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent); } + private void applyInitialLinkProperties(@NonNull NetworkAgentInfo nai) { + updateLinkProperties(nai, new LinkProperties(nai.linkProperties), null); + } + /** * @param naData captive portal data from NetworkAgent * @param apiData captive portal data from capport API @@ -7647,10 +8058,27 @@ return captivePortalBuilder.build(); } - private void wakeupModifyInterface(String iface, NetworkCapabilities caps, boolean add) { + @VisibleForTesting + static String makeNflogPrefix(String iface, long networkHandle) { + // This needs to be kept in sync and backwards compatible with the decoding logic in + // NetdEventListenerService, which is non-mainline code. + return SdkLevel.isAtLeastU() ? (networkHandle + ":" + iface) : ("iface:" + iface); + } + + private static boolean isWakeupMarkingSupported(NetworkCapabilities capabilities) { + if (capabilities.hasTransport(TRANSPORT_WIFI)) { + return true; + } + if (SdkLevel.isAtLeastU() && capabilities.hasTransport(TRANSPORT_CELLULAR)) { + return true; + } + return false; + } + + private void wakeupModifyInterface(String iface, NetworkAgentInfo nai, boolean add) { // Marks are only available on WiFi interfaces. Checking for // marks on unsupported interfaces is harmless. - if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + if (!isWakeupMarkingSupported(nai.networkCapabilities)) { return; } @@ -7663,7 +8091,7 @@ return; } - final String prefix = "iface:" + iface; + final String prefix = makeNflogPrefix(iface, nai.network.getNetworkHandle()); try { if (add) { mNetd.wakeupAddInterface(iface, prefix, mark, mask); @@ -7673,12 +8101,11 @@ } catch (Exception e) { loge("Exception modifying wakeup packet monitoring: " + e); } - } private void updateInterfaces(final @NonNull LinkProperties newLp, final @Nullable LinkProperties oldLp, final int netId, - final @NonNull NetworkCapabilities caps) { + final @NonNull NetworkAgentInfo nai) { final CompareResult<String> interfaceDiff = new CompareResult<>( oldLp != null ? oldLp.getAllInterfaceNames() : null, newLp.getAllInterfaceNames()); if (!interfaceDiff.added.isEmpty()) { @@ -7686,9 +8113,9 @@ try { if (DBG) log("Adding iface " + iface + " to network " + netId); mNetd.networkAddInterface(netId, iface); - wakeupModifyInterface(iface, caps, true); + wakeupModifyInterface(iface, nai, true); mDeps.reportNetworkInterfaceForTransports(mContext, iface, - caps.getTransportTypes()); + nai.networkCapabilities.getTransportTypes()); } catch (Exception e) { logw("Exception adding interface: " + e); } @@ -7697,7 +8124,7 @@ for (final String iface : interfaceDiff.removed) { try { if (DBG) log("Removing iface " + iface + " from network " + netId); - wakeupModifyInterface(iface, caps, false); + wakeupModifyInterface(iface, nai, false); mNetd.networkRemoveInterface(netId, iface); } catch (Exception e) { loge("Exception removing interface: " + e); @@ -8154,7 +8581,7 @@ // On T and above, allow rules are needed for all VPNs. Allow rule with null iface is a // wildcard to allow apps to receive packets on all interfaces. This is required to accept // incoming traffic in Lockdown mode by overriding the Lockdown blocking rule. - return SdkLevel.isAtLeastT() && nai.isVPN() && lp != null && lp.getInterfaceName() != null; + return mDeps.isAtLeastT() && nai.isVPN() && lp != null && lp.getInterfaceName() != null; } private static UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) { @@ -8186,11 +8613,11 @@ return stableRanges; } - private void maybeCloseSockets(NetworkAgentInfo nai, UidRangeParcel[] ranges, - int[] exemptUids) { + private void maybeCloseSockets(NetworkAgentInfo nai, Set<UidRange> ranges, + Set<Integer> exemptUids) { if (nai.isVPN() && !nai.networkAgentConfig.allowBypass) { try { - mNetd.socketDestroy(ranges, exemptUids); + mDeps.destroyLiveTcpSockets(UidRange.toIntRanges(ranges), exemptUids); } catch (Exception e) { loge("Exception in socket destroy: ", e); } @@ -8198,15 +8625,16 @@ } private void updateVpnUidRanges(boolean add, NetworkAgentInfo nai, Set<UidRange> uidRanges) { - int[] exemptUids = new int[2]; + final Set<Integer> exemptUids = new ArraySet<>(); // TODO: Excluding VPN_UID is necessary in order to not to kill the TCP connection used // by PPTP. Fix this by making Vpn set the owner UID to VPN_UID instead of system when // starting a legacy VPN, and remove VPN_UID here. (b/176542831) - exemptUids[0] = VPN_UID; - exemptUids[1] = nai.networkCapabilities.getOwnerUid(); + exemptUids.add(VPN_UID); + exemptUids.add(nai.networkCapabilities.getOwnerUid()); UidRangeParcel[] ranges = toUidRangeStableParcels(uidRanges); - maybeCloseSockets(nai, ranges, exemptUids); + // Close sockets before modifying uid ranges so that RST packets can reach to the server. + maybeCloseSockets(nai, uidRanges, exemptUids); try { if (add) { mNetd.networkAddUidRangesParcel(new NativeUidRangeConfig( @@ -8219,7 +8647,8 @@ loge("Exception while " + (add ? "adding" : "removing") + " uid ranges " + uidRanges + " on netId " + nai.network.netId + ". " + e); } - maybeCloseSockets(nai, ranges, exemptUids); + // Close sockets that established connection while requesting netd. + maybeCloseSockets(nai, uidRanges, exemptUids); } private boolean isProxySetOnAnyDefaultNetwork() { @@ -8400,14 +8829,14 @@ try { if (DBG) log("Sending " + pendingIntent); final BroadcastOptions options = BroadcastOptions.makeBasic(); - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { // Explicitly disallow the receiver from starting activities, to prevent apps from // utilizing the PendingIntent as a backdoor to do this. options.setPendingIntentBackgroundActivityLaunchAllowed(false); } pendingIntent.send(mContext, 0, intent, this /* onFinished */, null /* Handler */, null /* requiredPermission */, - SdkLevel.isAtLeastT() ? options.toBundle() : null); + mDeps.isAtLeastT() ? options.toBundle() : null); } catch (PendingIntent.CanceledException e) { if (DBG) log(pendingIntent + " was not sent, it had been canceled."); mPendingIntentWakeLock.release(); @@ -8653,6 +9082,78 @@ } } + /** + * Collect restricted uid ranges for the given network and UserHandle, these uids + * are not restricted for matched enterprise networks but being restricted for non-matched + * enterprise networks and non-enterprise networks. + */ + @NonNull + private ArraySet<UidRange> getRestrictedUidRangesForEnterpriseBlocking( + @NonNull NetworkAgentInfo nai, @NonNull UserHandle user) { + final ArraySet<UidRange> restrictedUidRanges = new ArraySet<>(); + for (final ProfileNetworkPreferenceInfo pref : mProfileNetworkPreferences) { + if (!pref.user.equals(user) || !pref.blockingNonEnterprise) continue; + + if (nai.networkCapabilities.hasCapability(NET_CAPABILITY_ENTERPRISE)) { + // The NC is built from a `ProfileNetworkPreference` which has only one + // enterprise ID, so it's guaranteed to have exactly one. + final int prefId = pref.capabilities.getEnterpriseIds()[0]; + if (nai.networkCapabilities.hasEnterpriseId(prefId)) { + continue; + } + } + + if (UidRangeUtils.doesRangeSetOverlap(restrictedUidRanges, + pref.capabilities.getUidRanges())) { + throw new IllegalArgumentException( + "Overlapping uid range in preference: " + pref); + } + restrictedUidRanges.addAll(pref.capabilities.getUidRanges()); + } + return restrictedUidRanges; + } + + private void updateProfileAllowedNetworks() { + // Netd command is not implemented before U. + if (!mDeps.isAtLeastU()) return; + + ensureRunningOnConnectivityServiceThread(); + final ArrayList<NativeUidRangeConfig> configs = new ArrayList<>(); + final List<UserHandle> users = mContext.getSystemService(UserManager.class) + .getUserHandles(true /* excludeDying */); + if (users.isEmpty()) { + throw new IllegalStateException("No user is available"); + } + + for (final NetworkAgentInfo nai : mNetworkAgentInfos) { + ArraySet<UidRange> allowedUidRanges = new ArraySet<>(); + for (final UserHandle user : users) { + final ArraySet<UidRange> restrictedUidRanges = + getRestrictedUidRangesForEnterpriseBlocking(nai, user); + allowedUidRanges.addAll(UidRangeUtils.removeRangeSetFromUidRange( + UidRange.createForUser(user), restrictedUidRanges)); + } + + final UidRangeParcel[] rangesParcel = toUidRangeStableParcels(allowedUidRanges); + configs.add(new NativeUidRangeConfig( + nai.network.netId, rangesParcel, 0 /* subPriority */)); + } + + // The netd API replaces the previous configs with the current configs. + // Thus, for network disconnection or preference removal, no need to + // unset previous config. Instead, collecting all currently needed + // configs and issue to netd. + try { + mNetd.setNetworkAllowlist(configs.toArray(new NativeUidRangeConfig[0])); + } catch (ServiceSpecificException e) { + // Has the interface disappeared since the network was built? + Log.wtf(TAG, "Unexpected ServiceSpecificException", e); + } catch (RemoteException e) { + // Netd died. This will cause a runtime restart anyway. + Log.wtf(TAG, "Unexpected RemoteException", e); + } + } + private void makeDefaultNetwork(@Nullable final NetworkAgentInfo newDefaultNetwork) { try { if (null != newDefaultNetwork) { @@ -9268,23 +9769,35 @@ + oldInfo.getState() + " to " + state); } - if (!networkAgent.isCreated() - && (state == NetworkInfo.State.CONNECTED - || (state == NetworkInfo.State.CONNECTING && networkAgent.isVPN()))) { - + if (shouldCreateNativeNetwork(networkAgent, state)) { // A network that has just connected has zero requests and is thus a foreground network. networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND); if (!createNativeNetwork(networkAgent)) return; + + networkAgent.setCreated(); + + // If the network is created immediately on register, then apply the LinkProperties now. + // Otherwise, this is done further down when the network goes into connected state. + // Applying the LinkProperties means that the network is ready to carry traffic - + // interfaces and routing rules have been added, DNS servers programmed, etc. + // For VPNs, this must be done before the capabilities are updated, because as soon as + // that happens, UIDs are routed to the network. + if (shouldCreateNetworksImmediately()) { + applyInitialLinkProperties(networkAgent); + } + + // TODO: should this move earlier? It doesn't seem to have anything to do with whether + // a network is created or not. if (networkAgent.propagateUnderlyingCapabilities()) { // Initialize the network's capabilities to their starting values according to the // underlying networks. This ensures that the capabilities are correct before // anything happens to the network. updateCapabilitiesForNetwork(networkAgent); } - networkAgent.setCreated(); networkAgent.onNetworkCreated(); updateAllowedUids(networkAgent, null, networkAgent.networkCapabilities); + updateProfileAllowedNetworks(); } if (!networkAgent.everConnected() && state == NetworkInfo.State.CONNECTED) { @@ -9295,8 +9808,19 @@ networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities); handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig()); - updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties), - null); + if (!shouldCreateNetworksImmediately()) { + applyInitialLinkProperties(networkAgent); + } else { + // The network was created when the agent registered, and the LinkProperties are + // already up-to-date. However, updateLinkProperties also makes some changes only + // when the network connects. Apply those changes here. On T and below these are + // handled by the applyInitialLinkProperties call just above. + // TODO: stop relying on updateLinkProperties(..., null) to do this. + // If something depends on both LinkProperties and connected state, it should be in + // this method as well. + networkAgent.clatd.update(); + updateProxy(networkAgent.linkProperties, null); + } // If a rate limit has been configured and is applicable to this network (network // provides internet connectivity), apply it. The tc police filter cannot be attached @@ -9327,13 +9851,13 @@ // in the absence of a satisfactory, scalable solution which follows an easy/standard // process to check the interface version, just use an SDK check. NetworkStack will // always be new enough when running on T+. - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { networkAgent.networkMonitor().notifyNetworkConnected(params); } else { networkAgent.networkMonitor().notifyNetworkConnected(params.linkProperties, params.networkCapabilities); } - final long delay = activelyPreferBadWifi() + final long delay = !avoidBadWifi() && activelyPreferBadWifi() ? ACTIVELY_PREFER_BAD_WIFI_INITIAL_TIMEOUT_MS : DONT_ACTIVELY_PREFER_BAD_WIFI_INITIAL_TIMEOUT_MS; scheduleEvaluationTimeout(networkAgent.network, delay); @@ -9630,20 +10154,24 @@ enforceKeepalivePermission(); mKeepaliveTracker.startNattKeepalive( getNetworkAgentInfoForNetwork(network), null /* fd */, - intervalSeconds, cb, - srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT); + intervalSeconds, cb, srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT, + // Keep behavior of the deprecated method as it is. Set automaticOnOffKeepalives to + // false and set the underpinned network to null because there is no way and no + // plan to configure automaticOnOffKeepalives or underpinnedNetwork in this + // deprecated method. + false /* automaticOnOffKeepalives */, null /* underpinnedNetwork */); } @Override public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId, int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr, - String dstAddr) { + String dstAddr, boolean automaticOnOffKeepalives, Network underpinnedNetwork) { try { final FileDescriptor fd = pfd.getFileDescriptor(); mKeepaliveTracker.startNattKeepalive( getNetworkAgentInfoForNetwork(network), fd, resourceId, - intervalSeconds, cb, - srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT); + intervalSeconds, cb, srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT, + automaticOnOffKeepalives, underpinnedNetwork); } finally { // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks. // startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately. @@ -9671,9 +10199,20 @@ } @Override - public void stopKeepalive(Network network, int slot) { + public void stopKeepalive(@NonNull final ISocketKeepaliveCallback cb) { mHandler.sendMessage(mHandler.obtainMessage( - NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE, slot, SocketKeepalive.SUCCESS, network)); + NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE, 0, SocketKeepalive.SUCCESS, + Objects.requireNonNull(cb).asBinder())); + } + + @Override + public int[] getSupportedKeepalives() { + enforceAnyPermissionOf(mContext, android.Manifest.permission.NETWORK_SETTINGS, + // Backwards compatibility with CTS 13 + android.Manifest.permission.QUERY_ALL_PACKAGES); + + return BinderUtils.withCleanCallingIdentity(() -> + KeepaliveResourceUtil.getSupportedKeepalives(mContext)); } @Override @@ -10388,6 +10927,18 @@ callback)); } + private boolean hasUnderlyingTestNetworks(NetworkCapabilities nc) { + final List<Network> underlyingNetworks = nc.getUnderlyingNetworks(); + if (underlyingNetworks == null) return false; + + for (Network network : underlyingNetworks) { + if (getNetworkCapabilitiesInternal(network).hasTransport(TRANSPORT_TEST)) { + return true; + } + } + return false; + } + @Override public void simulateDataStall(int detectionMethod, long timestampMillis, @NonNull Network network, @NonNull PersistableBundle extras) { @@ -10398,14 +10949,18 @@ android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK); final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network); - if (!nc.hasTransport(TRANSPORT_TEST)) { - throw new SecurityException("Data Stall simulation is only possible for test networks"); + if (!nc.hasTransport(TRANSPORT_TEST) && !hasUnderlyingTestNetworks(nc)) { + throw new SecurityException( + "Data Stall simulation is only possible for test networks or networks built on" + + " top of test networks"); } final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); - if (nai == null || nai.creatorUid != mDeps.getCallingUid()) { - throw new SecurityException("Data Stall simulation is only possible for network " - + "creators"); + if (nai == null + || (nai.creatorUid != mDeps.getCallingUid() + && nai.creatorUid != Process.SYSTEM_UID)) { + throw new SecurityException( + "Data Stall simulation is only possible for network " + "creators"); } // Instead of passing the data stall directly to the ConnectivityDiagnostics handler, treat @@ -10772,7 +11327,7 @@ if (um.isManagedProfile(profile.getIdentifier())) { return true; } - if (SdkLevel.isAtLeastT() && dpm.getDeviceOwner() != null) return true; + if (mDeps.isAtLeastT() && dpm.getDeviceOwner() != null) return true; return false; } @@ -10816,11 +11371,12 @@ + "or the device owner must be set. "); } - final List<ProfileNetworkPreferenceList.Preference> preferenceList = new ArrayList<>(); + final List<ProfileNetworkPreferenceInfo> preferenceList = new ArrayList<>(); boolean hasDefaultPreference = false; for (final ProfileNetworkPreference preference : preferences) { final NetworkCapabilities nc; boolean allowFallback = true; + boolean blockingNonEnterprise = false; switch (preference.getPreference()) { case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT: nc = null; @@ -10830,6 +11386,9 @@ "Invalid enterprise identifier in setProfileNetworkPreferences"); } break; + case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING: + blockingNonEnterprise = true; + // continue to process the enterprise preference. case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK: allowFallback = false; // continue to process the enterprise preference. @@ -10863,8 +11422,8 @@ throw new IllegalArgumentException( "Invalid preference in setProfileNetworkPreferences"); } - preferenceList.add(new ProfileNetworkPreferenceList.Preference( - profile, nc, allowFallback)); + preferenceList.add(new ProfileNetworkPreferenceInfo( + profile, nc, allowFallback, blockingNonEnterprise)); if (hasDefaultPreference && preferenceList.size() > 1) { throw new IllegalArgumentException( "Default profile preference should not be set along with other preference"); @@ -10913,9 +11472,9 @@ } private ArraySet<NetworkRequestInfo> createNrisFromProfileNetworkPreferences( - @NonNull final ProfileNetworkPreferenceList prefs) { + @NonNull final NetworkPreferenceList<UserHandle, ProfileNetworkPreferenceInfo> prefs) { final ArraySet<NetworkRequestInfo> result = new ArraySet<>(); - for (final ProfileNetworkPreferenceList.Preference pref : prefs.preferences) { + for (final ProfileNetworkPreferenceInfo pref : prefs) { // The NRI for a user should contain the request for capabilities. // If fallback to default network is needed then NRI should include // the request for the default network. Create an image of it to @@ -10945,12 +11504,12 @@ * */ private boolean isRangeAlreadyInPreferenceList( - @NonNull List<ProfileNetworkPreferenceList.Preference> preferenceList, + @NonNull List<ProfileNetworkPreferenceInfo> preferenceList, @NonNull Set<UidRange> uidRangeSet) { if (uidRangeSet.size() == 0 || preferenceList.size() == 0) { return false; } - for (ProfileNetworkPreferenceList.Preference pref : preferenceList) { + for (ProfileNetworkPreferenceInfo pref : preferenceList) { if (UidRangeUtils.doesRangeSetOverlap( UidRange.fromIntRanges(pref.capabilities.getUids()), uidRangeSet)) { return true; @@ -10960,7 +11519,7 @@ } private void handleSetProfileNetworkPreference( - @NonNull final List<ProfileNetworkPreferenceList.Preference> preferenceList, + @NonNull final List<ProfileNetworkPreferenceInfo> preferenceList, @Nullable final IOnCompleteListener listener) { /* * handleSetProfileNetworkPreference is always called for single user. @@ -10969,15 +11528,15 @@ * Clear all the existing preferences for the user before applying new preferences. * */ - mProfileNetworkPreferences = mProfileNetworkPreferences.withoutUser( - preferenceList.get(0).user); - for (final ProfileNetworkPreferenceList.Preference preference : preferenceList) { + mProfileNetworkPreferences = mProfileNetworkPreferences.minus(preferenceList.get(0).user); + for (final ProfileNetworkPreferenceInfo preference : preferenceList) { mProfileNetworkPreferences = mProfileNetworkPreferences.plus(preference); } removeDefaultNetworkRequestsForPreference(PREFERENCE_ORDER_PROFILE); addPerAppDefaultNetworkRequests( createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences)); + updateProfileAllowedNetworks(); // Finally, rematch. rematchAllNetworksAndRequests(); @@ -11050,7 +11609,7 @@ private boolean canNetworkBeRateLimited(@NonNull final NetworkAgentInfo networkAgent) { // Rate-limiting cannot run correctly before T because the BPF program is not loaded. - if (!SdkLevel.isAtLeastT()) return false; + if (!mDeps.isAtLeastT()) return false; final NetworkCapabilities agentCaps = networkAgent.networkCapabilities; // Only test networks (they cannot hold NET_CAPABILITY_INTERNET) and networks that provide @@ -11107,6 +11666,60 @@ } /** + * Sets the specified UIDs to get/receive the VPN as the only default network. + * + * Calling this will overwrite the existing network preference for this session, and the + * specified UIDs won't get any default network when no VPN is connected. + * + * @param session The VPN session which manages the passed UIDs. + * @param ranges The uid ranges which will treat VPN as the only preferred network. Clear the + * setting for this session if the array is empty. Null is not allowed, the + * method will use {@link Objects#requireNonNull(Object)} to check this variable. + * @hide + */ + @Override + public void setVpnNetworkPreference(String session, UidRange[] ranges) { + Objects.requireNonNull(ranges); + enforceNetworkStackOrSettingsPermission(); + final UidRange[] sortedRanges = UidRangeUtils.sortRangesByStartUid(ranges); + if (UidRangeUtils.sortedRangesContainOverlap(sortedRanges)) { + throw new IllegalArgumentException( + "setVpnNetworkPreference: Passed UID ranges overlap"); + } + + mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_VPN_NETWORK_PREFERENCE, + new VpnNetworkPreferenceInfo(session, + new ArraySet<UidRange>(Arrays.asList(ranges))))); + } + + private void handleSetVpnNetworkPreference(VpnNetworkPreferenceInfo preferenceInfo) { + Log.d(TAG, "handleSetVpnNetworkPreference: preferenceInfo = " + preferenceInfo); + + mVpnNetworkPreferences = mVpnNetworkPreferences.minus(preferenceInfo.getKey()); + mVpnNetworkPreferences = mVpnNetworkPreferences.plus(preferenceInfo); + + removeDefaultNetworkRequestsForPreference(PREFERENCE_ORDER_VPN); + addPerAppDefaultNetworkRequests(createNrisForVpnNetworkPreference(mVpnNetworkPreferences)); + // Finally, rematch. + rematchAllNetworksAndRequests(); + } + + private ArraySet<NetworkRequestInfo> createNrisForVpnNetworkPreference( + @NonNull NetworkPreferenceList<String, VpnNetworkPreferenceInfo> preferenceList) { + final ArraySet<NetworkRequestInfo> nris = new ArraySet<>(); + for (VpnNetworkPreferenceInfo preferenceInfo : preferenceList) { + final List<NetworkRequest> requests = new ArrayList<>(); + // Request VPN only, so other networks won't be the fallback options when VPN is not + // connected temporarily. + requests.add(createVpnRequest()); + final Set<UidRange> uidRanges = new ArraySet(preferenceInfo.getUidRangesNoCopy()); + setNetworkRequestUids(requests, uidRanges); + nris.add(new NetworkRequestInfo(Process.myUid(), requests, PREFERENCE_ORDER_VPN)); + } + return nris; + } + + /** * Check the validity of an OEM network preference to be used for testing purposes. * @param preference the preference to validate * @return true if this is a valid OEM network preference test request. @@ -11447,6 +12060,12 @@ } } + @Override + public int getUidFirewallRule(final int chain, final int uid) { + enforceNetworkStackOrSettingsPermission(); + return mBpfNetMaps.getUidRule(chain, uid); + } + private int getFirewallRuleType(int chain, int rule) { final int defaultRule; switch (chain) { @@ -11470,6 +12089,23 @@ return rule; } + private void closeSocketsForFirewallChainLocked(final int chain) + throws ErrnoException, SocketException, InterruptedIOException { + if (mBpfNetMaps.isFirewallAllowList(chain)) { + // Allowlist means the firewall denies all by default, uids must be explicitly allowed + // So, close all non-system socket owned by uids that are not explicitly allowed + Set<Range<Integer>> ranges = new ArraySet<>(); + ranges.add(new Range<>(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE)); + final Set<Integer> exemptUids = mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(chain); + mDeps.destroyLiveTcpSockets(ranges, exemptUids); + } else { + // Denylist means the firewall allows all by default, uids must be explicitly denied + // So, close socket owned by uids that are explicitly denied + final Set<Integer> ownerUids = mBpfNetMaps.getUidsWithDenyRuleOnDenyListChain(chain); + mDeps.destroyLiveTcpSocketsByOwnerUids(ownerUids); + } + } + @Override public void setFirewallChainEnabled(final int chain, final boolean enable) { enforceNetworkStackOrSettingsPermission(); @@ -11479,6 +12115,14 @@ } catch (ServiceSpecificException e) { throw new IllegalStateException(e); } + + if (mDeps.isAtLeastU() && enable) { + try { + closeSocketsForFirewallChainLocked(chain); + } catch (ErrnoException | SocketException | InterruptedIOException e) { + Log.e(TAG, "Failed to close sockets after enabling chain (" + chain + "): " + e); + } + } } @Override @@ -11494,4 +12138,10 @@ mBpfNetMaps.replaceUidChain(chain, uids); } + + @Override + public IBinder getCompanionDeviceManagerProxyService() { + enforceNetworkStackPermission(mContext); + return mCdmps; + } }
diff --git a/service/src/com/android/server/TestNetworkService.java b/service/src/com/android/server/TestNetworkService.java index 5549fbe..843b7b3 100644 --- a/service/src/com/android/server/TestNetworkService.java +++ b/service/src/com/android/server/TestNetworkService.java
@@ -310,9 +310,11 @@ NetworkStackConstants.IPV6_ADDR_ANY, 0), null, iface)); } + // For testing purpose, fill legacy type for NetworkStatsService since it does not + // support transport types. final TestNetworkAgent agent = new TestNetworkAgent(context, looper, nc, lp, - new NetworkAgentConfig.Builder().build(), callingUid, binder, - mNetworkProvider); + new NetworkAgentConfig.Builder().setLegacyType(ConnectivityManager.TYPE_TEST) + .build(), callingUid, binder, mNetworkProvider); agent.register(); agent.markConnected(); return agent;
diff --git a/service/src/com/android/server/connectivity/ApplicationSelfCertifiedNetworkCapabilities.java b/service/src/com/android/server/connectivity/ApplicationSelfCertifiedNetworkCapabilities.java new file mode 100644 index 0000000..76e966f --- /dev/null +++ b/service/src/com/android/server/connectivity/ApplicationSelfCertifiedNetworkCapabilities.java
@@ -0,0 +1,209 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity; + + +import android.annotation.NonNull; +import android.net.NetworkCapabilities; +import android.util.Log; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayDeque; + + +/** + * The class for parsing and checking the self-declared application network capabilities. + * + * ApplicationSelfCertifiedNetworkCapabilities is an immutable class that + * can parse the self-declared application network capabilities in the application resources. The + * class also provides a helper method to check whether the requested network capabilities + * already self-declared. + */ +public final class ApplicationSelfCertifiedNetworkCapabilities { + + public static final String PRIORITIZE_LATENCY = "NET_CAPABILITY_PRIORITIZE_LATENCY"; + public static final String PRIORITIZE_BANDWIDTH = "NET_CAPABILITY_PRIORITIZE_BANDWIDTH"; + + private static final String TAG = + ApplicationSelfCertifiedNetworkCapabilities.class.getSimpleName(); + private static final String NETWORK_CAPABILITIES_DECLARATION_TAG = + "network-capabilities-declaration"; + private static final String USES_NETWORK_CAPABILITY_TAG = "uses-network-capability"; + private static final String NAME_TAG = "name"; + + private long mRequestedNetworkCapabilities = 0; + + /** + * Creates {@link ApplicationSelfCertifiedNetworkCapabilities} from a xml parser. + * + * <p> Here is an example of the xml syntax: + * + * <pre> + * {@code + * <network-capabilities-declaration xmlns:android="http://schemas.android.com/apk/res/android"> + * <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_LATENCY"/> + * <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_BANDWIDTH"/> + * </network-capabilities-declaration> + * } + * </pre> + * <p> + * + * @param xmlParser The underlying {@link XmlPullParser} that will read the xml. + * @return An ApplicationSelfCertifiedNetworkCapabilities object. + * @throws InvalidTagException if the capabilities in xml config contains invalid tag. + * @throws XmlPullParserException if xml parsing failed. + * @throws IOException if unable to read the xml file properly. + */ + @NonNull + public static ApplicationSelfCertifiedNetworkCapabilities createFromXml( + @NonNull final XmlPullParser xmlParser) + throws InvalidTagException, XmlPullParserException, IOException { + return new ApplicationSelfCertifiedNetworkCapabilities(parseXml(xmlParser)); + } + + private static long parseXml(@NonNull final XmlPullParser xmlParser) + throws InvalidTagException, XmlPullParserException, IOException { + long requestedNetworkCapabilities = 0; + final ArrayDeque<String> openTags = new ArrayDeque<>(); + + while (checkedNextTag(xmlParser, openTags) != XmlPullParser.START_TAG) { + continue; + } + + // Validates the tag is "network-capabilities-declaration" + if (!xmlParser.getName().equals(NETWORK_CAPABILITIES_DECLARATION_TAG)) { + throw new InvalidTagException("Invalid tag: " + xmlParser.getName()); + } + + checkedNextTag(xmlParser, openTags); + int eventType = xmlParser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + switch (eventType) { + case XmlPullParser.START_TAG: + // USES_NETWORK_CAPABILITY_TAG should directly be declared under + // NETWORK_CAPABILITIES_DECLARATION_TAG. + if (xmlParser.getName().equals(USES_NETWORK_CAPABILITY_TAG) + && openTags.size() == 1) { + int capability = parseDeclarationTag(xmlParser); + if (capability >= 0) { + requestedNetworkCapabilities |= 1L << capability; + } + } else { + Log.w(TAG, "Unknown tag: " + xmlParser.getName() + " ,tags stack size: " + + openTags.size()); + } + break; + default: + break; + } + eventType = checkedNextTag(xmlParser, openTags); + } + // Checks all the tags are parsed. + if (!openTags.isEmpty()) { + throw new InvalidTagException("Unbalanced tag: " + openTags.peek()); + } + return requestedNetworkCapabilities; + } + + private static int parseDeclarationTag(@NonNull final XmlPullParser xmlParser) { + String name = null; + for (int i = 0; i < xmlParser.getAttributeCount(); i++) { + final String attrName = xmlParser.getAttributeName(i); + if (attrName.equals(NAME_TAG)) { + name = xmlParser.getAttributeValue(i); + } else { + Log.w(TAG, "Unknown attribute name: " + attrName); + } + } + if (name != null) { + switch (name) { + case PRIORITIZE_BANDWIDTH: + return NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH; + case PRIORITIZE_LATENCY: + return NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY; + default: + Log.w(TAG, "Unknown capability declaration name: " + name); + } + } else { + Log.w(TAG, "uses-network-capability name must be specified"); + } + // Invalid capability + return -1; + } + + private static int checkedNextTag(@NonNull final XmlPullParser xmlParser, + @NonNull final ArrayDeque<String> openTags) + throws XmlPullParserException, IOException, InvalidTagException { + if (xmlParser.getEventType() == XmlPullParser.START_TAG) { + openTags.addFirst(xmlParser.getName()); + } else if (xmlParser.getEventType() == XmlPullParser.END_TAG) { + if (!openTags.isEmpty() && openTags.peekFirst().equals(xmlParser.getName())) { + openTags.removeFirst(); + } else { + throw new InvalidTagException("Unbalanced tag: " + xmlParser.getName()); + } + } + return xmlParser.next(); + } + + private ApplicationSelfCertifiedNetworkCapabilities(long requestedNetworkCapabilities) { + mRequestedNetworkCapabilities = requestedNetworkCapabilities; + } + + /** + * Enforces self-certified capabilities are declared. + * + * @param networkCapabilities the input NetworkCapabilities to check against. + * @throws SecurityException if the capabilities are not properly self-declared. + */ + public void enforceSelfCertifiedNetworkCapabilitiesDeclared( + @NonNull final NetworkCapabilities networkCapabilities) { + if (networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + && !hasPrioritizeBandwidth()) { + throw new SecurityException( + "Missing " + ApplicationSelfCertifiedNetworkCapabilities.PRIORITIZE_BANDWIDTH + + " declaration"); + } + if (networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) + && !hasPrioritizeLatency()) { + throw new SecurityException( + "Missing " + ApplicationSelfCertifiedNetworkCapabilities.PRIORITIZE_LATENCY + + " declaration"); + } + } + + /** + * Checks if NET_CAPABILITY_PRIORITIZE_LATENCY is declared. + */ + private boolean hasPrioritizeLatency() { + return (mRequestedNetworkCapabilities & (1L + << NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)) != 0; + } + + /** + * Checks if NET_CAPABILITY_PRIORITIZE_BANDWIDTH is declared. + */ + private boolean hasPrioritizeBandwidth() { + return (mRequestedNetworkCapabilities & (1L + << NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)) != 0; + } +}
diff --git a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java new file mode 100644 index 0000000..f8285ed --- /dev/null +++ b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
@@ -0,0 +1,861 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity; + +import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET; +import static android.net.SocketKeepalive.MIN_INTERVAL_SEC; +import static android.net.SocketKeepalive.SUCCESS_PAUSED; +import static android.provider.DeviceConfig.NAMESPACE_TETHERING; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.SOL_SOCKET; +import static android.system.OsConstants.SO_SNDTIMEO; + +import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE; +import static com.android.net.module.util.netlink.NetlinkConstants.SOCKDIAG_MSG_HEADER_SIZE; +import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY; +import static com.android.net.module.util.netlink.NetlinkUtils.IO_TIMEOUT_MS; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AlarmManager; +import android.content.Context; +import android.net.INetd; +import android.net.ISocketKeepaliveCallback; +import android.net.MarkMaskParcel; +import android.net.Network; +import android.net.SocketKeepalive.InvalidSocketException; +import android.os.FileUtils; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.RemoteException; +import android.os.SystemClock; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; +import android.system.StructTimeval; +import android.util.LocalLog; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; +import com.android.net.module.util.BinderUtils; +import com.android.net.module.util.CollectionUtils; +import com.android.net.module.util.DeviceConfigUtils; +import com.android.net.module.util.HexDump; +import com.android.net.module.util.SocketUtils; +import com.android.net.module.util.netlink.InetDiagMessage; +import com.android.net.module.util.netlink.NetlinkMessage; +import com.android.net.module.util.netlink.NetlinkUtils; +import com.android.net.module.util.netlink.StructNlAttr; + +import java.io.FileDescriptor; +import java.io.InterruptedIOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.SocketException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Manages automatic on/off socket keepalive requests. + * + * Provides methods to stop and start automatic keepalive requests, and keeps track of keepalives + * across all networks. This class is tightly coupled to ConnectivityService. It is not + * thread-safe and its handle* methods must be called only from the ConnectivityService handler + * thread. + */ +public class AutomaticOnOffKeepaliveTracker { + private static final String TAG = "AutomaticOnOffKeepaliveTracker"; + private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET6, AF_INET}; + private static final long LOW_TCP_POLLING_INTERVAL_MS = 1_000L; + private static final int ADJUST_TCP_POLLING_DELAY_MS = 2000; + private static final String AUTOMATIC_ON_OFF_KEEPALIVE_VERSION = + "automatic_on_off_keepalive_version"; + + // ConnectivityService parses message constants from itself and AutomaticOnOffKeepaliveTracker + // with MessageUtils for debugging purposes, and crashes if some messages have the same values. + private static final int BASE = 2000; + /** + * Sent by AutomaticOnOffKeepaliveTracker periodically (when relevant) to trigger monitor + * automatic keepalive request. + * + * NATT keepalives have an automatic mode where the system only sends keepalive packets when + * TCP sockets are open over a VPN. The system will check periodically for presence of + * such open sockets, and this message is what triggers the re-evaluation. + * + * obj = A Binder object associated with the keepalive. + */ + public static final int CMD_MONITOR_AUTOMATIC_KEEPALIVE = BASE + 1; + + /** + * Sent by AutomaticOnOffKeepaliveTracker to ConnectivityService to start a keepalive. + * + * obj = AutomaticKeepaliveInfo object + */ + public static final int CMD_REQUEST_START_KEEPALIVE = BASE + 2; + + /** + * States for {@code #AutomaticOnOffKeepalive}. + * + * If automatic mode is off for this keepalive, the state is STATE_ALWAYS_ON and it stays + * so for the entire lifetime of this object. + * + * If enabled, a new AutomaticOnOffKeepalive starts with STATE_ENABLED. The system will monitor + * the TCP sockets on VPN networks running on top of the specified network, and turn off + * keepalive if there is no TCP socket any of the VPN networks. Conversely, it will turn + * keepalive back on if any TCP socket is open on any of the VPN networks. + * + * When there is no TCP socket on any of the VPN networks, the state becomes STATE_SUSPENDED. + * The {@link KeepaliveTracker.KeepaliveInfo} object is kept to remember the parameters so it + * is possible to resume keepalive later with the same parameters. + * + * When the system detects some TCP socket is open on one of the VPNs while in STATE_SUSPENDED, + * this AutomaticOnOffKeepalive goes to STATE_ENABLED again. + * + * When finishing keepalive, this object is deleted. + */ + private static final int STATE_ENABLED = 0; + private static final int STATE_SUSPENDED = 1; + private static final int STATE_ALWAYS_ON = 2; + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "STATE_" }, value = { + STATE_ENABLED, + STATE_SUSPENDED, + STATE_ALWAYS_ON + }) + private @interface AutomaticOnOffState {} + + @NonNull + private final Handler mConnectivityServiceHandler; + @NonNull + private final KeepaliveTracker mKeepaliveTracker; + @NonNull + private final Context mContext; + @NonNull + private final AlarmManager mAlarmManager; + + /** + * The {@code inetDiagReqV2} messages for different IP family. + * + * Key: Ip family type. + * Value: Bytes array represent the {@code inetDiagReqV2}. + * + * This should only be accessed in the connectivity service handler thread. + */ + private final SparseArray<byte[]> mSockDiagMsg = new SparseArray<>(); + private final Dependencies mDependencies; + private final INetd mNetd; + /** + * Keeps track of automatic on/off keepalive requests. + * This should be only updated in ConnectivityService handler thread. + */ + private final ArrayList<AutomaticOnOffKeepalive> mAutomaticOnOffKeepalives = new ArrayList<>(); + // TODO: Remove this when TCP polling design is replaced with callback. + private long mTestLowTcpPollingTimerUntilMs = 0; + + private static final int MAX_EVENTS_LOGS = 40; + private final LocalLog mEventLog = new LocalLog(MAX_EVENTS_LOGS); + + private final KeepaliveStatsTracker mKeepaliveStatsTracker = new KeepaliveStatsTracker(); + /** + * Information about a managed keepalive. + * + * The keepalive in mKi is managed by this object. This object can be in one of three states + * (in mAutomatiOnOffState) : + * • STATE_ALWAYS_ON : this keepalive is always on + * • STATE_ENABLED : this keepalive is currently on, and monitored for possibly being turned + * off if no TCP socket is open on the VPN. + * • STATE_SUSPENDED : this keepalive is currently off, and monitored for possibly being + * resumed if a TCP socket is open on the VPN. + * See the documentation for the states for more detail. + */ + public class AutomaticOnOffKeepalive implements IBinder.DeathRecipient { + @NonNull + private final KeepaliveTracker.KeepaliveInfo mKi; + @NonNull + private final ISocketKeepaliveCallback mCallback; + @Nullable + private final FileDescriptor mFd; + @Nullable + private final AlarmManager.OnAlarmListener mAlarmListener; + @AutomaticOnOffState + private int mAutomaticOnOffState; + @Nullable + private final Network mUnderpinnedNetwork; + + AutomaticOnOffKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki, + final boolean autoOnOff, @Nullable Network underpinnedNetwork) + throws InvalidSocketException { + this.mKi = Objects.requireNonNull(ki); + mCallback = ki.mCallback; + mUnderpinnedNetwork = underpinnedNetwork; + // Reading DeviceConfig will check if the calling uid and calling package name are the + // same. Clear calling identity to align the calling uid and package + final boolean enabled = BinderUtils.withCleanCallingIdentity( + () -> mDependencies.isFeatureEnabled(AUTOMATIC_ON_OFF_KEEPALIVE_VERSION, + true /* defaultEnabled */)); + if (autoOnOff && enabled) { + mAutomaticOnOffState = STATE_ENABLED; + if (null == ki.mFd) { + throw new IllegalArgumentException("fd can't be null with automatic " + + "on/off keepalives"); + } + try { + mFd = Os.dup(ki.mFd); + } catch (ErrnoException e) { + Log.e(TAG, "Cannot dup fd: ", e); + throw new InvalidSocketException(ERROR_INVALID_SOCKET, e); + } + mAlarmListener = () -> mConnectivityServiceHandler.obtainMessage( + CMD_MONITOR_AUTOMATIC_KEEPALIVE, mCallback.asBinder()) + .sendToTarget(); + } else { + mAutomaticOnOffState = STATE_ALWAYS_ON; + // A null fd is acceptable in KeepaliveInfo for backward compatibility of + // PacketKeepalive API, but it must never happen with automatic keepalives. + // TODO : remove mFd from KeepaliveInfo or from this class. + mFd = ki.mFd; + mAlarmListener = null; + } + } + + @VisibleForTesting + public ISocketKeepaliveCallback getCallback() { + return mCallback; + } + + public Network getNetwork() { + return mKi.getNai().network; + } + + @Nullable + public Network getUnderpinnedNetwork() { + return mUnderpinnedNetwork; + } + + public boolean match(Network network, int slot) { + return mKi.getNai().network().equals(network) && mKi.getSlot() == slot; + } + + @Override + public void binderDied() { + mEventLog.log("Binder died : " + mCallback); + mConnectivityServiceHandler.post(() -> cleanupAutoOnOffKeepalive(this)); + } + + /** Close this automatic on/off keepalive */ + public void close() { + // Close the duplicated fd that maintains the lifecycle of socket. If this fd was + // not duplicated this is a no-op. + FileUtils.closeQuietly(mFd); + } + + private String getAutomaticOnOffStateName(int state) { + switch (state) { + case STATE_ENABLED: + return "STATE_ENABLED"; + case STATE_SUSPENDED: + return "STATE_SUSPENDED"; + case STATE_ALWAYS_ON: + return "STATE_ALWAYS_ON"; + default: + Log.e(TAG, "Get unexpected state:" + state); + return Integer.toString(state); + } + } + + @Override + public String toString() { + return "AutomaticOnOffKeepalive [ " + + mKi + + ", state=" + getAutomaticOnOffStateName(mAutomaticOnOffState) + + " ]"; + } + } + + public AutomaticOnOffKeepaliveTracker(@NonNull Context context, @NonNull Handler handler) { + this(context, handler, new Dependencies(context)); + } + + @VisibleForTesting + public AutomaticOnOffKeepaliveTracker(@NonNull Context context, @NonNull Handler handler, + @NonNull Dependencies dependencies) { + mContext = Objects.requireNonNull(context); + mDependencies = Objects.requireNonNull(dependencies); + mConnectivityServiceHandler = Objects.requireNonNull(handler); + mNetd = mDependencies.getNetd(); + mKeepaliveTracker = mDependencies.newKeepaliveTracker( + mContext, mConnectivityServiceHandler); + + mAlarmManager = mDependencies.getAlarmManager(context); + } + + private void startTcpPollingAlarm(@NonNull AutomaticOnOffKeepalive ki) { + if (ki.mAlarmListener == null) return; + + final long triggerAtMillis = + mDependencies.getElapsedRealtime() + getTcpPollingIntervalMs(ki); + // Setup a non-wake up alarm. + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, triggerAtMillis, null /* tag */, + ki.mAlarmListener, mConnectivityServiceHandler); + } + + /** + * Determine if any state transition is needed for the specific automatic keepalive. + */ + public void handleMonitorAutomaticKeepalive(@NonNull final AutomaticOnOffKeepalive ki, + final int vpnNetId) { + // Might happen if the automatic keepalive was removed by the app just as the alarm fires. + if (!mAutomaticOnOffKeepalives.contains(ki)) return; + if (STATE_ALWAYS_ON == ki.mAutomaticOnOffState) { + throw new IllegalStateException("Should not monitor non-auto keepalive"); + } + + handleMonitorTcpConnections(ki, vpnNetId); + } + + /** + * Determine if disable or re-enable keepalive is needed or not based on TCP sockets status. + */ + private void handleMonitorTcpConnections(@NonNull AutomaticOnOffKeepalive ki, int vpnNetId) { + // Might happen if the automatic keepalive was removed by the app just as the alarm fires. + if (!mAutomaticOnOffKeepalives.contains(ki)) return; + if (STATE_ALWAYS_ON == ki.mAutomaticOnOffState) { + throw new IllegalStateException("Should not monitor non-auto keepalive"); + } + if (!isAnyTcpSocketConnected(vpnNetId)) { + // No TCP socket exists. Stop keepalive if ENABLED, and remain SUSPENDED if currently + // SUSPENDED. + if (ki.mAutomaticOnOffState == STATE_ENABLED) { + ki.mAutomaticOnOffState = STATE_SUSPENDED; + handlePauseKeepalive(ki.mKi); + } + } else { + handleMaybeResumeKeepalive(ki); + } + // TODO: listen to socket status instead of periodically check. + startTcpPollingAlarm(ki); + } + + /** + * Resume an auto on/off keepalive, unless it's already resumed + * @param autoKi the keepalive to resume + */ + public void handleMaybeResumeKeepalive(@NonNull AutomaticOnOffKeepalive autoKi) { + mEventLog.log("Resume keepalive " + autoKi.mCallback + " on " + autoKi.getNetwork()); + // Might happen if the automatic keepalive was removed by the app just as the alarm fires. + if (!mAutomaticOnOffKeepalives.contains(autoKi)) return; + if (STATE_ALWAYS_ON == autoKi.mAutomaticOnOffState) { + throw new IllegalStateException("Should not resume non-auto keepalive"); + } + if (autoKi.mAutomaticOnOffState == STATE_ENABLED) return; + KeepaliveTracker.KeepaliveInfo newKi; + try { + // Get fd from AutomaticOnOffKeepalive since the fd in the original + // KeepaliveInfo should be closed. + newKi = autoKi.mKi.withFd(autoKi.mFd); + } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) { + Log.e(TAG, "Fail to construct keepalive", e); + mKeepaliveTracker.notifyErrorCallback(autoKi.mCallback, ERROR_INVALID_SOCKET); + return; + } + autoKi.mAutomaticOnOffState = STATE_ENABLED; + handleResumeKeepalive(newKi); + } + + /** + * Find the AutomaticOnOffKeepalive associated with a given callback. + * @return the keepalive associated with this callback, or null if none + */ + @Nullable + public AutomaticOnOffKeepalive getKeepaliveForBinder(@NonNull final IBinder token) { + ensureRunningOnHandlerThread(); + + return CollectionUtils.findFirst(mAutomaticOnOffKeepalives, + it -> it.mCallback.asBinder().equals(token)); + } + + /** + * Handle keepalive events from lower layer. + * + * Forward to KeepaliveTracker. + */ + public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) { + mKeepaliveTracker.handleEventSocketKeepalive(nai, slot, reason); + } + + /** + * Handle stop all keepalives on the specific network. + */ + public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) { + mEventLog.log("Stop all keepalives on " + nai.network + " because " + reason); + mKeepaliveTracker.handleStopAllKeepalives(nai, reason); + final List<AutomaticOnOffKeepalive> matches = + CollectionUtils.filter(mAutomaticOnOffKeepalives, it -> it.mKi.getNai() == nai); + for (final AutomaticOnOffKeepalive ki : matches) { + cleanupAutoOnOffKeepalive(ki); + } + } + + /** + * Handle start keepalive contained within a message. + * + * The message is expected to contain a KeepaliveTracker.KeepaliveInfo. + */ + public void handleStartKeepalive(Message message) { + final AutomaticOnOffKeepalive autoKi = (AutomaticOnOffKeepalive) message.obj; + mEventLog.log("Start keepalive " + autoKi.mCallback + " on " + autoKi.getNetwork()); + mKeepaliveStatsTracker.onStartKeepalive(); + mKeepaliveTracker.handleStartKeepalive(autoKi.mKi); + + // Add automatic on/off request into list to track its life cycle. + try { + autoKi.mKi.mCallback.asBinder().linkToDeath(autoKi, 0); + } catch (RemoteException e) { + // The underlying keepalive performs its own cleanup + autoKi.binderDied(); + return; + } + mAutomaticOnOffKeepalives.add(autoKi); + if (STATE_ALWAYS_ON != autoKi.mAutomaticOnOffState) { + startTcpPollingAlarm(autoKi); + } + } + + private void handleResumeKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) { + mKeepaliveStatsTracker.onResumeKeepalive(); + mKeepaliveTracker.handleStartKeepalive(ki); + mEventLog.log("Resumed successfully keepalive " + ki.mCallback + " on " + ki.mNai); + } + + private void handlePauseKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) { + mEventLog.log("Suspend keepalive " + ki.mCallback + " on " + ki.mNai); + mKeepaliveStatsTracker.onPauseKeepalive(); + // TODO : mKT.handleStopKeepalive should take a KeepaliveInfo instead + mKeepaliveTracker.handleStopKeepalive(ki.getNai(), ki.getSlot(), SUCCESS_PAUSED); + } + + /** + * Handle stop keepalives on the specific network with given slot. + */ + public void handleStopKeepalive(@NonNull final AutomaticOnOffKeepalive autoKi, int reason) { + mEventLog.log("Stop keepalive " + autoKi.mCallback + " because " + reason); + // Stop the keepalive unless it was suspended. This includes the case where it's managed + // but enabled, and the case where it's always on. + if (autoKi.mAutomaticOnOffState != STATE_SUSPENDED) { + final KeepaliveTracker.KeepaliveInfo ki = autoKi.mKi; + mKeepaliveTracker.handleStopKeepalive(ki.getNai(), ki.getSlot(), reason); + } else { + mKeepaliveTracker.finalizePausedKeepalive(autoKi.mKi); + } + + cleanupAutoOnOffKeepalive(autoKi); + } + + private void cleanupAutoOnOffKeepalive(@NonNull final AutomaticOnOffKeepalive autoKi) { + ensureRunningOnHandlerThread(); + mKeepaliveStatsTracker.onStopKeepalive(autoKi.mAutomaticOnOffState != STATE_SUSPENDED); + autoKi.close(); + if (null != autoKi.mAlarmListener) mAlarmManager.cancel(autoKi.mAlarmListener); + + // If the KI is not in the array, it's because it was already removed, or it was never + // added ; the only ways this can happen is if the keepalive is stopped by the app and the + // app dies immediately, or if the app died before the link to death could be registered. + if (!mAutomaticOnOffKeepalives.remove(autoKi)) return; + + autoKi.mKi.mCallback.asBinder().unlinkToDeath(autoKi, 0); + } + + /** + * Called when requesting that keepalives be started on a IPsec NAT-T socket. See + * {@link android.net.SocketKeepalive}. + * + * Forward to KeepaliveTracker. + **/ + public void startNattKeepalive(@Nullable NetworkAgentInfo nai, + @Nullable FileDescriptor fd, + int intervalSeconds, + @NonNull ISocketKeepaliveCallback cb, + @NonNull String srcAddrString, + int srcPort, + @NonNull String dstAddrString, + int dstPort, boolean automaticOnOffKeepalives, @Nullable Network underpinnedNetwork) { + final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd, + intervalSeconds, cb, srcAddrString, srcPort, dstAddrString, dstPort); + if (null == ki) return; + try { + final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki, + automaticOnOffKeepalives, underpinnedNetwork); + mEventLog.log("Start natt keepalive " + cb + " on " + nai.network + + " " + srcAddrString + ":" + srcPort + + " → " + dstAddrString + ":" + dstPort + + " auto=" + autoKi + + " underpinned=" + underpinnedNetwork); + mConnectivityServiceHandler.obtainMessage(CMD_REQUEST_START_KEEPALIVE, autoKi) + .sendToTarget(); + } catch (InvalidSocketException e) { + mKeepaliveTracker.notifyErrorCallback(cb, e.error); + } + } + + /** + * Called when requesting that keepalives be started on a IPsec NAT-T socket. See + * {@link android.net.SocketKeepalive}. + * + * Forward to KeepaliveTracker. + **/ + public void startNattKeepalive(@Nullable NetworkAgentInfo nai, + @Nullable FileDescriptor fd, + int resourceId, + int intervalSeconds, + @NonNull ISocketKeepaliveCallback cb, + @NonNull String srcAddrString, + @NonNull String dstAddrString, + int dstPort, + boolean automaticOnOffKeepalives, + @Nullable Network underpinnedNetwork) { + final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd, + resourceId, intervalSeconds, cb, srcAddrString, dstAddrString, dstPort); + if (null == ki) return; + try { + final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki, + automaticOnOffKeepalives, underpinnedNetwork); + mEventLog.log("Start natt keepalive " + cb + " on " + nai.network + + " " + srcAddrString + + " → " + dstAddrString + ":" + dstPort + + " auto=" + autoKi + + " underpinned=" + underpinnedNetwork); + mConnectivityServiceHandler.obtainMessage(CMD_REQUEST_START_KEEPALIVE, autoKi) + .sendToTarget(); + } catch (InvalidSocketException e) { + mKeepaliveTracker.notifyErrorCallback(cb, e.error); + } + } + + /** + * Called by ConnectivityService to start TCP keepalive on a file descriptor. + * + * In order to offload keepalive for application correctly, sequence number, ack number and + * other fields are needed to form the keepalive packet. Thus, this function synchronously + * puts the socket into repair mode to get the necessary information. After the socket has been + * put into repair mode, the application cannot access the socket until reverted to normal. + * See {@link android.net.SocketKeepalive}. + * + * Forward to KeepaliveTracker. + **/ + public void startTcpKeepalive(@Nullable NetworkAgentInfo nai, + @NonNull FileDescriptor fd, + int intervalSeconds, + @NonNull ISocketKeepaliveCallback cb) { + final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeTcpKeepaliveInfo(nai, fd, + intervalSeconds, cb); + if (null == ki) return; + try { + final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki, + false /* autoOnOff, tcp keepalives are never auto on/off */, + null /* underpinnedNetwork, tcp keepalives do not refer to this */); + mConnectivityServiceHandler.obtainMessage(CMD_REQUEST_START_KEEPALIVE, autoKi) + .sendToTarget(); + } catch (InvalidSocketException e) { + mKeepaliveTracker.notifyErrorCallback(cb, e.error); + } + } + + /** + * Dump AutomaticOnOffKeepaliveTracker state. + */ + public void dump(IndentingPrintWriter pw) { + mKeepaliveTracker.dump(pw); + // Reading DeviceConfig will check if the calling uid and calling package name are the same. + // Clear calling identity to align the calling uid and package so that it won't fail if cts + // would like to call dump() + final boolean featureEnabled = BinderUtils.withCleanCallingIdentity( + () -> mDependencies.isFeatureEnabled(AUTOMATIC_ON_OFF_KEEPALIVE_VERSION, + true /* defaultEnabled */)); + pw.println("AutomaticOnOff enabled: " + featureEnabled); + pw.increaseIndent(); + for (AutomaticOnOffKeepalive autoKi : mAutomaticOnOffKeepalives) { + pw.println(autoKi.toString()); + } + pw.decreaseIndent(); + + pw.println("Events (most recent first):"); + pw.increaseIndent(); + mEventLog.reverseDump(pw); + pw.decreaseIndent(); + } + + /** + * Check all keepalives on the network are still valid. + * + * Forward to KeepaliveTracker. + */ + public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) { + mKeepaliveTracker.handleCheckKeepalivesStillValid(nai); + } + + @VisibleForTesting + boolean isAnyTcpSocketConnected(int netId) { + FileDescriptor fd = null; + + try { + fd = mDependencies.createConnectedNetlinkSocket(); + + // Get network mask + final MarkMaskParcel parcel = mNetd.getFwmarkForNetwork(netId); + final int networkMark = (parcel != null) ? parcel.mark : NetlinkUtils.UNKNOWN_MARK; + final int networkMask = (parcel != null) ? parcel.mask : NetlinkUtils.NULL_MASK; + + // Send request for each IP family + for (final int family : ADDRESS_FAMILIES) { + if (isAnyTcpSocketConnectedForFamily(fd, family, networkMark, networkMask)) { + return true; + } + } + } catch (ErrnoException | SocketException | InterruptedIOException | RemoteException e) { + Log.e(TAG, "Fail to get socket info via netlink.", e); + } finally { + SocketUtils.closeSocketQuietly(fd); + } + + return false; + } + + private boolean isAnyTcpSocketConnectedForFamily(FileDescriptor fd, int family, int networkMark, + int networkMask) throws ErrnoException, InterruptedIOException { + ensureRunningOnHandlerThread(); + // Build SocketDiag messages and cache it. + if (mSockDiagMsg.get(family) == null) { + mSockDiagMsg.put(family, InetDiagMessage.buildInetDiagReqForAliveTcpSockets(family)); + } + mDependencies.sendRequest(fd, mSockDiagMsg.get(family)); + + // Iteration limitation as a protection to avoid possible infinite loops. + // DEFAULT_RECV_BUFSIZE could read more than 20 sockets per time. Max iteration + // should be enough to go through reasonable TCP sockets in the device. + final int maxIteration = 100; + int parsingIteration = 0; + while (parsingIteration < maxIteration) { + final ByteBuffer bytes = mDependencies.recvSockDiagResponse(fd); + + try { + while (NetlinkUtils.enoughBytesRemainForValidNlMsg(bytes)) { + final int startPos = bytes.position(); + + final int nlmsgLen = bytes.getInt(); + final int nlmsgType = bytes.getShort(); + if (isEndOfMessageOrError(nlmsgType)) return false; + // TODO: Parse InetDiagMessage to get uid and dst address information to filter + // socket via NetlinkMessage.parse. + + // Skip the header to move to data part. + bytes.position(startPos + SOCKDIAG_MSG_HEADER_SIZE); + + if (isTargetTcpSocket(bytes, nlmsgLen, networkMark, networkMask)) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + bytes.position(startPos); + final InetDiagMessage diagMsg = (InetDiagMessage) NetlinkMessage.parse( + bytes, OsConstants.NETLINK_INET_DIAG); + Log.d(TAG, String.format("Found open TCP connection by uid %d to %s" + + " cookie %d", + diagMsg.inetDiagMsg.idiag_uid, + diagMsg.inetDiagMsg.id.remSocketAddress, + diagMsg.inetDiagMsg.id.cookie)); + } + return true; + } + } + } catch (BufferUnderflowException e) { + // The exception happens in random place in either header position or any data + // position. Partial bytes from the middle of the byte buffer may not be enough to + // clarify, so print out the content before the error to possibly prevent printing + // the whole 8K buffer. + final int exceptionPos = bytes.position(); + final String hex = HexDump.dumpHexString(bytes.array(), 0, exceptionPos); + Log.e(TAG, "Unexpected socket info parsing: " + hex, e); + } + + parsingIteration++; + } + return false; + } + + private boolean isEndOfMessageOrError(int nlmsgType) { + return nlmsgType == NLMSG_DONE || nlmsgType != SOCK_DIAG_BY_FAMILY; + } + + private boolean isTargetTcpSocket(@NonNull ByteBuffer bytes, int nlmsgLen, int networkMark, + int networkMask) { + final int mark = readSocketDataAndReturnMark(bytes, nlmsgLen); + return (mark & networkMask) == networkMark; + } + + private int readSocketDataAndReturnMark(@NonNull ByteBuffer bytes, int nlmsgLen) { + final int nextMsgOffset = bytes.position() + nlmsgLen - SOCKDIAG_MSG_HEADER_SIZE; + int mark = NetlinkUtils.INIT_MARK_VALUE; + // Get socket mark + // TODO: Add a parsing method in NetlinkMessage.parse to support this to skip the remaining + // data. + while (bytes.position() < nextMsgOffset) { + final StructNlAttr nlattr = StructNlAttr.parse(bytes); + if (nlattr != null && nlattr.nla_type == NetlinkUtils.INET_DIAG_MARK) { + mark = nlattr.getValueAsInteger(); + } + } + return mark; + } + + private void ensureRunningOnHandlerThread() { + if (mConnectivityServiceHandler.getLooper().getThread() != Thread.currentThread()) { + throw new IllegalStateException( + "Not running on handler thread: " + Thread.currentThread().getName()); + } + } + + private long getTcpPollingIntervalMs(@NonNull AutomaticOnOffKeepalive ki) { + final boolean useLowTimer = mTestLowTcpPollingTimerUntilMs > System.currentTimeMillis(); + // Adjust the polling interval to be smaller than the keepalive delay to preserve + // some time for the system to restart the keepalive. + final int timer = ki.mKi.getKeepaliveIntervalSec() * 1000 - ADJUST_TCP_POLLING_DELAY_MS; + if (timer < MIN_INTERVAL_SEC) { + Log.wtf(TAG, "Unreasonably low keepalive delay: " + ki.mKi.getKeepaliveIntervalSec()); + } + return useLowTimer ? LOW_TCP_POLLING_INTERVAL_MS : Math.max(timer, MIN_INTERVAL_SEC); + } + + /** + * Temporarily use low TCP polling timer for testing. + * The value works when the time set is more than {@link System.currentTimeMillis()}. + */ + public void handleSetTestLowTcpPollingTimer(long timeMs) { + Log.d(TAG, "handleSetTestLowTcpPollingTimer: " + timeMs); + mTestLowTcpPollingTimerUntilMs = timeMs; + } + + /** + * Dependencies class for testing. + */ + @VisibleForTesting + public static class Dependencies { + private final Context mContext; + + public Dependencies(final Context context) { + mContext = context; + } + + /** + * Create a netlink socket connected to the kernel. + * + * @return fd the fileDescriptor of the socket. + */ + public FileDescriptor createConnectedNetlinkSocket() + throws ErrnoException, SocketException { + final FileDescriptor fd = NetlinkUtils.createNetLinkInetDiagSocket(); + NetlinkUtils.connectSocketToNetlink(fd); + Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, + StructTimeval.fromMillis(IO_TIMEOUT_MS)); + return fd; + } + + /** + * Send composed message request to kernel. + * + * The given FileDescriptor is expected to be created by + * {@link #createConnectedNetlinkSocket} or equivalent way. + * + * @param fd a netlink socket {@code FileDescriptor} connected to the kernel. + * @param msg the byte array representing the request message to write to kernel. + */ + public void sendRequest(@NonNull final FileDescriptor fd, + @NonNull final byte[] msg) + throws ErrnoException, InterruptedIOException { + Os.write(fd, msg, 0 /* byteOffset */, msg.length); + } + + /** + * Get an INetd connector. + */ + public INetd getNetd() { + return INetd.Stub.asInterface( + (IBinder) mContext.getSystemService(Context.NETD_SERVICE)); + } + + /** + * Get an instance of AlarmManager + */ + public AlarmManager getAlarmManager(@NonNull final Context ctx) { + return ctx.getSystemService(AlarmManager.class); + } + + /** + * Receive the response message from kernel via given {@code FileDescriptor}. + * The usage should follow the {@code #sendRequest} call with the same + * FileDescriptor. + * + * The overall response may be large but the individual messages should not be + * excessively large(8-16kB) because trying to get the kernel to return + * everything in one big buffer is inefficient as it forces the kernel to allocate + * large chunks of linearly physically contiguous memory. The usage should iterate the + * call of this method until the end of the overall message. + * + * The default receiving buffer size should be small enough that it is always + * processed within the {@link NetlinkUtils#IO_TIMEOUT_MS} timeout. + */ + public ByteBuffer recvSockDiagResponse(@NonNull final FileDescriptor fd) + throws ErrnoException, InterruptedIOException { + return NetlinkUtils.recvMessage( + fd, NetlinkUtils.DEFAULT_RECV_BUFSIZE, NetlinkUtils.IO_TIMEOUT_MS); + } + + /** + * Construct a new KeepaliveTracker. + */ + public KeepaliveTracker newKeepaliveTracker(@NonNull Context context, + @NonNull Handler connectivityserviceHander) { + return new KeepaliveTracker(mContext, connectivityserviceHander); + } + + /** + * Find out if a feature is enabled from DeviceConfig. + * + * @param name The name of the property to look up. + * @param defaultEnabled whether to consider the feature enabled in the absence of + * the flag. This MUST be a statically-known constant. + * @return whether the feature is enabled + */ + public boolean isFeatureEnabled(@NonNull final String name, final boolean defaultEnabled) { + return DeviceConfigUtils.isFeatureEnabled(mContext, NAMESPACE_TETHERING, name, + DeviceConfigUtils.TETHERING_MODULE_NAME, defaultEnabled); + } + + /** + * Returns milliseconds since boot, including time spent in sleep. + * + * @return elapsed milliseconds since boot. + */ + public long getElapsedRealtime() { + return SystemClock.elapsedRealtime(); + } + } +}
diff --git a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java index b06c8aa..4325763 100644 --- a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java +++ b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
@@ -38,6 +38,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.modules.utils.HandlerExecutor; import com.android.networkstack.apishim.TelephonyManagerShimImpl; import com.android.networkstack.apishim.common.TelephonyManagerShim; import com.android.networkstack.apishim.common.TelephonyManagerShim.CarrierPrivilegesListenerShim; @@ -46,7 +47,6 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; -import java.util.concurrent.RejectedExecutionException; /** * Tracks the uid of the carrier privileged app that provides the carrier config. @@ -105,27 +105,6 @@ } /** - * An adapter {@link Executor} that posts all executed tasks onto the given - * {@link Handler}. - * - * TODO : migrate to the version in frameworks/libs/net when it's ready - * - * @hide - */ - public class HandlerExecutor implements Executor { - private final Handler mHandler; - public HandlerExecutor(@NonNull Handler handler) { - mHandler = handler; - } - @Override - public void execute(Runnable command) { - if (!mHandler.post(command)) { - throw new RejectedExecutionException(mHandler + " is shutting down"); - } - } - } - - /** * Broadcast receiver for ACTION_MULTI_SIM_CONFIG_CHANGED * * <p>The broadcast receiver is registered with mHandler
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java index 5d04632..fbe706c 100644 --- a/service/src/com/android/server/connectivity/ClatCoordinator.java +++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -237,9 +237,8 @@ /** * Stop clatd. */ - public void stopClatd(String iface, String pfx96, String v4, String v6, int pid) - throws IOException { - native_stopClatd(iface, pfx96, v4, v6, pid); + public void stopClatd(int pid) throws IOException { + native_stopClatd(pid); } /** @@ -843,9 +842,7 @@ Log.i(TAG, "Stopping clatd pid=" + mClatdTracker.pid + " on " + mClatdTracker.iface); maybeStopBpf(mClatdTracker); - mDeps.stopClatd(mClatdTracker.iface, mClatdTracker.pfx96.getHostAddress(), - mClatdTracker.v4.getHostAddress(), mClatdTracker.v6.getHostAddress(), - mClatdTracker.pid); + mDeps.stopClatd(mClatdTracker.pid); untagSocket(mClatdTracker.cookie); Log.i(TAG, "clatd on " + mClatdTracker.iface + " stopped"); @@ -944,7 +941,6 @@ private static native int native_startClatd(FileDescriptor tunfd, FileDescriptor readsock6, FileDescriptor writesock6, String iface, String pfx96, String v4, String v6) throws IOException; - private static native void native_stopClatd(String iface, String pfx96, String v4, String v6, - int pid) throws IOException; + private static native void native_stopClatd(int pid) throws IOException; private static native long native_getSocketCookie(FileDescriptor sock) throws IOException; }
diff --git a/service/src/com/android/server/connectivity/ConnectivityFlags.java b/service/src/com/android/server/connectivity/ConnectivityFlags.java index 122ea1c..9039a14 100644 --- a/service/src/com/android/server/connectivity/ConnectivityFlags.java +++ b/service/src/com/android/server/connectivity/ConnectivityFlags.java
@@ -61,6 +61,6 @@ */ public void loadFlags(ConnectivityService.Dependencies deps, Context ctx) { mNoRematchAllRequestsOnRegister = deps.isFeatureEnabled( - ctx, NO_REMATCH_ALL_REQUESTS_ON_REGISTER, false /* defaultEnabled */); + ctx, NO_REMATCH_ALL_REQUESTS_ON_REGISTER); } }
diff --git a/framework/src/android/net/ConnectivityResources.java b/service/src/com/android/server/connectivity/ConnectivityResources.java similarity index 67% rename from framework/src/android/net/ConnectivityResources.java rename to service/src/com/android/server/connectivity/ConnectivityResources.java index 18f0de0..9089e4a 100644 --- a/framework/src/android/net/ConnectivityResources.java +++ b/service/src/com/android/server/connectivity/ConnectivityResources.java
@@ -14,22 +14,16 @@ * limitations under the License. */ -package android.net; - -import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; +package com.android.server.connectivity; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.content.Intent; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.res.Resources; -import android.util.Log; import com.android.internal.annotations.VisibleForTesting; - -import java.util.List; +import com.android.net.module.util.DeviceConfigUtils; /** * Utility to obtain the {@link com.android.server.ConnectivityService} {@link Resources}, in the @@ -37,10 +31,6 @@ * @hide */ public class ConnectivityResources { - private static final String RESOURCES_APK_INTENT = - "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK"; - private static final String RES_PKG_DIR = "/apex/com.android.tethering/"; - @NonNull private final Context mContext; @@ -76,21 +66,10 @@ return mResourcesContext; } - final List<ResolveInfo> pkgs = mContext.getPackageManager() - .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY); - pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith(RES_PKG_DIR)); - if (pkgs.size() > 1) { - Log.wtf(ConnectivityResources.class.getSimpleName(), - "More than one package found: " + pkgs); - } - if (pkgs.isEmpty()) { - throw new IllegalStateException("No connectivity resource package found"); - } - + final String resPkg = DeviceConfigUtils.getConnectivityResourcesPackageName(mContext); final Context pkgContext; try { - pkgContext = mContext.createPackageContext( - pkgs.get(0).activityInfo.applicationInfo.packageName, 0 /* flags */); + pkgContext = mContext.createPackageContext(resPkg, 0 /* flags */); } catch (PackageManager.NameNotFoundException e) { throw new IllegalStateException("Resolved package not found", e); }
diff --git a/service/src/com/android/server/connectivity/DscpPolicyTracker.java b/service/src/com/android/server/connectivity/DscpPolicyTracker.java index 2bfad10..8d566b6 100644 --- a/service/src/com/android/server/connectivity/DscpPolicyTracker.java +++ b/service/src/com/android/server/connectivity/DscpPolicyTracker.java
@@ -66,8 +66,8 @@ private Set<String> mAttachedIfaces; - private final BpfMap<Struct.U32, DscpPolicyValue> mBpfDscpIpv4Policies; - private final BpfMap<Struct.U32, DscpPolicyValue> mBpfDscpIpv6Policies; + private final BpfMap<Struct.S32, DscpPolicyValue> mBpfDscpIpv4Policies; + private final BpfMap<Struct.S32, DscpPolicyValue> mBpfDscpIpv6Policies; // The actual policy rules used by the BPF code to process packets // are in mBpfDscpIpv4Policies and mBpfDscpIpv4Policies. Both of @@ -85,10 +85,10 @@ public DscpPolicyTracker() throws ErrnoException { mAttachedIfaces = new HashSet<String>(); mIfaceIndexToPolicyIdBpfMapIndex = new HashMap<Integer, SparseIntArray>(); - mBpfDscpIpv4Policies = new BpfMap<Struct.U32, DscpPolicyValue>(IPV4_POLICY_MAP_PATH, - BpfMap.BPF_F_RDWR, Struct.U32.class, DscpPolicyValue.class); - mBpfDscpIpv6Policies = new BpfMap<Struct.U32, DscpPolicyValue>(IPV6_POLICY_MAP_PATH, - BpfMap.BPF_F_RDWR, Struct.U32.class, DscpPolicyValue.class); + mBpfDscpIpv4Policies = new BpfMap<Struct.S32, DscpPolicyValue>(IPV4_POLICY_MAP_PATH, + BpfMap.BPF_F_RDWR, Struct.S32.class, DscpPolicyValue.class); + mBpfDscpIpv6Policies = new BpfMap<Struct.S32, DscpPolicyValue>(IPV6_POLICY_MAP_PATH, + BpfMap.BPF_F_RDWR, Struct.S32.class, DscpPolicyValue.class); } private boolean isUnusedIndex(int index) { @@ -181,7 +181,7 @@ // are both null or if they are both instances of Inet4Address. if (matchesIpv4(policy)) { mBpfDscpIpv4Policies.insertOrReplaceEntry( - new Struct.U32(addIndex), + new Struct.S32(addIndex), new DscpPolicyValue(policy.getSourceAddress(), policy.getDestinationAddress(), ifIndex, policy.getSourcePort(), policy.getDestinationPortRange(), @@ -192,7 +192,7 @@ // are both null or if they are both instances of Inet6Address. if (matchesIpv6(policy)) { mBpfDscpIpv6Policies.insertOrReplaceEntry( - new Struct.U32(addIndex), + new Struct.S32(addIndex), new DscpPolicyValue(policy.getSourceAddress(), policy.getDestinationAddress(), ifIndex, policy.getSourcePort(), policy.getDestinationPortRange(), @@ -258,8 +258,8 @@ boolean sendCallback) { int status = DSCP_POLICY_STATUS_POLICY_NOT_FOUND; try { - mBpfDscpIpv4Policies.replaceEntry(new Struct.U32(index), DscpPolicyValue.NONE); - mBpfDscpIpv6Policies.replaceEntry(new Struct.U32(index), DscpPolicyValue.NONE); + mBpfDscpIpv4Policies.replaceEntry(new Struct.S32(index), DscpPolicyValue.NONE); + mBpfDscpIpv6Policies.replaceEntry(new Struct.S32(index), DscpPolicyValue.NONE); status = DSCP_POLICY_STATUS_DELETED; } catch (ErrnoException e) { Log.e(TAG, "Failed to delete policy from map: ", e);
diff --git a/service/src/com/android/server/connectivity/FullScore.java b/service/src/com/android/server/connectivity/FullScore.java index 2303894..87ae0c9 100644 --- a/service/src/com/android/server/connectivity/FullScore.java +++ b/service/src/com/android/server/connectivity/FullScore.java
@@ -23,7 +23,7 @@ import static android.net.NetworkScore.KEEP_CONNECTED_NONE; import static android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI; -import static com.android.net.module.util.BitUtils.appendStringRepresentationOfBitMaskToStringBuilder; +import static com.android.net.module.util.BitUtils.describeDifferences; import android.annotation.NonNull; import android.annotation.Nullable; @@ -338,31 +338,14 @@ /** * Returns a short but human-readable string of updates from an older score. - * @param old the old capabilities to diff from + * @param old the old score to diff from * @return a string fit for logging differences, or null if no differences. - * this method cannot return the empty string. + * this method cannot return the empty string. See BitUtils#describeDifferences. */ @Nullable public String describeDifferencesFrom(@Nullable final FullScore old) { final long oldPolicies = null == old ? 0 : old.mPolicies; - final long changed = oldPolicies ^ mPolicies; - if (0 == changed) return null; - // If the control reaches here, there are changes (additions, removals, or both) so - // the code below is guaranteed to add something to the string and can't return "". - final long removed = oldPolicies & changed; - final long added = mPolicies & changed; - final StringBuilder sb = new StringBuilder(); - if (0 != removed) { - sb.append("-"); - appendStringRepresentationOfBitMaskToStringBuilder(sb, removed, - FullScore::policyNameOf, "-"); - } - if (0 != added) { - sb.append("+"); - appendStringRepresentationOfBitMaskToStringBuilder(sb, added, - FullScore::policyNameOf, "+"); - } - return sb.toString(); + return describeDifferences(oldPolicies, mPolicies, FullScore::policyNameOf); } // Example output :
diff --git a/Cronet/AndroidManifest.xml b/service/src/com/android/server/connectivity/InvalidTagException.java similarity index 62% copy from Cronet/AndroidManifest.xml copy to service/src/com/android/server/connectivity/InvalidTagException.java index f3b3c3e..b924d27 100644 --- a/Cronet/AndroidManifest.xml +++ b/service/src/com/android/server/connectivity/InvalidTagException.java
@@ -1,7 +1,5 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +13,16 @@ * 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> + +package com.android.server.connectivity; + + +/** + * An exception thrown when a Tag is not valid in self_certified_network_capabilities.xml. + */ +public class InvalidTagException extends Exception { + + public InvalidTagException(String message) { + super(message); + } +}
diff --git a/service/src/com/android/server/connectivity/KeepaliveResourceUtil.java b/service/src/com/android/server/connectivity/KeepaliveResourceUtil.java new file mode 100644 index 0000000..92b080d --- /dev/null +++ b/service/src/com/android/server/connectivity/KeepaliveResourceUtil.java
@@ -0,0 +1,90 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity; + +import android.annotation.NonNull; +import android.content.Context; +import android.content.res.Resources; +import android.net.NetworkCapabilities; +import android.text.TextUtils; +import android.util.AndroidRuntimeException; + +import com.android.connectivity.resources.R; + +/** + * Utilities to fetch keepalive configuration from resources. + */ +public abstract class KeepaliveResourceUtil { + + /** + * Read supported keepalive count for each transport type from overlay resource. + * + * @param context The context to read resource from. + * @return An array of supported keepalive count for each transport type. + */ + @NonNull + public static int[] getSupportedKeepalives(@NonNull Context context) { + String[] res = null; + try { + final ConnectivityResources connRes = new ConnectivityResources(context); + res = connRes.get().getStringArray(R.array.config_networkSupportedKeepaliveCount); + } catch (Resources.NotFoundException unused) { + } + if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource"); + + final int[] ret = new int[NetworkCapabilities.MAX_TRANSPORT + 1]; + for (final String row : res) { + if (TextUtils.isEmpty(row)) { + throw new KeepaliveDeviceConfigurationException("Empty string"); + } + final String[] arr = row.split(","); + if (arr.length != 2) { + throw new KeepaliveDeviceConfigurationException("Invalid parameter length"); + } + + int transport; + int supported; + try { + transport = Integer.parseInt(arr[0]); + supported = Integer.parseInt(arr[1]); + } catch (NumberFormatException e) { + throw new KeepaliveDeviceConfigurationException("Invalid number format"); + } + + if (!NetworkCapabilities.isValidTransport(transport)) { + throw new KeepaliveDeviceConfigurationException("Invalid transport " + transport); + } + + if (supported < 0) { + throw new KeepaliveDeviceConfigurationException( + "Invalid supported count " + supported + " for " + + NetworkCapabilities.transportNameOf(transport)); + } + ret[transport] = supported; + } + return ret; + } + + /** + * An exception thrown when the keepalive resource configuration is invalid. + */ + public static class KeepaliveDeviceConfigurationException extends AndroidRuntimeException { + public KeepaliveDeviceConfigurationException(final String msg) { + super(msg); + } + } +}
diff --git a/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java b/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java new file mode 100644 index 0000000..290d201 --- /dev/null +++ b/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java
@@ -0,0 +1,191 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity; + +import android.os.SystemClock; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.metrics.DailykeepaliveInfoReported; +import com.android.metrics.DurationForNumOfKeepalive; +import com.android.metrics.DurationPerNumOfKeepalive; + +import java.util.ArrayList; +import java.util.List; + +// TODO(b/273451360): Also track KeepaliveLifetimeForCarrier and DailykeepaliveInfoReported +/** + * Tracks carrier and duration metrics of automatic on/off keepalives. + * + * <p>This class follows AutomaticOnOffKeepaliveTracker closely and its on*Keepalive methods needs + * to be called in a timely manner to keep the metrics accurate. It is also not thread-safe and all + * public methods must be called by the same thread, namely the ConnectivityService handler thread. + */ +public class KeepaliveStatsTracker { + private static final String TAG = KeepaliveStatsTracker.class.getSimpleName(); + + private final Dependencies mDependencies; + // List of duration stats metric where the index is the number of concurrent keepalives. + // Each DurationForNumOfKeepalive message stores a registered duration and an active duration. + // Registered duration is the total time spent with mNumRegisteredKeepalive == index. + // Active duration is the total time spent with mNumActiveKeepalive == index. + private final List<DurationForNumOfKeepalive.Builder> mDurationPerNumOfKeepalive = + new ArrayList<>(); + + private int mNumRegisteredKeepalive = 0; + private int mNumActiveKeepalive = 0; + + // A timestamp of the most recent time the duration metrics was updated. + private long mTimestampSinceLastUpdateDurations; + + /** Dependency class */ + @VisibleForTesting + public static class Dependencies { + // Returns a timestamp with the time base of SystemClock.uptimeMillis to keep durations + // relative to start time and avoid timezone change. + public long getUptimeMillis() { + return SystemClock.uptimeMillis(); + } + } + + public KeepaliveStatsTracker() { + this(new Dependencies()); + } + + @VisibleForTesting + public KeepaliveStatsTracker(Dependencies dependencies) { + mDependencies = dependencies; + mTimestampSinceLastUpdateDurations = mDependencies.getUptimeMillis(); + } + + /** Ensures the list of duration metrics is large enough for number of registered keepalives. */ + private void ensureDurationPerNumOfKeepaliveSize() { + if (mNumActiveKeepalive < 0 || mNumRegisteredKeepalive < 0) { + throw new IllegalStateException( + "Number of active or registered keepalives is negative"); + } + if (mNumActiveKeepalive > mNumRegisteredKeepalive) { + throw new IllegalStateException( + "Number of active keepalives greater than registered keepalives"); + } + + while (mDurationPerNumOfKeepalive.size() <= mNumRegisteredKeepalive) { + final DurationForNumOfKeepalive.Builder durationForNumOfKeepalive = + DurationForNumOfKeepalive.newBuilder(); + durationForNumOfKeepalive.setNumOfKeepalive(mDurationPerNumOfKeepalive.size()); + durationForNumOfKeepalive.setKeepaliveRegisteredDurationsMsec(0); + durationForNumOfKeepalive.setKeepaliveActiveDurationsMsec(0); + + mDurationPerNumOfKeepalive.add(durationForNumOfKeepalive); + } + } + + /** + * Updates the durations metrics to the given time. This should always be called before making a + * change to mNumRegisteredKeepalive or mNumActiveKeepalive to keep the duration metrics + * correct. + * + * @param timeNow a timestamp obtained using Dependencies.getUptimeMillis + */ + private void updateDurationsPerNumOfKeepalive(long timeNow) { + if (mDurationPerNumOfKeepalive.size() < mNumRegisteredKeepalive) { + Log.e(TAG, "Unexpected jump in number of registered keepalive"); + } + ensureDurationPerNumOfKeepaliveSize(); + + final int durationIncrease = (int) (timeNow - mTimestampSinceLastUpdateDurations); + final DurationForNumOfKeepalive.Builder durationForNumOfRegisteredKeepalive = + mDurationPerNumOfKeepalive.get(mNumRegisteredKeepalive); + + durationForNumOfRegisteredKeepalive.setKeepaliveRegisteredDurationsMsec( + durationForNumOfRegisteredKeepalive.getKeepaliveRegisteredDurationsMsec() + + durationIncrease); + + final DurationForNumOfKeepalive.Builder durationForNumOfActiveKeepalive = + mDurationPerNumOfKeepalive.get(mNumActiveKeepalive); + + durationForNumOfActiveKeepalive.setKeepaliveActiveDurationsMsec( + durationForNumOfActiveKeepalive.getKeepaliveActiveDurationsMsec() + + durationIncrease); + + mTimestampSinceLastUpdateDurations = timeNow; + } + + /** Inform the KeepaliveStatsTracker a keepalive has just started and is active. */ + public void onStartKeepalive() { + final long timeNow = mDependencies.getUptimeMillis(); + updateDurationsPerNumOfKeepalive(timeNow); + + mNumRegisteredKeepalive++; + mNumActiveKeepalive++; + } + + /** Inform the KeepaliveStatsTracker a keepalive has just been paused. */ + public void onPauseKeepalive() { + final long timeNow = mDependencies.getUptimeMillis(); + updateDurationsPerNumOfKeepalive(timeNow); + + mNumActiveKeepalive--; + } + + /** Inform the KeepaliveStatsTracker a keepalive has just been resumed. */ + public void onResumeKeepalive() { + final long timeNow = mDependencies.getUptimeMillis(); + updateDurationsPerNumOfKeepalive(timeNow); + + mNumActiveKeepalive++; + } + + /** Inform the KeepaliveStatsTracker a keepalive has just been stopped. */ + public void onStopKeepalive(boolean wasActive) { + final long timeNow = mDependencies.getUptimeMillis(); + updateDurationsPerNumOfKeepalive(timeNow); + + mNumRegisteredKeepalive--; + if (wasActive) mNumActiveKeepalive--; + } + + /** + * Builds and returns DailykeepaliveInfoReported proto. + */ + public DailykeepaliveInfoReported buildKeepaliveMetrics() { + final long timeNow = mDependencies.getUptimeMillis(); + updateDurationsPerNumOfKeepalive(timeNow); + + final DurationPerNumOfKeepalive.Builder durationPerNumOfKeepalive = + DurationPerNumOfKeepalive.newBuilder(); + + mDurationPerNumOfKeepalive.forEach( + durationForNumOfKeepalive -> + durationPerNumOfKeepalive.addDurationForNumOfKeepalive( + durationForNumOfKeepalive)); + + final DailykeepaliveInfoReported.Builder dailyKeepaliveInfoReported = + DailykeepaliveInfoReported.newBuilder(); + + // TODO(b/273451360): fill all the other values and write to ConnectivityStatsLog. + dailyKeepaliveInfoReported.setDurationPerNumOfKeepalive(durationPerNumOfKeepalive); + + return dailyKeepaliveInfoReported.build(); + } + + /** Resets the stored metrics but maintains the state of keepalives */ + public void resetMetrics() { + mDurationPerNumOfKeepalive.clear(); + ensureDurationPerNumOfKeepaliveSize(); + } +}
diff --git a/service/src/com/android/server/connectivity/KeepaliveTracker.java b/service/src/com/android/server/connectivity/KeepaliveTracker.java index 3b58823..cc226ce 100644 --- a/service/src/com/android/server/connectivity/KeepaliveTracker.java +++ b/service/src/com/android/server/connectivity/KeepaliveTracker.java
@@ -18,7 +18,6 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NattSocketKeepalive.NATT_PORT; -import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE; import static android.net.SocketKeepalive.BINDER_DIED; import static android.net.SocketKeepalive.DATA_RECEIVED; import static android.net.SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES; @@ -33,11 +32,11 @@ import static android.net.SocketKeepalive.MIN_INTERVAL_SEC; import static android.net.SocketKeepalive.NO_KEEPALIVE; import static android.net.SocketKeepalive.SUCCESS; +import static android.net.SocketKeepalive.SUCCESS_PAUSED; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.net.ConnectivityResources; import android.net.ISocketKeepaliveCallback; import android.net.InetAddresses; import android.net.InvalidPacketException; @@ -50,7 +49,6 @@ import android.os.Binder; import android.os.Handler; import android.os.IBinder; -import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.system.ErrnoException; @@ -59,6 +57,7 @@ import android.util.Pair; import com.android.connectivity.resources.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.net.module.util.HexDump; import com.android.net.module.util.IpUtils; @@ -88,7 +87,6 @@ /** Keeps track of keepalive requests. */ private final HashMap <NetworkAgentInfo, HashMap<Integer, KeepaliveInfo>> mKeepalives = new HashMap<> (); - private final Handler mConnectivityServiceHandler; @NonNull private final TcpKeepaliveController mTcpController; @NonNull @@ -109,10 +107,10 @@ private final int mAllowedUnprivilegedSlotsForUid; public KeepaliveTracker(Context context, Handler handler) { - mConnectivityServiceHandler = handler; mTcpController = new TcpKeepaliveController(handler); mContext = context; - mSupportedKeepalives = KeepaliveUtils.getSupportedKeepalives(mContext); + + mSupportedKeepalives = KeepaliveResourceUtil.getSupportedKeepalives(context); final ConnectivityResources res = new ConnectivityResources(mContext); mReservedPrivilegedSlots = res.get().getInteger( @@ -127,15 +125,20 @@ * All information about this keepalive is known at construction time except the slot number, * which is only returned when the hardware has successfully started the keepalive. */ - class KeepaliveInfo implements IBinder.DeathRecipient { + @VisibleForTesting + public class KeepaliveInfo implements IBinder.DeathRecipient { + // TODO : remove this member. Only AutoOnOffKeepalive should have a reference to this. + public final ISocketKeepaliveCallback mCallback; // Bookkeeping data. - private final ISocketKeepaliveCallback mCallback; private final int mUid; private final int mPid; private final boolean mPrivileged; - private final NetworkAgentInfo mNai; + public final NetworkAgentInfo mNai; private final int mType; - private final FileDescriptor mFd; + public final FileDescriptor mFd; + // True if this was resumed from a previously turned off keepalive, otherwise false. + // This is necessary to send the correct callbacks. + public final boolean mResumed; public static final int TYPE_NATT = 1; public static final int TYPE_TCP = 2; @@ -162,6 +165,16 @@ int interval, int type, @Nullable FileDescriptor fd) throws InvalidSocketException { + this(callback, nai, packet, interval, type, fd, false /* resumed */); + } + + KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback, + @NonNull NetworkAgentInfo nai, + @NonNull KeepalivePacketData packet, + int interval, + int type, + @Nullable FileDescriptor fd, + boolean resumed) throws InvalidSocketException { mCallback = callback; mPid = Binder.getCallingPid(); mUid = Binder.getCallingUid(); @@ -171,6 +184,7 @@ mPacket = packet; mInterval = interval; mType = type; + mResumed = resumed; // For SocketKeepalive, a dup of fd is kept in mFd so the source port from which the // keepalives are sent cannot be reused by another app even if the fd gets closed by @@ -234,6 +248,8 @@ /** Called when the application process is killed. */ public void binderDied() { + // TODO b/267106526 : this is not called on the handler thread but stop() happily + // assumes it is, which means this is a pretty dangerous race condition. stop(BINDER_DIED); } @@ -243,6 +259,14 @@ } } + public int getSlot() { + return mSlot; + } + + int getKeepaliveIntervalSec() { + return mInterval; + } + private int checkNetworkConnected() { if (!mNai.networkInfo.isConnectedOrConnecting()) { return ERROR_INVALID_NETWORK; @@ -325,6 +349,10 @@ } void start(int slot) { + // BINDER_DIED can happen if the binder died before the KeepaliveInfo was created and + // the constructor set the state to BINDER_DIED. If that's the case, the KI is already + // cleaned up. + if (BINDER_DIED == mStartedState) return; mSlot = slot; int error = isValid(); if (error == SUCCESS) { @@ -369,7 +397,10 @@ // To prevent races from re-entrance of stop(), return if the state is already stopping. // This might happen if multiple event sources stop keepalive in a short time. Such as // network disconnect after user calls stop(), or tear down socket after binder died. - if (mStartedState == STOPPING) return; + // Note that it's always possible this method is called by the auto keepalive timer + // or any other way after the binder died, hence the check for BINDER_DIED. If the + // binder has died, then the KI has already been cleaned up. + if (mStartedState == STOPPING || mStartedState == BINDER_DIED) return; // Store the reason of stopping, and report it after the keepalive is fully stopped. if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) { @@ -380,9 +411,10 @@ + ": " + reason); switch (mStartedState) { case NOT_STARTED: - // Remove the reference of the keepalive that meet error before starting, + // Remove the reference to this keepalive that had an error before starting, // e.g. invalid parameter. cleanupStoppedKeepalive(mNai, mSlot); + if (BINDER_DIED == reason) mStartedState = BINDER_DIED; break; default: mStartedState = STOPPING; @@ -415,6 +447,14 @@ void onFileDescriptorInitiatedStop(final int socketKeepaliveReason) { handleStopKeepalive(mNai, mSlot, socketKeepaliveReason); } + + /** + * Construct a new KeepaliveInfo from existing KeepaliveInfo with a new fd. + */ + public KeepaliveInfo withFd(@NonNull FileDescriptor fd) throws InvalidSocketException { + return new KeepaliveInfo(mCallback, mNai, mPacket, mInterval, mType, fd, + true /* resumed */); + } } void notifyErrorCallback(ISocketKeepaliveCallback cb, int error) { @@ -444,8 +484,10 @@ return slot; } - public void handleStartKeepalive(Message message) { - KeepaliveInfo ki = (KeepaliveInfo) message.obj; + /** + * Handle start keepalives with the message. + */ + public void handleStartKeepalive(KeepaliveInfo ki) { NetworkAgentInfo nai = ki.getNai(); int slot = findFirstFreeSlot(nai); mKeepalives.get(nai).put(slot, ki); @@ -512,6 +554,12 @@ } catch (RemoteException e) { Log.w(TAG, "Discarded onStop callback: " + reason); } + } else if (reason == SUCCESS_PAUSED) { + try { + ki.mCallback.onPaused(); + } catch (RemoteException e) { + Log.w(TAG, "Discarded onPaused callback: " + reason); + } } else if (reason == DATA_RECEIVED) { try { ki.mCallback.onDataReceived(); @@ -521,7 +569,20 @@ } else if (reason == ERROR_STOP_REASON_UNINITIALIZED) { throw new IllegalStateException("Unexpected stop reason: " + reason); } else if (reason == ERROR_NO_SUCH_SLOT) { - throw new IllegalStateException("No such slot: " + reason); + // There are multiple independent reasons a keepalive can stop. Some + // are software (e.g. the app stops the keepalive) and some are hardware + // (e.g. the SIM card gets removed). Therefore, there is a very low + // probability that both of these happen at the same time, which would + // result in the first stop attempt returning SUCCESS and the second + // stop attempt returning NO_SUCH_SLOT. Such a race condition can be + // ignored with a log. + // This should still be reported because if it happens with any frequency + // it probably means there is a bug where the system server is trying + // to use a non-existing hardware slot. + // TODO : separate the non-existing hardware slot from the case where + // there is no keepalive running on this slot. + Log.wtf(TAG, "Keepalive on slot " + slot + " can't be stopped : " + reason); + notifyErrorCallback(ki.mCallback, reason); } else { notifyErrorCallback(ki.mCallback, reason); } @@ -529,6 +590,25 @@ ki.unlinkDeathRecipient(); } + /** + * Finalize a paused keepalive. + * + * This will simply send the onStopped() callback after checking that this keepalive is + * indeed paused. + * + * @param ki the keepalive to finalize + */ + public void finalizePausedKeepalive(@NonNull final KeepaliveInfo ki) { + if (SUCCESS_PAUSED != ki.mStopReason) { + throw new IllegalStateException("Keepalive is not paused"); + } + try { + ki.mCallback.onStopped(); + } catch (RemoteException e) { + Log.w(TAG, "Discarded onStopped callback while finalizing paused keepalive"); + } + } + public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) { HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai); if (networkKeepalives != null) { @@ -578,9 +658,14 @@ Log.d(TAG, "Started keepalive " + slot + " on " + nai.toShortString()); ki.mStartedState = KeepaliveInfo.STARTED; try { - ki.mCallback.onStarted(slot); + if (ki.mResumed) { + ki.mCallback.onResumed(); + } else { + ki.mCallback.onStarted(); + } } catch (RemoteException e) { - Log.w(TAG, "Discarded onStarted(" + slot + ") callback"); + Log.w(TAG, "Discarded " + (ki.mResumed ? "onResumed" : "onStarted") + + " callback for slot " + slot); } } else { Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.toShortString() @@ -604,7 +689,8 @@ * Called when requesting that keepalives be started on a IPsec NAT-T socket. See * {@link android.net.SocketKeepalive}. **/ - public void startNattKeepalive(@Nullable NetworkAgentInfo nai, + @Nullable + public KeepaliveInfo makeNattKeepaliveInfo(@Nullable NetworkAgentInfo nai, @Nullable FileDescriptor fd, int intervalSeconds, @NonNull ISocketKeepaliveCallback cb, @@ -614,7 +700,7 @@ int dstPort) { if (nai == null) { notifyErrorCallback(cb, ERROR_INVALID_NETWORK); - return; + return null; } InetAddress srcAddress, dstAddress; @@ -623,7 +709,7 @@ dstAddress = InetAddresses.parseNumericAddress(dstAddrString); } catch (IllegalArgumentException e) { notifyErrorCallback(cb, ERROR_INVALID_IP_ADDRESS); - return; + return null; } KeepalivePacketData packet; @@ -632,7 +718,7 @@ srcAddress, srcPort, dstAddress, NATT_PORT); } catch (InvalidPacketException e) { notifyErrorCallback(cb, e.getError()); - return; + return null; } KeepaliveInfo ki = null; try { @@ -641,15 +727,14 @@ } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) { Log.e(TAG, "Fail to construct keepalive", e); notifyErrorCallback(cb, ERROR_INVALID_SOCKET); - return; + return null; } - Log.d(TAG, "Created keepalive: " + ki.toString()); - mConnectivityServiceHandler.obtainMessage( - NetworkAgent.CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget(); + Log.d(TAG, "Created keepalive: " + ki); + return ki; } /** - * Called by ConnectivityService to start TCP keepalive on a file descriptor. + * Make a KeepaliveInfo for a TCP socket. * * In order to offload keepalive for application correctly, sequence number, ack number and * other fields are needed to form the keepalive packet. Thus, this function synchronously @@ -658,13 +743,14 @@ * * See {@link android.net.SocketKeepalive}. **/ - public void startTcpKeepalive(@Nullable NetworkAgentInfo nai, + @Nullable + public KeepaliveInfo makeTcpKeepaliveInfo(@Nullable NetworkAgentInfo nai, @NonNull FileDescriptor fd, int intervalSeconds, @NonNull ISocketKeepaliveCallback cb) { if (nai == null) { notifyErrorCallback(cb, ERROR_INVALID_NETWORK); - return; + return null; } final TcpKeepalivePacketData packet; @@ -672,10 +758,10 @@ packet = TcpKeepaliveController.getTcpKeepalivePacket(fd); } catch (InvalidSocketException e) { notifyErrorCallback(cb, e.error); - return; + return null; } catch (InvalidPacketException e) { notifyErrorCallback(cb, e.getError()); - return; + return null; } KeepaliveInfo ki = null; try { @@ -684,20 +770,22 @@ } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) { Log.e(TAG, "Fail to construct keepalive e=" + e); notifyErrorCallback(cb, ERROR_INVALID_SOCKET); - return; + return null; } Log.d(TAG, "Created keepalive: " + ki.toString()); - mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget(); + return ki; } - /** - * Called when requesting that keepalives be started on a IPsec NAT-T socket. This function is - * identical to {@link #startNattKeepalive}, but also takes a {@code resourceId}, which is the - * resource index bound to the {@link UdpEncapsulationSocket} when creating by - * {@link com.android.server.IpSecService} to verify whether the given - * {@link UdpEncapsulationSocket} is legitimate. - **/ - public void startNattKeepalive(@Nullable NetworkAgentInfo nai, + /** + * Make a KeepaliveInfo for an IPSec NAT-T socket. + * + * This function is identical to {@link #makeNattKeepaliveInfo}, but also takes a + * {@code resourceId}, which is the resource index bound to the {@link UdpEncapsulationSocket} + * when creating by {@link com.android.server.IpSecService} to verify whether the given + * {@link UdpEncapsulationSocket} is legitimate. + **/ + @Nullable + public KeepaliveInfo makeNattKeepaliveInfo(@Nullable NetworkAgentInfo nai, @Nullable FileDescriptor fd, int resourceId, int intervalSeconds, @@ -708,6 +796,7 @@ // Ensure that the socket is created by IpSecService. if (!isNattKeepaliveSocketValid(fd, resourceId)) { notifyErrorCallback(cb, ERROR_INVALID_SOCKET); + return null; } // Get src port to adopt old API. @@ -717,10 +806,11 @@ srcPort = ((InetSocketAddress) srcSockAddr).getPort(); } catch (ErrnoException e) { notifyErrorCallback(cb, ERROR_INVALID_SOCKET); + return null; } // Forward request to old API. - startNattKeepalive(nai, fd, intervalSeconds, cb, srcAddrString, srcPort, + return makeNattKeepaliveInfo(nai, fd, intervalSeconds, cb, srcAddrString, srcPort, dstAddrString, dstPort); } @@ -739,6 +829,9 @@ return true; } + /** + * Dump KeepaliveTracker state. + */ public void dump(IndentingPrintWriter pw) { pw.println("Supported Socket keepalives: " + Arrays.toString(mSupportedKeepalives)); pw.println("Reserved Privileged keepalives: " + mReservedPrivilegedSlots);
diff --git a/service/src/com/android/server/connectivity/LingerMonitor.java b/service/src/com/android/server/connectivity/LingerMonitor.java index df34ce7..8503fcc 100644 --- a/service/src/com/android/server/connectivity/LingerMonitor.java +++ b/service/src/com/android/server/connectivity/LingerMonitor.java
@@ -25,7 +25,6 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; -import android.net.ConnectivityResources; import android.net.NetworkCapabilities; import android.os.SystemClock; import android.os.UserHandle;
diff --git a/service/src/com/android/server/connectivity/MultinetworkPolicyTracker.java b/service/src/com/android/server/connectivity/MultinetworkPolicyTracker.java index 58196f7..93018bb 100644 --- a/service/src/com/android/server/connectivity/MultinetworkPolicyTracker.java +++ b/service/src/com/android/server/connectivity/MultinetworkPolicyTracker.java
@@ -28,7 +28,6 @@ import android.content.IntentFilter; import android.content.res.Resources; import android.database.ContentObserver; -import android.net.ConnectivityResources; import android.net.Uri; import android.os.Build; import android.os.Handler;
diff --git a/service/src/com/android/server/connectivity/NetworkDiagnostics.java b/service/src/com/android/server/connectivity/NetworkDiagnostics.java index 509110d..4f80d47 100644 --- a/service/src/com/android/server/connectivity/NetworkDiagnostics.java +++ b/service/src/com/android/server/connectivity/NetworkDiagnostics.java
@@ -18,6 +18,12 @@ import static android.system.OsConstants.*; +import static com.android.net.module.util.NetworkStackConstants.DNS_OVER_TLS_PORT; +import static com.android.net.module.util.NetworkStackConstants.ICMP_HEADER_LEN; +import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN; +import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN; +import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU; + import android.annotation.NonNull; import android.annotation.Nullable; import android.net.InetAddresses; @@ -33,6 +39,7 @@ import android.system.Os; import android.system.StructTimeval; import android.text.TextUtils; +import android.util.Log; import android.util.Pair; import com.android.internal.util.IndentingPrintWriter; @@ -172,7 +179,7 @@ } } - private final Map<InetAddress, Measurement> mIcmpChecks = new HashMap<>(); + private final Map<Pair<InetAddress, Integer>, Measurement> mIcmpChecks = new HashMap<>(); private final Map<Pair<InetAddress, InetAddress>, Measurement> mExplicitSourceIcmpChecks = new HashMap<>(); private final Map<InetAddress, Measurement> mDnsUdpChecks = new HashMap<>(); @@ -205,17 +212,21 @@ mLinkProperties.addDnsServer(TEST_DNS6); } + final int mtu = mLinkProperties.getMtu(); for (RouteInfo route : mLinkProperties.getRoutes()) { if (route.getType() == RouteInfo.RTN_UNICAST && route.hasGateway()) { InetAddress gateway = route.getGateway(); - prepareIcmpMeasurement(gateway); + // Use mtu in the route if exists. Otherwise, use the one in the link property. + final int routeMtu = route.getMtu(); + prepareIcmpMeasurements(gateway, (routeMtu > 0) ? routeMtu : mtu); if (route.isIPv6Default()) { prepareExplicitSourceIcmpMeasurements(gateway); } } } + for (InetAddress nameserver : mLinkProperties.getDnsServers()) { - prepareIcmpMeasurement(nameserver); + prepareIcmpMeasurements(nameserver, mtu); prepareDnsMeasurement(nameserver); // Unlike the DnsResolver which doesn't do certificate validation in opportunistic mode, @@ -261,11 +272,50 @@ localAddr.getHostAddress(), inetSockAddr.getPort()); } - private void prepareIcmpMeasurement(InetAddress target) { - if (!mIcmpChecks.containsKey(target)) { - Measurement measurement = new Measurement(); - measurement.thread = new Thread(new IcmpCheck(target, measurement)); - mIcmpChecks.put(target, measurement); + private static int getHeaderLen(@NonNull InetAddress target) { + // Convert IPv4 mapped v6 address to v4 if any. + try { + final InetAddress addr = InetAddress.getByAddress(target.getAddress()); + // An ICMPv6 header is technically 4 bytes, but the implementation in IcmpCheck#run() + // will always fill in another 4 bytes padding in the v6 diagnostic packets, so the size + // before icmp data is always 8 bytes in the implementation of ICMP diagnostics for both + // v4 and v6 packets. Thus, it's fine to use the v4 header size in the length + // calculation. + if (addr instanceof Inet6Address) { + return IPV6_HEADER_LEN + ICMP_HEADER_LEN; + } + } catch (UnknownHostException e) { + Log.e(TAG, "Create InetAddress fail(" + target + "): " + e); + } + + return IPV4_HEADER_MIN_LEN + ICMP_HEADER_LEN; + } + + private void prepareIcmpMeasurements(@NonNull InetAddress target, int targetNetworkMtu) { + // Test with different size payload ICMP. + // 1. Test with 0 payload. + addPayloadIcmpMeasurement(target, 0); + final int header = getHeaderLen(target); + // 2. Test with full size MTU. + addPayloadIcmpMeasurement(target, targetNetworkMtu - header); + // 3. If v6, make another measurement with the full v6 min MTU, unless that's what + // was done above. + if ((target instanceof Inet6Address) && (targetNetworkMtu != IPV6_MIN_MTU)) { + addPayloadIcmpMeasurement(target, IPV6_MIN_MTU - header); + } + } + + private void addPayloadIcmpMeasurement(@NonNull InetAddress target, int payloadLen) { + // This can happen if the there is no mtu filled(which is 0) in the link property. + // The value becomes negative after minus header length. + if (payloadLen < 0) return; + + final Pair<InetAddress, Integer> lenTarget = + new Pair<>(target, Integer.valueOf(payloadLen)); + if (!mIcmpChecks.containsKey(lenTarget)) { + final Measurement measurement = new Measurement(); + measurement.thread = new Thread(new IcmpCheck(target, payloadLen, measurement)); + mIcmpChecks.put(lenTarget, measurement); } } @@ -276,7 +326,7 @@ Pair<InetAddress, InetAddress> srcTarget = new Pair<>(source, target); if (!mExplicitSourceIcmpChecks.containsKey(srcTarget)) { Measurement measurement = new Measurement(); - measurement.thread = new Thread(new IcmpCheck(source, target, measurement)); + measurement.thread = new Thread(new IcmpCheck(source, target, 0, measurement)); mExplicitSourceIcmpChecks.put(srcTarget, measurement); } } @@ -334,8 +384,8 @@ ArrayList<Measurement> measurements = new ArrayList(totalMeasurementCount()); // Sort measurements IPv4 first. - for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) { - if (entry.getKey() instanceof Inet4Address) { + for (Map.Entry<Pair<InetAddress, Integer>, Measurement> entry : mIcmpChecks.entrySet()) { + if (entry.getKey().first instanceof Inet4Address) { measurements.add(entry.getValue()); } } @@ -357,8 +407,8 @@ } // IPv6 measurements second. - for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) { - if (entry.getKey() instanceof Inet6Address) { + for (Map.Entry<Pair<InetAddress, Integer>, Measurement> entry : mIcmpChecks.entrySet()) { + if (entry.getKey().first instanceof Inet6Address) { measurements.add(entry.getValue()); } } @@ -489,8 +539,11 @@ private static final int PACKET_BUFSIZE = 512; private final int mProtocol; private final int mIcmpType; + private final int mPayloadSize; + // The length parameter is effectively the -s flag to ping/ping6 to specify the number of + // data bytes to be sent. + IcmpCheck(InetAddress source, InetAddress target, int length, Measurement measurement) { - public IcmpCheck(InetAddress source, InetAddress target, Measurement measurement) { super(source, target, measurement); if (mAddressFamily == AF_INET6) { @@ -502,12 +555,13 @@ mIcmpType = NetworkConstants.ICMPV4_ECHO_REQUEST_TYPE; mMeasurement.description = "ICMPv4"; } - - mMeasurement.description += " dst{" + mTarget.getHostAddress() + "}"; + mPayloadSize = length; + mMeasurement.description += " payloadLength{" + mPayloadSize + "}" + + " dst{" + mTarget.getHostAddress() + "}"; } - public IcmpCheck(InetAddress target, Measurement measurement) { - this(null, target, measurement); + IcmpCheck(InetAddress target, int length, Measurement measurement) { + this(null, target, length, measurement); } @Override @@ -523,9 +577,11 @@ mMeasurement.description += " src{" + socketAddressToString(mSocketAddress) + "}"; // Build a trivial ICMP packet. - final byte[] icmpPacket = { - (byte) mIcmpType, 0, 0, 0, 0, 0, 0, 0 // ICMP header - }; + // The v4 ICMP header ICMP_HEADER_LEN (which is 8) and v6 is only 4 bytes (4 bytes + // message body followed by header before the payload). + // Use 8 bytes for both v4 and v6 for simplicity. + final byte[] icmpPacket = new byte[ICMP_HEADER_LEN + mPayloadSize]; + icmpPacket[0] = (byte) mIcmpType; int count = 0; mMeasurement.startTime = now(); @@ -675,7 +731,6 @@ private class DnsTlsCheck extends DnsUdpCheck { private static final int TCP_CONNECT_TIMEOUT_MS = 2500; private static final int TCP_TIMEOUT_MS = 2000; - private static final int DNS_TLS_PORT = 853; private static final int DNS_HEADER_SIZE = 12; private final String mHostname; @@ -714,7 +769,8 @@ final byte[] dnsPacket = getDnsQueryPacket(sixRandomDigits); mMeasurement.startTime = now(); - sslSocket.connect(new InetSocketAddress(mTarget, DNS_TLS_PORT), TCP_CONNECT_TIMEOUT_MS); + sslSocket.connect(new InetSocketAddress(mTarget, DNS_OVER_TLS_PORT), + TCP_CONNECT_TIMEOUT_MS); // Synchronous call waiting for the TLS handshake complete. sslSocket.startHandshake();
diff --git a/service/src/com/android/server/connectivity/NetworkNotificationManager.java b/service/src/com/android/server/connectivity/NetworkNotificationManager.java index 45da0ea..8b0cb7c 100644 --- a/service/src/com/android/server/connectivity/NetworkNotificationManager.java +++ b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
@@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import android.annotation.NonNull; +import android.app.ActivityOptions; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -29,10 +30,11 @@ import android.content.Intent; import android.content.res.Resources; import android.graphics.drawable.Icon; -import android.net.ConnectivityResources; import android.net.NetworkSpecifier; import android.net.TelephonyNetworkSpecifier; import android.net.wifi.WifiInfo; +import android.os.Build; +import android.os.Bundle; import android.os.UserHandle; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -45,6 +47,7 @@ import com.android.connectivity.resources.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; +import com.android.modules.utils.build.SdkLevel; public class NetworkNotificationManager { @@ -328,7 +331,26 @@ } try { - intent.send(); + Bundle options = null; + + if (SdkLevel.isAtLeastU() && intent.isActivity()) { + // Also check SDK_INT >= T separately, as the linter in some T-based branches does + // not recognize "isAtLeastU && something" as an SDK check for T+ APIs. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // Android U requires pending intent background start mode to be specified: + // See #background-activity-restrictions in + // https://developer.android.com/about/versions/14/behavior-changes-14 + // But setPendingIntentBackgroundActivityStartMode is U+, and replaces + // setPendingIntentBackgroundActivityLaunchAllowed which is T+ but deprecated. + // Use setPendingIntentBackgroundActivityLaunchAllowed as the U+ version is not + // yet available in all branches. + final ActivityOptions activityOptions = ActivityOptions.makeBasic(); + activityOptions.setPendingIntentBackgroundActivityLaunchAllowed(true); + options = activityOptions.toBundle(); + } + } + + intent.send(null, 0, null, null, null, null, options); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Error sending dialog PendingIntent", e); }
diff --git a/service/src/com/android/server/connectivity/NetworkPreferenceList.java b/service/src/com/android/server/connectivity/NetworkPreferenceList.java new file mode 100644 index 0000000..fa6d157 --- /dev/null +++ b/service/src/com/android/server/connectivity/NetworkPreferenceList.java
@@ -0,0 +1,100 @@ +/* + * 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; + +import android.annotation.NonNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * A generic data class containing network preferences. + * @param <K> The type of key in T + * @param <T> The type of preference stored in this preference list + */ +public class NetworkPreferenceList<K, T extends NetworkPreferenceList.NetworkPreference<K>> + implements Iterable<T> { + /** + * A network preference + * @param <K> the type of key by which this preference is indexed. A NetworkPreferenceList + * can have multiple preferences associated with this key, but has methods to + * work on the keys. + */ + public interface NetworkPreference<K> { + /** + * Whether this preference codes for cancelling the preference for this key + * + * A preference that codes for cancelling is removed from the list of preferences, since + * it means the behavior should be the same as if there was no preference for this key. + */ + boolean isCancel(); + /** The key */ + K getKey(); + } + + @NonNull private final List<T> mPreferences; + + public NetworkPreferenceList() { + mPreferences = Collections.EMPTY_LIST; + } + + private NetworkPreferenceList(@NonNull final List<T> list) { + mPreferences = Collections.unmodifiableList(list); + } + + /** + * Returns a new object consisting of this object plus the passed preference. + * + * If the passed preference is a cancel preference (see {@link NetworkPreference#isCancel()} + * then it is not added. + */ + public NetworkPreferenceList<K, T> plus(@NonNull final T pref) { + final ArrayList<T> newPrefs = new ArrayList<>(mPreferences); + if (!pref.isCancel()) { + newPrefs.add(pref); + } + return new NetworkPreferenceList<>(newPrefs); + } + + /** + * Remove all preferences corresponding to a key. + */ + public NetworkPreferenceList<K, T> minus(@NonNull final K key) { + final ArrayList<T> newPrefs = new ArrayList<>(); + for (final T existingPref : mPreferences) { + if (!existingPref.getKey().equals(key)) { + newPrefs.add(existingPref); + } + } + return new NetworkPreferenceList<>(newPrefs); + } + + public boolean isEmpty() { + return mPreferences.isEmpty(); + } + + @Override + public Iterator<T> iterator() { + return mPreferences.iterator(); + } + + @Override public String toString() { + return "NetworkPreferenceList : " + mPreferences; + } +}
diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java index ff979d8..c15f042 100755 --- a/service/src/com/android/server/connectivity/PermissionMonitor.java +++ b/service/src/com/android/server/connectivity/PermissionMonitor.java
@@ -1211,18 +1211,6 @@ } } - /** Should only be used by unit tests */ - @VisibleForTesting - public synchronized Set<UidRange> getVpnInterfaceUidRanges(String iface) { - return mVpnInterfaceUidRanges.get(iface); - } - - /** Should only be used by unit tests */ - @VisibleForTesting - synchronized Set<UidRange> getVpnLockdownUidRanges() { - return mVpnLockdownUidRanges.getSet(); - } - private synchronized void onSettingChanged() { // Step1. Update uids allowed to use restricted networks and compute the set of uids to // update.
diff --git a/service/src/com/android/server/connectivity/ProfileNetworkPreferenceInfo.java b/service/src/com/android/server/connectivity/ProfileNetworkPreferenceInfo.java new file mode 100644 index 0000000..7679660 --- /dev/null +++ b/service/src/com/android/server/connectivity/ProfileNetworkPreferenceInfo.java
@@ -0,0 +1,65 @@ +/* + * 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; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.NetworkCapabilities; +import android.os.UserHandle; + +/** + * A single profile preference, as it applies to a given user profile. + */ +public class ProfileNetworkPreferenceInfo + implements NetworkPreferenceList.NetworkPreference<UserHandle> { + @NonNull + public final UserHandle user; + // Capabilities are only null when sending an object to remove the setting for a user + @Nullable + public final NetworkCapabilities capabilities; + public final boolean allowFallback; + public final boolean blockingNonEnterprise; + + public ProfileNetworkPreferenceInfo(@NonNull final UserHandle user, + @Nullable final NetworkCapabilities capabilities, + final boolean allowFallback, final boolean blockingNonEnterprise) { + this.user = user; + this.capabilities = null == capabilities ? null : new NetworkCapabilities(capabilities); + this.allowFallback = allowFallback; + this.blockingNonEnterprise = blockingNonEnterprise; + } + + @Override + public boolean isCancel() { + return null == capabilities; + } + + @Override + @NonNull + public UserHandle getKey() { + return user; + } + + /** toString */ + public String toString() { + return "[ProfileNetworkPreference user=" + user + + " caps=" + capabilities + + " allowFallback=" + allowFallback + + " blockingNonEnterprise=" + blockingNonEnterprise + + "]"; + } +}
diff --git a/service/src/com/android/server/connectivity/ProfileNetworkPreferenceList.java b/service/src/com/android/server/connectivity/ProfileNetworkPreferenceList.java deleted file mode 100644 index 5bafef9..0000000 --- a/service/src/com/android/server/connectivity/ProfileNetworkPreferenceList.java +++ /dev/null
@@ -1,103 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.connectivity; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.NetworkCapabilities; -import android.os.UserHandle; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A data class containing all the per-profile network preferences. - * - * A given profile can only have one preference. - */ -public class ProfileNetworkPreferenceList { - /** - * A single preference, as it applies to a given user profile. - */ - public static class Preference { - @NonNull public final UserHandle user; - // Capabilities are only null when sending an object to remove the setting for a user - @Nullable public final NetworkCapabilities capabilities; - public final boolean allowFallback; - - public Preference(@NonNull final UserHandle user, - @Nullable final NetworkCapabilities capabilities, - final boolean allowFallback) { - this.user = user; - this.capabilities = null == capabilities ? null : new NetworkCapabilities(capabilities); - this.allowFallback = allowFallback; - } - - /** toString */ - public String toString() { - return "[ProfileNetworkPreference user=" + user - + " caps=" + capabilities - + " allowFallback=" + allowFallback - + "]"; - } - } - - @NonNull public final List<Preference> preferences; - - public ProfileNetworkPreferenceList() { - preferences = Collections.EMPTY_LIST; - } - - private ProfileNetworkPreferenceList(@NonNull final List<Preference> list) { - preferences = Collections.unmodifiableList(list); - } - - /** - * Returns a new object consisting of this object plus the passed preference. - * - * It is not expected that unwanted preference already exists for the same user. - * All preferences for the user that were previously configured should be cleared before - * adding a new preference. - * Passing a Preference object containing a null capabilities object is equivalent - * to removing the preference for this user. - */ - public ProfileNetworkPreferenceList plus(@NonNull final Preference pref) { - final ArrayList<Preference> newPrefs = new ArrayList<>(preferences); - if (null != pref.capabilities) { - newPrefs.add(pref); - } - return new ProfileNetworkPreferenceList(newPrefs); - } - - /** - * Remove all preferences corresponding to a user. - */ - public ProfileNetworkPreferenceList withoutUser(UserHandle user) { - final ArrayList<Preference> newPrefs = new ArrayList<>(); - for (final Preference existingPref : preferences) { - if (!existingPref.user.equals(user)) { - newPrefs.add(existingPref); - } - } - return new ProfileNetworkPreferenceList(newPrefs); - } - - public boolean isEmpty() { - return preferences.isEmpty(); - } -}
diff --git a/service/src/com/android/server/connectivity/UidRangeUtils.java b/service/src/com/android/server/connectivity/UidRangeUtils.java index 541340b..f36797d 100644 --- a/service/src/com/android/server/connectivity/UidRangeUtils.java +++ b/service/src/com/android/server/connectivity/UidRangeUtils.java
@@ -184,4 +184,41 @@ uidRangeSet.add(new UidRange(start, stop)); return uidRangeSet; } + + private static int compare(UidRange range1, UidRange range2) { + return range1.start - range2.start; + } + + /** + * Sort the given UidRange array. + * + * @param ranges The array of UidRange which is going to be sorted. + * @return Array of UidRange. + */ + public static UidRange[] sortRangesByStartUid(UidRange[] ranges) { + final ArrayList uidRanges = new ArrayList(Arrays.asList(ranges)); + Collections.sort(uidRanges, UidRangeUtils::compare); + return (UidRange[]) uidRanges.toArray(new UidRange[0]); + } + + /** + * Check if the given sorted UidRange array contains overlap or not. + * + * Note that the sorted UidRange array must be sorted by increasing lower bound. If it's not, + * the behavior is undefined. + * + * @param ranges The sorted UidRange array which is going to be checked if there is an overlap + * or not. + * @return A boolean to indicate if the given sorted UidRange array contains overlap or not. + */ + public static boolean sortedRangesContainOverlap(UidRange[] ranges) { + final ArrayList uidRanges = new ArrayList(Arrays.asList(ranges)); + for (int i = 0; i + 1 < uidRanges.size(); i++) { + if (((UidRange) uidRanges.get(i + 1)).start <= ((UidRange) uidRanges.get(i)).stop) { + return true; + } + } + + return false; + } }
diff --git a/service/src/com/android/server/connectivity/VpnNetworkPreferenceInfo.java b/service/src/com/android/server/connectivity/VpnNetworkPreferenceInfo.java new file mode 100644 index 0000000..3e111ab --- /dev/null +++ b/service/src/com/android/server/connectivity/VpnNetworkPreferenceInfo.java
@@ -0,0 +1,63 @@ +/* + * 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; + +import android.annotation.NonNull; +import android.net.UidRange; +import android.util.ArraySet; + +/** + * Record the session and UidRange for a VPN preference. + */ +public class VpnNetworkPreferenceInfo + implements NetworkPreferenceList.NetworkPreference<String> { + + @NonNull + public final String mSession; + + @NonNull + public final ArraySet<UidRange> mUidRanges; + + public VpnNetworkPreferenceInfo(@NonNull String session, + @NonNull ArraySet<UidRange> uidRanges) { + this.mSession = session; + this.mUidRanges = uidRanges; + } + + @Override + public boolean isCancel() { + return mUidRanges.isEmpty(); + } + + @Override + @NonNull + public String getKey() { + return mSession; + } + + @NonNull + public ArraySet<UidRange> getUidRangesNoCopy() { + return mUidRanges; + } + + /** toString */ + public String toString() { + return "[VpnNetworkPreference session = " + mSession + + " uidRanges = " + mUidRanges + + "]"; + } +}
diff --git a/service/src/com/android/server/connectivity/wear/CompanionDeviceManagerProxyService.java b/service/src/com/android/server/connectivity/wear/CompanionDeviceManagerProxyService.java new file mode 100644 index 0000000..d3e3843 --- /dev/null +++ b/service/src/com/android/server/connectivity/wear/CompanionDeviceManagerProxyService.java
@@ -0,0 +1,60 @@ +/* + * 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.wear; + +import android.annotation.SuppressLint; +import android.companion.AssociationInfo; +import android.companion.CompanionDeviceManager; +import android.content.Context; +import android.net.wear.ICompanionDeviceManagerProxy; +import android.os.Binder; +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import com.android.net.module.util.PermissionUtils; + +import java.util.List; + +/** + * A proxy for {@link CompanionDeviceManager}, for use by Tethering with NetworkStack permissions. + */ +public class CompanionDeviceManagerProxyService extends ICompanionDeviceManagerProxy.Stub { + private final Context mContext; + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public CompanionDeviceManagerProxyService(Context context) { + mContext = context; + } + + // TODO(b/193460475): Android Lint handles change from SystemApi to public incorrectly. + // CompanionDeviceManager#getAllAssociations() is made public in U, + // but existed in T as an identical SystemApi. + @SuppressLint("NewApi") + @Override + public List<AssociationInfo> getAllAssociations() { + PermissionUtils.enforceNetworkStackPermission(mContext); + final long token = Binder.clearCallingIdentity(); + try { + final CompanionDeviceManager cdm = mContext.getSystemService( + CompanionDeviceManager.class); + return cdm.getAllAssociations(); + } finally { + Binder.restoreCallingIdentity(token); + } + } +}
diff --git a/tests/common/Android.bp b/tests/common/Android.bp index 5c9cc63..8e47235 100644 --- a/tests/common/Android.bp +++ b/tests/common/Android.bp
@@ -65,7 +65,7 @@ defaults: ["jarjar-rules-combine-defaults"], srcs: [ "tethering-jni-jarjar-rules.txt", - ":connectivity-jarjar-rules", + ":frameworks-net-tests-jarjar-rules", ":TetheringTestsJarJarRules", ":NetworkStackJarJarRules", ],
diff --git a/tests/common/AndroidTest_Coverage.xml b/tests/common/AndroidTest_Coverage.xml index 48d26b8..c94ec27 100644 --- a/tests/common/AndroidTest_Coverage.xml +++ b/tests/common/AndroidTest_Coverage.xml
@@ -13,7 +13,7 @@ limitations under the License. --> <configuration description="Runs coverage tests for Connectivity"> - <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="test-file-name" value="ConnectivityCoverageTests.apk" /> <option name="install-arg" value="-t" /> </target_preparer>
diff --git a/tests/common/java/android/net/LinkPropertiesTest.java b/tests/common/java/android/net/LinkPropertiesTest.java index 5ee375f..09f5d6e 100644 --- a/tests/common/java/android/net/LinkPropertiesTest.java +++ b/tests/common/java/android/net/LinkPropertiesTest.java
@@ -32,6 +32,7 @@ import android.compat.testing.PlatformCompatChangeRule; import android.net.LinkProperties.ProvisioningChange; +import android.net.connectivity.ConnectivityCompatChanges; import android.os.Build; import android.system.OsConstants; import android.util.ArraySet; @@ -1261,7 +1262,7 @@ @Test @IgnoreUpTo(Build.VERSION_CODES.R) @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+") - @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES}) + @EnableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES}) public void testHasExcludeRoute() { LinkProperties lp = new LinkProperties(); lp.setInterfaceName("tun0"); @@ -1274,7 +1275,7 @@ @Test @IgnoreUpTo(Build.VERSION_CODES.R) @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+") - @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES}) + @EnableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES}) public void testRouteAddWithSameKey() throws Exception { LinkProperties lp = new LinkProperties(); lp.setInterfaceName("wlan0"); @@ -1348,14 +1349,14 @@ @Test @IgnoreUpTo(Build.VERSION_CODES.R) @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+") - @EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES}) + @EnableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES}) public void testExcludedRoutesEnabledByCompatChange() { assertExcludeRoutesVisible(); } @Test @IgnoreUpTo(Build.VERSION_CODES.R) @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+") - @DisableCompatChanges({LinkProperties.EXCLUDED_ROUTES}) + @DisableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES}) public void testExcludedRoutesDisabledByCompatChange() { checkExcludeRoutesNotVisibleAfterS(); }
diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java index 7b374d2..aae3425 100644 --- a/tests/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -21,6 +21,7 @@ import static android.net.NetworkCapabilities.MIN_TRANSPORT; import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND; @@ -36,6 +37,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH; import static android.net.NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY; +import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; @@ -113,6 +115,9 @@ private static final int TEST_SUBID2 = 2; private static final int TEST_SUBID3 = 3; + private static final Set<Integer> TEST_NETWORKS_EXTRA_ALLOWED_CAPS_ON_NON_CELL = + Set.of(NET_CAPABILITY_CBS, NET_CAPABILITY_DUN, NET_CAPABILITY_RCS); + @Rule public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule(); @@ -1321,16 +1326,31 @@ } @Test - public void testRestrictCapabilitiesForTestNetworkByNotOwnerWithRestrictedNc() { - testRestrictCapabilitiesForTestNetworkWithRestrictedNc(false /* isOwner */); + public void testRestrictCapabilitiesForTestNetworkRestrictedNc_NotOwner_NotCell() { + testRestrictCapabilitiesForTestNetworkWithRestrictedNc( + false /* isOwner */, false /* isCell */); } @Test - public void testRestrictCapabilitiesForTestNetworkByOwnerWithRestrictedNc() { - testRestrictCapabilitiesForTestNetworkWithRestrictedNc(true /* isOwner */); + public void testRestrictCapabilitiesForTestNetworkRestrictedNc_Owner_NotCell() { + testRestrictCapabilitiesForTestNetworkWithRestrictedNc( + true /* isOwner */, false /* isCell */); } - private void testRestrictCapabilitiesForTestNetworkWithRestrictedNc(boolean isOwner) { + @Test + public void testRestrictCapabilitiesForTestNetworkRestrictedNc_NotOwner_Cell() { + testRestrictCapabilitiesForTestNetworkWithRestrictedNc( + false /* isOwner */, true /* isCell */); + } + + @Test + public void testRestrictCapabilitiesForTestNetworkRestrictedNc_Owner_Cell() { + testRestrictCapabilitiesForTestNetworkWithRestrictedNc( + true /* isOwner */, false /* isCell */); + } + + private void testRestrictCapabilitiesForTestNetworkWithRestrictedNc( + boolean isOwner, boolean isCell) { final int ownerUid = 1234; final int signalStrength = -80; final int[] administratorUids = {1001, ownerUid}; @@ -1339,29 +1359,50 @@ // the networkCapabilities will contain more than one transport type. However, // networkCapabilities must have a single transport specified to use NetworkSpecifier. Thus, // do not verify this part since it's verified in other tests. - final NetworkCapabilities restrictedNc = new NetworkCapabilities.Builder() + final NetworkCapabilities.Builder restrictedNcBuilder = new NetworkCapabilities.Builder() .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) - .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_MMS) .addCapability(NET_CAPABILITY_NOT_METERED) .setAdministratorUids(administratorUids) .setOwnerUid(ownerUid) .setSignalStrength(signalStrength) .setTransportInfo(transportInfo) - .setSubscriptionIds(Set.of(TEST_SUBID1)).build(); + .setSubscriptionIds(Set.of(TEST_SUBID1)); + for (int cap : TEST_NETWORKS_EXTRA_ALLOWED_CAPS_ON_NON_CELL) { + restrictedNcBuilder.addCapability(cap); + } + + if (isCell) { + restrictedNcBuilder.addTransportType(TRANSPORT_CELLULAR); + } + final NetworkCapabilities restrictedNc = restrictedNcBuilder.build(); + final int creatorUid = isOwner ? ownerUid : INVALID_UID; restrictedNc.restrictCapabilitiesForTestNetwork(creatorUid); final NetworkCapabilities.Builder expectedNcBuilder = new NetworkCapabilities.Builder() .removeCapability(NET_CAPABILITY_NOT_RESTRICTED); - // If the test network is restricted, then the network may declare any transport, and - // appended with TRANSPORT_TEST. - expectedNcBuilder.addTransportType(TRANSPORT_CELLULAR); + + if (isCell) { + // If the test network is restricted, then the network may declare any transport, and + // appended with TRANSPORT_TEST. + expectedNcBuilder.addTransportType(TRANSPORT_CELLULAR); + } else { + // If the test network only has TRANSPORT_TEST, then it can keep the subscription IDs. + expectedNcBuilder.setSubscriptionIds(Set.of(TEST_SUBID1)); + } expectedNcBuilder.addTransportType(TRANSPORT_TEST); + // Only TEST_NETWORKS_ALLOWED_CAPABILITIES will be kept. expectedNcBuilder.addCapability(NET_CAPABILITY_NOT_METERED); expectedNcBuilder.removeCapability(NET_CAPABILITY_TRUSTED); + if (!isCell) { + for (int cap : TEST_NETWORKS_EXTRA_ALLOWED_CAPS_ON_NON_CELL) { + expectedNcBuilder.addCapability(cap); + } + } + expectedNcBuilder.setSignalStrength(signalStrength).setTransportInfo(transportInfo); if (creatorUid == ownerUid) { // Only retain the owner and administrator UIDs if they match the app registering the
diff --git a/tests/common/java/android/net/NetworkProviderTest.kt b/tests/common/java/android/net/NetworkProviderTest.kt index c0e7f61..fcbb0dd 100644 --- a/tests/common/java/android/net/NetworkProviderTest.kt +++ b/tests/common/java/android/net/NetworkProviderTest.kt
@@ -79,6 +79,7 @@ @After fun tearDown() { mHandlerThread.quitSafely() + mHandlerThread.join() instrumentation.getUiAutomation().dropShellPermissionIdentity() }
diff --git a/tests/common/java/android/net/VpnTransportInfoTest.java b/tests/common/java/android/net/VpnTransportInfoTest.java index 161f9ee..2d01df7 100644 --- a/tests/common/java/android/net/VpnTransportInfoTest.java +++ b/tests/common/java/android/net/VpnTransportInfoTest.java
@@ -53,7 +53,7 @@ assertParcelingIsLossless(v); final VpnTransportInfo v2 = - new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345", true); + new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345", true, true); assertParcelingIsLossless(v2); } @@ -66,8 +66,10 @@ final VpnTransportInfo v13 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1); final VpnTransportInfo v14 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session1); final VpnTransportInfo v15 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1); - final VpnTransportInfo v16 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1, true); - final VpnTransportInfo v17 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1, true); + final VpnTransportInfo v16 = new VpnTransportInfo( + VpnManager.TYPE_VPN_OEM, session1, true, true); + final VpnTransportInfo v17 = new VpnTransportInfo( + VpnManager.TYPE_VPN_OEM, session1, true, true); final VpnTransportInfo v21 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session2); final VpnTransportInfo v31 = v11.makeCopy(REDACT_FOR_NETWORK_SETTINGS); @@ -92,19 +94,30 @@ @DevSdkIgnoreRule.IgnoreAfter(Build.VERSION_CODES.TIRAMISU) @Test - public void testGetBypassable_beforeU() { + public void testIsBypassable_beforeU() { final VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345"); - assertThrows(UnsupportedOperationException.class, () -> v.getBypassable()); + assertThrows(UnsupportedOperationException.class, () -> v.isBypassable()); } @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @Test - public void testGetBypassable_afterU() { + public void testIsBypassable_afterU() { final VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345"); - assertFalse(v.getBypassable()); + assertFalse(v.isBypassable()); final VpnTransportInfo v2 = - new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345", true); - assertTrue(v2.getBypassable()); + new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345", true, false); + assertTrue(v2.isBypassable()); + } + + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testShouldLongLivedTcpExcluded() { + final VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345"); + assertFalse(v.areLongLivedTcpConnectionsExpensive()); + + final VpnTransportInfo v2 = new VpnTransportInfo( + VpnManager.TYPE_VPN_PLATFORM, "12345", true, true); + assertTrue(v2.areLongLivedTcpConnectionsExpensive()); } }
diff --git a/tests/common/java/android/net/netstats/NetworkTemplateTest.kt b/tests/common/java/android/net/netstats/NetworkTemplateTest.kt index cdf32a4..fd7bd74 100644 --- a/tests/common/java/android/net/netstats/NetworkTemplateTest.kt +++ b/tests/common/java/android/net/netstats/NetworkTemplateTest.kt
@@ -19,31 +19,28 @@ import android.net.NetworkStats.DEFAULT_NETWORK_ALL import android.net.NetworkStats.METERED_ALL import android.net.NetworkStats.METERED_YES -import android.net.NetworkStats.ROAMING_YES import android.net.NetworkStats.ROAMING_ALL +import android.net.NetworkStats.ROAMING_YES import android.net.NetworkTemplate import android.net.NetworkTemplate.MATCH_BLUETOOTH import android.net.NetworkTemplate.MATCH_CARRIER import android.net.NetworkTemplate.MATCH_ETHERNET import android.net.NetworkTemplate.MATCH_MOBILE -import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD import android.net.NetworkTemplate.MATCH_PROXY import android.net.NetworkTemplate.MATCH_WIFI -import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD import android.net.NetworkTemplate.NETWORK_TYPE_ALL import android.net.NetworkTemplate.OEM_MANAGED_ALL +import android.os.Build import android.telephony.TelephonyManager -import com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL -import com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT import com.android.testutils.ConnectivityModuleTest import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.SC_V2 +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith private const val TEST_IMSI1 = "imsi" private const val TEST_WIFI_KEY1 = "wifiKey1" @@ -66,10 +63,8 @@ } // Verify hidden match rules cannot construct templates. - listOf(MATCH_WIFI_WILDCARD, MATCH_MOBILE_WILDCARD, MATCH_PROXY).forEach { - assertFailsWith<IllegalArgumentException> { - NetworkTemplate.Builder(it).build() - } + assertFailsWith<IllegalArgumentException> { + NetworkTemplate.Builder(MATCH_PROXY).build() } // Verify template which matches metered cellular and carrier networks with @@ -77,10 +72,9 @@ listOf(MATCH_MOBILE, MATCH_CARRIER).forEach { matchRule -> NetworkTemplate.Builder(matchRule).setSubscriberIds(setOf(TEST_IMSI1)) .setMeteredness(METERED_YES).build().let { - val expectedTemplate = NetworkTemplate(matchRule, TEST_IMSI1, - arrayOf(TEST_IMSI1), emptyArray<String>(), METERED_YES, - ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT) + val expectedTemplate = NetworkTemplate(matchRule, arrayOf(TEST_IMSI1), + emptyArray<String>(), METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, + NETWORK_TYPE_ALL, OEM_MANAGED_ALL) assertEquals(expectedTemplate, it) } } @@ -90,10 +84,9 @@ listOf(MATCH_MOBILE, MATCH_CARRIER).forEach { matchRule -> NetworkTemplate.Builder(matchRule).setSubscriberIds(setOf(TEST_IMSI1)) .setRoaming(ROAMING_YES).setMeteredness(METERED_YES).build().let { - val expectedTemplate = NetworkTemplate(matchRule, TEST_IMSI1, - arrayOf(TEST_IMSI1), emptyArray<String>(), METERED_YES, - ROAMING_YES, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT) + val expectedTemplate = NetworkTemplate(matchRule, arrayOf(TEST_IMSI1), + emptyArray<String>(), METERED_YES, ROAMING_YES, DEFAULT_NETWORK_ALL, + NETWORK_TYPE_ALL, OEM_MANAGED_ALL) assertEquals(expectedTemplate, it) } } @@ -103,45 +96,67 @@ NetworkTemplate.Builder(MATCH_CARRIER).build() } + // Verify carrier and mobile template cannot contain one of subscriber Id is null. + assertFailsWith<IllegalArgumentException> { + NetworkTemplate.Builder(MATCH_CARRIER).setSubscriberIds(setOf(null)).build() + } + val firstSdk = Build.VERSION.DEVICE_INITIAL_SDK_INT + if (firstSdk > Build.VERSION_CODES.TIRAMISU) { + assertFailsWith<IllegalArgumentException> { + NetworkTemplate.Builder(MATCH_MOBILE).setSubscriberIds(setOf(null)).build() + } + } else { + NetworkTemplate.Builder(MATCH_MOBILE).setSubscriberIds(setOf(null)).build().let { + val expectedTemplate = NetworkTemplate( + MATCH_MOBILE, + arrayOfNulls<String>(1) /*subscriberIds*/, + emptyArray<String>() /*wifiNetworkKey*/, + METERED_ALL, + ROAMING_ALL, + DEFAULT_NETWORK_ALL, + NETWORK_TYPE_ALL, + OEM_MANAGED_ALL + ) + assertEquals(expectedTemplate, it) + } + } + // Verify template which matches metered cellular networks, // regardless of IMSI. See buildTemplateMobileWildcard. NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES).build().let { - val expectedTemplate = NetworkTemplate(MATCH_MOBILE_WILDCARD, null /*subscriberId*/, - emptyArray<String>() /*subscriberIds*/, emptyArray<String>(), + val expectedTemplate = NetworkTemplate(MATCH_MOBILE, + emptyArray<String>() /*subscriberIds*/, emptyArray<String>() /*wifiNetworkKey*/, METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_ALL) + OEM_MANAGED_ALL) assertEquals(expectedTemplate, it) } // Verify template which matches metered cellular networks and ratType. - // See NetworkTemplate#buildTemplateMobileWithRatType. NetworkTemplate.Builder(MATCH_MOBILE).setSubscriberIds(setOf(TEST_IMSI1)) .setMeteredness(METERED_YES).setRatType(TelephonyManager.NETWORK_TYPE_UMTS) .build().let { - val expectedTemplate = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, - arrayOf(TEST_IMSI1), emptyArray<String>(), METERED_YES, - ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_UMTS, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT) + val expectedTemplate = NetworkTemplate(MATCH_MOBILE, arrayOf(TEST_IMSI1), + emptyArray<String>(), METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, + TelephonyManager.NETWORK_TYPE_UMTS, OEM_MANAGED_ALL) assertEquals(expectedTemplate, it) } // Verify template which matches all wifi networks, // regardless of Wifi Network Key. See buildTemplateWifiWildcard and buildTemplateWifi. NetworkTemplate.Builder(MATCH_WIFI).build().let { - val expectedTemplate = NetworkTemplate(MATCH_WIFI_WILDCARD, null /*subscriberId*/, - emptyArray<String>() /*subscriberIds*/, emptyArray<String>(), - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_ALL) + val expectedTemplate = NetworkTemplate(MATCH_WIFI, + emptyArray<String>() /*subscriberIds*/, emptyArray<String>(), METERED_ALL, + ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL) assertEquals(expectedTemplate, it) } // Verify template which matches wifi networks with the given Wifi Network Key. // See buildTemplateWifi(wifiNetworkKey). NetworkTemplate.Builder(MATCH_WIFI).setWifiNetworkKeys(setOf(TEST_WIFI_KEY1)).build().let { - val expectedTemplate = NetworkTemplate(MATCH_WIFI, null /*subscriberId*/, - emptyArray<String>() /*subscriberIds*/, arrayOf(TEST_WIFI_KEY1), - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_ALL) + val expectedTemplate = + NetworkTemplate(MATCH_WIFI, emptyArray<String>() /*subscriberIds*/, + arrayOf(TEST_WIFI_KEY1), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, + NETWORK_TYPE_ALL, OEM_MANAGED_ALL) assertEquals(expectedTemplate, it) } @@ -149,10 +164,9 @@ // given Wifi Network Key, and IMSI. See buildTemplateWifi(wifiNetworkKey, subscriberId). NetworkTemplate.Builder(MATCH_WIFI).setSubscriberIds(setOf(TEST_IMSI1)) .setWifiNetworkKeys(setOf(TEST_WIFI_KEY1)).build().let { - val expectedTemplate = NetworkTemplate(MATCH_WIFI, TEST_IMSI1, - arrayOf(TEST_IMSI1), arrayOf(TEST_WIFI_KEY1), - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT) + val expectedTemplate = NetworkTemplate(MATCH_WIFI, arrayOf(TEST_IMSI1), + arrayOf(TEST_WIFI_KEY1), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, + NETWORK_TYPE_ALL, OEM_MANAGED_ALL) assertEquals(expectedTemplate, it) } @@ -160,10 +174,10 @@ // See buildTemplateEthernet and buildTemplateBluetooth. listOf(MATCH_ETHERNET, MATCH_BLUETOOTH).forEach { matchRule -> NetworkTemplate.Builder(matchRule).build().let { - val expectedTemplate = NetworkTemplate(matchRule, null /*subscriberId*/, + val expectedTemplate = NetworkTemplate(matchRule, emptyArray<String>() /*subscriberIds*/, emptyArray<String>(), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_ALL) + OEM_MANAGED_ALL) assertEquals(expectedTemplate, it) } } @@ -195,10 +209,10 @@ // Verify template which matches wifi wildcard with the given empty key set. NetworkTemplate.Builder(MATCH_WIFI).setWifiNetworkKeys(setOf<String>()).build().let { - val expectedTemplate = NetworkTemplate(MATCH_WIFI_WILDCARD, null /*subscriberId*/, + val expectedTemplate = NetworkTemplate(MATCH_WIFI, emptyArray<String>() /*subscriberIds*/, emptyArray<String>(), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_ALL) + OEM_MANAGED_ALL) assertEquals(expectedTemplate, it) } }
diff --git a/tests/cts/OWNERS b/tests/cts/OWNERS index 089d06f..8388cb7 100644 --- a/tests/cts/OWNERS +++ b/tests/cts/OWNERS
@@ -2,6 +2,5 @@ set noparent file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking_xts -# Only temporary ownership to improve ethernet code quality (b/236280707) -# TODO: remove by 12/31/2022 -per-file net/src/android/net/cts/EthernetManagerTest.kt = prohr@google.com #{LAST_RESORT_SUGGESTION} +# IPsec +per-file **IpSec* = benedictwong@google.com, nharold@google.com
diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp index 47ea53e..891c2dd 100644 --- a/tests/cts/hostside/Android.bp +++ b/tests/cts/hostside/Android.bp
@@ -12,6 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. +next_app_data = [ ":CtsHostsideNetworkTestsAppNext" ] + +// The above line is put in place to prevent any future automerger merge conflict between aosp, +// downstream branches. The CtsHostsideNetworkTestsAppNext target will not exist in +// some downstream branches, but it should exist in aosp and some downstream branches. + + + + + package { default_applicable_licenses: ["Android-Apache-2.0"], } @@ -37,7 +47,9 @@ data: [ ":CtsHostsideNetworkTestsApp", ":CtsHostsideNetworkTestsApp2", - ":CtsHostsideNetworkTestsAppNext", - ], + ":CtsHostsideNetworkCapTestsAppWithoutProperty", + ":CtsHostsideNetworkCapTestsAppWithProperty", + ":CtsHostsideNetworkCapTestsAppSdk33", + ] + next_app_data, per_testcase_directory: true, }
diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index 7a73313..e83e36a 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml
@@ -16,6 +16,7 @@ <configuration description="Config for CTS net host test cases"> <option name="test-suite-tag" value="cts" /> <option name="config-descriptor:metadata" key="component" value="networking" /> + <option name="config-descriptor:metadata" key="token" value="SIM_CARD" /> <option name="config-descriptor:metadata" key="parameter" value="instant_app" /> <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" /> <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
diff --git a/tests/cts/hostside/TEST_MAPPING b/tests/cts/hostside/TEST_MAPPING index ab6de82..2cfd7af 100644 --- a/tests/cts/hostside/TEST_MAPPING +++ b/tests/cts/hostside/TEST_MAPPING
@@ -8,6 +8,9 @@ }, { "exclude-annotation": "android.platform.test.annotations.FlakyTest" + }, + { + "exclude-annotation": "android.platform.test.annotations.RequiresDevice" } ] }
diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp index 12e7d33..2245382 100644 --- a/tests/cts/hostside/app/Android.bp +++ b/tests/cts/hostside/app/Android.bp
@@ -30,7 +30,6 @@ "cts-net-utils", "ctstestrunner-axt", "modules-utils-build", - "ub-uiautomator", ], libs: [ "android.test.runner",
diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml index 56d3cb5..ca3397b 100644 --- a/tests/cts/hostside/app/AndroidManifest.xml +++ b/tests/cts/hostside/app/AndroidManifest.xml
@@ -34,7 +34,8 @@ <application android:requestLegacyExternalStorage="true"> <uses-library android:name="android.test.runner"/> - <activity android:name=".MyActivity"/> + <activity android:name=".MyActivity" + android:configChanges="density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"/> <service android:name=".MyVpnService" android:permission="android.permission.BIND_VPN_SERVICE" android:exported="true">
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataWarningReceiverTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataWarningReceiverTest.java index b2e81ff..13bbab6 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataWarningReceiverTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataWarningReceiverTest.java
@@ -19,18 +19,18 @@ import static com.android.cts.net.hostside.NetworkPolicyTestUtils.clearSnoozeTimestamps; import android.content.pm.PackageManager; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.Direction; -import android.support.test.uiautomator.UiObject2; -import android.support.test.uiautomator.Until; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionPlan; import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.Direction; import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.Until; import com.android.compatibility.common.util.SystemUtil; -import com.android.compatibility.common.util.UiAutomatorUtils; +import com.android.compatibility.common.util.UiAutomatorUtils2; import org.junit.After; import org.junit.Assume; @@ -84,7 +84,7 @@ final UiDevice uiDevice = UiDevice.getInstance(mInstrumentation); uiDevice.openNotification(); try { - final UiObject2 uiObject = UiAutomatorUtils.waitFindObject( + final UiObject2 uiObject = UiAutomatorUtils2.waitFindObject( By.text("Data warning")); Assume.assumeNotNull(uiObject); uiObject.wait(Until.clickable(true), 10_000L);
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java index 449454e..fe522a0 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java
@@ -32,6 +32,7 @@ import com.android.networkstack.apishim.VpnServiceBuilderShimImpl; import com.android.networkstack.apishim.common.UnsupportedApiLevelException; import com.android.networkstack.apishim.common.VpnServiceBuilderShim; +import com.android.testutils.PacketReflector; import java.io.IOException; import java.net.InetAddress;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java deleted file mode 100644 index 124c2c3..0000000 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java +++ /dev/null
@@ -1,254 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.cts.net.hostside; - -import static android.system.OsConstants.ICMP6_ECHO_REPLY; -import static android.system.OsConstants.ICMP6_ECHO_REQUEST; -import static android.system.OsConstants.ICMP_ECHO; -import static android.system.OsConstants.ICMP_ECHOREPLY; - -import android.system.ErrnoException; -import android.system.Os; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; - -public class PacketReflector extends Thread { - - private static int IPV4_HEADER_LENGTH = 20; - private static int IPV6_HEADER_LENGTH = 40; - - private static int IPV4_ADDR_OFFSET = 12; - private static int IPV6_ADDR_OFFSET = 8; - private static int IPV4_ADDR_LENGTH = 4; - private static int IPV6_ADDR_LENGTH = 16; - - private static int IPV4_PROTO_OFFSET = 9; - private static int IPV6_PROTO_OFFSET = 6; - - private static final byte IPPROTO_ICMP = 1; - private static final byte IPPROTO_TCP = 6; - private static final byte IPPROTO_UDP = 17; - private static final byte IPPROTO_ICMPV6 = 58; - - private static int ICMP_HEADER_LENGTH = 8; - private static int TCP_HEADER_LENGTH = 20; - private static int UDP_HEADER_LENGTH = 8; - - private static final byte ICMP_ECHO = 8; - private static final byte ICMP_ECHOREPLY = 0; - - private static String TAG = "PacketReflector"; - - private FileDescriptor mFd; - private byte[] mBuf; - - public PacketReflector(FileDescriptor fd, int mtu) { - super("PacketReflector"); - mFd = fd; - mBuf = new byte[mtu]; - } - - private static void swapBytes(byte[] buf, int pos1, int pos2, int len) { - for (int i = 0; i < len; i++) { - byte b = buf[pos1 + i]; - buf[pos1 + i] = buf[pos2 + i]; - buf[pos2 + i] = b; - } - } - - private static void swapAddresses(byte[] buf, int version) { - int addrPos, addrLen; - switch(version) { - case 4: - addrPos = IPV4_ADDR_OFFSET; - addrLen = IPV4_ADDR_LENGTH; - break; - case 6: - addrPos = IPV6_ADDR_OFFSET; - addrLen = IPV6_ADDR_LENGTH; - break; - default: - throw new IllegalArgumentException(); - } - swapBytes(buf, addrPos, addrPos + addrLen, addrLen); - } - - // Reflect TCP packets: swap the source and destination addresses, but don't change the ports. - // This is used by the test to "connect to itself" through the VPN. - private void processTcpPacket(byte[] buf, int version, int len, int hdrLen) { - if (len < hdrLen + TCP_HEADER_LENGTH) { - return; - } - - // Swap src and dst IP addresses. - swapAddresses(buf, version); - - // Send the packet back. - writePacket(buf, len); - } - - // Echo UDP packets: swap source and destination addresses, and source and destination ports. - // This is used by the test to check that the bytes it sends are echoed back. - private void processUdpPacket(byte[] buf, int version, int len, int hdrLen) { - if (len < hdrLen + UDP_HEADER_LENGTH) { - return; - } - - // Swap src and dst IP addresses. - swapAddresses(buf, version); - - // Swap dst and src ports. - int portOffset = hdrLen; - swapBytes(buf, portOffset, portOffset + 2, 2); - - // Send the packet back. - writePacket(buf, len); - } - - private void processIcmpPacket(byte[] buf, int version, int len, int hdrLen) { - if (len < hdrLen + ICMP_HEADER_LENGTH) { - return; - } - - byte type = buf[hdrLen]; - if (!(version == 4 && type == ICMP_ECHO) && - !(version == 6 && type == (byte) ICMP6_ECHO_REQUEST)) { - return; - } - - // Save the ping packet we received. - byte[] request = buf.clone(); - - // Swap src and dst IP addresses, and send the packet back. - // This effectively pings the device to see if it replies. - swapAddresses(buf, version); - writePacket(buf, len); - - // The device should have replied, and buf should now contain a ping response. - int received = readPacket(buf); - if (received != len) { - Log.i(TAG, "Reflecting ping did not result in ping response: " + - "read=" + received + " expected=" + len); - return; - } - - byte replyType = buf[hdrLen]; - if ((type == ICMP_ECHO && replyType != ICMP_ECHOREPLY) - || (type == (byte) ICMP6_ECHO_REQUEST && replyType != (byte) ICMP6_ECHO_REPLY)) { - Log.i(TAG, "Received unexpected ICMP reply: original " + type - + ", reply " + replyType); - return; - } - - // Compare the response we got with the original packet. - // The only thing that should have changed are addresses, type and checksum. - // Overwrite them with the received bytes and see if the packet is otherwise identical. - request[hdrLen] = buf[hdrLen]; // Type - request[hdrLen + 2] = buf[hdrLen + 2]; // Checksum byte 1. - request[hdrLen + 3] = buf[hdrLen + 3]; // Checksum byte 2. - - // Since Linux kernel 4.2, net.ipv6.auto_flowlabels is set by default, and therefore - // the request and reply may have different IPv6 flow label: ignore that as well. - if (version == 6) { - request[1] = (byte)(request[1] & 0xf0 | buf[1] & 0x0f); - request[2] = buf[2]; - request[3] = buf[3]; - } - - for (int i = 0; i < len; i++) { - if (buf[i] != request[i]) { - Log.i(TAG, "Received non-matching packet when expecting ping response."); - return; - } - } - - // Now swap the addresses again and reflect the packet. This sends a ping reply. - swapAddresses(buf, version); - writePacket(buf, len); - } - - private void writePacket(byte[] buf, int len) { - try { - Os.write(mFd, buf, 0, len); - } catch (ErrnoException|IOException e) { - Log.e(TAG, "Error writing packet: " + e.getMessage()); - } - } - - private int readPacket(byte[] buf) { - int len; - try { - len = Os.read(mFd, buf, 0, buf.length); - } catch (ErrnoException|IOException e) { - Log.e(TAG, "Error reading packet: " + e.getMessage()); - len = -1; - } - return len; - } - - // Reads one packet from our mFd, and possibly writes the packet back. - private void processPacket() { - int len = readPacket(mBuf); - if (len < 1) { - return; - } - - int version = mBuf[0] >> 4; - int addrPos, protoPos, hdrLen, addrLen; - if (version == 4) { - hdrLen = IPV4_HEADER_LENGTH; - protoPos = IPV4_PROTO_OFFSET; - addrPos = IPV4_ADDR_OFFSET; - addrLen = IPV4_ADDR_LENGTH; - } else if (version == 6) { - hdrLen = IPV6_HEADER_LENGTH; - protoPos = IPV6_PROTO_OFFSET; - addrPos = IPV6_ADDR_OFFSET; - addrLen = IPV6_ADDR_LENGTH; - } else { - return; - } - - if (len < hdrLen) { - return; - } - - byte proto = mBuf[protoPos]; - switch (proto) { - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - processIcmpPacket(mBuf, version, len, hdrLen); - break; - case IPPROTO_TCP: - processTcpPacket(mBuf, version, len, hdrLen); - break; - case IPPROTO_UDP: - processUdpPacket(mBuf, version, len, hdrLen); - break; - } - } - - public void run() { - Log.i(TAG, "PacketReflector starting fd=" + mFd + " valid=" + mFd.valid()); - while (!interrupted() && mFd.valid()) { - processPacket(); - } - Log.i(TAG, "PacketReflector exiting fd=" + mFd + " valid=" + mFd.valid()); - } -}
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 8c18a89..73a6502 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -18,6 +18,8 @@ import static android.Manifest.permission.MANAGE_TEST_NETWORKS; import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.Manifest.permission.READ_DEVICE_CONFIG; +import static android.Manifest.permission.WRITE_DEVICE_CONFIG; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.content.pm.PackageManager.FEATURE_WIFI; import static android.net.ConnectivityManager.TYPE_VPN; @@ -36,11 +38,18 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; +import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_DATA_RECEIVED; +import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_ERROR; +import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_PAUSED; +import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_RESUMED; +import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_STARTED; +import static com.android.cts.net.hostside.VpnTest.TestSocketKeepaliveCallback.CallbackType.ON_STOPPED; import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN; import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE; import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_EXPORTED; import static com.android.testutils.Cleanup.testAndCleanup; import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2; +import static com.android.testutils.RecorderCallback.CallbackEntry.BLOCKED_STATUS_INT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -63,6 +72,7 @@ import android.database.Cursor; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.IpSecManager; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; @@ -70,6 +80,7 @@ import android.net.NetworkRequest; import android.net.Proxy; import android.net.ProxyInfo; +import android.net.SocketKeepalive; import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.TransportInfo; @@ -78,6 +89,7 @@ import android.net.VpnService; import android.net.VpnTransportInfo; import android.net.cts.util.CtsNetUtils; +import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; import android.os.Build; import android.os.Handler; @@ -86,28 +98,32 @@ import android.os.Process; import android.os.SystemProperties; import android.os.UserHandle; +import android.provider.DeviceConfig; import android.provider.Settings; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiSelector; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.system.StructPollfd; -import android.telephony.TelephonyManager; import android.test.MoreAsserts; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Log; import android.util.Range; import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiSelector; import com.android.compatibility.common.util.BlockingBroadcastReceiver; import com.android.modules.utils.build.SdkLevel; +import com.android.net.module.util.ArrayTrackRecord; +import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.PacketBuilder; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.RecorderCallback; +import com.android.testutils.RecorderCallback.CallbackEntry; import com.android.testutils.TestableNetworkCallback; import org.junit.After; @@ -136,8 +152,9 @@ import java.util.List; import java.util.Objects; import java.util.Random; +import java.util.UUID; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; /** @@ -187,6 +204,12 @@ public static int SOCKET_TIMEOUT_MS = 100; public static String TEST_HOST = "connectivitycheck.gstatic.com"; + private static final String AUTOMATIC_ON_OFF_KEEPALIVE_VERSION = + "automatic_on_off_keepalive_version"; + // Enabled since version 1 means it's always enabled because the version is always above 1 + private static final String AUTOMATIC_ON_OFF_KEEPALIVE_ENABLED = "1"; + private static final long TEST_TCP_POLLING_TIMER_EXPIRED_PERIOD_MS = 60_000L; + private UiDevice mDevice; private MyActivity mActivity; private String mPackageName; @@ -195,16 +218,18 @@ private RemoteSocketFactoryClient mRemoteSocketFactoryClient; private CtsNetUtils mCtsNetUtils; private PackageManager mPackageManager; - private TelephonyManager mTelephonyManager; - + private Context mTestContext; + private Context mTargetContext; Network mNetwork; - NetworkCallback mCallback; final Object mLock = new Object(); final Object mLockShutdown = new Object(); private String mOldPrivateDnsMode; private String mOldPrivateDnsSpecifier; + // The registered callbacks. + private List<NetworkCallback> mRegisteredCallbacks = new ArrayList<>(); + @Rule public final DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule(); @@ -225,37 +250,59 @@ @Before public void setUp() throws Exception { mNetwork = null; - mCallback = null; + mTestContext = getInstrumentation().getContext(); + mTargetContext = getInstrumentation().getTargetContext(); storePrivateDnsSetting(); - mDevice = UiDevice.getInstance(getInstrumentation()); - mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(), - MyActivity.class); + mActivity = launchActivity(mTargetContext.getPackageName(), MyActivity.class); mPackageName = mActivity.getPackageName(); mCM = (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mActivity.getSystemService(Context.WIFI_SERVICE); mRemoteSocketFactoryClient = new RemoteSocketFactoryClient(mActivity); mRemoteSocketFactoryClient.bind(); mDevice.waitForIdle(); - mCtsNetUtils = new CtsNetUtils(getInstrumentation().getContext()); - mPackageManager = getInstrumentation().getContext().getPackageManager(); - mTelephonyManager = - getInstrumentation().getContext().getSystemService(TelephonyManager.class); + mCtsNetUtils = new CtsNetUtils(mTestContext); + mPackageManager = mTestContext.getPackageManager(); } @After public void tearDown() throws Exception { restorePrivateDnsSetting(); mRemoteSocketFactoryClient.unbind(); - if (mCallback != null) { - mCM.unregisterNetworkCallback(mCallback); - } mCtsNetUtils.tearDown(); Log.i(TAG, "Stopping VPN"); stopVpn(); + unregisterRegisteredCallbacks(); mActivity.finish(); } + private void registerNetworkCallback(NetworkRequest request, NetworkCallback callback) { + mCM.registerNetworkCallback(request, callback); + mRegisteredCallbacks.add(callback); + } + + private void registerDefaultNetworkCallback(NetworkCallback callback) { + mCM.registerDefaultNetworkCallback(callback); + mRegisteredCallbacks.add(callback); + } + + private void registerSystemDefaultNetworkCallback(NetworkCallback callback, Handler h) { + mCM.registerSystemDefaultNetworkCallback(callback, h); + mRegisteredCallbacks.add(callback); + } + + private void registerDefaultNetworkCallbackForUid(int uid, NetworkCallback callback, + Handler h) { + mCM.registerDefaultNetworkCallbackForUid(uid, callback, h); + mRegisteredCallbacks.add(callback); + } + + private void unregisterRegisteredCallbacks() { + for (NetworkCallback callback: mRegisteredCallbacks) { + mCM.unregisterNetworkCallback(callback); + } + } + private void prepareVpn() throws Exception { final int REQUEST_ID = 42; @@ -371,7 +418,7 @@ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(); - mCallback = new NetworkCallback() { + final NetworkCallback callback = new NetworkCallback() { public void onAvailable(Network network) { synchronized (mLock) { Log.i(TAG, "Got available callback for network=" + network); @@ -380,7 +427,7 @@ } } }; - mCM.registerNetworkCallback(request, mCallback); // Unregistered in tearDown. + registerNetworkCallback(request, callback); // Start the service and wait up for TIMEOUT_MS ms for the VPN to come up. establishVpn(addresses, routes, excludedRoutes, allowedApplications, disallowedApplications, @@ -405,7 +452,7 @@ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(); - mCallback = new NetworkCallback() { + final NetworkCallback callback = new NetworkCallback() { public void onLost(Network network) { synchronized (mLockShutdown) { Log.i(TAG, "Got lost callback for network=" + network @@ -416,7 +463,7 @@ } } }; - mCM.registerNetworkCallback(request, mCallback); // Unregistered in tearDown. + registerNetworkCallback(request, callback); // Simply calling mActivity.stopService() won't stop the service, because the system binds // to the service for the purpose of sending it a revoke command if another VPN comes up, // and stopping a bound service has no effect. Instead, "start" the service again with an @@ -739,7 +786,7 @@ } private ContentResolver getContentResolver() { - return getInstrumentation().getContext().getContentResolver(); + return mTestContext.getContentResolver(); } private boolean isPrivateDnsInStrictMode() { @@ -761,34 +808,16 @@ mOldPrivateDnsSpecifier); } - // TODO: replace with CtsNetUtils.awaitPrivateDnsSetting in Q or above. private void expectPrivateDnsHostname(final String hostname) throws Exception { - final NetworkRequest request = new NetworkRequest.Builder() - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) - .build(); - final CountDownLatch latch = new CountDownLatch(1); - final NetworkCallback callback = new NetworkCallback() { - @Override - public void onLinkPropertiesChanged(Network network, LinkProperties lp) { - if (network.equals(mNetwork) && - Objects.equals(lp.getPrivateDnsServerName(), hostname)) { - latch.countDown(); - } - } - }; - - mCM.registerNetworkCallback(request, callback); - - try { - assertTrue("Private DNS hostname was not " + hostname + " after " + TIMEOUT_MS + "ms", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } finally { - mCM.unregisterNetworkCallback(callback); + for (Network network : mCtsNetUtils.getTestableNetworks()) { + // Wait for private DNS setting to propagate. + mCtsNetUtils.awaitPrivateDnsSetting("Test wait private DNS setting timeout", + network, hostname, false); } } private void setAndVerifyPrivateDns(boolean strictMode) throws Exception { - final ContentResolver cr = getInstrumentation().getContext().getContentResolver(); + final ContentResolver cr = mTestContext.getContentResolver(); String privateDnsHostname; if (strictMode) { @@ -839,8 +868,13 @@ callback.eventuallyExpect(RecorderCallback.CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS, entry -> (Objects.equals(expectUnderlyingNetworks, - ((RecorderCallback.CallbackEntry.CapabilitiesChanged) entry) - .getCaps().getUnderlyingNetworks()))); + entry.getCaps().getUnderlyingNetworks()))); + } + + private void expectVpnNetwork(TestableNetworkCallback callback) { + callback.eventuallyExpect(RecorderCallback.CallbackEntry.NETWORK_CAPS_UPDATED, + NETWORK_CALLBACK_TIMEOUT_MS, + entry -> entry.getCaps().hasTransport(TRANSPORT_VPN)); } @Test @IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available @@ -866,7 +900,7 @@ false /* isAlwaysMetered */); // Acquire the NETWORK_SETTINGS permission for getting the underlying networks. runWithShellPermissionIdentity(() -> { - mCM.registerNetworkCallback(makeVpnNetworkRequest(), callback); + registerNetworkCallback(makeVpnNetworkRequest(), callback); // Check that this VPN doesn't have any underlying networks. expectUnderlyingNetworks(callback, new ArrayList<Network>()); @@ -899,8 +933,6 @@ } else { mCtsNetUtils.ensureWifiDisconnected(null); } - }, () -> { - mCM.unregisterNetworkCallback(callback); }); } @@ -921,7 +953,7 @@ } final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver( - getInstrumentation().getTargetContext(), MyVpnService.ACTION_ESTABLISHED); + mTargetContext, MyVpnService.ACTION_ESTABLISHED); receiver.register(); // Test the behaviour of a variety of types of network callbacks. @@ -934,9 +966,9 @@ UserHandle.of(5 /* userId */).getUid(Process.FIRST_APPLICATION_UID); final Handler h = new Handler(Looper.getMainLooper()); runWithShellPermissionIdentity(() -> { - mCM.registerSystemDefaultNetworkCallback(systemDefaultCallback, h); - mCM.registerDefaultNetworkCallbackForUid(otherUid, otherUidCallback, h); - mCM.registerDefaultNetworkCallbackForUid(Process.myUid(), myUidCallback, h); + registerSystemDefaultNetworkCallback(systemDefaultCallback, h); + registerDefaultNetworkCallbackForUid(otherUid, otherUidCallback, h); + registerDefaultNetworkCallbackForUid(Process.myUid(), myUidCallback, h); }, NETWORK_SETTINGS); for (TestableNetworkCallback callback : List.of(systemDefaultCallback, otherUidCallback, myUidCallback)) { @@ -987,9 +1019,6 @@ // fail and could cause the default network to switch (e.g., from wifi to cellular). systemDefaultCallback.assertNoCallback(); otherUidCallback.assertNoCallback(); - mCM.unregisterNetworkCallback(systemDefaultCallback); - mCM.unregisterNetworkCallback(otherUidCallback); - mCM.unregisterNetworkCallback(myUidCallback); } checkStrictModePrivateDns(); @@ -1018,6 +1047,183 @@ checkStrictModePrivateDns(); } + private int getSupportedKeepalives(NetworkCapabilities nc) throws Exception { + // Get number of supported concurrent keepalives for testing network. + final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives( + mTargetContext); + return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( + keepalivesPerTransport, nc); + } + + // This class can't be private, otherwise the constants can't be static imported. + static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback { + // This must be larger than the alarm delay in AutomaticOnOffKeepaliveTracker. + private static final int KEEPALIVE_TIMEOUT_MS = 10_000; + public enum CallbackType { + ON_STARTED, + ON_RESUMED, + ON_STOPPED, + ON_PAUSED, + ON_ERROR, + ON_DATA_RECEIVED + } + private ArrayTrackRecord<CallbackType> mHistory = new ArrayTrackRecord<>(); + private ArrayTrackRecord<CallbackType>.ReadHead mEvents = mHistory.newReadHead(); + + @Override + public void onStarted() { + mHistory.add(ON_STARTED); + } + + @Override + public void onResumed() { + mHistory.add(ON_RESUMED); + } + + @Override + public void onStopped() { + mHistory.add(ON_STOPPED); + } + + @Override + public void onPaused() { + mHistory.add(ON_PAUSED); + } + + @Override + public void onError(final int error) { + mHistory.add(ON_ERROR); + } + + @Override + public void onDataReceived() { + mHistory.add(ON_DATA_RECEIVED); + } + + public CallbackType poll() { + return mEvents.poll(KEEPALIVE_TIMEOUT_MS, it -> true); + } + } + + private InetAddress getV4AddrByName(final String hostname) throws Exception { + final InetAddress[] allAddrs = InetAddress.getAllByName(hostname); + for (InetAddress addr : allAddrs) { + if (addr instanceof Inet4Address) return addr; + } + return null; + } + + @Test + public void testAutomaticOnOffKeepaliveModeNoClose() throws Exception { + doTestAutomaticOnOffKeepaliveMode(false); + } + + @Test + public void testAutomaticOnOffKeepaliveModeClose() throws Exception { + doTestAutomaticOnOffKeepaliveMode(true); + } + + private void startKeepalive(SocketKeepalive kp, TestSocketKeepaliveCallback callback) { + runWithShellPermissionIdentity(() -> { + // Only SocketKeepalive.start() requires READ_DEVICE_CONFIG because feature is protected + // by a feature flag. But also verify ON_STARTED callback received here to ensure + // keepalive is indeed started because start() runs in the executor thread and shell + // permission may be dropped before reading DeviceConfig. + kp.start(10 /* intervalSec */, SocketKeepalive.FLAG_AUTOMATIC_ON_OFF, mNetwork); + + // Verify callback status. + assertEquals(ON_STARTED, callback.poll()); + }, READ_DEVICE_CONFIG); + } + + private void doTestAutomaticOnOffKeepaliveMode(final boolean closeSocket) throws Exception { + assumeTrue(supportedHardware()); + + // Get default network first before starting VPN + final Network defaultNetwork = mCM.getActiveNetwork(); + final TestableNetworkCallback cb = new TestableNetworkCallback(); + registerDefaultNetworkCallback(cb); + cb.expect(CallbackEntry.AVAILABLE, defaultNetwork); + final NetworkCapabilities cap = + cb.expect(CallbackEntry.NETWORK_CAPS_UPDATED, defaultNetwork).getCaps(); + final LinkProperties lp = + cb.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, defaultNetwork).getLp(); + cb.expect(CallbackEntry.BLOCKED_STATUS, defaultNetwork); + + // Setup VPN + final FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + final String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; + startVpn(new String[]{"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[]{"192.0.2.0/24", "2001:db8::/32"}, + allowedApps, "" /* disallowedApplications */, null /* proxyInfo */, + null /* underlyingNetworks */, false /* isAlwaysMetered */); + assertSocketClosed(fd, TEST_HOST); + + // Decrease the TCP polling timer for testing. + runWithShellPermissionIdentity(() -> mCM.setTestLowTcpPollingTimerForKeepalive( + System.currentTimeMillis() + TEST_TCP_POLLING_TIMER_EXPIRED_PERIOD_MS), + NETWORK_SETTINGS); + + // Setup keepalive + final int supported = getSupportedKeepalives(cap); + assumeTrue("Network " + defaultNetwork + " does not support keepalive", supported != 0); + final InetAddress srcAddr = CollectionUtils.findFirst(lp.getAddresses(), + it -> it instanceof Inet4Address); + assumeTrue("This test requires native IPv4", srcAddr != null); + + final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + + final String origMode = runWithShellPermissionIdentity(() -> { + final String mode = DeviceConfig.getProperty( + DeviceConfig.NAMESPACE_CONNECTIVITY, AUTOMATIC_ON_OFF_KEEPALIVE_VERSION); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_CONNECTIVITY, + AUTOMATIC_ON_OFF_KEEPALIVE_VERSION, + AUTOMATIC_ON_OFF_KEEPALIVE_ENABLED, false /* makeDefault */); + return mode; + }, READ_DEVICE_CONFIG, WRITE_DEVICE_CONFIG); + + final IpSecManager ipSec = mTargetContext.getSystemService(IpSecManager.class); + SocketKeepalive kp = null; + try (IpSecManager.UdpEncapsulationSocket nattSocket = ipSec.openUdpEncapsulationSocket()) { + final InetAddress dstAddr = getV4AddrByName(TEST_HOST); + assertNotNull(dstAddr); + + // Start keepalive with dynamic keepalive mode enabled. + final Executor executor = mTargetContext.getMainExecutor(); + kp = mCM.createSocketKeepalive(defaultNetwork, nattSocket, + srcAddr, dstAddr, executor, callback); + startKeepalive(kp, callback); + + // There should be no open sockets on the VPN network, because any + // open sockets were closed when startVpn above was called. So the + // first TCP poll should trigger ON_PAUSED. + assertEquals(ON_PAUSED, callback.poll()); + + final Socket s = new Socket(); + mNetwork.bindSocket(s); + s.connect(new InetSocketAddress(dstAddr, 80)); + assertEquals(ON_RESUMED, callback.poll()); + + if (closeSocket) { + s.close(); + assertEquals(ON_PAUSED, callback.poll()); + } + + kp.stop(); + assertEquals(ON_STOPPED, callback.poll()); + } finally { + if (kp != null) kp.stop(); + + runWithShellPermissionIdentity(() -> { + DeviceConfig.setProperty( + DeviceConfig.NAMESPACE_CONNECTIVITY, + AUTOMATIC_ON_OFF_KEEPALIVE_VERSION, + origMode, false); + mCM.setTestLowTcpPollingTimerForKeepalive(0); + }, WRITE_DEVICE_CONFIG, NETWORK_SETTINGS); + } + } + @Test public void testAppDisallowed() throws Exception { assumeTrue(supportedHardware()); @@ -1053,6 +1259,31 @@ } @Test + public void testSocketClosed() throws Exception { + assumeTrue(supportedHardware()); + + final FileDescriptor localFd = openSocketFd(TEST_HOST, 80, TIMEOUT_MS); + final List<FileDescriptor> remoteFds = new ArrayList<>(); + + for (int i = 0; i < 30; i++) { + remoteFds.add(openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS)); + } + + final String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"192.0.2.0/24", "2001:db8::/32"}, + allowedApps, "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */); + + // Socket owned by VPN uid is not closed + assertSocketStillOpen(localFd, TEST_HOST); + + // Sockets not owned by VPN uid are closed + for (final FileDescriptor remoteFd: remoteFds) { + assertSocketClosed(remoteFd, TEST_HOST); + } + } + + @Test public void testExcludedRoutes() throws Exception { assumeTrue(supportedHardware()); assumeTrue(SdkLevel.isAtLeastT()); @@ -1517,7 +1748,7 @@ private boolean received; public ProxyChangeBroadcastReceiver() { - super(getInstrumentation().getContext(), Proxy.PROXY_CHANGE_ACTION); + super(mTestContext, Proxy.PROXY_CHANGE_ACTION); received = false; } @@ -1547,12 +1778,11 @@ "" /* allowedApps */, "com.android.providers.downloads", null /* proxyInfo */, null /* underlyingNetworks */, false /* isAlwaysMetered */); - final Context context = getInstrumentation().getContext(); - final DownloadManager dm = context.getSystemService(DownloadManager.class); + final DownloadManager dm = mTestContext.getSystemService(DownloadManager.class); final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver(); try { final int flags = SdkLevel.isAtLeastT() ? RECEIVER_EXPORTED : 0; - context.registerReceiver(receiver, + mTestContext.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), flags); // Enqueue a request and check only one download. @@ -1570,7 +1800,7 @@ assertEquals(1, dm.remove(id)); assertEquals(0, getTotalNumberDownloads(dm, new Query())); } finally { - context.unregisterReceiver(receiver); + mTestContext.unregisterReceiver(receiver); } } @@ -1607,8 +1837,7 @@ // Create a TUN interface final FileDescriptor tunFd = runWithShellPermissionIdentity(() -> { - final TestNetworkManager tnm = getInstrumentation().getContext().getSystemService( - TestNetworkManager.class); + final TestNetworkManager tnm = mTestContext.getSystemService(TestNetworkManager.class); final TestNetworkInterface iface = tnm.createTunInterface(List.of( TEST_IP4_DST_ADDR, TEST_IP6_DST_ADDR)); return iface.getFileDescriptor().getFileDescriptor(); @@ -1619,10 +1848,10 @@ testAndCleanup(() -> { runWithShellPermissionIdentity(() -> { - mCM.registerDefaultNetworkCallbackForUid(remoteUid, remoteUidCallback, + registerDefaultNetworkCallbackForUid(remoteUid, remoteUidCallback, new Handler(Looper.getMainLooper())); }, NETWORK_SETTINGS); - remoteUidCallback.expectAvailableCallbacks(network); + remoteUidCallback.expectAvailableCallbacksWithBlockedReasonNone(network); // The remote UDP socket can receive packets coming from the TUN interface checkBlockIncomingPacket(tunFd, remoteUdpFd, EXPECT_PASS); @@ -1635,7 +1864,8 @@ // setRequireVpnForUids setup a lockdown rule asynchronously. So it needs to wait for // BlockedStatusCallback to be fired before checking the blocking status of incoming // packets. - remoteUidCallback.expectBlockedStatusCallback(network, BLOCKED_REASON_LOCKDOWN_VPN); + remoteUidCallback.expect(BLOCKED_STATUS_INT, network, + cb -> cb.getReason() == BLOCKED_REASON_LOCKDOWN_VPN); if (SdkLevel.isAtLeastT()) { // On T and above, lockdown rule drop packets not coming from lo regardless of the @@ -1654,8 +1884,6 @@ checkBlockIncomingPacket(tunFd, remoteUdpFd, EXPECT_BLOCK); }, /* cleanup */ () -> { - mCM.unregisterNetworkCallback(remoteUidCallback); - }, /* cleanup */ () -> { Os.close(tunFd); }, /* cleanup */ () -> { Os.close(remoteUdpFd); @@ -1666,6 +1894,54 @@ }); } + @Test + public void testSetVpnDefaultForUids() throws Exception { + assumeTrue(supportedHardware()); + assumeTrue(SdkLevel.isAtLeastU()); + + final Network defaultNetwork = mCM.getActiveNetwork(); + assertNotNull("There must be a default network", defaultNetwork); + + final TestableNetworkCallback defaultNetworkCallback = new TestableNetworkCallback(); + final String session = UUID.randomUUID().toString(); + final int myUid = Process.myUid(); + + testAndCleanup(() -> { + registerDefaultNetworkCallback(defaultNetworkCallback); + defaultNetworkCallback.expectAvailableCallbacks(defaultNetwork); + + final Range<Integer> myUidRange = new Range<>(myUid, myUid); + runWithShellPermissionIdentity(() -> { + mCM.setVpnDefaultForUids(session, List.of(myUidRange)); + }, NETWORK_SETTINGS); + + // The VPN will be the only default network for the app, so it's expected to receive + // onLost() callback. + defaultNetworkCallback.eventuallyExpect(CallbackEntry.LOST); + + final ArrayList<Network> underlyingNetworks = new ArrayList<>(); + underlyingNetworks.add(defaultNetwork); + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"} /* addresses */, + new String[] {"0.0.0.0/0", "::/0"} /* routes */, + "" /* allowedApplications */, "" /* disallowedApplications */, + null /* proxyInfo */, underlyingNetworks, false /* isAlwaysMetered */); + + expectVpnNetwork(defaultNetworkCallback); + }, /* cleanup */ () -> { + stopVpn(); + defaultNetworkCallback.eventuallyExpect(CallbackEntry.LOST); + }, /* cleanup */ () -> { + runWithShellPermissionIdentity(() -> { + mCM.setVpnDefaultForUids(session, new ArraySet<>()); + }, NETWORK_SETTINGS); + // The default network of the app will be changed back to wifi when the VPN network + // preference feature is disabled. + defaultNetworkCallback.eventuallyExpect(CallbackEntry.AVAILABLE, + NETWORK_CALLBACK_TIMEOUT_MS, + entry -> defaultNetwork.equals(entry.getNetwork())); + }); + } + private ByteBuffer buildIpv4UdpPacket(final Inet4Address dstAddr, final Inet4Address srcAddr, final short dstPort, final short srcPort, final byte[] payload) throws IOException { @@ -1756,13 +2032,10 @@ } private class DetailedBlockedStatusCallback extends TestableNetworkCallback { - public void expectAvailableCallbacks(Network network) { + public void expectAvailableCallbacksWithBlockedReasonNone(Network network) { super.expectAvailableCallbacks(network, false /* suspended */, true /* validated */, BLOCKED_REASON_NONE, NETWORK_CALLBACK_TIMEOUT_MS); } - public void expectBlockedStatusCallback(Network network, int blockedStatus) { - super.expectBlockedStatusCallback(blockedStatus, network, NETWORK_CALLBACK_TIMEOUT_MS); - } public void onBlockedStatusChanged(Network network, int blockedReasons) { getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons)); }
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java index 2e79182..37dc7a0 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
@@ -99,7 +99,8 @@ } case TYPE_COMPONENT_EXPEDITED_JOB: { final int capabilities = activityManager.getUidProcessCapabilities(Process.myUid()); - if ((capabilities & ActivityManager.PROCESS_CAPABILITY_NETWORK) == 0) { + if ((capabilities + & ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) == 0) { observer.onNetworkStateChecked( INetworkStateObserver.RESULT_ERROR_UNEXPECTED_CAPABILITIES, "Unexpected capabilities: " + capabilities);
diff --git a/tests/cts/hostside/networkslicingtestapp/Android.bp b/tests/cts/hostside/networkslicingtestapp/Android.bp new file mode 100644 index 0000000..2aa3f69 --- /dev/null +++ b/tests/cts/hostside/networkslicingtestapp/Android.bp
@@ -0,0 +1,65 @@ +// +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +java_defaults { + name: "CtsHostsideNetworkCapTestsAppDefaults", + platform_apis: true, + static_libs: [ + "androidx.test.ext.junit", + "androidx.test.rules", + "modules-utils-build", + "cts-net-utils", + ], + srcs: ["src/**/*.java"], + // Tag this module as a cts test artifact + test_suites: [ + "cts", + "general-tests", + "sts", + ], +} + +android_test_helper_app { + name: "CtsHostsideNetworkCapTestsAppWithoutProperty", + defaults: [ + "cts_support_defaults", + "CtsHostsideNetworkCapTestsAppDefaults" + ], + manifest: "AndroidManifestWithoutProperty.xml", +} + +android_test_helper_app { + name: "CtsHostsideNetworkCapTestsAppWithProperty", + defaults: [ + "cts_support_defaults", + "CtsHostsideNetworkCapTestsAppDefaults" + ], + manifest: "AndroidManifestWithProperty.xml", +} + +android_test_helper_app { + name: "CtsHostsideNetworkCapTestsAppSdk33", + defaults: [ + "cts_support_defaults", + "CtsHostsideNetworkCapTestsAppDefaults" + ], + target_sdk_version: "33", + manifest: "AndroidManifestWithoutProperty.xml", +}
diff --git a/tests/cts/hostside/networkslicingtestapp/AndroidManifestWithProperty.xml b/tests/cts/hostside/networkslicingtestapp/AndroidManifestWithProperty.xml new file mode 100644 index 0000000..3ef0376 --- /dev/null +++ b/tests/cts/hostside/networkslicingtestapp/AndroidManifestWithProperty.xml
@@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.cts.net.hostside.networkslicingtestapp"> + + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> + + <application> + <uses-library android:name="android.test.runner"/> + <property android:name="android.net.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES" + android:resource="@xml/self_certified_network_capabilities_both" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.cts.net.hostside.networkslicingtestapp"/> + +</manifest>
diff --git a/tests/cts/hostside/networkslicingtestapp/AndroidManifestWithoutProperty.xml b/tests/cts/hostside/networkslicingtestapp/AndroidManifestWithoutProperty.xml new file mode 100644 index 0000000..fe66684 --- /dev/null +++ b/tests/cts/hostside/networkslicingtestapp/AndroidManifestWithoutProperty.xml
@@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.cts.net.hostside.networkslicingtestapp"> + + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> + + <application> + <uses-library android:name="android.test.runner"/> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.cts.net.hostside.networkslicingtestapp"/> + +</manifest>
diff --git a/tests/cts/hostside/networkslicingtestapp/res/xml/self_certified_network_capabilities_both.xml b/tests/cts/hostside/networkslicingtestapp/res/xml/self_certified_network_capabilities_both.xml new file mode 100644 index 0000000..4066be2 --- /dev/null +++ b/tests/cts/hostside/networkslicingtestapp/res/xml/self_certified_network_capabilities_both.xml
@@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<network-capabilities-declaration xmlns:android="http://schemas.android.com/apk/res/android"> + <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_LATENCY"/> + <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_BANDWIDTH"/> +</network-capabilities-declaration>
diff --git a/tests/cts/hostside/networkslicingtestapp/src/com.android.cts.net.hostside.networkslicingtestapp/NetworkSelfDeclaredCapabilitiesTest.java b/tests/cts/hostside/networkslicingtestapp/src/com.android.cts.net.hostside.networkslicingtestapp/NetworkSelfDeclaredCapabilitiesTest.java new file mode 100644 index 0000000..39792fc --- /dev/null +++ b/tests/cts/hostside/networkslicingtestapp/src/com.android.cts.net.hostside.networkslicingtestapp/NetworkSelfDeclaredCapabilitiesTest.java
@@ -0,0 +1,98 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.cts.net.hostside.networkslicingtestapp; + +import static org.junit.Assert.assertThrows; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Build; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class NetworkSelfDeclaredCapabilitiesTest { + + @Rule + public final DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule(); + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void requestNetwork_withoutRequestCapabilities() { + final ConnectivityManager cm = + (ConnectivityManager) + InstrumentationRegistry.getInstrumentation() + .getContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + final NetworkRequest request = + new NetworkRequest.Builder().build(); + final ConnectivityManager.NetworkCallback callback = + new ConnectivityManager.NetworkCallback(); + cm.requestNetwork(request, callback); + cm.unregisterNetworkCallback(callback); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void requestNetwork_withSelfDeclaredCapabilities() { + final ConnectivityManager cm = + (ConnectivityManager) + InstrumentationRegistry.getInstrumentation() + .getContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + final NetworkRequest request = + new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) + .build(); + final ConnectivityManager.NetworkCallback callback = + new ConnectivityManager.NetworkCallback(); + cm.requestNetwork(request, callback); + cm.unregisterNetworkCallback(callback); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void requestNetwork_lackingRequiredSelfDeclaredCapabilities() { + final ConnectivityManager cm = + (ConnectivityManager) + InstrumentationRegistry.getInstrumentation() + .getContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + final NetworkRequest request = + new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) + .build(); + final ConnectivityManager.NetworkCallback callback = + new ConnectivityManager.NetworkCallback(); + assertThrows( + SecurityException.class, + () -> cm.requestNetwork(request, callback)); + } + +}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index d0567ae..2aa1032 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java
@@ -31,6 +31,7 @@ import com.android.tradefed.testtype.IAbi; import com.android.tradefed.testtype.IAbiReceiver; import com.android.tradefed.testtype.IBuildReceiver; +import com.android.tradefed.util.RunUtil; import java.io.FileNotFoundException; import java.util.Map; @@ -120,7 +121,7 @@ i++; Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result + "); sleeping 1s before polling again"); - Thread.sleep(1000); + RunUtil.getDefault().sleep(1000); } fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds"); }
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index 7a613b3..21c78b7 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -20,6 +20,7 @@ import com.android.ddmlib.Log; import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.util.RunUtil; public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase { @@ -359,7 +360,7 @@ } Log.v(TAG, "whitelist check for uid " + uid + " doesn't match yet (expected " + expected + ", got " + actual + "); sleeping 1s before polling again"); - Thread.sleep(1000); + RunUtil.getDefault().sleep(1000); } fail("whitelist check for uid " + uid + " failed: expected " + expected + ", got " + actual); @@ -384,7 +385,7 @@ if (result.equals(expectedResult)) return; Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '" + expectedResult + "' on attempt #; sleeping 1s before polling again"); - Thread.sleep(1000); + RunUtil.getDefault().sleep(1000); } fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries + " attempts");
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideSelfDeclaredNetworkCapabilitiesCheckTest.java b/tests/cts/hostside/src/com/android/cts/net/HostsideSelfDeclaredNetworkCapabilitiesCheckTest.java new file mode 100644 index 0000000..4c2985d --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideSelfDeclaredNetworkCapabilitiesCheckTest.java
@@ -0,0 +1,96 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.cts.net; + +public class HostsideSelfDeclaredNetworkCapabilitiesCheckTest extends HostsideNetworkTestCase { + + private static final String TEST_WITH_PROPERTY_IN_CURRENT_SDK_APK = + "CtsHostsideNetworkCapTestsAppWithProperty.apk"; + private static final String TEST_WITHOUT_PROPERTY_IN_CURRENT_SDK_APK = + "CtsHostsideNetworkCapTestsAppWithoutProperty.apk"; + private static final String TEST_IN_SDK_33_APK = + "CtsHostsideNetworkCapTestsAppSdk33.apk"; + private static final String TEST_APP_PKG = + "com.android.cts.net.hostside.networkslicingtestapp"; + private static final String TEST_CLASS_NAME = ".NetworkSelfDeclaredCapabilitiesTest"; + private static final String WITH_SELF_DECLARED_CAPABILITIES_METHOD = + "requestNetwork_withSelfDeclaredCapabilities"; + private static final String LACKING_SELF_DECLARED_CAPABILITIES_METHOD = + "requestNetwork_lackingRequiredSelfDeclaredCapabilities"; + private static final String WITHOUT_REQUEST_CAPABILITIES_METHOD = + "requestNetwork_withoutRequestCapabilities"; + + + public void testRequestNetworkInCurrentSdkWithProperty() throws Exception { + uninstallPackage(TEST_APP_PKG, false); + installPackage(TEST_WITH_PROPERTY_IN_CURRENT_SDK_APK); + // If the self-declared capabilities are defined, + // the ConnectivityManager.requestNetwork() call should always pass. + runDeviceTests(TEST_APP_PKG, + TEST_APP_PKG + TEST_CLASS_NAME, + WITH_SELF_DECLARED_CAPABILITIES_METHOD); + runDeviceTests(TEST_APP_PKG, + TEST_APP_PKG + TEST_CLASS_NAME, + WITHOUT_REQUEST_CAPABILITIES_METHOD); + uninstallPackage(TEST_APP_PKG, true); + } + + public void testRequestNetworkInCurrentSdkWithoutProperty() throws Exception { + uninstallPackage(TEST_APP_PKG, false); + installPackage(TEST_WITHOUT_PROPERTY_IN_CURRENT_SDK_APK); + // If the self-declared capabilities are not defined, + // the ConnectivityManager.requestNetwork() call will fail if the properly is not declared. + runDeviceTests(TEST_APP_PKG, + TEST_APP_PKG + TEST_CLASS_NAME, + LACKING_SELF_DECLARED_CAPABILITIES_METHOD); + runDeviceTests(TEST_APP_PKG, + TEST_APP_PKG + TEST_CLASS_NAME, + WITHOUT_REQUEST_CAPABILITIES_METHOD); + uninstallPackage(TEST_APP_PKG, true); + } + + public void testRequestNetworkInSdk33() throws Exception { + uninstallPackage(TEST_APP_PKG, false); + installPackage(TEST_IN_SDK_33_APK); + // In Sdk33, the ConnectivityManager.requestNetwork() call should always pass. + runDeviceTests(TEST_APP_PKG, + TEST_APP_PKG + TEST_CLASS_NAME, + WITH_SELF_DECLARED_CAPABILITIES_METHOD); + runDeviceTests(TEST_APP_PKG, + TEST_APP_PKG + TEST_CLASS_NAME, + WITHOUT_REQUEST_CAPABILITIES_METHOD); + uninstallPackage(TEST_APP_PKG, true); + } + + public void testReinstallPackageWillUpdateProperty() throws Exception { + uninstallPackage(TEST_APP_PKG, false); + installPackage(TEST_WITHOUT_PROPERTY_IN_CURRENT_SDK_APK); + runDeviceTests(TEST_APP_PKG, + TEST_APP_PKG + TEST_CLASS_NAME, + LACKING_SELF_DECLARED_CAPABILITIES_METHOD); + uninstallPackage(TEST_APP_PKG, true); + + + // Updates package. + installPackage(TEST_WITH_PROPERTY_IN_CURRENT_SDK_APK); + runDeviceTests(TEST_APP_PKG, + TEST_APP_PKG + TEST_CLASS_NAME, + WITH_SELF_DECLARED_CAPABILITIES_METHOD); + uninstallPackage(TEST_APP_PKG, true); + + } +} +
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java index 4d90a4a..3ca4775 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
@@ -16,6 +16,8 @@ package com.android.cts.net; +import android.platform.test.annotations.RequiresDevice; + public class HostsideVpnTests extends HostsideNetworkTestCase { @Override @@ -49,6 +51,10 @@ runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppDisallowed"); } + public void testSocketClosed() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testSocketClosed"); + } + public void testGetConnectionOwnerUidSecurity() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testGetConnectionOwnerUidSecurity"); } @@ -89,6 +95,18 @@ TEST_PKG, TEST_PKG + ".VpnTest", "testAlwaysMeteredVpnWithNullUnderlyingNetwork"); } + @RequiresDevice // Keepalive is not supported on virtual hardware + public void testAutomaticOnOffKeepaliveModeClose() throws Exception { + runDeviceTests( + TEST_PKG, TEST_PKG + ".VpnTest", "testAutomaticOnOffKeepaliveModeClose"); + } + + @RequiresDevice // Keepalive is not supported on virtual hardware + public void testAutomaticOnOffKeepaliveModeNoClose() throws Exception { + runDeviceTests( + TEST_PKG, TEST_PKG + ".VpnTest", "testAutomaticOnOffKeepaliveModeNoClose"); + } + public void testAlwaysMeteredVpnWithNonNullUnderlyingNetwork() throws Exception { runDeviceTests( TEST_PKG, @@ -120,4 +138,8 @@ public void testBlockIncomingPackets() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testBlockIncomingPackets"); } + + public void testSetVpnDefaultForUids() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testSetVpnDefaultForUids"); + } }
diff --git a/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java b/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java index 19e61c6..1a528b1 100644 --- a/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java +++ b/tests/cts/hostside/src/com/android/cts/net/ProcNetTest.java
@@ -166,4 +166,15 @@ assertTrue(interval <= upperBoundSec); } } + + /** + * Verify that cubic is used as the congestion control algorithm. + * (This repeats the VTS test, and is here for good performance of the internet as a whole.) + * TODO: revisit this once a better CC algorithm like BBR2 is available. + */ + public void testCongestionControl() throws Exception { + String path = "/proc/sys/net/ipv4/tcp_congestion_control"; + String value = mDevice.executeAdbCommand("shell", "cat", path).trim(); + assertEquals(value, "cubic"); + } }
diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 23cb15c..51ee074 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp
@@ -61,7 +61,7 @@ // uncomment when b/13249961 is fixed // sdk_version: "current", platform_apis: true, - data: [":ConnectivityChecker"], + data: [":ConnectivityTestPreparer"], per_testcase_directory: true, host_required: ["net-tests-utils-host-common"], test_config_template: "AndroidTestTemplate.xml", @@ -114,34 +114,39 @@ ], } -android_test { - name: "CtsNetTestCasesMaxTargetSdk31", // Must match CtsNetTestCasesMaxTargetSdk31 annotation. +java_defaults { + name: "CtsNetTestCasesMaxTargetSdkDefaults", defaults: [ "CtsNetTestCasesDefaults", "CtsNetTestCasesApiStableDefaults", ], - target_sdk_version: "31", - package_name: "android.net.cts.maxtargetsdk31", // CTS package names must be unique. - instrumentation_target_package: "android.net.cts.maxtargetsdk31", test_suites: [ "cts", "general-tests", - "mts-networking", + "mts-tethering", ], } android_test { + name: "CtsNetTestCasesMaxTargetSdk33", // Must match CtsNetTestCasesMaxTargetSdk33 annotation. + defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"], + target_sdk_version: "33", + package_name: "android.net.cts.maxtargetsdk33", + instrumentation_target_package: "android.net.cts.maxtargetsdk33", +} + +android_test { + name: "CtsNetTestCasesMaxTargetSdk31", // Must match CtsNetTestCasesMaxTargetSdk31 annotation. + defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"], + target_sdk_version: "31", + package_name: "android.net.cts.maxtargetsdk31", // CTS package names must be unique. + instrumentation_target_package: "android.net.cts.maxtargetsdk31", +} + +android_test { name: "CtsNetTestCasesMaxTargetSdk30", // Must match CtsNetTestCasesMaxTargetSdk30 annotation. - defaults: [ - "CtsNetTestCasesDefaults", - "CtsNetTestCasesApiStableDefaults", - ], + defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"], target_sdk_version: "30", package_name: "android.net.cts.maxtargetsdk30", // CTS package names must be unique. instrumentation_target_package: "android.net.cts.maxtargetsdk30", - test_suites: [ - "cts", - "general-tests", - "mts-networking", - ], }
diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 25490da..68e36ff 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml
@@ -37,9 +37,6 @@ <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> - <!-- TODO (b/186093901): remove after fixing resource querying --> - <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> - <!-- This test also uses signature permissions through adopting the shell identity. The permissions acquired that way include (probably not exhaustive) : android.permission.MANAGE_TEST_NETWORKS @@ -54,8 +51,6 @@ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.net.cts" android:label="CTS tests of android.net"> - <meta-data android:name="listener" - android:value="com.android.cts.runner.CtsTestRunListener" /> </instrumentation> </manifest>
diff --git a/tests/cts/net/AndroidTestTemplate.xml b/tests/cts/net/AndroidTestTemplate.xml index d2fb04a..8efa99f 100644 --- a/tests/cts/net/AndroidTestTemplate.xml +++ b/tests/cts/net/AndroidTestTemplate.xml
@@ -28,7 +28,7 @@ <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="{MODULE}.apk" /> </target_preparer> - <target_preparer class="com.android.testutils.ConnectivityCheckTargetPreparer"> + <target_preparer class="com.android.testutils.ConnectivityTestTargetPreparer"> </target_preparer> <target_preparer class="com.android.testutils.DisableConfigSyncTargetPreparer"> </target_preparer>
diff --git a/tests/cts/net/api23Test/AndroidManifest.xml b/tests/cts/net/api23Test/AndroidManifest.xml index 69ee0dd..44c63f6 100644 --- a/tests/cts/net/api23Test/AndroidManifest.xml +++ b/tests/cts/net/api23Test/AndroidManifest.xml
@@ -39,7 +39,5 @@ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.net.cts.api23test" android:label="CTS tests of android.net"> - <meta-data android:name="listener" - android:value="com.android.cts.runner.CtsTestRunListener"/> </instrumentation> </manifest>
diff --git a/tests/cts/net/native/dns/Android.bp b/tests/cts/net/native/dns/Android.bp index 434e529..49b9337 100644 --- a/tests/cts/net/native/dns/Android.bp +++ b/tests/cts/net/native/dns/Android.bp
@@ -24,6 +24,10 @@ "liblog", "libutils", ], + static_libs: [ + "libbase", + "libnetdutils", + ], // To be compatible with Q devices, the min_sdk_version must be 29. min_sdk_version: "29", }
diff --git a/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp b/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp index e501475..68bd227 100644 --- a/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp +++ b/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp
@@ -28,6 +28,7 @@ #include <android/multinetwork.h> #include <gtest/gtest.h> +#include <netdutils/NetNativeTestBase.h> namespace { constexpr int MAXPACKET = 8 * 1024; @@ -101,7 +102,9 @@ } // namespace -TEST (NativeDnsAsyncTest, Async_Query) { +class NativeDnsAsyncTest : public NetNativeTestBase {}; + +TEST_F(NativeDnsAsyncTest, Async_Query) { // V4 int fd1 = android_res_nquery( NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_a, 0); @@ -123,7 +126,7 @@ expectAnswersValid(fd1, AF_INET6, ns_r_noerror); } -TEST (NativeDnsAsyncTest, Async_Send) { +TEST_F(NativeDnsAsyncTest, Async_Send) { // V4 uint8_t buf1[MAXPACKET] = {}; int len1 = res_mkquery(ns_o_query, "www.googleapis.com", @@ -162,7 +165,7 @@ expectAnswersValid(fd1, AF_INET6, ns_r_noerror); } -TEST (NativeDnsAsyncTest, Async_NXDOMAIN) { +TEST_F(NativeDnsAsyncTest, Async_NXDOMAIN) { uint8_t buf[MAXPACKET] = {}; int len = res_mkquery(ns_o_query, "test1-nx.metric.gstatic.com", ns_c_in, ns_t_a, nullptr, 0, nullptr, buf, sizeof(buf)); @@ -191,7 +194,7 @@ expectAnswersValid(fd1, AF_INET6, ns_r_nxdomain); } -TEST (NativeDnsAsyncTest, Async_Cancel) { +TEST_F(NativeDnsAsyncTest, Async_Cancel) { int fd = android_res_nquery( NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_a, 0); errno = 0; @@ -202,7 +205,7 @@ // otherwise it will hit fdsan double-close fd. } -TEST (NativeDnsAsyncTest, Async_Query_MALFORMED) { +TEST_F(NativeDnsAsyncTest, Async_Query_MALFORMED) { // Empty string to create BLOB and query, we will get empty result and rcode = 0 // on DNSTLS. int fd = android_res_nquery( @@ -221,7 +224,7 @@ EXPECT_EQ(-EMSGSIZE, fd); } -TEST (NativeDnsAsyncTest, Async_Send_MALFORMED) { +TEST_F(NativeDnsAsyncTest, Async_Send_MALFORMED) { uint8_t buf[10] = {}; // empty BLOB int fd = android_res_nsend(NETWORK_UNSPECIFIED, buf, 10, 0);
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index 7c24c95..dc22369 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -37,8 +37,6 @@ import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig import android.net.cts.util.CtsNetUtils -import com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTPS_URL -import com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTP_URL import android.platform.test.annotations.AppModeFull import android.provider.DeviceConfig import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY @@ -47,28 +45,30 @@ import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.runner.AndroidJUnit4 import com.android.modules.utils.build.SdkLevel.isAtLeastR +import com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTPS_URL +import com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTP_URL import com.android.testutils.DeviceConfigRule -import com.android.testutils.RecorderCallback +import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged import com.android.testutils.TestHttpServer import com.android.testutils.TestHttpServer.Request import com.android.testutils.TestableNetworkCallback import com.android.testutils.runAsShell import fi.iki.elonen.NanoHTTPD.Response.Status -import junit.framework.AssertionFailedError -import org.junit.After -import org.junit.Assume.assumeTrue -import org.junit.Assume.assumeFalse -import org.junit.Before -import org.junit.BeforeClass -import org.junit.Rule -import org.junit.runner.RunWith import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException +import junit.framework.AssertionFailedError import kotlin.test.Test import kotlin.test.assertNotEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue +import org.junit.After +import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.runner.RunWith private const val TEST_HTTPS_URL_PATH = "/https_path" private const val TEST_HTTP_URL_PATH = "/http_path" @@ -151,8 +151,8 @@ .build() val cellCb = TestableNetworkCallback(timeoutMs = TEST_TIMEOUT_MS) cm.registerNetworkCallback(cellReq, cellCb) - val cb = cellCb.eventuallyExpectOrNull<RecorderCallback.CallbackEntry.CapabilitiesChanged> { - it.network == cellNetwork && it.caps.hasCapability(NET_CAPABILITY_VALIDATED) + val cb = cellCb.poll { it.network == cellNetwork && + it is CapabilitiesChanged && it.caps.hasCapability(NET_CAPABILITY_VALIDATED) } assertNotNull(cb, "Mobile network $cellNetwork has no access to the internet. " + "Check the mobile data connection.")
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 7662ba3..60befca 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
@@ -117,7 +117,7 @@ private static final int FAIL_RATE_PERCENTAGE = 100; private static final int UNKNOWN_DETECTION_METHOD = 4; private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0; - private static final int CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT = 5000; + private static final int CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT = 10000; private static final int DELAY_FOR_BROADCAST_IDLE = 30_000; private static final Executor INLINE_EXECUTOR = x -> x.run();
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 96acac3..ee2f6bb 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -96,6 +96,7 @@ import static com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTP_URL; 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; import static com.android.testutils.MiscAsserts.assertThrows; @@ -224,6 +225,7 @@ import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.Socket; +import java.net.SocketException; import java.net.URL; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; @@ -233,6 +235,7 @@ import java.util.Objects; import java.util.Random; import java.util.Set; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -276,6 +279,7 @@ // TODO(b/252972908): reset the original timer when aosp/2188755 is ramped up. private static final int LISTEN_ACTIVITY_TIMEOUT_MS = 30_000; private static final int NO_CALLBACK_TIMEOUT_MS = 100; + private static final int NETWORK_REQUEST_TIMEOUT_MS = 3000; private static final int SOCKET_TIMEOUT_MS = 100; private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500; @@ -1130,18 +1134,16 @@ final ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); - mContext.registerReceiver(receiver, filter); + final int flags = SdkLevel.isAtLeastT() ? RECEIVER_EXPORTED : 0; + mContext.registerReceiver(receiver, filter, flags); // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION. final Intent intent = new Intent(NETWORK_CALLBACK_ACTION) .setPackage(mContext.getPackageName()); // While ConnectivityService would put extra info such as network or request id before // broadcasting the inner intent. The MUTABLE flag needs to be added accordingly. - // TODO: replace with PendingIntent.FLAG_MUTABLE when this code compiles against S+ or - // shims. - final int pendingIntentFlagMutable = 1 << 25; final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0 /*requestCode*/, - intent, PendingIntent.FLAG_CANCEL_CURRENT | pendingIntentFlagMutable); + intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE); // We will register for a WIFI network being available or lost. mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent); @@ -1181,14 +1183,13 @@ // Avoid receiving broadcasts from other runs by appending a timestamp final String broadcastAction = NETWORK_CALLBACK_ACTION + System.currentTimeMillis(); try { - // TODO: replace with PendingIntent.FLAG_MUTABLE when this code compiles against S+ // Intent is mutable to receive EXTRA_NETWORK_REQUEST from ConnectivityService - final int pendingIntentFlagMutable = 1 << 25; final String extraBoolKey = "extra_bool"; firstIntent = PendingIntent.getBroadcast(mContext, 0 /* requestCode */, - new Intent(broadcastAction).putExtra(extraBoolKey, false), - PendingIntent.FLAG_UPDATE_CURRENT | pendingIntentFlagMutable); + new Intent(broadcastAction).putExtra(extraBoolKey, false) + .setPackage(mContext.getPackageName()), + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); if (useListen) { mCm.registerNetworkCallback(firstRequest, firstIntent); @@ -1200,8 +1201,9 @@ // intent will be updated with the new extras secondIntent = PendingIntent.getBroadcast(mContext, 0 /* requestCode */, - new Intent(broadcastAction).putExtra(extraBoolKey, true), - PendingIntent.FLAG_UPDATE_CURRENT | pendingIntentFlagMutable); + new Intent(broadcastAction).putExtra(extraBoolKey, true) + .setPackage(mContext.getPackageName()), + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); // Because secondIntent.intentFilterEquals the first, the request should be replaced if (useListen) { @@ -1224,7 +1226,8 @@ networkFuture.complete(intent.getParcelableExtra(EXTRA_NETWORK)); } }; - mContext.registerReceiver(receiver, filter); + final int flags = SdkLevel.isAtLeastT() ? RECEIVER_EXPORTED : 0; + mContext.registerReceiver(receiver, filter, flags); final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); try { @@ -1654,7 +1657,8 @@ final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); // Get number of supported concurrent keepalives for testing network. - final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); + final int[] keepalivesPerTransport = runAsShell(NETWORK_SETTINGS, + () -> mCm.getSupportedKeepalives()); return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( keepalivesPerTransport, nc); } @@ -1669,6 +1673,9 @@ * keepalives is set to 0. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + // getSupportedKeepalives is available in updatable ConnectivityManager (S+) + // Also, this feature is not mainlined before S, and it's fine to skip on R- devices. + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest @Test public void testKeepaliveWifiUnsupported() throws Exception { assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); @@ -1685,6 +1692,9 @@ } @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + // getSupportedKeepalives is available in updatable ConnectivityManager (S+) + // Also, this feature is not mainlined before S, and it's fine to skip on R- devices. + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest @Test @RequiresDevice // Keepalive is not supported on virtual hardware public void testCreateTcpKeepalive() throws Exception { @@ -1893,6 +1903,9 @@ */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @Test + // getSupportedKeepalives is available in updatable ConnectivityManager (S+) + // Also, this feature is not mainlined before S, and it's fine to skip on R- devices. + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest @RequiresDevice // Keepalive is not supported on virtual hardware public void testSocketKeepaliveLimitWifi() throws Exception { assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); @@ -1943,6 +1956,9 @@ */ @AppModeFull(reason = "Cannot request network in instant app mode") @Test + // getSupportedKeepalives is available in updatable ConnectivityManager (S+) + // Also, this feature is not mainlined before S, and it's fine to skip on R- devices. + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest @RequiresDevice // Keepalive is not supported on virtual hardware public void testSocketKeepaliveLimitTelephony() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { @@ -1989,6 +2005,9 @@ */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") @Test + // getSupportedKeepalives is available in updatable ConnectivityManager (S+) + // Also, this feature is not mainlined before S, and it's fine to skip on R- devices. + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest @RequiresDevice // Keepalive is not supported on virtual hardware public void testSocketKeepaliveUnprivileged() throws Exception { assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); @@ -2111,7 +2130,12 @@ @AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps") @Test public void testSetAirplaneMode() throws Exception{ - final boolean supportWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI); + // Starting from T, wifi supports airplane mode enhancement which may not disconnect wifi + // when airplane mode is on. The actual behavior that the device will have could only be + // checked with hidden wifi APIs(see Settings.Secure.WIFI_APM_STATE). Thus, stop verifying + // wifi on T+ device. + final boolean verifyWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI) + && !SdkLevel.isAtLeastT(); final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); // store the current state of airplane mode final boolean isAirplaneModeEnabled = isAirplaneModeEnabled(); @@ -2122,7 +2146,7 @@ // Verify that networks are available as expected if wifi or cell is supported. Continue the // test if none of them are supported since test should still able to verify the permission // mechanism. - if (supportWifi) { + if (verifyWifi) { mCtsNetUtils.ensureWifiConnected(); registerCallbackAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb); } @@ -2146,7 +2170,7 @@ // Verify that the enabling airplane mode takes effect as expected to prevent flakiness // caused by fast airplane mode switches. Ensure network lost before turning off // airplane mode. - if (supportWifi) waitForLost(wifiCb); + if (verifyWifi) waitForLost(wifiCb); if (supportTelephony) waitForLost(telephonyCb); // Verify we can disable Airplane Mode with correct permission: @@ -2155,7 +2179,7 @@ // Verify that turning airplane mode off takes effect as expected. // connectToCell only registers a request, it cannot / does not need to be called twice mCtsNetUtils.ensureWifiConnected(); - if (supportWifi) waitForAvailable(wifiCb); + if (verifyWifi) waitForAvailable(wifiCb); if (supportTelephony) waitForAvailable(telephonyCb); } finally { // Restore the previous state of airplane mode and permissions: @@ -2175,15 +2199,12 @@ c -> c instanceof CallbackEntry.Available); } - private void waitForAvailable( + private void waitForTransport( @NonNull final TestableNetworkCallback cb, final int expectedTransport) { - cb.eventuallyExpect( - CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, - entry -> { - final NetworkCapabilities nc = mCm.getNetworkCapabilities(entry.getNetwork()); - return nc.hasTransport(expectedTransport); - } - ); + cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, + NETWORK_CALLBACK_TIMEOUT_MS, + entry -> ((CallbackEntry.CapabilitiesChanged) entry).getCaps() + .hasTransport(expectedTransport)); } private void waitForAvailable( @@ -2378,19 +2399,20 @@ } private class DetailedBlockedStatusCallback extends TestableNetworkCallback { - public void expectAvailableCallbacks(Network network) { + public void expectAvailableCallbacksWithBlockedReasonNone(Network network) { super.expectAvailableCallbacks(network, false /* suspended */, true /* validated */, BLOCKED_REASON_NONE, NETWORK_CALLBACK_TIMEOUT_MS); } public void eventuallyExpectBlockedStatusCallback(Network network, int blockedStatus) { super.eventuallyExpect(CallbackEntry.BLOCKED_STATUS_INT, NETWORK_CALLBACK_TIMEOUT_MS, - (it) -> it.getNetwork().equals(network) && it.getBlocked() == blockedStatus); + (it) -> it.getNetwork().equals(network) && it.getReason() == blockedStatus); } public void onBlockedStatusChanged(Network network, int blockedReasons) { + Log.v(TAG, "onBlockedStatusChanged " + network + " " + blockedReasons); getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons)); } private void assertNoBlockedStatusCallback() { - super.assertNoCallbackThat(NO_CALLBACK_TIMEOUT_MS, + super.assertNoCallback(NO_CALLBACK_TIMEOUT_MS, c -> c instanceof CallbackEntry.BlockedStatus); } } @@ -2407,7 +2429,21 @@ } } - private void doTestBlockedStatusCallback() throws Exception { + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + public void testBlockedStatusCallback() throws Exception { + // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 + // shims, and @IgnoreUpTo does not check that. + assumeTrue(TestUtils.shouldTestSApis()); + // The test will need a stable active network that is persistent during the test. + // Try to connect to a wifi network and wait for it becomes the default network before + // starting the test to prevent from sudden active network change caused by previous + // executed tests. + if (mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + final Network expectedDefaultNetwork = mCtsNetUtils.ensureWifiConnected(); + mCtsNetUtils.expectNetworkIsSystemDefault(expectedDefaultNetwork); + } + final DetailedBlockedStatusCallback myUidCallback = new DetailedBlockedStatusCallback(); final DetailedBlockedStatusCallback otherUidCallback = new DetailedBlockedStatusCallback(); @@ -2416,35 +2452,40 @@ final Handler handler = new Handler(Looper.getMainLooper()); registerDefaultNetworkCallback(myUidCallback, handler); - registerDefaultNetworkCallbackForUid(otherUid, otherUidCallback, handler); + runWithShellPermissionIdentity(() -> registerDefaultNetworkCallbackForUid( + otherUid, otherUidCallback, handler), NETWORK_SETTINGS); - final Network defaultNetwork = mCm.getActiveNetwork(); + final Network defaultNetwork = myUidCallback.expect(CallbackEntry.AVAILABLE).getNetwork(); final List<DetailedBlockedStatusCallback> allCallbacks = List.of(myUidCallback, otherUidCallback); for (DetailedBlockedStatusCallback callback : allCallbacks) { - callback.expectAvailableCallbacks(defaultNetwork); + callback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE); } final Range<Integer> myUidRange = new Range<>(myUid, myUid); final Range<Integer> otherUidRange = new Range<>(otherUid, otherUid); - setRequireVpnForUids(true, List.of(myUidRange)); + runWithShellPermissionIdentity(() -> setRequireVpnForUids( + true, List.of(myUidRange)), NETWORK_SETTINGS); myUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN); otherUidCallback.assertNoBlockedStatusCallback(); - setRequireVpnForUids(true, List.of(myUidRange, otherUidRange)); + runWithShellPermissionIdentity(() -> setRequireVpnForUids( + true, List.of(myUidRange, otherUidRange)), NETWORK_SETTINGS); myUidCallback.assertNoBlockedStatusCallback(); otherUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN); // setRequireVpnForUids does no deduplication or refcounting. Removing myUidRange does not // unblock myUid because it was added to the blocked ranges twice. - setRequireVpnForUids(false, List.of(myUidRange)); + runWithShellPermissionIdentity(() -> + setRequireVpnForUids(false, List.of(myUidRange)), NETWORK_SETTINGS); myUidCallback.assertNoBlockedStatusCallback(); otherUidCallback.assertNoBlockedStatusCallback(); - setRequireVpnForUids(false, List.of(myUidRange, otherUidRange)); + runWithShellPermissionIdentity(() -> setRequireVpnForUids( + false, List.of(myUidRange, otherUidRange)), NETWORK_SETTINGS); myUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE); otherUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE); @@ -2453,11 +2494,14 @@ } @Test - public void testBlockedStatusCallback() { - // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 - // shims, and @IgnoreUpTo does not check that. - assumeTrue(TestUtils.shouldTestSApis()); - runWithShellPermissionIdentity(() -> doTestBlockedStatusCallback(), NETWORK_SETTINGS); + public void testSetVpnDefaultForUids() { + assumeTrue(TestUtils.shouldTestUApis()); + final String session = UUID.randomUUID().toString(); + assertThrows(NullPointerException.class, () -> mCm.setVpnDefaultForUids(session, null)); + assertThrows(SecurityException.class, + () -> mCm.setVpnDefaultForUids(session, new ArraySet<>())); + // For testing the complete behavior of setVpnDefaultForUids(), please refer to + // HostsideVpnTests. } private void doTestLegacyLockdownEnabled() throws Exception { @@ -2531,16 +2575,23 @@ tetherUtils.registerTetheringEventCallback(); try { tetherEventCallback.assumeWifiTetheringSupported(mContext); + // To prevent WiFi-to-WiFi interruption while entering APM: + // - If WiFi is retained while entering APM, hotspot will also remain enabled. + // - If WiFi is off before APM or disabled while entering APM, hotspot will be + // disabled. + // + // To ensure hotspot always be disabled after enabling APM, disable wifi before + // enabling the hotspot. + mCtsNetUtils.disableWifi(); - final TestableNetworkCallback wifiCb = new TestableNetworkCallback(); - mCtsNetUtils.ensureWifiConnected(); - registerCallbackAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb); + tetherUtils.startWifiTethering(tetherEventCallback); // Update setting to verify the behavior. setAirplaneMode(true); - // Verify wifi lost to make sure airplane mode takes effect. This could + // Verify softap lost to make sure airplane mode takes effect. This could // prevent the race condition between airplane mode enabled and the followed // up wifi tethering enabled. - waitForLost(wifiCb); + tetherEventCallback.expectNoTetheringActive(); + // start wifi tethering tetherUtils.startWifiTethering(tetherEventCallback); @@ -2565,6 +2616,7 @@ ConnectivitySettingsManager.setPrivateDnsMode(mContext, curPrivateDnsMode); tetherUtils.unregisterTetheringEventCallback(tetherEventCallback); tetherUtils.stopAllTethering(); + mCtsNetUtils.ensureWifiConnected(); } } @@ -2649,7 +2701,8 @@ // Validate that an unmetered network is used over other networks. waitForAvailable(defaultCallback, wifiNetwork); - waitForAvailable(systemDefaultCallback, wifiNetwork); + systemDefaultCallback.eventuallyExpect(CallbackEntry.AVAILABLE, + NETWORK_CALLBACK_TIMEOUT_MS, cb -> wifiNetwork.equals(cb.getNetwork())); // Validate that when setting unmetered to metered, unmetered is lost and replaced by // the network with the TEST transport. Also wait for validation here, in case there @@ -2661,11 +2714,14 @@ // callbacks may be received. Eventually, metered Wi-Fi should be the final available // callback in any case therefore confirm its receipt before continuing to assure the // system is in the expected state. - waitForAvailable(systemDefaultCallback, TRANSPORT_WIFI); + waitForTransport(systemDefaultCallback, TRANSPORT_WIFI); }, /* cleanup */ () -> { - // Validate that removing the test network will fallback to the default network. + // Validate that removing the test network will fallback to the default network. runWithShellPermissionIdentity(tnt::teardown); - defaultCallback.expect(CallbackEntry.LOST, tnt, NETWORK_CALLBACK_TIMEOUT_MS); + // The other callbacks (LP or NC changes) would receive before LOST callback. Use + // eventuallyExpect to check callback for avoiding test flake. + defaultCallback.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS, + lost -> tnt.getNetwork().equals(lost.getNetwork())); waitForAvailable(defaultCallback); }, /* cleanup */ () -> { setWifiMeteredStatusAndWait(ssid, oldMeteredValue, false /* waitForValidation */); @@ -2685,6 +2741,7 @@ // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 // shims, and @IgnoreUpTo does not check that. assumeTrue(TestUtils.shouldTestSApis()); + assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); final TestNetworkTracker tnt = callWithShellPermissionIdentity( () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS)); @@ -2698,7 +2755,8 @@ OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY); registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback); waitForAvailable(defaultCallback, tnt.getNetwork()); - waitForAvailable(systemDefaultCallback, wifiNetwork); + systemDefaultCallback.eventuallyExpect(CallbackEntry.AVAILABLE, + NETWORK_CALLBACK_TIMEOUT_MS, cb -> wifiNetwork.equals(cb.getNetwork())); }, /* cleanup */ () -> { runWithShellPermissionIdentity(tnt::teardown); defaultCallback.expect(CallbackEntry.LOST, tnt, NETWORK_CALLBACK_TIMEOUT_MS); @@ -2922,13 +2980,13 @@ allowBadWifi(); - final Network cellNetwork = mCtsNetUtils.connectToCell(); - final Network wifiNetwork = prepareValidatedNetwork(); - - registerDefaultNetworkCallback(defaultCb); - registerNetworkCallback(makeWifiNetworkRequest(), wifiCb); - try { + final Network cellNetwork = mCtsNetUtils.connectToCell(); + final Network wifiNetwork = prepareValidatedNetwork(); + + registerDefaultNetworkCallback(defaultCb); + registerNetworkCallback(makeWifiNetworkRequest(), wifiCb); + // Verify wifi is the default network. defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, entry -> wifiNetwork.equals(entry.getNetwork())); @@ -2958,7 +3016,7 @@ defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, entry -> cellNetwork.equals(entry.getNetwork())); // The network should not validate again. - wifiCb.assertNoCallbackThat(NO_CALLBACK_TIMEOUT_MS, c -> isValidatedCaps(c)); + wifiCb.assertNoCallback(NO_CALLBACK_TIMEOUT_MS, c -> isValidatedCaps(c)); } finally { resetAvoidBadWifi(previousAvoidBadWifi); mHttpServer.stop(); @@ -3130,7 +3188,7 @@ */ private void assertNoCallbackExceptCapOrLpChange( @NonNull final TestableNetworkCallback cb) { - cb.assertNoCallbackThat(NO_CALLBACK_TIMEOUT_MS, + cb.assertNoCallback(NO_CALLBACK_TIMEOUT_MS, c -> !(c instanceof CallbackEntry.CapabilitiesChanged || c instanceof CallbackEntry.LinkPropertiesChanged)); } @@ -3351,7 +3409,7 @@ } private void checkFirewallBlocking(final DatagramSocket srcSock, final DatagramSocket dstSock, - final boolean expectBlock) throws Exception { + final boolean expectBlock, final int chain) throws Exception { final Random random = new Random(); final byte[] sendData = new byte[100]; random.nextBytes(sendData); @@ -3364,19 +3422,28 @@ if (expectBlock) { return; } - fail("Expect not to be blocked by firewall but sending packet was blocked"); - } - - if (expectBlock) { - fail("Expect to be blocked by firewall but sending packet was not blocked"); + fail("Expect not to be blocked by firewall but sending packet was blocked:" + + " chain=" + chain + + " chainEnabled=" + mCm.getFirewallChainEnabled(chain) + + " uidFirewallRule=" + mCm.getUidFirewallRule(chain, Process.myUid())); } dstSock.receive(pkt); assertArrayEquals(sendData, pkt.getData()); + + if (expectBlock) { + fail("Expect to be blocked by firewall but sending packet was not blocked:" + + " chain=" + chain + + " chainEnabled=" + mCm.getFirewallChainEnabled(chain) + + " uidFirewallRule=" + mCm.getUidFirewallRule(chain, Process.myUid())); + } } private static final boolean EXPECT_PASS = false; private static final boolean EXPECT_BLOCK = true; + + // ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed + // DENYLIST means the firewall allows all by default, uids must be explicitly denyed private static final boolean ALLOWLIST = true; private static final boolean DENYLIST = false; @@ -3388,34 +3455,40 @@ runWithShellPermissionIdentity(() -> { // Firewall chain status will be restored after the test. final boolean wasChainEnabled = mCm.getFirewallChainEnabled(chain); + final int previousUidFirewallRule = mCm.getUidFirewallRule(chain, myUid); final DatagramSocket srcSock = new DatagramSocket(); final DatagramSocket dstSock = new DatagramSocket(); testAndCleanup(() -> { if (wasChainEnabled) { mCm.setFirewallChainEnabled(chain, false /* enable */); } + if (previousUidFirewallRule == ruleToAddMatch) { + mCm.setUidFirewallRule(chain, myUid, ruleToRemoveMatch); + } dstSock.setSoTimeout(SOCKET_TIMEOUT_MS); // Chain disabled, UID not on chain. - checkFirewallBlocking(srcSock, dstSock, EXPECT_PASS); + checkFirewallBlocking(srcSock, dstSock, EXPECT_PASS, chain); // Chain enabled, UID not on chain. mCm.setFirewallChainEnabled(chain, true /* enable */); assertTrue(mCm.getFirewallChainEnabled(chain)); - checkFirewallBlocking(srcSock, dstSock, isAllowList ? EXPECT_BLOCK : EXPECT_PASS); + checkFirewallBlocking( + srcSock, dstSock, isAllowList ? EXPECT_BLOCK : EXPECT_PASS, chain); // Chain enabled, UID on chain. mCm.setUidFirewallRule(chain, myUid, ruleToAddMatch); - checkFirewallBlocking(srcSock, dstSock, isAllowList ? EXPECT_PASS : EXPECT_BLOCK); + checkFirewallBlocking( + srcSock, dstSock, isAllowList ? EXPECT_PASS : EXPECT_BLOCK, chain); // Chain disabled, UID on chain. mCm.setFirewallChainEnabled(chain, false /* enable */); assertFalse(mCm.getFirewallChainEnabled(chain)); - checkFirewallBlocking(srcSock, dstSock, EXPECT_PASS); + checkFirewallBlocking(srcSock, dstSock, EXPECT_PASS, chain); // Chain disabled, UID not on chain. mCm.setUidFirewallRule(chain, myUid, ruleToRemoveMatch); - checkFirewallBlocking(srcSock, dstSock, EXPECT_PASS); + checkFirewallBlocking(srcSock, dstSock, EXPECT_PASS, chain); }, /* cleanup */ () -> { srcSock.close(); dstSock.close(); @@ -3423,8 +3496,9 @@ // Restore the global chain status mCm.setFirewallChainEnabled(chain, wasChainEnabled); }, /* cleanup */ () -> { + // Restore the uid firewall rule status try { - mCm.setUidFirewallRule(chain, myUid, ruleToRemoveMatch); + mCm.setUidFirewallRule(chain, myUid, previousUidFirewallRule); } catch (IllegalStateException ignored) { // Removing match causes an exception when the rule entry for the uid does // not exist. But this is fine and can be ignored. @@ -3435,20 +3509,149 @@ @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest @AppModeFull(reason = "Socket cannot bind in instant app mode") - public void testFirewallBlocking() { - // ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed + public void testFirewallBlockingDozable() { doTestFirewallBlocking(FIREWALL_CHAIN_DOZABLE, ALLOWLIST); - doTestFirewallBlocking(FIREWALL_CHAIN_POWERSAVE, ALLOWLIST); - doTestFirewallBlocking(FIREWALL_CHAIN_RESTRICTED, ALLOWLIST); - doTestFirewallBlocking(FIREWALL_CHAIN_LOW_POWER_STANDBY, ALLOWLIST); + } - // DENYLIST means the firewall allows all by default, uids must be explicitly denyed + @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testFirewallBlockingPowersave() { + doTestFirewallBlocking(FIREWALL_CHAIN_POWERSAVE, ALLOWLIST); + } + + @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testFirewallBlockingRestricted() { + doTestFirewallBlocking(FIREWALL_CHAIN_RESTRICTED, ALLOWLIST); + } + + @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testFirewallBlockingLowPowerStandby() { + doTestFirewallBlocking(FIREWALL_CHAIN_LOW_POWER_STANDBY, ALLOWLIST); + } + + @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testFirewallBlockingStandby() { doTestFirewallBlocking(FIREWALL_CHAIN_STANDBY, DENYLIST); + } + + @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testFirewallBlockingOemDeny1() { doTestFirewallBlocking(FIREWALL_CHAIN_OEM_DENY_1, DENYLIST); + } + + @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testFirewallBlockingOemDeny2() { doTestFirewallBlocking(FIREWALL_CHAIN_OEM_DENY_2, DENYLIST); + } + + @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest + @AppModeFull(reason = "Socket cannot bind in instant app mode") + public void testFirewallBlockingOemDeny3() { doTestFirewallBlocking(FIREWALL_CHAIN_OEM_DENY_3, DENYLIST); } + private void assertSocketOpen(final Socket socket) throws Exception { + mCtsNetUtils.testHttpRequest(socket); + } + + private void assertSocketClosed(final Socket socket) throws Exception { + try { + mCtsNetUtils.testHttpRequest(socket); + fail("Socket is expected to be closed"); + } catch (SocketException expected) { + } + } + + private static final boolean EXPECT_OPEN = false; + private static final boolean EXPECT_CLOSE = true; + + private void doTestFirewallCloseSocket(final int chain, final int rule, final int targetUid, + final boolean expectClose) { + runWithShellPermissionIdentity(() -> { + // Firewall chain status will be restored after the test. + final boolean wasChainEnabled = mCm.getFirewallChainEnabled(chain); + final int previousUidFirewallRule = mCm.getUidFirewallRule(chain, targetUid); + final Socket socket = new Socket(TEST_HOST, HTTP_PORT); + socket.setSoTimeout(NETWORK_REQUEST_TIMEOUT_MS); + testAndCleanup(() -> { + mCm.setFirewallChainEnabled(chain, false /* enable */); + assertSocketOpen(socket); + + try { + mCm.setUidFirewallRule(chain, targetUid, rule); + } catch (IllegalStateException ignored) { + // Removing match causes an exception when the rule entry for the uid does + // not exist. But this is fine and can be ignored. + } + mCm.setFirewallChainEnabled(chain, true /* enable */); + + if (expectClose) { + assertSocketClosed(socket); + } else { + assertSocketOpen(socket); + } + }, /* cleanup */ () -> { + // Restore the global chain status + mCm.setFirewallChainEnabled(chain, wasChainEnabled); + }, /* cleanup */ () -> { + // Restore the uid firewall rule status + try { + mCm.setUidFirewallRule(chain, targetUid, previousUidFirewallRule); + } catch (IllegalStateException ignored) { + // Removing match causes an exception when the rule entry for the uid does + // not exist. But this is fine and can be ignored. + } + }, /* cleanup */ () -> { + socket.close(); + }); + }, NETWORK_SETTINGS); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest + public void testFirewallCloseSocketAllowlistChainAllow() { + doTestFirewallCloseSocket(FIREWALL_CHAIN_DOZABLE, FIREWALL_RULE_ALLOW, + Process.myUid(), EXPECT_OPEN); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest + public void testFirewallCloseSocketAllowlistChainDeny() { + doTestFirewallCloseSocket(FIREWALL_CHAIN_DOZABLE, FIREWALL_RULE_DENY, + Process.myUid(), EXPECT_CLOSE); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest + public void testFirewallCloseSocketAllowlistChainOtherUid() { + doTestFirewallCloseSocket(FIREWALL_CHAIN_DOZABLE, FIREWALL_RULE_ALLOW, + Process.myUid() + 1, EXPECT_CLOSE); + doTestFirewallCloseSocket(FIREWALL_CHAIN_DOZABLE, FIREWALL_RULE_DENY, + Process.myUid() + 1, EXPECT_CLOSE); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest + public void testFirewallCloseSocketDenylistChainAllow() { + doTestFirewallCloseSocket(FIREWALL_CHAIN_STANDBY, FIREWALL_RULE_ALLOW, + Process.myUid(), EXPECT_OPEN); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest + public void testFirewallCloseSocketDenylistChainDeny() { + doTestFirewallCloseSocket(FIREWALL_CHAIN_STANDBY, FIREWALL_RULE_DENY, + Process.myUid(), EXPECT_CLOSE); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest + public void testFirewallCloseSocketDenylistChainOtherUid() { + doTestFirewallCloseSocket(FIREWALL_CHAIN_STANDBY, FIREWALL_RULE_ALLOW, + Process.myUid() + 1, EXPECT_OPEN); + doTestFirewallCloseSocket(FIREWALL_CHAIN_STANDBY, FIREWALL_RULE_DENY, + Process.myUid() + 1, EXPECT_OPEN); + } + private void assumeTestSApis() { // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 // shims, and @IgnoreUpTo does not check that.
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt index 7e91478..732a42b 100644 --- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt +++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -57,8 +57,8 @@ import android.os.Handler import android.os.Looper import android.os.OutcomeReceiver -import android.os.SystemProperties import android.os.Process +import android.os.SystemProperties import android.platform.test.annotations.AppModeFull import androidx.test.platform.app.InstrumentationRegistry import com.android.net.module.util.ArrayTrackRecord @@ -77,16 +77,10 @@ import com.android.testutils.assertThrows import com.android.testutils.runAsShell import com.android.testutils.waitForIdle -import org.junit.After -import org.junit.Assume.assumeFalse -import org.junit.Assume.assumeTrue -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith import java.io.IOException import java.net.Inet6Address -import java.util.Random import java.net.Socket +import java.util.Random import java.util.concurrent.CompletableFuture import java.util.concurrent.ExecutionException import java.util.concurrent.TimeUnit @@ -99,6 +93,12 @@ import kotlin.test.assertNull import kotlin.test.assertTrue import kotlin.test.fail +import org.junit.After +import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith private const val TAG = "EthernetManagerTest" // This timeout does not affect the test duration for passing tests. It needs to be long enough to @@ -392,7 +392,15 @@ } // Setting the carrier up / down relies on TUNSETCARRIER which was added in kernel version 5.0. - private fun assumeChangingCarrierSupported() = assumeTrue(isKernelVersionAtLeast("5.0.0")) + private fun assumeChangingCarrierSupported() { + assumeTrue(isKernelVersionAtLeast("5.0.0")) + } + + // Configuring a tap interface without carrier relies on IFF_NO_CARRIER + // which was added in kernel version 6.0. + private fun assumeCreateInterfaceWithoutCarrierSupported() { + assumeTrue(isKernelVersionAtLeast("6.0.0")) + } private fun isAdbOverEthernet(): Boolean { // If no ethernet interface is available, adb is not connected over ethernet. @@ -417,7 +425,7 @@ } // WARNING: setting hasCarrier to false requires kernel support. Call - // assumeChangingCarrierSupported() at the top of your test. + // assumeCreateInterfaceWithoutCarrierSupported() at the top of your test. private fun createInterface(hasCarrier: Boolean = true): EthernetTestInterface { val iface = EthernetTestInterface( context, @@ -530,12 +538,10 @@ eventuallyExpect(Lost::class) { n?.equals(it.network) ?: true } private fun TestableNetworkCallback.assertNeverLost(n: Network? = null) = - assertNoCallbackThat() { - it is Lost && (n?.equals(it.network) ?: true) - } + assertNoCallback { it is Lost && (n?.equals(it.network) ?: true) } private fun TestableNetworkCallback.assertNeverAvailable(n: Network? = null) = - assertNoCallbackThat { it is Available && (n?.equals(it.network) ?: true) } + assertNoCallback { it is Available && (n?.equals(it.network) ?: true) } private fun TestableNetworkCallback.expectCapabilitiesWithInterfaceName(name: String) = expect<CapabilitiesChanged> { it.caps.networkSpecifier == EthernetNetworkSpecifier(name) } @@ -646,10 +652,9 @@ val listener = EthernetStateListener() addInterfaceStateListener(listener) - // TODO(b/236895792): THIS IS A BUG! Existing server mode interfaces are not reported when - // an InterfaceStateListener is registered. // Note: using eventuallyExpect as there may be other interfaces present. - // listener.eventuallyExpect(iface, STATE_LINK_UP, ROLE_SERVER) + listener.eventuallyExpect(InterfaceStateChanged(iface.name, + STATE_LINK_UP, ROLE_SERVER, /* IpConfiguration */ null)) releaseTetheredInterface() listener.eventuallyExpect(iface, STATE_LINK_UP, ROLE_CLIENT) @@ -794,15 +799,13 @@ @Test fun testNetworkRequest_forInterfaceWhileTogglingCarrier() { + assumeCreateInterfaceWithoutCarrierSupported() assumeChangingCarrierSupported() val iface = createInterface(false /* hasCarrier */) val cb = requestNetwork(ETH_REQUEST) - // TUNSETCARRIER races with the bring up code, so the network *can* become available despite - // it being "created with no carrier". - // TODO(b/249611919): re-enable assertion once kernel supports IFF_NO_CARRIER. - // cb.assertNeverAvailable() + cb.assertNeverAvailable() iface.setCarrierEnabled(true) cb.expect<Available>()
diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java index ac50740..805dd65 100644 --- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java +++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
@@ -60,7 +60,11 @@ import com.android.internal.util.HexDump; import com.android.networkstack.apishim.ConstantsShim; +import com.android.networkstack.apishim.Ikev2VpnProfileBuilderShimImpl; +import com.android.networkstack.apishim.Ikev2VpnProfileShimImpl; import com.android.networkstack.apishim.VpnManagerShimImpl; +import com.android.networkstack.apishim.common.Ikev2VpnProfileBuilderShim; +import com.android.networkstack.apishim.common.Ikev2VpnProfileShim; import com.android.networkstack.apishim.common.VpnManagerShim; import com.android.networkstack.apishim.common.VpnProfileStateShim; import com.android.testutils.DevSdkIgnoreRule; @@ -223,17 +227,28 @@ } private Ikev2VpnProfile buildIkev2VpnProfileCommon( - @NonNull Ikev2VpnProfile.Builder builder, boolean isRestrictedToTestNetworks, - boolean requiresValidation) throws Exception { + @NonNull Ikev2VpnProfileBuilderShim builderShim, boolean isRestrictedToTestNetworks, + boolean requiresValidation, boolean automaticIpVersionSelectionEnabled, + boolean automaticNattKeepaliveTimerEnabled) throws Exception { - builder.setBypassable(true) + builderShim.setBypassable(true) .setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS) .setProxy(TEST_PROXY_INFO) .setMaxMtu(TEST_MTU) .setMetered(false); if (TestUtils.shouldTestTApis()) { - builder.setRequiresInternetValidation(requiresValidation); + builderShim.setRequiresInternetValidation(requiresValidation); } + + if (TestUtils.shouldTestUApis()) { + builderShim.setAutomaticIpVersionSelectionEnabled(automaticIpVersionSelectionEnabled); + builderShim.setAutomaticNattKeepaliveTimerEnabled(automaticNattKeepaliveTimerEnabled); + } + + // Convert shim back to Ikev2VpnProfile.Builder since restrictToTestNetworks is a hidden + // method and is not defined in shims. + // TODO: replace it in alternative way to remove the hidden method usage + final Ikev2VpnProfile.Builder builder = (Ikev2VpnProfile.Builder) builderShim.getBuilder(); if (isRestrictedToTestNetworks) { builder.restrictToTestNetworks(); } @@ -249,13 +264,16 @@ ? IkeSessionTestUtils.IKE_PARAMS_V6 : IkeSessionTestUtils.IKE_PARAMS_V4, IkeSessionTestUtils.CHILD_PARAMS); - final Ikev2VpnProfile.Builder builder = - new Ikev2VpnProfile.Builder(params) + final Ikev2VpnProfileBuilderShim builderShim = + Ikev2VpnProfileBuilderShimImpl.newInstance(params) .setRequiresInternetValidation(requiresValidation) .setProxy(TEST_PROXY_INFO) .setMaxMtu(TEST_MTU) .setMetered(false); - + // Convert shim back to Ikev2VpnProfile.Builder since restrictToTestNetworks is a hidden + // method and is not defined in shims. + // TODO: replace it in alternative way to remove the hidden method usage + final Ikev2VpnProfile.Builder builder = (Ikev2VpnProfile.Builder) builderShim.getBuilder(); if (isRestrictedToTestNetworks) { builder.restrictToTestNetworks(); } @@ -263,31 +281,35 @@ } private Ikev2VpnProfile buildIkev2VpnProfilePsk(@NonNull String remote, - boolean isRestrictedToTestNetworks, boolean requiresValidation) throws Exception { - final Ikev2VpnProfile.Builder builder = - new Ikev2VpnProfile.Builder(remote, TEST_IDENTITY).setAuthPsk(TEST_PSK); + boolean isRestrictedToTestNetworks, boolean requiresValidation) + throws Exception { + final Ikev2VpnProfileBuilderShim builder = + Ikev2VpnProfileBuilderShimImpl.newInstance(remote, TEST_IDENTITY) + .setAuthPsk(TEST_PSK); return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks, - requiresValidation); + requiresValidation, false /* automaticIpVersionSelectionEnabled */, + false /* automaticNattKeepaliveTimerEnabled */); } private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks) throws Exception { - - final Ikev2VpnProfile.Builder builder = - new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY) + final Ikev2VpnProfileBuilderShim builder = + Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY) .setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa); return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks, - false /* requiresValidation */); + false /* requiresValidation */, false /* automaticIpVersionSelectionEnabled */, + false /* automaticNattKeepaliveTimerEnabled */); } private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks) throws Exception { - final Ikev2VpnProfile.Builder builder = - new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY) + final Ikev2VpnProfileBuilderShim builder = + Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY) .setAuthDigitalSignature( mUserCertKey.cert, mUserCertKey.key, mServerRootCa); return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks, - false /* requiresValidation */); + false /* requiresValidation */, false /* automaticIpVersionSelectionEnabled */, + false /* automaticNattKeepaliveTimerEnabled */); } private void checkBasicIkev2VpnProfile(@NonNull Ikev2VpnProfile profile) throws Exception { @@ -529,11 +551,10 @@ assertFalse(profileState.isLockdownEnabled()); } - cb.expectCapabilitiesThat(vpnNetwork, TIMEOUT_MS, - caps -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasCapability(NET_CAPABILITY_INTERNET) - && !caps.hasCapability(NET_CAPABILITY_VALIDATED) - && Process.myUid() == caps.getOwnerUid()); + cb.expectCaps(vpnNetwork, TIMEOUT_MS, c -> c.hasTransport(TRANSPORT_VPN) + && c.hasCapability(NET_CAPABILITY_INTERNET) + && !c.hasCapability(NET_CAPABILITY_VALIDATED) + && Process.myUid() == c.getOwnerUid()); cb.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, vpnNetwork); cb.expect(CallbackEntry.BLOCKED_STATUS, vpnNetwork); @@ -688,6 +709,56 @@ true /* testSessionKey */, false /* testIkeTunConnParams */); } + @Test + public void testBuildIkev2VpnProfileWithAutomaticNattKeepaliveTimerEnabled() throws Exception { + // Cannot use @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) because this test also requires API + // 34 shims, and @IgnoreUpTo does not check that. + assumeTrue(TestUtils.shouldTestUApis()); + + final Ikev2VpnProfile profileWithDefaultValue = buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6, + false /* isRestrictedToTestNetworks */, false /* requiresValidation */); + final Ikev2VpnProfileShim<Ikev2VpnProfile> shimWithDefaultValue = + Ikev2VpnProfileShimImpl.newInstance(profileWithDefaultValue); + assertFalse(shimWithDefaultValue.isAutomaticNattKeepaliveTimerEnabled()); + + final Ikev2VpnProfileBuilderShim builder = + Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY) + .setAuthPsk(TEST_PSK); + final Ikev2VpnProfile profile = buildIkev2VpnProfileCommon(builder, + false /* isRestrictedToTestNetworks */, + false /* requiresValidation */, + false /* automaticIpVersionSelectionEnabled */, + true /* automaticNattKeepaliveTimerEnabled */); + final Ikev2VpnProfileShim<Ikev2VpnProfile> shim = + Ikev2VpnProfileShimImpl.newInstance(profile); + assertTrue(shim.isAutomaticNattKeepaliveTimerEnabled()); + } + + @Test + public void testBuildIkev2VpnProfileWithAutomaticIpVersionSelectionEnabled() throws Exception { + // Cannot use @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) because this test also requires API + // 34 shims, and @IgnoreUpTo does not check that. + assumeTrue(TestUtils.shouldTestUApis()); + + final Ikev2VpnProfile profileWithDefaultValue = buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6, + false /* isRestrictedToTestNetworks */, false /* requiresValidation */); + final Ikev2VpnProfileShim<Ikev2VpnProfile> shimWithDefaultValue = + Ikev2VpnProfileShimImpl.newInstance(profileWithDefaultValue); + assertFalse(shimWithDefaultValue.isAutomaticIpVersionSelectionEnabled()); + + final Ikev2VpnProfileBuilderShim builder = + Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY) + .setAuthPsk(TEST_PSK); + final Ikev2VpnProfile profile = buildIkev2VpnProfileCommon(builder, + false /* isRestrictedToTestNetworks */, + false /* requiresValidation */, + true /* automaticIpVersionSelectionEnabled */, + false /* automaticNattKeepaliveTimerEnabled */); + final Ikev2VpnProfileShim<Ikev2VpnProfile> shim = + Ikev2VpnProfileShimImpl.newInstance(profile); + assertTrue(shim.isAutomaticIpVersionSelectionEnabled()); + } + private static class CertificateAndKey { public final X509Certificate cert; public final PrivateKey key;
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 8234ec1..cc0a5df 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -16,6 +16,7 @@ package android.net.cts; +import static android.Manifest.permission.NETWORK_SETTINGS; import static android.net.IpSecAlgorithm.AUTH_AES_CMAC; import static android.net.IpSecAlgorithm.AUTH_AES_XCBC; import static android.net.IpSecAlgorithm.AUTH_CRYPT_AES_GCM; @@ -52,7 +53,9 @@ import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel; import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel; +import static com.android.testutils.DeviceInfoUtils.isKernelVersionAtLeast; import static com.android.testutils.MiscAsserts.assertThrows; +import static com.android.testutils.TestPermissionUtil.runAsShell; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -62,6 +65,8 @@ import android.net.IpSecAlgorithm; import android.net.IpSecManager; +import android.net.IpSecManager.SecurityParameterIndex; +import android.net.IpSecManager.UdpEncapsulationSocket; import android.net.IpSecTransform; import android.net.TrafficStats; import android.os.Build; @@ -73,6 +78,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.modules.utils.build.SdkLevel; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; @@ -120,7 +126,7 @@ @Test public void testAllocSpi() throws Exception { for (InetAddress addr : GOOGLE_DNS_LIST) { - IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null; + SecurityParameterIndex randomSpi, droidSpi; randomSpi = mISM.allocateSecurityParameterIndex(addr); assertTrue( "Failed to receive a valid SPI", @@ -258,6 +264,24 @@ accepted.close(); } + private IpSecTransform buildTransportModeTransform( + SecurityParameterIndex spi, InetAddress localAddr, + UdpEncapsulationSocket encapSocket) + throws Exception { + final IpSecTransform.Builder builder = + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) + .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + new IpSecAlgorithm( + IpSecAlgorithm.AUTH_HMAC_SHA256, + AUTH_KEY, + AUTH_KEY.length * 8)); + if (encapSocket != null) { + builder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); + } + return builder.buildTransportModeTransform(localAddr, spi); + } + /* * Alloc outbound SPI * Alloc inbound SPI @@ -268,21 +292,8 @@ * release transform * send data (expect exception) */ - @Test - public void testCreateTransform() throws Exception { - InetAddress localAddr = InetAddress.getByName(IPV4_LOOPBACK); - IpSecManager.SecurityParameterIndex spi = - mISM.allocateSecurityParameterIndex(localAddr); - - IpSecTransform transform = - new IpSecTransform.Builder(InstrumentationRegistry.getContext()) - .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) - .setAuthentication( - new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA256, - AUTH_KEY, - AUTH_KEY.length * 8)) - .buildTransportModeTransform(localAddr, spi); + private void doTestCreateTransform(String loopbackAddrString, boolean encap) throws Exception { + InetAddress localAddr = InetAddress.getByName(loopbackAddrString); final boolean [][] applyInApplyOut = { {false, false}, {false, true}, {true, false}, {true,true}}; @@ -291,57 +302,110 @@ byte[] in = new byte[data.length]; DatagramPacket inPacket = new DatagramPacket(in, in.length); - DatagramSocket localSocket; int localPort; for(boolean[] io : applyInApplyOut) { boolean applyIn = io[0]; boolean applyOut = io[1]; - // Bind localSocket to a random available port. - localSocket = new DatagramSocket(0); - localPort = localSocket.getLocalPort(); - localSocket.setSoTimeout(200); - outPacket.setPort(localPort); - if (applyIn) { - mISM.applyTransportModeTransform( - localSocket, IpSecManager.DIRECTION_IN, transform); - } - if (applyOut) { - mISM.applyTransportModeTransform( - localSocket, IpSecManager.DIRECTION_OUT, transform); - } - if (applyIn == applyOut) { - localSocket.send(outPacket); - localSocket.receive(inPacket); - assertTrue("Encapsulated data did not match.", - Arrays.equals(outPacket.getData(), inPacket.getData())); - mISM.removeTransportModeTransforms(localSocket); - localSocket.close(); - } else { - try { + try ( + SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(localAddr); + UdpEncapsulationSocket encapSocket = encap + ? getPrivilegedUdpEncapSocket(/*ipv6=*/ localAddr instanceof Inet6Address) + : null; + IpSecTransform transform = buildTransportModeTransform(spi, localAddr, + encapSocket); + // Bind localSocket to a random available port. + DatagramSocket localSocket = new DatagramSocket(0); + ) { + localPort = localSocket.getLocalPort(); + localSocket.setSoTimeout(200); + outPacket.setPort(localPort); + if (applyIn) { + mISM.applyTransportModeTransform( + localSocket, IpSecManager.DIRECTION_IN, transform); + } + if (applyOut) { + mISM.applyTransportModeTransform( + localSocket, IpSecManager.DIRECTION_OUT, transform); + } + if (applyIn == applyOut) { localSocket.send(outPacket); localSocket.receive(inPacket); - } catch (IOException e) { - continue; - } finally { + assertTrue("Encrypted data did not match.", + Arrays.equals(outPacket.getData(), inPacket.getData())); mISM.removeTransportModeTransforms(localSocket); - localSocket.close(); + } else { + try { + localSocket.send(outPacket); + localSocket.receive(inPacket); + } catch (IOException e) { + continue; + } finally { + mISM.removeTransportModeTransforms(localSocket); + } + // FIXME: This check is disabled because sockets currently receive data + // if there is a valid SA for decryption, even when the input policy is + // not applied to a socket. + // fail("Data IO should fail on asymmetrical transforms! + Input=" + // + applyIn + " Output=" + applyOut); } - // FIXME: This check is disabled because sockets currently receive data - // if there is a valid SA for decryption, even when the input policy is - // not applied to a socket. - // fail("Data IO should fail on asymmetrical transforms! + Input=" - // + applyIn + " Output=" + applyOut); } } - transform.close(); + } + + private UdpEncapsulationSocket getPrivilegedUdpEncapSocket(boolean ipv6) throws Exception { + return runAsShell(NETWORK_SETTINGS, () -> { + if (ipv6) { + return mISM.openUdpEncapsulationSocket(65536); + } else { + // Can't pass 0 to IpSecManager#openUdpEncapsulationSocket(int). + return mISM.openUdpEncapsulationSocket(); + } + }); + } + + private static boolean isIpv6UdpEncapSupportedByKernel() { + return isKernelVersionAtLeast("5.15.31") + || (isKernelVersionAtLeast("5.10.108") && !isKernelVersionAtLeast("5.15.0")); + } + + // Packet private for use in IpSecManagerTunnelTest + static boolean isIpv6UdpEncapSupported() { + return SdkLevel.isAtLeastU() && isIpv6UdpEncapSupportedByKernel(); + } + + // Packet private for use in IpSecManagerTunnelTest + static void assumeExperimentalIpv6UdpEncapSupported() throws Exception { + assumeTrue("Not supported before U", SdkLevel.isAtLeastU()); + assumeTrue("Not supported by kernel", isIpv6UdpEncapSupportedByKernel()); + } + + @Test + public void testCreateTransformIpv4() throws Exception { + doTestCreateTransform(IPV4_LOOPBACK, false); + } + + @Test + public void testCreateTransformIpv6() throws Exception { + doTestCreateTransform(IPV6_LOOPBACK, false); + } + + @Test + public void testCreateTransformIpv4Encap() throws Exception { + doTestCreateTransform(IPV4_LOOPBACK, true); + } + + @Test + public void testCreateTransformIpv6Encap() throws Exception { + assumeExperimentalIpv6UdpEncapSupported(); + doTestCreateTransform(IPV6_LOOPBACK, true); } /** Snapshot of TrafficStats as of initStatsChecker call for later comparisons */ private static class StatsChecker { private static final double ERROR_MARGIN_BYTES = 1.05; private static final double ERROR_MARGIN_PKTS = 1.05; - private static final int MAX_WAIT_TIME_MILLIS = 1000; + private static final int MAX_WAIT_TIME_MILLIS = 3000; private static long uidTxBytes; private static long uidRxBytes; @@ -393,9 +457,8 @@ long newUidRxPackets = TrafficStats.getUidRxPackets(Os.getuid()); assertEquals(expectedTxByteDelta, newUidTxBytes - uidTxBytes); - assertTrue( - newUidRxBytes - uidRxBytes >= minRxByteDelta - && newUidRxBytes - uidRxBytes <= maxRxByteDelta); + assertTrue("Not enough bytes", newUidRxBytes - uidRxBytes >= minRxByteDelta); + assertTrue("Too many bytes", newUidRxBytes - uidRxBytes <= maxRxByteDelta); assertEquals(expectedTxPacketDelta, newUidTxPackets - uidTxPackets); assertEquals(expectedRxPacketDelta, newUidRxPackets - uidRxPackets); } @@ -503,8 +566,8 @@ StatsChecker.initStatsChecker(); InetAddress local = InetAddress.getByName(localAddress); - try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket(); - IpSecManager.SecurityParameterIndex spi = + try (UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket(); + SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(local)) { IpSecTransform.Builder transformBuilder = @@ -656,7 +719,7 @@ public void testIkeOverUdpEncapSocket() throws Exception { // IPv6 not supported for UDP-encap-ESP InetAddress local = InetAddress.getByName(IPV4_LOOPBACK); - try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + try (UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { NativeUdpSocket wrappedEncapSocket = new NativeUdpSocket(encapSocket.getFileDescriptor()); checkIkePacket(wrappedEncapSocket, local); @@ -665,7 +728,7 @@ IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); - try (IpSecManager.SecurityParameterIndex spi = + try (SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(local); IpSecTransform transform = new IpSecTransform.Builder(InstrumentationRegistry.getContext()) @@ -1498,7 +1561,7 @@ @Test public void testOpenUdpEncapSocketSpecificPort() throws Exception { - IpSecManager.UdpEncapsulationSocket encapSocket = null; + UdpEncapsulationSocket encapSocket = null; int port = -1; for (int i = 0; i < MAX_PORT_BIND_ATTEMPTS; i++) { try { @@ -1527,7 +1590,7 @@ @Test public void testOpenUdpEncapSocketRandomPort() throws Exception { - try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + try (UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { assertTrue("Returned invalid port", encapSocket.getPort() != 0); } }
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index a9a3380..1ede5c1 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java
@@ -18,6 +18,8 @@ import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; import static android.net.IpSecManager.UdpEncapsulationSocket; +import static android.net.cts.IpSecManagerTest.assumeExperimentalIpv6UdpEncapSupported; +import static android.net.cts.IpSecManagerTest.isIpv6UdpEncapSupported; import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE; import static android.net.cts.PacketUtils.AES_CBC_IV_LEN; import static android.net.cts.PacketUtils.BytePayload; @@ -32,10 +34,13 @@ import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; +import static com.android.compatibility.common.util.PropertyUtil.getVsrApiLevel; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; @@ -73,6 +78,7 @@ import java.net.InetAddress; import java.net.NetworkInterface; +// TODO: b/268552823 Improve the readability of IpSecManagerTunnelTest @RunWith(AndroidJUnit4.class) @AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") public class IpSecManagerTunnelTest extends IpSecBaseTest { @@ -107,6 +113,7 @@ private static final int IP4_PREFIX_LEN = 32; private static final int IP6_PREFIX_LEN = 128; + private static final int IP6_UDP_ENCAP_SOCKET_PORT_ANY = 65536; private static final int TIMEOUT_MS = 500; @@ -255,14 +262,23 @@ * * @param ipsecNetwork The IPsec Interface based Network for binding sockets on * @param tunnelIface The IPsec tunnel interface that will be tested - * @param underlyingTunUtils The utility of the IPsec tunnel interface's underlying TUN - * network - * @return the integer port of the inner socket if outbound, or 0 if inbound - * IpSecTunnelTestRunnable + * @param tunUtils The utility of the IPsec tunnel interface's underlying TUN network + * @param inTunnelTransform The inbound tunnel mode transform + * @param outTunnelTransform The outbound tunnel mode transform + * @param localOuter The local address of the outer IP packet + * @param remoteOuter The remote address of the outer IP packet + * @param seqNum The expected sequence number of the inbound packet * @throws Exception if any part of the test failed. */ public abstract int run( - Network ipsecNetwork, IpSecTunnelInterface tunnelIface, TunUtils underlyingTunUtils) + Network ipsecNetwork, + IpSecTunnelInterface tunnelIface, + TunUtils tunUtils, + IpSecTransform inTunnelTransform, + IpSecTransform outTunnelTransform, + InetAddress localOuter, + InetAddress remoteOuter, + int seqNum) throws Exception; } @@ -297,19 +313,41 @@ return expectedPacketSize; } + private UdpEncapsulationSocket openUdpEncapsulationSocket(int ipVersion) throws Exception { + if (ipVersion == AF_INET) { + return mISM.openUdpEncapsulationSocket(); + } + + if (!isIpv6UdpEncapSupported()) { + throw new UnsupportedOperationException("IPv6 UDP encapsulation unsupported"); + } + + return mISM.openUdpEncapsulationSocket(IP6_UDP_ENCAP_SOCKET_PORT_ANY); + } + private interface IpSecTunnelTestRunnableFactory { + /** + * Build a IpSecTunnelTestRunnable. + * + * @param transportInTunnelMode indicate if there needs to be a transport mode transform + * inside the tunnel mode transform + * @param spi The IPsec SPI + * @param localInner The local address of the inner IP packet + * @param remoteInner The remote address of the inner IP packet + * @param inTransportTransform The inbound transport mode transform + * @param outTransportTransform The outbound transport mode transform + * @param encapSocket The UDP encapsulation socket or null + * @param innerSocketPort The inner socket port + */ IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( boolean transportInTunnelMode, int spi, InetAddress localInner, InetAddress remoteInner, - InetAddress localOuter, - InetAddress remoteOuter, IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, - int encapPort, - int innerSocketPort, - int expectedPacketSize) + UdpEncapsulationSocket encapSocket, + int innerSocketPort) throws Exception; } @@ -319,17 +357,21 @@ int spi, InetAddress localInner, InetAddress remoteInner, - InetAddress localOuter, - InetAddress remoteOuter, IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, - int encapPort, - int unusedInnerSocketPort, - int expectedPacketSize) { + UdpEncapsulationSocket encapSocket, + int unusedInnerSocketPort) { return new IpSecTunnelTestRunnable() { @Override public int run( - Network ipsecNetwork, IpSecTunnelInterface tunnelIface, TunUtils tunUtils) + Network ipsecNetwork, + IpSecTunnelInterface tunnelIface, + TunUtils tunUtils, + IpSecTransform inTunnelTransform, + IpSecTransform outTunnelTransform, + InetAddress localOuter, + InetAddress remoteOuter, + int seqNum) throws Exception { // Build a socket and send traffic JavaUdpSocket socket = new JavaUdpSocket(localInner); @@ -349,9 +391,14 @@ // Verify that an encrypted packet is sent. As of right now, checking encrypted // body is not possible, due to the test not knowing some of the fields of the // inner IP header (flow label, flags, etc) + int innerFamily = localInner instanceof Inet4Address ? AF_INET : AF_INET6; + int outerFamily = localOuter instanceof Inet4Address ? AF_INET : AF_INET6; + boolean useEncap = encapSocket != null; + int expectedPacketSize = + getPacketSize( + innerFamily, outerFamily, useEncap, transportInTunnelMode); tunUtils.awaitEspPacketNoPlaintext( - spi, TEST_DATA, encapPort != 0, expectedPacketSize); - + spi, TEST_DATA, useEncap, expectedPacketSize); socket.close(); return innerSocketPort; @@ -367,18 +414,22 @@ int spi, InetAddress localInner, InetAddress remoteInner, - InetAddress localOuter, - InetAddress remoteOuter, IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, - int encapPort, - int innerSocketPort, - int expectedPacketSize) + UdpEncapsulationSocket encapSocket, + int innerSocketPort) throws Exception { return new IpSecTunnelTestRunnable() { @Override public int run( - Network ipsecNetwork, IpSecTunnelInterface tunnelIface, TunUtils tunUtils) + Network ipsecNetwork, + IpSecTunnelInterface tunnelIface, + TunUtils tunUtils, + IpSecTransform inTunnelTransform, + IpSecTransform outTunnelTransform, + InetAddress localOuter, + InetAddress remoteOuter, + int seqNum) throws Exception { // Build a socket and receive traffic JavaUdpSocket socket = new JavaUdpSocket(localInner, innerSocketPort); @@ -412,18 +463,22 @@ int spi, InetAddress localInner, InetAddress remoteInner, - InetAddress localOuter, - InetAddress remoteOuter, IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, - int encapPort, - int innerSocketPort, - int expectedPacketSize) + UdpEncapsulationSocket encapSocket, + int innerSocketPort) throws Exception { return new IpSecTunnelTestRunnable() { @Override public int run( - Network ipsecNetwork, IpSecTunnelInterface tunnelIface, TunUtils tunUtils) + Network ipsecNetwork, + IpSecTunnelInterface tunnelIface, + TunUtils tunUtils, + IpSecTransform inTunnelTransform, + IpSecTransform outTunnelTransform, + InetAddress localOuter, + InetAddress remoteOuter, + int seqNum) throws Exception { // Build a socket and receive traffic JavaUdpSocket socket = new JavaUdpSocket(localInner); @@ -448,7 +503,8 @@ remoteOuter, localOuter, socket.getPort(), - encapPort); + encapSocket != null ? encapSocket.getPort() : 0, + seqNum); } else { pkt = getTunnelModePacket( @@ -458,7 +514,8 @@ remoteOuter, localOuter, socket.getPort(), - encapPort); + encapSocket != null ? encapSocket.getPort() : 0, + seqNum); } tunUtils.injectPacket(pkt); @@ -475,13 +532,16 @@ private class MigrateIpSecTunnelTestRunnableFactory implements IpSecTunnelTestRunnableFactory { private final IpSecTunnelTestRunnableFactory mTestRunnableFactory; + private final boolean mTestEncapTypeChange; - MigrateIpSecTunnelTestRunnableFactory(boolean isOutputTest) { + MigrateIpSecTunnelTestRunnableFactory(boolean isOutputTest, boolean testEncapTypeChange) { if (isOutputTest) { mTestRunnableFactory = new OutputIpSecTunnelTestRunnableFactory(); } else { mTestRunnableFactory = new InputPacketGeneratorIpSecTunnelTestRunnableFactory(); } + + mTestEncapTypeChange = testEncapTypeChange; } @Override @@ -490,17 +550,21 @@ int spi, InetAddress localInner, InetAddress remoteInner, - InetAddress localOuter, - InetAddress remoteOuter, IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, - int encapPort, - int unusedInnerSocketPort, - int expectedPacketSize) { + UdpEncapsulationSocket encapSocket, + int unusedInnerSocketPort) { return new IpSecTunnelTestRunnable() { @Override public int run( - Network ipsecNetwork, IpSecTunnelInterface tunnelIface, TunUtils tunUtils) + Network ipsecNetwork, + IpSecTunnelInterface tunnelIface, + TunUtils tunUtils, + IpSecTransform inTunnelTransform, + IpSecTransform outTunnelTransform, + InetAddress localOuter, + InetAddress remoteOuter, + int seqNum) throws Exception { mTestRunnableFactory .getIpSecTunnelTestRunnable( @@ -508,17 +572,25 @@ spi, localInner, remoteInner, - localOuter, - remoteOuter, inTransportTransform, outTransportTransform, - encapPort, - unusedInnerSocketPort, - expectedPacketSize) - .run(ipsecNetwork, tunnelIface, sTunWrapper.utils); - + encapSocket, + unusedInnerSocketPort) + .run( + ipsecNetwork, + tunnelIface, + tunUtils, + inTunnelTransform, + outTunnelTransform, + localOuter, + remoteOuter, + seqNum); tunnelIface.setUnderlyingNetwork(sTunWrapperNew.network); + final boolean useEncapBeforeMigrate = encapSocket != null; + final boolean useEncapAfterMigrate = + mTestEncapTypeChange ? !useEncapBeforeMigrate : useEncapBeforeMigrate; + // Verify migrating to IPv4 and IPv6 addresses. It ensures that not only // can IPsec tunnel migrate across interfaces, IPsec tunnel can also migrate to // a different address on the same interface. @@ -527,21 +599,24 @@ remoteInner, LOCAL_OUTER_4_NEW, REMOTE_OUTER_4_NEW, - encapPort != 0, + useEncapAfterMigrate, transportInTunnelMode, sTunWrapperNew.utils, tunnelIface, ipsecNetwork); - checkMigratedTunnel( - localInner, - remoteInner, - LOCAL_OUTER_6_NEW, - REMOTE_OUTER_6_NEW, - false, // IPv6 does not support UDP encapsulation - transportInTunnelMode, - sTunWrapperNew.utils, - tunnelIface, - ipsecNetwork); + + if (!useEncapAfterMigrate || isIpv6UdpEncapSupported()) { + checkMigratedTunnel( + localInner, + remoteInner, + LOCAL_OUTER_6_NEW, + REMOTE_OUTER_6_NEW, + useEncapAfterMigrate, + transportInTunnelMode, + sTunWrapperNew.utils, + tunnelIface, + ipsecNetwork); + } return 0; } @@ -581,7 +656,8 @@ buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); IpSecTransform outTransportTransform = buildIpSecTransform(sContext, outTransportSpi, null, localInner); - UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + UdpEncapsulationSocket encapSocket = + useEncap ? openUdpEncapsulationSocket(outerFamily) : null) { // Configure tunnel mode Transform parameters IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); @@ -591,7 +667,7 @@ new IpSecAlgorithm( IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4)); - if (useEncap) { + if (encapSocket != null) { transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); } @@ -615,19 +691,152 @@ spi, localInner, remoteInner, - localOuter, - remoteOuter, inTransportTransform, outTransportTransform, - useEncap ? encapSocket.getPort() : 0, - 0, - expectedPacketSize) - .run(ipsecNetwork, tunnelIface, tunUtils); + encapSocket, + 0) + .run( + ipsecNetwork, + tunnelIface, + tunUtils, + inTransform, + outTransform, + localOuter, + remoteOuter, + 1 /* seqNum */); } } } } + private class MigrateTunnelModeIpSecTransformTestRunnableFactory + implements IpSecTunnelTestRunnableFactory { + private final IpSecTunnelTestRunnableFactory mTestRunnableFactory; + + MigrateTunnelModeIpSecTransformTestRunnableFactory(boolean isOutputTest) { + if (isOutputTest) { + mTestRunnableFactory = new OutputIpSecTunnelTestRunnableFactory(); + } else { + mTestRunnableFactory = new InputPacketGeneratorIpSecTunnelTestRunnableFactory(); + } + } + + @Override + public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + UdpEncapsulationSocket encapSocket, + int unusedInnerSocketPort) { + return new IpSecTunnelTestRunnable() { + @Override + public int run( + Network ipsecNetwork, + IpSecTunnelInterface tunnelIface, + TunUtils tunUtils, + IpSecTransform inTunnelTransform, + IpSecTransform outTunnelTransform, + InetAddress localOuter, + InetAddress remoteOuter, + int seqNum) + throws Exception { + final IpSecTunnelTestRunnable testRunnable = + mTestRunnableFactory.getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + localInner, + remoteInner, + inTransportTransform, + outTransportTransform, + encapSocket, + unusedInnerSocketPort); + testRunnable.run( + ipsecNetwork, + tunnelIface, + tunUtils, + inTunnelTransform, + outTunnelTransform, + localOuter, + remoteOuter, + seqNum++); + + tunnelIface.setUnderlyingNetwork(sTunWrapperNew.network); + + final boolean useEncap = encapSocket != null; + if (useEncap) { + sTunWrapperNew.network.bindSocket(encapSocket.getFileDescriptor()); + } + + // Updating UDP encapsulation socket is not supported. Thus this runnable will + // only cover 1) migration from non-encap to non-encap and 2) migration from + // encap to encap with the same family + if (!useEncap || localOuter instanceof Inet4Address) { + checkMigrateTunnelModeTransform( + testRunnable, + inTunnelTransform, + outTunnelTransform, + tunnelIface, + ipsecNetwork, + sTunWrapperNew.utils, + LOCAL_OUTER_4_NEW, + REMOTE_OUTER_4_NEW, + seqNum++); + } + if (!useEncap || localOuter instanceof Inet6Address) { + checkMigrateTunnelModeTransform( + testRunnable, + inTunnelTransform, + outTunnelTransform, + tunnelIface, + ipsecNetwork, + sTunWrapperNew.utils, + LOCAL_OUTER_6_NEW, + REMOTE_OUTER_6_NEW, + seqNum++); + } + + // Unused return value for MigrateTunnelModeIpSecTransformTest + return 0; + } + }; + } + + private void checkMigrateTunnelModeTransform( + IpSecTunnelTestRunnable testRunnable, + IpSecTransform inTunnelTransform, + IpSecTransform outTunnelTransform, + IpSecTunnelInterface tunnelIface, + Network ipsecNetwork, + TunUtils tunUtils, + InetAddress newLocalOuter, + InetAddress newRemoteOuter, + int seqNum) + throws Exception { + mISM.startTunnelModeTransformMigration( + inTunnelTransform, newRemoteOuter, newLocalOuter); + mISM.startTunnelModeTransformMigration( + outTunnelTransform, newLocalOuter, newRemoteOuter); + + mISM.applyTunnelModeTransform( + tunnelIface, IpSecManager.DIRECTION_IN, inTunnelTransform); + mISM.applyTunnelModeTransform( + tunnelIface, IpSecManager.DIRECTION_OUT, outTunnelTransform); + + testRunnable.run( + ipsecNetwork, + tunnelIface, + tunUtils, + inTunnelTransform, + outTunnelTransform, + newLocalOuter, + newRemoteOuter, + seqNum); + } + } + private void checkTunnelOutput( int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) throws Exception { @@ -651,17 +860,36 @@ } private void checkMigrateTunnelOutput( - int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + int innerFamily, + int outerFamily, + boolean useEncap, + boolean transportInTunnelMode, + boolean isEncapTypeChanged) throws Exception { checkTunnel( innerFamily, outerFamily, useEncap, transportInTunnelMode, - new MigrateIpSecTunnelTestRunnableFactory(true)); + new MigrateIpSecTunnelTestRunnableFactory(true, isEncapTypeChanged)); } private void checkMigrateTunnelInput( + int innerFamily, + int outerFamily, + boolean useEncap, + boolean transportInTunnelMode, + boolean isEncapTypeChanged) + throws Exception { + checkTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + new MigrateIpSecTunnelTestRunnableFactory(false, isEncapTypeChanged)); + } + + private void checkMigrateTunnelModeTransformOutput( int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) throws Exception { checkTunnel( @@ -669,7 +897,18 @@ outerFamily, useEncap, transportInTunnelMode, - new MigrateIpSecTunnelTestRunnableFactory(false)); + new MigrateTunnelModeIpSecTransformTestRunnableFactory(true /* isOutputTest */)); + } + + private void checkMigrateTunnelModeTransformInput( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + checkTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + new MigrateTunnelModeIpSecTransformTestRunnableFactory(false /* isOutputTest */)); } /** @@ -701,7 +940,8 @@ buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); IpSecTransform outTransportTransform = buildIpSecTransform(sContext, outTransportSpi, null, localInner); - UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + UdpEncapsulationSocket encapSocket = + useEncap ? openUdpEncapsulationSocket(outerFamily) : null) { // Run output direction tests IpSecTunnelTestRunnable outputIpSecTunnelTestRunnable = @@ -711,22 +951,19 @@ spi, localInner, remoteInner, - localOuter, - remoteOuter, inTransportTransform, outTransportTransform, - useEncap ? encapSocket.getPort() : 0, - 0, - expectedPacketSize); + encapSocket, + 0); int innerSocketPort = buildTunnelNetworkAndRunTests( - localInner, - remoteInner, - localOuter, - remoteOuter, - spi, - useEncap ? encapSocket : null, - outputIpSecTunnelTestRunnable); + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + encapSocket, + outputIpSecTunnelTestRunnable); // Input direction tests, with matching inner socket ports. IpSecTunnelTestRunnable inputIpSecTunnelTestRunnable = @@ -736,20 +973,17 @@ spi, remoteInner, localInner, - localOuter, - remoteOuter, inTransportTransform, outTransportTransform, - useEncap ? encapSocket.getPort() : 0, - innerSocketPort, - expectedPacketSize); + encapSocket, + innerSocketPort); buildTunnelNetworkAndRunTests( remoteInner, localInner, localOuter, remoteOuter, spi, - useEncap ? encapSocket : null, + encapSocket, inputIpSecTunnelTestRunnable); } } @@ -783,7 +1017,8 @@ buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); IpSecTransform outTransportTransform = buildIpSecTransform(sContext, outTransportSpi, null, localInner); - UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + UdpEncapsulationSocket encapSocket = + useEncap ? openUdpEncapsulationSocket(outerFamily) : null) { buildTunnelNetworkAndRunTests( localInner, @@ -791,19 +1026,16 @@ localOuter, remoteOuter, spi, - useEncap ? encapSocket : null, + encapSocket, factory.getIpSecTunnelTestRunnable( transportInTunnelMode, spi, localInner, remoteInner, - localOuter, - remoteOuter, inTransportTransform, outTransportTransform, - useEncap ? encapSocket.getPort() : 0, - 0, - expectedPacketSize)); + encapSocket, + 0)); } } @@ -851,6 +1083,7 @@ if (encapSocket != null) { transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); + sTunWrapper.network.bindSocket(encapSocket.getFileDescriptor()); } // Apply transform and check that traffic is properly encrypted @@ -862,7 +1095,16 @@ mISM.applyTunnelModeTransform( tunnelIface, IpSecManager.DIRECTION_OUT, outTransform); - innerSocketPort = test.run(testNetwork, tunnelIface, sTunWrapper.utils); + innerSocketPort = + test.run( + testNetwork, + tunnelIface, + sTunWrapper.utils, + inTransform, + outTransform, + localOuter, + remoteOuter, + 1 /* seqNum */); } // Teardown the test network @@ -901,13 +1143,14 @@ } private EspHeader buildTransportModeEspPacket( - int spi, InetAddress src, InetAddress dst, int port, Payload payload) throws Exception { + int spi, int seqNum, InetAddress src, InetAddress dst, Payload payload) + throws Exception { IpHeader preEspIpHeader = getIpHeader(payload.getProtocolId(), src, dst, payload); return new EspHeader( payload.getProtocolId(), spi, - 1, // sequence number + seqNum, CRYPT_KEY, // Same key for auth and crypt payload.getPacketBytes(preEspIpHeader)); } @@ -920,13 +1163,14 @@ InetAddress dstOuter, int port, int encapPort, + int seqNum, Payload payload) throws Exception { IpHeader innerIp = getIpHeader(payload.getProtocolId(), srcInner, dstInner, payload); return new EspHeader( innerIp.getProtocolId(), spi, - 1, // sequence number + seqNum, // sequence number CRYPT_KEY, // Same key for auth and crypt innerIp.getPacketBytes()); } @@ -950,13 +1194,14 @@ InetAddress srcOuter, InetAddress dstOuter, int port, - int encapPort) + int encapPort, + int seqNum) throws Exception { UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA)); EspHeader espPayload = buildTunnelModeEspPacket( - spi, srcInner, dstInner, srcOuter, dstOuter, port, encapPort, udp); + spi, srcInner, dstInner, srcOuter, dstOuter, port, encapPort, seqNum, udp); return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes(); } @@ -968,11 +1213,13 @@ InetAddress srcOuter, InetAddress dstOuter, int port, - int encapPort) + int encapPort, + int seqNum) throws Exception { UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA)); - EspHeader espPayload = buildTransportModeEspPacket(spiInner, srcInner, dstInner, port, udp); + EspHeader espPayload = + buildTransportModeEspPacket(spiInner, seqNum, srcInner, dstInner, udp); espPayload = buildTunnelModeEspPacket( spiOuter, @@ -982,16 +1229,65 @@ dstOuter, port, encapPort, + seqNum, espPayload); return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes(); } private void doTestMigrateTunnel( + int innerFamily, + int outerFamily, + boolean useEncap, + boolean transportInTunnelMode, + boolean testEncapTypeChange) + throws Exception { + assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); + checkMigrateTunnelOutput( + innerFamily, outerFamily, useEncap, transportInTunnelMode, testEncapTypeChange); + checkMigrateTunnelInput( + innerFamily, outerFamily, useEncap, transportInTunnelMode, testEncapTypeChange); + } + + private void doTestMigrateTunnel( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + doTestMigrateTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + false /* testEncapTypeChange */); + } + + private void doTestMigrateTunnelWithEncapTypeChange( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + doTestMigrateTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + true /* testEncapTypeChange */); + } + + private void doTestMigrateTunnelModeTransform( int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); - checkTunnelOutput(innerFamily, outerFamily, useEncap, transportInTunnelMode); - checkTunnelInput(innerFamily, outerFamily, useEncap, transportInTunnelMode); + assumeTrue(mCtsNetUtils.hasIpsecTunnelMigrateFeature()); + checkMigrateTunnelModeTransformOutput( + innerFamily, outerFamily, useEncap, transportInTunnelMode); + checkMigrateTunnelModeTransformInput( + innerFamily, outerFamily, useEncap, transportInTunnelMode); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testHasIpSecTunnelMigrateFeature() throws Exception { + // FEATURE_IPSEC_TUNNEL_MIGRATION is required when VSR API is U/U+ + if (getVsrApiLevel() > Build.VERSION_CODES.TIRAMISU) { + assertTrue(mCtsNetUtils.hasIpsecTunnelMigrateFeature()); + } } // Transport-in-Tunnel mode tests @@ -1008,6 +1304,12 @@ doTestMigrateTunnel(AF_INET, AF_INET, false, true); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTransportInTunnelModeV4InV4_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV4InV4Reflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1027,6 +1329,12 @@ doTestMigrateTunnel(AF_INET, AF_INET, true, true); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTransportInTunnelModeV4InV4UdpEncap_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET, AF_INET, true, true); + } + @Test public void testTransportInTunnelModeV4InV4UdpEncapReflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1046,6 +1354,12 @@ doTestMigrateTunnel(AF_INET, AF_INET6, false, true); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTransportInTunnelModeV4InV6_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET, AF_INET6, false, true); + } + @Test public void testTransportInTunnelModeV4InV6Reflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1065,6 +1379,12 @@ doTestMigrateTunnel(AF_INET6, AF_INET, false, true); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTransportInTunnelModeV6InV4_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET6, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV4Reflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1084,6 +1404,12 @@ doTestMigrateTunnel(AF_INET6, AF_INET, true, true); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTransportInTunnelModeV6InV4UdpEncap_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET6, AF_INET, true, true); + } + @Test public void testTransportInTunnelModeV6InV4UdpEncapReflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1103,6 +1429,12 @@ doTestMigrateTunnel(AF_INET, AF_INET6, false, true); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTransportInTunnelModeV6InV6_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET, AF_INET6, false, true); + } + @Test public void testTransportInTunnelModeV6InV6Reflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1123,6 +1455,12 @@ doTestMigrateTunnel(AF_INET, AF_INET, false, false); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTunnelV4InV4_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET, AF_INET, false, false); + } + @Test public void testTunnelV4InV4Reflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1142,6 +1480,12 @@ doTestMigrateTunnel(AF_INET, AF_INET, true, false); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTunnelV4InV4UdpEncap_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET, AF_INET, true, false); + } + @Test public void testTunnelV4InV4UdpEncapReflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1161,6 +1505,12 @@ doTestMigrateTunnel(AF_INET, AF_INET6, false, false); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTunnelV4InV6_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET, AF_INET6, false, false); + } + @Test public void testTunnelV4InV6Reflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1180,6 +1530,12 @@ doTestMigrateTunnel(AF_INET6, AF_INET, false, false); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTunnelV6InV4_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET6, AF_INET, false, false); + } + @Test public void testTunnelV6InV4Reflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1199,6 +1555,12 @@ doTestMigrateTunnel(AF_INET6, AF_INET, true, false); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTunnelV6InV4UdpEncap_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET6, AF_INET, true, false); + } + @Test public void testTunnelV6InV4UdpEncapReflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); @@ -1218,9 +1580,115 @@ doTestMigrateTunnel(AF_INET6, AF_INET6, false, false); } + @IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testMigrateTunnelV6InV6_EncapTypeChange() throws Exception { + doTestMigrateTunnelWithEncapTypeChange(AF_INET6, AF_INET6, false, false); + } + @Test public void testTunnelV6InV6Reflected() throws Exception { assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature()); checkTunnelReflected(AF_INET6, AF_INET6, false, false); } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTransportInTunnelModeV4InV4() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET, AF_INET, false, true); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTransportInTunnelModeV6InV4() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET6, AF_INET, false, true); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTransportInTunnelModeV4InV6() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET, AF_INET6, false, true); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTransportInTunnelModeV6InV6() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET, AF_INET6, false, true); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTransportInTunnelModeV4InV4UdpEncap() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET, AF_INET, true, true); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTransportInTunnelModeV6InV4UdpEncap() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET6, AF_INET, true, true); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTransportInTunnelModeV4InV6UdpEncap() throws Exception { + assumeExperimentalIpv6UdpEncapSupported(); + doTestMigrateTunnelModeTransform(AF_INET, AF_INET6, true, true); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTransportInTunnelModeV6InV6UdpEncap() throws Exception { + assumeExperimentalIpv6UdpEncapSupported(); + doTestMigrateTunnelModeTransform(AF_INET6, AF_INET6, true, true); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTunnelV4InV4() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET, AF_INET, false, false); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTunnelV6InV4() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET6, AF_INET, false, false); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTunnelV4InV6() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET, AF_INET6, false, false); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTunnelV6InV6() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET6, AF_INET6, false, false); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTunnelV4InV4UdpEncap() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET, AF_INET, true, false); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTunnelV6InV4UdpEncap() throws Exception { + doTestMigrateTunnelModeTransform(AF_INET6, AF_INET, true, false); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTunnelV4InV6UdpEncap() throws Exception { + assumeExperimentalIpv6UdpEncapSupported(); + doTestMigrateTunnelModeTransform(AF_INET, AF_INET6, true, false); + } + + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + public void testMigrateTransformTunnelV6InV6UdpEncap() throws Exception { + assumeExperimentalIpv6UdpEncapSupported(); + doTestMigrateTunnelModeTransform(AF_INET6, AF_INET6, true, false); + } }
diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java index 691ab99..17a9ca2 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java
@@ -18,21 +18,18 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; -import android.content.Context; import android.content.ContentResolver; +import android.content.Context; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkUtils; import android.net.cts.util.CtsNetUtils; import android.platform.test.annotations.AppModeFull; -import android.provider.Settings; import android.system.ErrnoException; import android.system.OsConstants; import android.test.AndroidTestCase; -import java.util.ArrayList; - public class MultinetworkApiTest extends AndroidTestCase { static { @@ -75,26 +72,8 @@ super.tearDown(); } - private Network[] getTestableNetworks() { - final ArrayList<Network> testableNetworks = new ArrayList<Network>(); - for (Network network : mCM.getAllNetworks()) { - final NetworkCapabilities nc = mCM.getNetworkCapabilities(network); - if (nc != null - && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { - testableNetworks.add(network); - } - } - - assertTrue( - "This test requires that at least one network be connected. " + - "Please ensure that the device is connected to a network.", - testableNetworks.size() >= 1); - return testableNetworks.toArray(new Network[0]); - } - public void testGetaddrinfo() throws ErrnoException { - for (Network network : getTestableNetworks()) { + for (Network network : mCtsNetUtils.getTestableNetworks()) { int errno = runGetaddrinfoCheck(network.getNetworkHandle()); if (errno != 0) { throw new ErrnoException( @@ -109,7 +88,7 @@ assertNull(mCM.getProcessDefaultNetwork()); assertEquals(0, NetworkUtils.getBoundNetworkForProcess()); - for (Network network : getTestableNetworks()) { + for (Network network : mCtsNetUtils.getTestableNetworks()) { mCM.setProcessDefaultNetwork(null); assertNull(mCM.getProcessDefaultNetwork()); @@ -128,7 +107,7 @@ mCM.setProcessDefaultNetwork(null); } - for (Network network : getTestableNetworks()) { + for (Network network : mCtsNetUtils.getTestableNetworks()) { NetworkUtils.bindProcessToNetwork(0); assertNull(mCM.getBoundNetworkForProcess()); @@ -148,7 +127,7 @@ @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") public void testSetsocknetwork() throws ErrnoException { - for (Network network : getTestableNetworks()) { + for (Network network : mCtsNetUtils.getTestableNetworks()) { int errno = runSetsocknetwork(network.getNetworkHandle()); if (errno != 0) { throw new ErrnoException( @@ -158,7 +137,7 @@ } public void testNativeDatagramTransmission() throws ErrnoException { - for (Network network : getTestableNetworks()) { + for (Network network : mCtsNetUtils.getTestableNetworks()) { int errno = runDatagramCheck(network.getNetworkHandle()); if (errno != 0) { throw new ErrnoException( @@ -181,7 +160,7 @@ public void testNetworkHandle() { // Test Network -> NetworkHandle -> Network results in the same Network. - for (Network network : getTestableNetworks()) { + for (Network network : mCtsNetUtils.getTestableNetworks()) { long networkHandle = network.getNetworkHandle(); Network newNetwork = Network.fromNetworkHandle(networkHandle); assertEquals(newNetwork, network); @@ -203,7 +182,7 @@ } public void testResNApi() throws Exception { - final Network[] testNetworks = getTestableNetworks(); + final Network[] testNetworks = mCtsNetUtils.getTestableNetworks(); for (Network network : testNetworks) { // Throws AssertionError directly in jni function if test fail. @@ -229,7 +208,7 @@ // b/144521720 try { mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER); - for (Network network : getTestableNetworks()) { + for (Network network : mCtsNetUtils.getTestableNetworks()) { // Wait for private DNS setting to propagate. mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout", network, GOOGLE_PRIVATE_DNS_SERVER, true);
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 6df71c8..cf5fc50 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -29,9 +29,9 @@ import android.net.NattKeepalivePacketData import android.net.Network import android.net.NetworkAgent -import android.net.NetworkAgentConfig import android.net.NetworkAgent.INVALID_NETWORK import android.net.NetworkAgent.VALID_NETWORK +import android.net.NetworkAgentConfig import android.net.NetworkCapabilities import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED @@ -46,21 +46,23 @@ import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED import android.net.NetworkCapabilities.TRANSPORT_CELLULAR import android.net.NetworkCapabilities.TRANSPORT_TEST -import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkCapabilities.TRANSPORT_VPN +import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkInfo import android.net.NetworkProvider import android.net.NetworkReleasedException import android.net.NetworkRequest import android.net.NetworkScore -import android.net.RouteInfo import android.net.QosCallback -import android.net.QosCallbackException import android.net.QosCallback.QosCallbackRegistrationException +import android.net.QosCallbackException import android.net.QosSession import android.net.QosSessionAttributes import android.net.QosSocketInfo +import android.net.RouteInfo import android.net.SocketKeepalive +import android.net.TestNetworkInterface +import android.net.TestNetworkManager import android.net.Uri import android.net.VpnManager import android.net.VpnTransportInfo @@ -71,6 +73,7 @@ import android.os.Handler import android.os.HandlerThread import android.os.Message +import android.os.Process import android.os.SystemClock import android.platform.test.annotations.AppModeFull import android.system.OsConstants.IPPROTO_TCP @@ -89,6 +92,7 @@ import com.android.testutils.DevSdkIgnoreRunner import com.android.testutils.RecorderCallback.CallbackEntry.Available import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus +import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged import com.android.testutils.RecorderCallback.CallbackEntry.Losing import com.android.testutils.RecorderCallback.CallbackEntry.Lost @@ -108,17 +112,6 @@ import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnValidationStatus import com.android.testutils.TestableNetworkCallback import com.android.testutils.assertThrows -import org.junit.After -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.any -import org.mockito.ArgumentMatchers.argThat -import org.mockito.ArgumentMatchers.eq -import org.mockito.Mockito.doReturn -import org.mockito.Mockito.mock -import org.mockito.Mockito.timeout -import org.mockito.Mockito.verify import java.io.Closeable import java.io.IOException import java.net.DatagramSocket @@ -136,6 +129,17 @@ import kotlin.test.assertNull import kotlin.test.assertTrue import kotlin.test.fail +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.argThat +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import org.mockito.Mockito.timeout +import org.mockito.Mockito.verify // This test doesn't really have a constraint on how fast the methods should return. If it's // going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio @@ -168,6 +172,7 @@ // for modules other than Connectivity does not provide much value. Only run them in connectivity // module MTS, so the tests only need to cover the case of an updated NetworkAgent. @ConnectivityModuleTest +@AppModeFull(reason = "Instant apps can't use NetworkAgent because it needs NETWORK_FACTORY'.") class NetworkAgentTest { private val LOCAL_IPV4_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.1") private val REMOTE_IPV4_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.2") @@ -178,6 +183,7 @@ private val agentsToCleanUp = mutableListOf<NetworkAgent>() private val callbacksToCleanUp = mutableListOf<TestableNetworkCallback>() private var qosTestSocket: Closeable? = null // either Socket or DatagramSocket + private val ifacesToCleanUp = mutableListOf<TestNetworkInterface>() @Before fun setUp() { @@ -189,8 +195,10 @@ fun tearDown() { agentsToCleanUp.forEach { it.unregister() } callbacksToCleanUp.forEach { mCM.unregisterNetworkCallback(it) } + ifacesToCleanUp.forEach { it.fileDescriptor.close() } qosTestSocket?.close() mHandlerThread.quitSafely() + mHandlerThread.join() instrumentation.getUiAutomation().dropShellPermissionIdentity() } @@ -268,7 +276,7 @@ removeCapability(NET_CAPABILITY_INTERNET) addCapability(NET_CAPABILITY_NOT_SUSPENDED) addCapability(NET_CAPABILITY_NOT_ROAMING) - addCapability(NET_CAPABILITY_NOT_VPN) + if (!transports.contains(TRANSPORT_VPN)) addCapability(NET_CAPABILITY_NOT_VPN) if (SdkLevel.isAtLeastS()) { addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) } @@ -303,7 +311,7 @@ context: Context = realContext, specifier: String? = UUID.randomUUID().toString(), initialConfig: NetworkAgentConfig? = null, - expectedInitSignalStrengthThresholds: IntArray? = intArrayOf(), + expectedInitSignalStrengthThresholds: IntArray = intArrayOf(), transports: IntArray = intArrayOf() ): Pair<TestableNetworkAgent, TestableNetworkCallback> { val callback = TestableNetworkCallback() @@ -316,8 +324,7 @@ agent.register() agent.markConnected() agent.expectCallback<OnNetworkCreated>() - agent.expectSignalStrengths(expectedInitSignalStrengthThresholds) - agent.expectValidationBypassedStatus() + agent.expectPostConnectionCallbacks(expectedInitSignalStrengthThresholds) callback.expectAvailableThenValidatedCallbacks(agent.network!!) return agent to callback } @@ -335,6 +342,19 @@ mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID))) } + private fun TestableNetworkAgent.expectPostConnectionCallbacks( + thresholds: IntArray = intArrayOf() + ) { + expectSignalStrengths(thresholds) + expectValidationBypassedStatus() + assertNoCallback() + } + + private fun createTunInterface(): TestNetworkInterface = realContext.getSystemService( + TestNetworkManager::class.java)!!.createTunInterface(emptyList()).also { + ifacesToCleanUp.add(it) + } + fun assertLinkPropertiesEventually( n: Network, description: String, @@ -391,9 +411,7 @@ val nc = NetworkCapabilities(agent.nc) nc.addCapability(NET_CAPABILITY_NOT_METERED) agent.sendNetworkCapabilities(nc) - callback.expectCapabilitiesThat(agent.network) { - it.hasCapability(NET_CAPABILITY_NOT_METERED) - } + callback.expectCaps(agent.network) { it.hasCapability(NET_CAPABILITY_NOT_METERED) } val networkInfo = mCM.getNetworkInfo(agent.network) assertEquals(subtypeUMTS, networkInfo.getSubtype()) assertEquals(subtypeNameUMTS, networkInfo.getSubtypeName()) @@ -434,27 +452,28 @@ (agent, callback) -> // Send signal strength and check that the callbacks are called appropriately. val nc = NetworkCapabilities(agent.nc) + val net = agent.network!! nc.setSignalStrength(20) agent.sendNetworkCapabilities(nc) callbacks.forEach { it.assertNoCallback(NO_CALLBACK_TIMEOUT) } nc.setSignalStrength(40) agent.sendNetworkCapabilities(nc) - callbacks[0].expectAvailableCallbacks(agent.network!!) + callbacks[0].expectAvailableCallbacks(net) callbacks[1].assertNoCallback(NO_CALLBACK_TIMEOUT) callbacks[2].assertNoCallback(NO_CALLBACK_TIMEOUT) nc.setSignalStrength(80) agent.sendNetworkCapabilities(nc) - callbacks[0].expectCapabilitiesThat(agent.network!!) { it.signalStrength == 80 } - callbacks[1].expectAvailableCallbacks(agent.network!!) - callbacks[2].expectAvailableCallbacks(agent.network!!) + callbacks[0].expectCaps(net) { it.signalStrength == 80 } + callbacks[1].expectAvailableCallbacks(net) + callbacks[2].expectAvailableCallbacks(net) nc.setSignalStrength(55) agent.sendNetworkCapabilities(nc) - callbacks[0].expectCapabilitiesThat(agent.network!!) { it.signalStrength == 55 } - callbacks[1].expectCapabilitiesThat(agent.network!!) { it.signalStrength == 55 } - callbacks[2].expect<Lost>(agent.network!!) + callbacks[0].expectCaps(net) { it.signalStrength == 55 } + callbacks[1].expectCaps(net) { it.signalStrength == 55 } + callbacks[2].expect<Lost>(net) } callbacks.forEach { mCM.unregisterNetworkCallback(it) @@ -507,15 +526,11 @@ val lp = LinkProperties(agent.lp) lp.setInterfaceName(ifaceName) agent.sendLinkProperties(lp) - callback.expectLinkPropertiesThat(agent.network!!) { - it.getInterfaceName() == ifaceName - } + callback.expect<LinkPropertiesChanged>(agent.network!!) { it.lp.interfaceName == ifaceName } val nc = NetworkCapabilities(agent.nc) nc.addCapability(NET_CAPABILITY_NOT_METERED) agent.sendNetworkCapabilities(nc) - callback.expectCapabilitiesThat(agent.network!!) { - it.hasCapability(NET_CAPABILITY_NOT_METERED) - } + callback.expectCaps(agent.network!!) { it.hasCapability(NET_CAPABILITY_NOT_METERED) } } private fun ncWithAllowedUids(vararg uids: Int) = NetworkCapabilities.Builder() @@ -533,12 +548,12 @@ // Make sure the UIDs have been ignored. callback.expect<Available>(agent.network!!) - callback.expectCapabilitiesThat(agent.network!!) { + callback.expectCaps(agent.network!!) { it.allowedUids.isEmpty() && !it.hasCapability(NET_CAPABILITY_VALIDATED) } callback.expect<LinkPropertiesChanged>(agent.network!!) callback.expect<BlockedStatus>(agent.network!!) - callback.expectCapabilitiesThat(agent.network!!) { + callback.expectCaps(agent.network!!) { it.allowedUids.isEmpty() && it.hasCapability(NET_CAPABILITY_VALIDATED) } callback.assertNoCallback(NO_CALLBACK_TIMEOUT) @@ -582,8 +597,8 @@ // tearDown() will unregister the requests and agents } - private fun hasAllTransports(nc: NetworkCapabilities?, transports: IntArray) = - nc != null && transports.all { nc.hasTransport(it) } + private fun NetworkCapabilities?.hasAllTransports(transports: IntArray) = + this != null && transports.all { hasTransport(it) } @Test @IgnoreUpTo(Build.VERSION_CODES.R) @@ -625,25 +640,25 @@ assertEquals(mySessionId, (vpnNc.transportInfo as VpnTransportInfo).sessionId) val testAndVpn = intArrayOf(TRANSPORT_TEST, TRANSPORT_VPN) - assertTrue(hasAllTransports(vpnNc, testAndVpn)) + assertTrue(vpnNc.hasAllTransports(testAndVpn)) assertFalse(vpnNc.hasCapability(NET_CAPABILITY_NOT_VPN)) - assertTrue(hasAllTransports(vpnNc, defaultNetworkTransports), + assertTrue(vpnNc.hasAllTransports(defaultNetworkTransports), "VPN transports ${Arrays.toString(vpnNc.transportTypes)}" + " lacking transports from ${Arrays.toString(defaultNetworkTransports)}") // Check that when no underlying networks are announced the underlying transport disappears. agent.setUnderlyingNetworks(listOf<Network>()) - callback.expectCapabilitiesThat(agent.network!!) { - it.transportTypes.size == 2 && hasAllTransports(it, testAndVpn) + callback.expectCaps(agent.network!!) { + it.transportTypes.size == 2 && it.hasAllTransports(testAndVpn) } // Put the underlying network back and check that the underlying transport reappears. val expectedTransports = (defaultNetworkTransports.toSet() + TRANSPORT_TEST + TRANSPORT_VPN) .toIntArray() agent.setUnderlyingNetworks(null) - callback.expectCapabilitiesThat(agent.network!!) { + callback.expectCaps(agent.network!!) { it.transportTypes.size == expectedTransports.size && - hasAllTransports(it, expectedTransports) + it.hasAllTransports(expectedTransports) } // Check that some underlying capabilities are propagated. @@ -757,7 +772,7 @@ val nc1 = NetworkCapabilities(agent.nc) .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) agent.sendNetworkCapabilities(nc1) - callback.expectCapabilitiesThat(agent.network!!) { + callback.expectCaps(agent.network!!) { it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) } @@ -765,7 +780,7 @@ val nc2 = NetworkCapabilities(agent.nc) .removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) agent.sendNetworkCapabilities(nc2) - callback.expectCapabilitiesThat(agent.network!!) { + callback.expectCaps(agent.network!!) { !it.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) } @@ -917,12 +932,10 @@ val history = ArrayTrackRecord<CallbackEntry>().newReadHead() sealed class CallbackEntry { - data class OnQosSessionAvailable(val sess: QosSession, val attr: QosSessionAttributes) - : CallbackEntry() - data class OnQosSessionLost(val sess: QosSession) - : CallbackEntry() - data class OnError(val ex: QosCallbackException) - : CallbackEntry() + data class OnQosSessionAvailable(val sess: QosSession, val attr: QosSessionAttributes) : + CallbackEntry() + data class OnQosSessionLost(val sess: QosSession) : CallbackEntry() + data class OnError(val ex: QosCallbackException) : CallbackEntry() } override fun onQosSessionAvailable(sess: QosSession, attr: QosSessionAttributes) { @@ -970,13 +983,11 @@ .also { assertNotNull(agent.network?.bindSocket(it)) } } - @AppModeFull(reason = "Instant apps don't have permission to bind sockets.") @Test fun testQosCallbackRegisterAndUnregister() { validateQosCallbackRegisterAndUnregister(IPPROTO_TCP) } - @AppModeFull(reason = "Instant apps don't have permission to bind sockets.") @Test fun testQosCallbackRegisterAndUnregisterWithDatagramSocket() { validateQosCallbackRegisterAndUnregister(IPPROTO_UDP) @@ -1013,13 +1024,11 @@ } } - @AppModeFull(reason = "Instant apps don't have permission to bind sockets.") @Test fun testQosCallbackOnQosSession() { validateQosCallbackOnQosSession(IPPROTO_TCP) } - @AppModeFull(reason = "Instant apps don't have permission to bind sockets.") @Test fun testQosCallbackOnQosSessionWithDatagramSocket() { validateQosCallbackOnQosSession(IPPROTO_UDP) @@ -1078,7 +1087,6 @@ } } - @AppModeFull(reason = "Instant apps don't have permission to bind sockets.") @Test fun testQosCallbackOnError() { val (agent, qosTestSocket) = setupForQosSocket() @@ -1117,7 +1125,6 @@ } } - @AppModeFull(reason = "Instant apps don't have permission to bind sockets.") @Test fun testQosCallbackIdsAreMappedCorrectly() { val (agent, qosTestSocket) = setupForQosSocket() @@ -1158,7 +1165,6 @@ } } - @AppModeFull(reason = "Instant apps don't have permission to bind sockets.") @Test fun testQosCallbackWhenNetworkReleased() { val (agent, qosTestSocket) = setupForQosSocket() @@ -1200,7 +1206,6 @@ ) } - @AppModeFull(reason = "Instant apps don't have permission to bind sockets.") @Test fun testUnregisterAfterReplacement() { // Keeps an eye on all test networks. @@ -1297,8 +1302,12 @@ requestNetwork(makeTestNetworkRequest(specifier = specifier6), callback) val agent6 = createNetworkAgent(specifier = specifier6) val network6 = agent6.register() - // No callbacks are sent, so check the LinkProperties to see if the network has connected. - assertLinkPropertiesEventuallyNotNull(agent6.network!!) + if (SdkLevel.isAtLeastU()) { + agent6.expectCallback<OnNetworkCreated>() + } else { + // No callbacks are sent, so check LinkProperties to wait for the network to be created. + assertLinkPropertiesEventuallyNotNull(agent6.network!!) + } // unregisterAfterReplacement tears down the network immediately. // Approximately check that this is the case by picking an unregister timeout that's longer @@ -1307,8 +1316,9 @@ val timeoutMs = agent6.DEFAULT_TIMEOUT_MS.toInt() + 1_000 agent6.unregisterAfterReplacement(timeoutMs) agent6.expectCallback<OnNetworkUnwanted>() - if (!SdkLevel.isAtLeastT()) { + if (!SdkLevel.isAtLeastT() || SdkLevel.isAtLeastU()) { // Before T, onNetworkDestroyed is called even if the network was never created. + // On U+, the network was created by register(). Destroying it sends onNetworkDestroyed. agent6.expectCallback<OnNetworkDestroyed>() } // Poll for LinkProperties becoming null, because when onNetworkUnwanted is called, the @@ -1330,14 +1340,10 @@ val (wifiAgent, wifiNetwork) = connectNetwork(TRANSPORT_WIFI) testCallback.expectAvailableCallbacks(wifiNetwork, validated = true) - testCallback.expectCapabilitiesThat(wifiNetwork) { - it.hasCapability(NET_CAPABILITY_VALIDATED) - } + testCallback.expectCaps(wifiNetwork) { it.hasCapability(NET_CAPABILITY_VALIDATED) } matchAllCallback.expectAvailableCallbacks(wifiNetwork, validated = false) matchAllCallback.expect<Losing>(cellNetwork) - matchAllCallback.expectCapabilitiesThat(wifiNetwork) { - it.hasCapability(NET_CAPABILITY_VALIDATED) - } + matchAllCallback.expectCaps(wifiNetwork) { it.hasCapability(NET_CAPABILITY_VALIDATED) } wifiAgent.unregisterAfterReplacement(5_000 /* timeoutMillis */) wifiAgent.expectCallback<OnNetworkDestroyed>() @@ -1385,4 +1391,101 @@ callback.expect<Available>(agent.network!!) callback.eventuallyExpect<Lost> { it.network == agent.network } } + + fun doTestNativeNetworkCreation(expectCreatedImmediately: Boolean, transports: IntArray) { + val iface = createTunInterface() + val ifName = iface.interfaceName + val nc = makeTestNetworkCapabilities(ifName, transports).also { + if (transports.contains(TRANSPORT_VPN)) { + val sessionId = "NetworkAgentTest-${Process.myPid()}" + it.transportInfo = VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, sessionId, + /*bypassable=*/ false, /*longLivedTcpConnectionsExpensive=*/ false) + it.underlyingNetworks = listOf() + } + } + val lp = LinkProperties().apply { + interfaceName = ifName + addLinkAddress(LinkAddress("2001:db8::1/64")) + addRoute(RouteInfo(IpPrefix("2001:db8::/64"), null /* nextHop */, ifName)) + addRoute(RouteInfo(IpPrefix("::/0"), + InetAddresses.parseNumericAddress("fe80::abcd"), + ifName)) + } + + // File a request containing the agent's specifier to receive callbacks and to ensure that + // the agent is not torn down due to being unneeded. + val request = makeTestNetworkRequest(specifier = ifName) + val requestCallback = TestableNetworkCallback() + requestNetwork(request, requestCallback) + + val listenCallback = TestableNetworkCallback() + registerNetworkCallback(request, listenCallback) + + // Register the NetworkAgent... + val agent = createNetworkAgent(realContext, initialNc = nc, initialLp = lp) + val network = agent.register() + + // ... and then change the NetworkCapabilities and LinkProperties. + nc.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) + agent.sendNetworkCapabilities(nc) + lp.addLinkAddress(LinkAddress("192.0.2.2/25")) + lp.addRoute(RouteInfo(IpPrefix("192.0.2.0/25"), null /* nextHop */, ifName)) + agent.sendLinkProperties(lp) + + requestCallback.assertNoCallback() + listenCallback.assertNoCallback() + if (!expectCreatedImmediately) { + agent.assertNoCallback() + agent.markConnected() + agent.expectCallback<OnNetworkCreated>() + } else { + agent.expectCallback<OnNetworkCreated>() + agent.markConnected() + } + agent.expectPostConnectionCallbacks() + + // onAvailable must be called only when the network connects, and no other callbacks may be + // called before that happens. The callbacks report the state of the network as it was when + // it connected, so they reflect the NC and LP changes made after registration. + requestCallback.expect<Available>(network) + listenCallback.expect<Available>(network) + + requestCallback.expect<CapabilitiesChanged>(network) { it.caps.hasCapability( + NET_CAPABILITY_TEMPORARILY_NOT_METERED) } + listenCallback.expect<CapabilitiesChanged>(network) { it.caps.hasCapability( + NET_CAPABILITY_TEMPORARILY_NOT_METERED) } + + requestCallback.expect<LinkPropertiesChanged>(network) { it.lp.equals(lp) } + listenCallback.expect<LinkPropertiesChanged>(network) { it.lp.equals(lp) } + + requestCallback.expect<BlockedStatus>() + listenCallback.expect<BlockedStatus>() + + // Except for network validation, ensure no more callbacks are sent. + requestCallback.expectCaps(network) { + it.hasCapability(NET_CAPABILITY_VALIDATED) + } + listenCallback.expectCaps(network) { + it.hasCapability(NET_CAPABILITY_VALIDATED) + } + unregister(agent) + // Lost implicitly checks that no further callbacks happened after connect. + requestCallback.expect<Lost>(network) + listenCallback.expect<Lost>(network) + assertNull(mCM.getLinkProperties(network)) + } + + @Test + fun testNativeNetworkCreation_PhysicalNetwork() { + // On T and below, the native network is only created when the agent connects. + // Starting in U, the native network is created as soon as the agent is registered. + doTestNativeNetworkCreation(expectCreatedImmediately = SdkLevel.isAtLeastU(), + intArrayOf(TRANSPORT_CELLULAR)) + } + + @Test + fun testNativeNetworkCreation_Vpn() { + // VPN networks are always created as soon as the agent is registered. + doTestNativeNetworkCreation(expectCreatedImmediately = true, intArrayOf(TRANSPORT_VPN)) + } }
diff --git a/tests/cts/net/src/android/net/cts/NetworkScoreTest.kt b/tests/cts/net/src/android/net/cts/NetworkScoreTest.kt index eb41d71..2704dd3 100644 --- a/tests/cts/net/src/android/net/cts/NetworkScoreTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkScoreTest.kt
@@ -30,6 +30,7 @@ import android.os.Build import android.os.Handler import android.os.HandlerThread +import android.util.Log import androidx.test.InstrumentationRegistry import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo @@ -41,6 +42,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import java.util.Collections // This test doesn't really have a constraint on how fast the methods should return. If it's // going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio @@ -64,10 +66,11 @@ @IgnoreUpTo(Build.VERSION_CODES.R) @RunWith(DevSdkIgnoreRunner::class) class NetworkScoreTest { + private val TAG = javaClass.simpleName private val mCm = testContext.getSystemService(ConnectivityManager::class.java) - private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") + private val mHandlerThread = HandlerThread("$TAG handler thread") private val mHandler by lazy { Handler(mHandlerThread.looper) } - private val agentsToCleanUp = mutableListOf<NetworkAgent>() + private val agentsToCleanUp = Collections.synchronizedList(mutableListOf<NetworkAgent>()) private val callbacksToCleanUp = mutableListOf<TestableNetworkCallback>() @Before @@ -83,14 +86,18 @@ .addTransportType(NetworkCapabilities.TRANSPORT_TEST).build(), cb, mHandler ) } + Log.i(TAG, "Teardown on thread ${System.identityHashCode(Thread.currentThread())} " + + "cleaning up ${agentsToCleanUp.size} agents") agentsToCleanUp.forEach { + Log.i(TAG, "Unregister agent for net ${it.network}") it.unregister() agentCleanUpCb.eventuallyExpect<CallbackEntry.Lost> { cb -> cb.network == it.network } } mCm.unregisterNetworkCallback(agentCleanUpCb) - mHandlerThread.quitSafely() callbacksToCleanUp.forEach { mCm.unregisterNetworkCallback(it) } + mHandlerThread.quitSafely() + mHandlerThread.join() } // Returns a networkCallback that sends onAvailable on the best network with TRANSPORT_TEST. @@ -144,6 +151,8 @@ val agent = object : NetworkAgent(context, looper, "NetworkScore test agent", nc, LinkProperties(), score, config, NetworkProvider(context, looper, "NetworkScore test provider")) {}.also { + Log.i(TAG, "Add on thread ${System.identityHashCode(Thread.currentThread())} " + + "agent to clean up $it") agentsToCleanUp.add(it) } runWithShellPermissionIdentity({ agent.register() }, MANAGE_TEST_NETWORKS)
diff --git a/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java b/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java index f86c5cd..83b9b81 100644 --- a/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java
@@ -210,7 +210,6 @@ private long mStartTime; private long mEndTime; - private long mBytesRead; private String mWriteSettingsMode; private String mUsageStatsMode; @@ -229,6 +228,7 @@ TrafficStats.setThreadStatsTag(NETWORK_TAG); urlc = (HttpURLConnection) network.openConnection(url); urlc.setConnectTimeout(TIMEOUT_MILLIS); + urlc.setReadTimeout(TIMEOUT_MILLIS); urlc.setUseCaches(false); // Disable compression so we generate enough traffic that assertWithinPercentage will // not be affected by the small amount of traffic (5-10kB) sent by the test harness. @@ -236,11 +236,10 @@ urlc.connect(); boolean ping = urlc.getResponseCode() == 200; if (ping) { - in = new InputStreamReader( - (InputStream) urlc.getContent()); - - mBytesRead = 0; - while (in.read() != -1) ++mBytesRead; + in = new InputStreamReader((InputStream) urlc.getContent()); + // Since the test doesn't really care about the precise amount of data, instead + // of reading all contents, just read few bytes at the beginning. + in.read(); } } catch (Exception e) { Log.i(LOG_TAG, "Badness during exercising remote server: " + e); @@ -379,7 +378,7 @@ .build(), callback); synchronized (this) { try { - wait((int) (TIMEOUT_MILLIS * 1.2)); + wait((int) (TIMEOUT_MILLIS * 2.4)); } catch (InterruptedException e) { } } @@ -394,7 +393,7 @@ assertFalse(mNetworkInterfacesToTest[networkTypeIndex].getSystemFeature() + " is a reported system feature, " + "however no corresponding connected network interface was found or the attempt " - + "to connect has timed out (timeout = " + TIMEOUT_MILLIS + "ms)." + + "to connect and read has timed out (timeout = " + (TIMEOUT_MILLIS * 2) + "ms)." + mNetworkInterfacesToTest[networkTypeIndex].getErrorMessage(), hasFeature); return false; } @@ -800,7 +799,7 @@ // harness, which is untagged, won't cause a failure. long firstTotal = resultsWithTraffic.get(0).total; for (QueryResult queryResult : resultsWithTraffic) { - assertWithinPercentage(queryResult + "", firstTotal, queryResult.total, 10); + assertWithinPercentage(queryResult + "", firstTotal, queryResult.total, 12); } // Expect to see no traffic when querying for any tag in tagsWithNoTraffic or any
diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt index 8e98dba..621af23 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt
@@ -146,6 +146,7 @@ httpServer.stop() handlerThread.threadHandler.post { reader.stop() } handlerThread.quitSafely() + handlerThread.join() iface.fileDescriptor.close() }
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt index 2b5c305..9808137 100644 --- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt +++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -19,17 +19,23 @@ import android.app.compat.CompatChanges import android.net.ConnectivityManager import android.net.ConnectivityManager.NetworkCallback +import android.net.InetAddresses.parseNumericAddress +import android.net.LinkAddress import android.net.LinkProperties +import android.net.LocalSocket +import android.net.LocalSocketAddress import android.net.Network import android.net.NetworkAgentConfig import android.net.NetworkCapabilities import android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED +import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED import android.net.NetworkCapabilities.TRANSPORT_TEST import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.net.TestNetworkSpecifier +import android.net.connectivity.ConnectivityCompatChanges import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStarted import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStopped import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.ServiceFound @@ -40,8 +46,15 @@ import android.net.cts.NsdManagerTest.NsdRegistrationRecord.RegistrationEvent.ServiceRegistered import android.net.cts.NsdManagerTest.NsdRegistrationRecord.RegistrationEvent.ServiceUnregistered import android.net.cts.NsdManagerTest.NsdRegistrationRecord.RegistrationEvent.UnregistrationFailed +import android.net.cts.NsdManagerTest.NsdResolveRecord.ResolveEvent.ResolutionStopped import android.net.cts.NsdManagerTest.NsdResolveRecord.ResolveEvent.ResolveFailed import android.net.cts.NsdManagerTest.NsdResolveRecord.ResolveEvent.ServiceResolved +import android.net.cts.NsdManagerTest.NsdResolveRecord.ResolveEvent.StopResolutionFailed +import android.net.cts.NsdManagerTest.NsdServiceInfoCallbackRecord.ServiceInfoCallbackEvent.RegisterCallbackFailed +import android.net.cts.NsdManagerTest.NsdServiceInfoCallbackRecord.ServiceInfoCallbackEvent.ServiceUpdated +import android.net.cts.NsdManagerTest.NsdServiceInfoCallbackRecord.ServiceInfoCallbackEvent.ServiceUpdatedLost +import android.net.cts.NsdManagerTest.NsdServiceInfoCallbackRecord.ServiceInfoCallbackEvent.UnregisterCallbackSucceeded +import android.net.cts.util.CtsNetUtils import android.net.nsd.NsdManager import android.net.nsd.NsdManager.DiscoveryListener import android.net.nsd.NsdManager.RegistrationListener @@ -52,20 +65,53 @@ import android.os.HandlerThread import android.os.Process.myTid import android.platform.test.annotations.AppModeFull +import android.system.ErrnoException +import android.system.Os +import android.system.OsConstants.AF_INET6 +import android.system.OsConstants.EADDRNOTAVAIL +import android.system.OsConstants.ENETUNREACH +import android.system.OsConstants.IPPROTO_UDP +import android.system.OsConstants.SOCK_DGRAM import android.util.Log +import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.runner.AndroidJUnit4 +import com.android.compatibility.common.util.PollingCheck +import com.android.compatibility.common.util.PropertyUtil +import com.android.modules.utils.build.SdkLevel.isAtLeastU import com.android.net.module.util.ArrayTrackRecord import com.android.net.module.util.TrackRecord import com.android.networkstack.apishim.NsdShimImpl +import com.android.networkstack.apishim.common.NsdShim import com.android.testutils.ConnectivityModuleTest import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.DevSdkIgnoreRunner +import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged +import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged import com.android.testutils.TestableNetworkAgent +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated import com.android.testutils.TestableNetworkCallback import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk30 +import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk33 import com.android.testutils.runAsShell import com.android.testutils.tryTest import com.android.testutils.waitForIdle +import java.io.File +import java.io.IOException +import java.net.Inet6Address +import java.net.InetAddress +import java.net.NetworkInterface +import java.net.ServerSocket +import java.nio.charset.StandardCharsets +import java.util.Random +import java.util.concurrent.Executor +import kotlin.math.min +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue +import kotlin.test.fail import org.junit.After import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertFalse @@ -75,17 +121,6 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import java.io.File -import java.net.ServerSocket -import java.nio.charset.StandardCharsets -import java.util.Random -import java.util.concurrent.Executor -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith -import kotlin.test.assertNotNull -import kotlin.test.assertNull -import kotlin.test.assertTrue -import kotlin.test.fail private const val TAG = "NsdManagerTest" private const val TIMEOUT_MS = 2000L @@ -96,11 +131,15 @@ // tried sequentially private const val REGISTRATION_TIMEOUT_MS = 10_000L private const val DBG = false +private const val TEST_PORT = 12345 private val nsdShim = NsdShimImpl.newInstance() @AppModeFull(reason = "Socket cannot bind in instant app mode") -@RunWith(AndroidJUnit4::class) +@RunWith(DevSdkIgnoreRunner::class) +@SmallTest +@ConnectivityModuleTest +@IgnoreUpTo(Build.VERSION_CODES.S_V2) class NsdManagerTest { // Rule used to filter CtsNetTestCasesMaxTargetSdkXX @get:Rule @@ -113,6 +152,7 @@ private val serviceName = "NsdTest%09d".format(Random().nextInt(1_000_000_000)) private val serviceType = "_nmt%09d._tcp".format(Random().nextInt(1_000_000_000)) private val handlerThread = HandlerThread(NsdManagerTest::class.java.simpleName) + private val ctsNetUtils by lazy{ CtsNetUtils(context) } private lateinit var testNetwork1: TestTapNetwork private lateinit var testNetwork2: TestTapNetwork @@ -155,7 +195,8 @@ inline fun <reified V : NsdEvent> expectCallback(timeoutMs: Long = TIMEOUT_MS): V { val nextEvent = nextEvents.poll(timeoutMs) - assertNotNull(nextEvent, "No callback received after $timeoutMs ms") + assertNotNull(nextEvent, "No callback received after $timeoutMs ms, expected " + + "${V::class.java.simpleName}") assertTrue(nextEvent is V, "Expected ${V::class.java.simpleName} but got " + nextEvent.javaClass.simpleName) return nextEvent @@ -182,10 +223,10 @@ val errorCode: Int ) : RegistrationEvent() - data class ServiceRegistered(override val serviceInfo: NsdServiceInfo) - : RegistrationEvent() - data class ServiceUnregistered(override val serviceInfo: NsdServiceInfo) - : RegistrationEvent() + data class ServiceRegistered(override val serviceInfo: NsdServiceInfo) : + RegistrationEvent() + data class ServiceUnregistered(override val serviceInfo: NsdServiceInfo) : + RegistrationEvent() } override fun onRegistrationFailed(si: NsdServiceInfo, err: Int) { @@ -208,11 +249,11 @@ private class NsdDiscoveryRecord(expectedThreadId: Int? = null) : DiscoveryListener, NsdRecord<NsdDiscoveryRecord.DiscoveryEvent>(expectedThreadId) { sealed class DiscoveryEvent : NsdEvent { - data class StartDiscoveryFailed(val serviceType: String, val errorCode: Int) - : DiscoveryEvent() + data class StartDiscoveryFailed(val serviceType: String, val errorCode: Int) : + DiscoveryEvent() - data class StopDiscoveryFailed(val serviceType: String, val errorCode: Int) - : DiscoveryEvent() + data class StopDiscoveryFailed(val serviceType: String, val errorCode: Int) : + DiscoveryEvent() data class DiscoveryStarted(val serviceType: String) : DiscoveryEvent() data class DiscoveryStopped(val serviceType: String) : DiscoveryEvent() @@ -246,23 +287,30 @@ fun waitForServiceDiscovered( serviceName: String, + serviceType: String, expectedNetwork: Network? = null ): NsdServiceInfo { - return expectCallbackEventually<ServiceFound> { + val serviceFound = expectCallbackEventually<ServiceFound> { it.serviceInfo.serviceName == serviceName && (expectedNetwork == null || expectedNetwork == nsdShim.getNetwork(it.serviceInfo)) }.serviceInfo + // Discovered service types have a dot at the end + assertEquals("$serviceType.", serviceFound.serviceType) + return serviceFound } } private class NsdResolveRecord : ResolveListener, NsdRecord<NsdResolveRecord.ResolveEvent>() { sealed class ResolveEvent : NsdEvent { - data class ResolveFailed(val serviceInfo: NsdServiceInfo, val errorCode: Int) - : ResolveEvent() + data class ResolveFailed(val serviceInfo: NsdServiceInfo, val errorCode: Int) : + ResolveEvent() data class ServiceResolved(val serviceInfo: NsdServiceInfo) : ResolveEvent() + data class ResolutionStopped(val serviceInfo: NsdServiceInfo) : ResolveEvent() + data class StopResolutionFailed(val serviceInfo: NsdServiceInfo, val errorCode: Int) : + ResolveEvent() } override fun onResolveFailed(si: NsdServiceInfo, err: Int) { @@ -272,6 +320,41 @@ override fun onServiceResolved(si: NsdServiceInfo) { add(ServiceResolved(si)) } + + override fun onResolutionStopped(si: NsdServiceInfo) { + add(ResolutionStopped(si)) + } + + override fun onStopResolutionFailed(si: NsdServiceInfo, err: Int) { + super.onStopResolutionFailed(si, err) + add(StopResolutionFailed(si, err)) + } + } + + private class NsdServiceInfoCallbackRecord : NsdShim.ServiceInfoCallbackShim, + NsdRecord<NsdServiceInfoCallbackRecord.ServiceInfoCallbackEvent>() { + sealed class ServiceInfoCallbackEvent : NsdEvent { + data class RegisterCallbackFailed(val errorCode: Int) : ServiceInfoCallbackEvent() + data class ServiceUpdated(val serviceInfo: NsdServiceInfo) : ServiceInfoCallbackEvent() + object ServiceUpdatedLost : ServiceInfoCallbackEvent() + object UnregisterCallbackSucceeded : ServiceInfoCallbackEvent() + } + + override fun onServiceInfoCallbackRegistrationFailed(err: Int) { + add(RegisterCallbackFailed(err)) + } + + override fun onServiceUpdated(si: NsdServiceInfo) { + add(ServiceUpdated(si)) + } + + override fun onServiceLost() { + add(ServiceUpdatedLost) + } + + override fun onServiceInfoCallbackUnregistered() { + add(UnregisterCallbackSucceeded) + } } @Before @@ -298,37 +381,85 @@ .build(), cb) val agent = registerTestNetworkAgent(iface.interfaceName) val network = agent.network ?: fail("Registered agent should have a network") + + cb.eventuallyExpect<LinkPropertiesChanged>(TIMEOUT_MS) { + it.lp.linkAddresses.isNotEmpty() + } + // The network has no INTERNET capability, so will be marked validated immediately - cb.expectAvailableThenValidatedCallbacks(network, TIMEOUT_MS) + // It does not matter if validated capabilities come before/after the link addresses change + cb.eventuallyExpect<CapabilitiesChanged>(TIMEOUT_MS, from = 0) { + it.caps.hasCapability(NET_CAPABILITY_VALIDATED) + } return TestTapNetwork(iface, cb, agent, network) } private fun registerTestNetworkAgent(ifaceName: String): TestableNetworkAgent { + val lp = LinkProperties().apply { + interfaceName = ifaceName + } + val agent = TestableNetworkAgent(context, handlerThread.looper, NetworkCapabilities().apply { removeCapability(NET_CAPABILITY_TRUSTED) addTransportType(TRANSPORT_TEST) setNetworkSpecifier(TestNetworkSpecifier(ifaceName)) - }, - LinkProperties().apply { - interfaceName = ifaceName - }, - NetworkAgentConfig.Builder().build()) - agent.register() + }, lp, NetworkAgentConfig.Builder().build()) + val network = agent.register() agent.markConnected() + agent.expectCallback<OnNetworkCreated>() + + // Wait until the link-local address can be used. Address flags are not available without + // elevated permissions, so check that bindSocket works. + PollingCheck.check("No usable v6 address on interface after $TIMEOUT_MS ms", TIMEOUT_MS) { + // To avoid race condition between socket connection succeeding and interface returning + // a non-empty address list. Verify that interface returns a non-empty list, before + // trying the socket connection. + if (NetworkInterface.getByName(ifaceName).interfaceAddresses.isEmpty()) { + return@check false + } + + val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP) + tryTest { + network.bindSocket(sock) + Os.connect(sock, parseNumericAddress("ff02::fb%$ifaceName"), 12345) + true + }.catch<ErrnoException> { + if (it.errno != ENETUNREACH && it.errno != EADDRNOTAVAIL) { + throw it + } + false + } cleanup { + Os.close(sock) + } + } + + lp.setLinkAddresses(NetworkInterface.getByName(ifaceName).interfaceAddresses.map { + LinkAddress(it.address, it.networkPrefixLength.toInt()) + }) + agent.sendLinkProperties(lp) return agent } + private fun makeTestServiceInfo(network: Network? = null) = NsdServiceInfo().also { + it.serviceType = serviceType + it.serviceName = serviceName + it.network = network + it.port = TEST_PORT + } + @After fun tearDown() { if (TestUtils.shouldTestTApis()) { runAsShell(MANAGE_TEST_NETWORKS) { - testNetwork1.close(cm) - testNetwork2.close(cm) + // Avoid throwing here if initializing failed in setUp + if (this::testNetwork1.isInitialized) testNetwork1.close(cm) + if (this::testNetwork2.isInitialized) testNetwork2.close(cm) } } handlerThread.waitForIdle(TIMEOUT_MS) handlerThread.quitSafely() + handlerThread.join() } @Test @@ -382,6 +513,10 @@ val registeredInfo = registrationRecord.expectCallback<ServiceRegistered>( REGISTRATION_TIMEOUT_MS).serviceInfo + // Only service name is included in ServiceRegistered callbacks + assertNull(registeredInfo.serviceType) + assertEquals(si.serviceName, registeredInfo.serviceName) + val discoveryRecord = NsdDiscoveryRecord() // Test discovering without an Executor nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord) @@ -390,12 +525,15 @@ discoveryRecord.expectCallback<DiscoveryStarted>() // Expect a service record to be discovered - val foundInfo = discoveryRecord.waitForServiceDiscovered(registeredInfo.serviceName) + val foundInfo = discoveryRecord.waitForServiceDiscovered( + registeredInfo.serviceName, serviceType) // Test resolving without an Executor val resolveRecord = NsdResolveRecord() nsdManager.resolveService(foundInfo, resolveRecord) val resolvedService = resolveRecord.expectCallback<ServiceResolved>().serviceInfo + assertEquals(".$serviceType", resolvedService.serviceType) + assertEquals(registeredInfo.serviceName, resolvedService.serviceName) // Check Txt attributes assertEquals(8, resolvedService.attributes.size) @@ -410,7 +548,12 @@ assertTrue(resolvedService.attributes.containsKey("nullBinaryDataAttr")) assertNull(resolvedService.attributes["nullBinaryDataAttr"]) assertTrue(resolvedService.attributes.containsKey("emptyBinaryDataAttr")) - assertNull(resolvedService.attributes["emptyBinaryDataAttr"]) + // TODO: change the check to target SDK U when this is what the code implements + if (isAtLeastU()) { + assertArrayEquals(byteArrayOf(), resolvedService.attributes["emptyBinaryDataAttr"]) + } else { + assertNull(resolvedService.attributes["emptyBinaryDataAttr"]) + } assertEquals(localPort, resolvedService.port) // Unregister the service @@ -418,9 +561,11 @@ registrationRecord.expectCallback<ServiceUnregistered>() // Expect a callback for service lost - discoveryRecord.expectCallbackEventually<ServiceLost> { + val lostCb = discoveryRecord.expectCallbackEventually<ServiceLost> { it.serviceInfo.serviceName == serviceName } + // Lost service types have a dot at the end + assertEquals("$serviceType.", lostCb.serviceInfo.serviceType) // Register service again to see if NsdManager can discover it val si2 = NsdServiceInfo() @@ -434,7 +579,8 @@ // Expect a service record to be discovered (and filter the ones // that are unrelated to this test) - val foundInfo2 = discoveryRecord.waitForServiceDiscovered(registeredInfo2.serviceName) + val foundInfo2 = discoveryRecord.waitForServiceDiscovered( + registeredInfo2.serviceName, serviceType) // Resolve the service val resolveRecord2 = NsdResolveRecord() @@ -471,7 +617,7 @@ testNetwork1.network, Executor { it.run() }, discoveryRecord) val foundInfo = discoveryRecord.waitForServiceDiscovered( - serviceName, testNetwork1.network) + serviceName, serviceType, testNetwork1.network) assertEquals(testNetwork1.network, nsdShim.getNetwork(foundInfo)) // Rewind to ensure the service is not found on the other interface @@ -518,6 +664,8 @@ val serviceDiscovered = discoveryRecord.expectCallback<ServiceFound>() assertEquals(registeredInfo1.serviceName, serviceDiscovered.serviceInfo.serviceName) + // Discovered service types have a dot at the end + assertEquals("$serviceType.", serviceDiscovered.serviceInfo.serviceType) assertEquals(testNetwork1.network, nsdShim.getNetwork(serviceDiscovered.serviceInfo)) // Unregister, then register the service back: it should be lost and found again @@ -530,6 +678,7 @@ val registeredInfo2 = registerService(registrationRecord, si, executor) val serviceDiscovered2 = discoveryRecord.expectCallback<ServiceFound>() assertEquals(registeredInfo2.serviceName, serviceDiscovered2.serviceInfo.serviceName) + assertEquals("$serviceType.", serviceDiscovered2.serviceInfo.serviceType) assertEquals(testNetwork1.network, nsdShim.getNetwork(serviceDiscovered2.serviceInfo)) // Teardown, then bring back up a network on the test interface: the service should @@ -545,6 +694,7 @@ val newNetwork = newAgent.network ?: fail("Registered agent should have a network") val serviceDiscovered3 = discoveryRecord.expectCallback<ServiceFound>() assertEquals(registeredInfo2.serviceName, serviceDiscovered3.serviceInfo.serviceName) + assertEquals("$serviceType.", serviceDiscovered3.serviceInfo.serviceType) assertEquals(newNetwork, nsdShim.getNetwork(serviceDiscovered3.serviceInfo)) } cleanupStep { nsdManager.stopServiceDiscovery(discoveryRecord) @@ -587,6 +737,20 @@ } } + private fun checkAddressScopeId(iface: TestNetworkInterface, address: List<InetAddress>) { + val targetSdkVersion = context.packageManager + .getTargetSdkVersion(context.applicationInfo.packageName) + if (targetSdkVersion <= Build.VERSION_CODES.TIRAMISU) { + return + } + val ifaceIdx = NetworkInterface.getByName(iface.interfaceName).index + address.forEach { + if (it is Inet6Address && it.isLinkLocalAddress) { + assertEquals(ifaceIdx, it.scopeId) + } + } + } + @Test fun testNsdManager_ResolveOnNetwork() { // This test requires shims supporting T+ APIs (NsdServiceInfo.network) @@ -606,12 +770,12 @@ nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord) val foundInfo1 = discoveryRecord.waitForServiceDiscovered( - serviceName, testNetwork1.network) + serviceName, serviceType, testNetwork1.network) assertEquals(testNetwork1.network, nsdShim.getNetwork(foundInfo1)) // Rewind as the service could be found on each interface in any order discoveryRecord.nextEvents.rewind(0) val foundInfo2 = discoveryRecord.waitForServiceDiscovered( - serviceName, testNetwork2.network) + serviceName, serviceType, testNetwork2.network) assertEquals(testNetwork2.network, nsdShim.getNetwork(foundInfo2)) nsdShim.resolveService(nsdManager, foundInfo1, Executor { it.run() }, resolveRecord) @@ -622,6 +786,7 @@ assertEquals(registeredInfo.serviceName, it.serviceName) assertEquals(si.port, it.port) assertEquals(testNetwork1.network, nsdShim.getNetwork(it)) + checkAddressScopeId(testNetwork1.iface, it.hostAddresses) } // TODO: check that MDNS packets are sent only on testNetwork1. } cleanupStep { @@ -655,7 +820,7 @@ testNetwork1.network, Executor { it.run() }, discoveryRecord) // Expect that service is found on testNetwork1 val foundInfo = discoveryRecord.waitForServiceDiscovered( - serviceName, testNetwork1.network) + serviceName, serviceType, testNetwork1.network) assertEquals(testNetwork1.network, nsdShim.getNetwork(foundInfo)) // Discover service on testNetwork2. @@ -670,7 +835,7 @@ null as Network? /* network */, Executor { it.run() }, discoveryRecord3) // Expect that service is found on testNetwork1 val foundInfo3 = discoveryRecord3.waitForServiceDiscovered( - serviceName, testNetwork1.network) + serviceName, serviceType, testNetwork1.network) assertEquals(testNetwork1.network, nsdShim.getNetwork(foundInfo3)) } cleanupStep { nsdManager.stopServiceDiscovery(discoveryRecord2) @@ -700,7 +865,7 @@ nsdManager.discoverServices( serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord ) - val foundInfo = discoveryRecord.waitForServiceDiscovered(serviceNames) + val foundInfo = discoveryRecord.waitForServiceDiscovered(serviceNames, serviceType) // Expect that resolving the service name works properly even service name contains // non-standard characters. @@ -715,6 +880,69 @@ } } + private fun checkConnectSocketToMdnsd(shouldFail: Boolean) { + val discoveryRecord = NsdDiscoveryRecord() + val localSocket = LocalSocket() + tryTest { + // Discover any service from NsdManager to enforce NsdService to start the mdnsd. + nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord) + discoveryRecord.expectCallback<DiscoveryStarted>() + + // Checks the /dev/socket/mdnsd is created. + val socket = File("/dev/socket/mdnsd") + val doesSocketExist = PollingCheck.waitFor( + TIMEOUT_MS, + { + socket.exists() + }, + { doesSocketExist -> + doesSocketExist + }, + ) + + // If the socket is not created, then no need to check the access. + if (doesSocketExist) { + // Create a LocalSocket and try to connect to mdnsd. + assertFalse("LocalSocket is connected.", localSocket.isConnected) + val address = LocalSocketAddress("mdnsd", LocalSocketAddress.Namespace.RESERVED) + if (shouldFail) { + assertFailsWith<IOException>("Expect fail but socket connected") { + localSocket.connect(address) + } + } else { + localSocket.connect(address) + assertTrue("LocalSocket is not connected.", localSocket.isConnected) + } + } + } cleanup { + localSocket.close() + nsdManager.stopServiceDiscovery(discoveryRecord) + discoveryRecord.expectCallback<DiscoveryStopped>() + } + } + + /** + * Starting from Android U, the access to the /dev/socket/mdnsd is blocked by the + * sepolicy(b/265364111). + */ + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + fun testCannotConnectSocketToMdnsd() { + val targetSdkVersion = context.packageManager + .getTargetSdkVersion(context.applicationInfo.packageName) + assumeTrue(targetSdkVersion > Build.VERSION_CODES.TIRAMISU) + val firstApiLevel = min(PropertyUtil.getFirstApiLevel(), PropertyUtil.getVendorApiLevel()) + // The sepolicy is implemented in the vendor image, so the access may not be blocked if + // the vendor image is not update to date. + assumeTrue(firstApiLevel > Build.VERSION_CODES.TIRAMISU) + checkConnectSocketToMdnsd(shouldFail = true) + } + + @Test @CtsNetTestCasesMaxTargetSdk33("mdnsd socket is accessible up to target SDK 33") + fun testCanConnectSocketToMdnsd() { + checkConnectSocketToMdnsd(shouldFail = false) + } + @Test @CtsNetTestCasesMaxTargetSdk30("Socket is started with the service up to target SDK 30") fun testManagerCreatesLegacySocket() { nsdManager // Ensure the lazy-init member is initialized, so NsdManager is created @@ -736,7 +964,146 @@ // when the compat change is disabled. // Note that before T the compat constant had a different int value. assertFalse(CompatChanges.isChangeEnabled( - NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)) + ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER)) + } + + @Test + fun testStopServiceResolution() { + // This test requires shims supporting U+ APIs (NsdManager.stopServiceResolution) + assumeTrue(TestUtils.shouldTestUApis()) + + val si = NsdServiceInfo() + si.serviceType = this@NsdManagerTest.serviceType + si.serviceName = this@NsdManagerTest.serviceName + si.port = 12345 // Test won't try to connect so port does not matter + + val resolveRecord = NsdResolveRecord() + // Try to resolve an unknown service then stop it immediately. + // Expected ResolutionStopped callback. + nsdShim.resolveService(nsdManager, si, { it.run() }, resolveRecord) + nsdShim.stopServiceResolution(nsdManager, resolveRecord) + val stoppedCb = resolveRecord.expectCallback<ResolutionStopped>() + assertEquals(si.serviceName, stoppedCb.serviceInfo.serviceName) + assertEquals(si.serviceType, stoppedCb.serviceInfo.serviceType) + } + + @Test + fun testRegisterServiceInfoCallback() { + // This test requires shims supporting U+ APIs (NsdManager.registerServiceInfoCallback) + assumeTrue(TestUtils.shouldTestUApis()) + + val lp = cm.getLinkProperties(testNetwork1.network) + assertNotNull(lp) + val addresses = lp.addresses + assertFalse(addresses.isEmpty()) + + val si = NsdServiceInfo().apply { + serviceType = this@NsdManagerTest.serviceType + serviceName = this@NsdManagerTest.serviceName + network = testNetwork1.network + port = 12345 // Test won't try to connect so port does not matter + } + + // Register service on the network + val registrationRecord = NsdRegistrationRecord() + registerService(registrationRecord, si) + + val discoveryRecord = NsdDiscoveryRecord() + val cbRecord = NsdServiceInfoCallbackRecord() + tryTest { + // Discover service on the network. + nsdShim.discoverServices(nsdManager, serviceType, NsdManager.PROTOCOL_DNS_SD, + testNetwork1.network, Executor { it.run() }, discoveryRecord) + val foundInfo = discoveryRecord.waitForServiceDiscovered( + serviceName, serviceType, testNetwork1.network) + + // Register service callback and check the addresses are the same as network addresses + nsdShim.registerServiceInfoCallback(nsdManager, foundInfo, { it.run() }, cbRecord) + val serviceInfoCb = cbRecord.expectCallback<ServiceUpdated>() + assertEquals(foundInfo.serviceName, serviceInfoCb.serviceInfo.serviceName) + val hostAddresses = serviceInfoCb.serviceInfo.hostAddresses + assertEquals(addresses.size, hostAddresses.size) + for (hostAddress in hostAddresses) { + assertTrue(addresses.contains(hostAddress)) + } + checkAddressScopeId(testNetwork1.iface, serviceInfoCb.serviceInfo.hostAddresses) + } cleanupStep { + nsdManager.unregisterService(registrationRecord) + registrationRecord.expectCallback<ServiceUnregistered>() + discoveryRecord.expectCallback<ServiceLost>() + cbRecord.expectCallback<ServiceUpdatedLost>() + } cleanupStep { + // Cancel subscription and check stop callback received. + nsdShim.unregisterServiceInfoCallback(nsdManager, cbRecord) + cbRecord.expectCallback<UnregisterCallbackSucceeded>() + } cleanup { + nsdManager.stopServiceDiscovery(discoveryRecord) + discoveryRecord.expectCallback<DiscoveryStopped>() + } + } + + @Test + fun testStopServiceResolutionFailedCallback() { + // This test requires shims supporting U+ APIs (NsdManager.stopServiceResolution) + assumeTrue(TestUtils.shouldTestUApis()) + + // It's not possible to make ResolutionListener#onStopResolutionFailed callback sending + // because it is only sent in very edge-case scenarios when the legacy implementation is + // used, and the legacy implementation is never used in the current AOSP builds. Considering + // that this callback isn't expected to be sent at all at the moment, and this is just an + // interface with no implementation. To verify this callback, just call + // onStopResolutionFailed on the record directly then verify it is received. + val resolveRecord = NsdResolveRecord() + resolveRecord.onStopResolutionFailed( + NsdServiceInfo(), NsdManager.FAILURE_OPERATION_NOT_RUNNING) + val failedCb = resolveRecord.expectCallback<StopResolutionFailed>() + assertEquals(NsdManager.FAILURE_OPERATION_NOT_RUNNING, failedCb.errorCode) + } + + @Test + fun testSubtypeAdvertisingAndDiscovery() { + val si = makeTestServiceInfo(network = testNetwork1.network) + // Test "_type._tcp.local,_subtype" syntax with the registration + si.serviceType = si.serviceType + ",_subtype" + + val registrationRecord = NsdRegistrationRecord() + + val baseTypeDiscoveryRecord = NsdDiscoveryRecord() + val subtypeDiscoveryRecord = NsdDiscoveryRecord() + val otherSubtypeDiscoveryRecord = NsdDiscoveryRecord() + tryTest { + registerService(registrationRecord, si) + + // Test "_subtype._type._tcp.local" syntax with discovery. Note this is not + // "_subtype._sub._type._tcp.local". + nsdManager.discoverServices(serviceType, + NsdManager.PROTOCOL_DNS_SD, + testNetwork1.network, Executor { it.run() }, baseTypeDiscoveryRecord) + nsdManager.discoverServices("_othersubtype.$serviceType", + NsdManager.PROTOCOL_DNS_SD, + testNetwork1.network, Executor { it.run() }, otherSubtypeDiscoveryRecord) + nsdManager.discoverServices("_subtype.$serviceType", + NsdManager.PROTOCOL_DNS_SD, + testNetwork1.network, Executor { it.run() }, subtypeDiscoveryRecord) + + subtypeDiscoveryRecord.waitForServiceDiscovered( + serviceName, serviceType, testNetwork1.network) + baseTypeDiscoveryRecord.waitForServiceDiscovered( + serviceName, serviceType, testNetwork1.network) + otherSubtypeDiscoveryRecord.expectCallback<DiscoveryStarted>() + // The subtype callback was registered later but called, no need for an extra delay + otherSubtypeDiscoveryRecord.assertNoCallback(timeoutMs = 0) + } cleanupStep { + nsdManager.stopServiceDiscovery(baseTypeDiscoveryRecord) + nsdManager.stopServiceDiscovery(subtypeDiscoveryRecord) + nsdManager.stopServiceDiscovery(otherSubtypeDiscoveryRecord) + + baseTypeDiscoveryRecord.expectCallback<DiscoveryStopped>() + subtypeDiscoveryRecord.expectCallback<DiscoveryStopped>() + otherSubtypeDiscoveryRecord.expectCallback<DiscoveryStopped>() + } cleanup { + nsdManager.unregisterService(registrationRecord) + } } /**
diff --git a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java index f0c87673..4854901 100644 --- a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java +++ b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
@@ -23,12 +23,14 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import android.app.Instrumentation; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.Network; import android.net.PacProxyManager; @@ -150,6 +152,9 @@ @AppModeFull(reason = "Instant apps can't bind sockets to localhost for a test proxy server") @Test public void testSetCurrentProxyScriptUrl() throws Exception { + // Devices without WebView/JavaScript cannot support PAC proxies + assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)); + // Register a PacProxyInstalledListener final TestPacProxyInstalledListener listener = new TestPacProxyInstalledListener(); final Executor executor = (Runnable r) -> r.run();
diff --git a/tests/cts/net/src/android/net/cts/RateLimitTest.java b/tests/cts/net/src/android/net/cts/RateLimitTest.java index 28cec1a..36b98fc 100644 --- a/tests/cts/net/src/android/net/cts/RateLimitTest.java +++ b/tests/cts/net/src/android/net/cts/RateLimitTest.java
@@ -301,29 +301,32 @@ public void testIngressRateLimit_testLimit() throws Exception { assumeKernelSupport(); + // These tests are not very precise, especially on lower-end devices. + // Add 30% tolerance to reduce test flakiness. Burst size is constant at 128KiB. + final double toleranceFactor = 1.3; + // If this value is too low, this test might become flaky because of the burst value that // allows to send at a higher data rate for a short period of time. The faster the data rate // and the longer the test, the less this test will be affected. final long dataLimitInBytesPerSecond = 2_000_000; // 2MB/s long resultInBytesPerSecond = runIngressDataRateMeasurement(Duration.ofSeconds(1)); assertGreaterThan("Failed initial test with rate limit disabled", resultInBytesPerSecond, - dataLimitInBytesPerSecond); + (long) (dataLimitInBytesPerSecond * toleranceFactor)); // enable rate limit and wait until the tc filter is installed before starting the test. ConnectivitySettingsManager.setIngressRateLimitInBytesPerSecond(mContext, dataLimitInBytesPerSecond); waitForTcPoliceFilterInstalled(Duration.ofSeconds(1)); - resultInBytesPerSecond = runIngressDataRateMeasurement(Duration.ofSeconds(10)); - // Add 10% tolerance to reduce test flakiness. Burst size is constant at 128KiB. + resultInBytesPerSecond = runIngressDataRateMeasurement(Duration.ofSeconds(15)); assertLessThan("Failed test with rate limit enabled", resultInBytesPerSecond, - (long) (dataLimitInBytesPerSecond * 1.1)); + (long) (dataLimitInBytesPerSecond * toleranceFactor)); ConnectivitySettingsManager.setIngressRateLimitInBytesPerSecond(mContext, -1); resultInBytesPerSecond = runIngressDataRateMeasurement(Duration.ofSeconds(1)); assertGreaterThan("Failed test with rate limit disabled", resultInBytesPerSecond, - dataLimitInBytesPerSecond); + (long) (dataLimitInBytesPerSecond * toleranceFactor)); } @Test
diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index cbe54f8..1a780a7 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
@@ -66,7 +66,6 @@ InetAddress[] addresses; try { addresses = InetAddress.getAllByName(TEST_HOST); - mTestHostAddress = addresses[0]; } catch (UnknownHostException uhe) { throw new AssertionError( "Unable to test SSLCertificateSocketFactory: cannot resolve " + TEST_HOST, uhe); @@ -76,10 +75,11 @@ .map(addr -> new InetSocketAddress(addr, HTTPS_PORT)) .collect(Collectors.toList()); - // Find the local IP address which will be used to connect to TEST_HOST. + // Find the local and remote IP addresses which will be used to connect to TEST_HOST. try { Socket testSocket = new Socket(TEST_HOST, HTTPS_PORT); mLocalAddress = testSocket.getLocalAddress(); + mTestHostAddress = testSocket.getInetAddress(); testSocket.close(); } catch (IOException ioe) { throw new AssertionError(""
diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java index 0377160..268d8d2 100644 --- a/tests/cts/net/src/android/net/cts/TunUtils.java +++ b/tests/cts/net/src/android/net/cts/TunUtils.java
@@ -22,7 +22,6 @@ import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_UDP; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import android.os.ParcelFileDescriptor; @@ -32,6 +31,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -140,10 +140,8 @@ public byte[] awaitEspPacketNoPlaintext( int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { final byte[] espPkt = awaitPacket( - (pkt) -> isEspFailIfSpecifiedPlaintextFound(pkt, spi, useEncap, plaintext)); - - // Validate packet size - assertEquals(expectedPacketSize, espPkt.length); + (pkt) -> expectedPacketSize == pkt.length + && isEspFailIfSpecifiedPlaintextFound(pkt, spi, useEncap, plaintext)); return espPkt; // We've found the packet we're looking for. } @@ -153,11 +151,11 @@ } private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { - // Check SPI byte by byte. - return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff) - && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff) - && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff) - && pkt[espOffset + 3] == (byte) (spi & 0xff); + ByteBuffer buffer = ByteBuffer.wrap(pkt); + buffer.get(new byte[espOffset]); // Skip IP, UDP header + int actualSpi = buffer.getInt(); + + return actualSpi == spi; } /** @@ -180,8 +178,13 @@ private static boolean isEsp(byte[] pkt, int spi, boolean encap) { if (isIpv6(pkt)) { - // IPv6 UDP encap not supported by kernels; assume non-encap. - return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi); + if (encap) { + return pkt[IP6_PROTO_OFFSET] == IPPROTO_UDP + && isSpiEqual(pkt, IP6_HDRLEN + UDP_HDRLEN, spi); + } else { + return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi); + } + } else { // Use default IPv4 header length (assuming no options) if (encap) {
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java index 3f2ff9d..ce789fc 100644 --- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java +++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -57,6 +57,8 @@ import android.text.TextUtils; import android.util.Log; +import androidx.annotation.Nullable; + import com.android.compatibility.common.util.PollingCheck; import com.android.compatibility.common.util.ShellIdentityUtils; import com.android.compatibility.common.util.SystemUtil; @@ -68,6 +70,8 @@ import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; +import java.util.ArrayList; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -75,6 +79,13 @@ public final class CtsNetUtils { private static final String TAG = CtsNetUtils.class.getSimpleName(); + + // Redefine this flag here so that IPsec code shipped in a mainline module can build on old + // platforms before FEATURE_IPSEC_TUNNEL_MIGRATION API is released. + // TODO: b/275378783 Remove this flag and use the platform API when it is available. + private static final String FEATURE_IPSEC_TUNNEL_MIGRATION = + "android.software.ipsec_tunnel_migration"; + private static final int SOCKET_TIMEOUT_MS = 2000; private static final int PRIVATE_DNS_PROBE_MS = 1_000; @@ -115,6 +126,11 @@ || getFirstApiLevel() >= Build.VERSION_CODES.Q; } + /** Checks if FEATURE_IPSEC_TUNNEL_MIGRATION is enabled on the device */ + public boolean hasIpsecTunnelMigrateFeature() { + return mContext.getPackageManager().hasSystemFeature(FEATURE_IPSEC_TUNNEL_MIGRATION); + } + /** * Sets the given appop using shell commands * @@ -170,7 +186,7 @@ } } - private Network expectNetworkIsSystemDefault(Network network) + public Network expectNetworkIsSystemDefault(Network network) throws Exception { final CompletableFuture<Network> future = new CompletableFuture(); final NetworkCallback cb = new NetworkCallback() { @@ -410,7 +426,7 @@ .build(); } - private void testHttpRequest(Socket s) throws IOException { + public void testHttpRequest(Socket s) throws IOException { OutputStream out = s.getOutputStream(); InputStream in = s.getInputStream(); @@ -418,7 +434,9 @@ byte[] responseBytes = new byte[4096]; out.write(requestBytes); in.read(responseBytes); - assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); + final String response = new String(responseBytes, "UTF-8"); + assertTrue("Received unexpected response: " + response, + response.startsWith("HTTP/1.0 204 No Content\r\n")); } private Socket getBoundSocket(Network network, String host, int port) throws IOException { @@ -494,17 +512,18 @@ * @throws InterruptedException If the thread is interrupted. */ public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, - @NonNull String server, boolean requiresValidatedServer) throws InterruptedException { + @Nullable String server, boolean requiresValidatedServer) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); - NetworkCallback callback = new NetworkCallback() { + final NetworkCallback callback = new NetworkCallback() { @Override public void onLinkPropertiesChanged(Network n, LinkProperties lp) { Log.i(TAG, "Link properties of network " + n + " changed to " + lp); if (requiresValidatedServer && lp.getValidatedPrivateDnsServers().isEmpty()) { return; } - if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) { + Log.i(TAG, "Set private DNS server to " + server); + if (network.equals(n) && Objects.equals(server, lp.getPrivateDnsServerName())) { latch.countDown(); } } @@ -527,6 +546,27 @@ } /** + * Get all testable Networks with internet capability. + */ + public Network[] getTestableNetworks() { + final ArrayList<Network> testableNetworks = new ArrayList<Network>(); + for (Network network : mCm.getAllNetworks()) { + final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + if (nc != null + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + testableNetworks.add(network); + } + } + + assertTrue("This test requires that at least one public Internet-providing" + + " network be connected. Please ensure that the device is connected to" + + " a network.", + testableNetworks.size() >= 1); + return testableNetworks.toArray(new Network[0]); + } + + /** * Receiver that captures the last connectivity change's network type and state. Recognizes * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. */
diff --git a/tests/cts/net/util/java/android/net/cts/util/IkeSessionTestUtils.java b/tests/cts/net/util/java/android/net/cts/util/IkeSessionTestUtils.java index 11eb466..25534b8 100644 --- a/tests/cts/net/util/java/android/net/cts/util/IkeSessionTestUtils.java +++ b/tests/cts/net/util/java/android/net/cts/util/IkeSessionTestUtils.java
@@ -42,8 +42,9 @@ public class IkeSessionTestUtils { private static final String TEST_SERVER_ADDR_V4 = "192.0.2.2"; private static final String TEST_SERVER_ADDR_V6 = "2001:db8::2"; - private static final String TEST_IDENTITY = "client.cts.android.com"; + public static final String TEST_IDENTITY = "client.cts.android.com"; private static final byte[] TEST_PSK = "ikeAndroidPsk".getBytes(); + public static final int TEST_KEEPALIVE_TIMEOUT_UNSET = -1; public static final IkeSessionParams IKE_PARAMS_V4 = getTestIkeSessionParams(false); public static final IkeSessionParams IKE_PARAMS_V6 = getTestIkeSessionParams(true); @@ -63,17 +64,26 @@ public static IkeSessionParams getTestIkeSessionParams(boolean testIpv6, IkeIdentification identification) { + return getTestIkeSessionParams(testIpv6, identification, TEST_KEEPALIVE_TIMEOUT_UNSET); + } + + public static IkeSessionParams getTestIkeSessionParams(boolean testIpv6, + IkeIdentification identification, int keepaliveTimer) { final String testServer = testIpv6 ? TEST_SERVER_ADDR_V6 : TEST_SERVER_ADDR_V4; final InetAddress addr = InetAddresses.parseNumericAddress(testServer); final IkeSessionParams.Builder ikeOptionsBuilder = new IkeSessionParams.Builder() .setServerHostname(testServer) - .setLocalIdentification(new IkeFqdnIdentification(TEST_IDENTITY)) + .setLocalIdentification(identification) .setRemoteIdentification(testIpv6 ? new IkeIpv6AddrIdentification((Inet6Address) addr) : new IkeIpv4AddrIdentification((Inet4Address) addr)) .setAuthPsk(TEST_PSK) + .addSaProposal(getIkeSaProposals()); + if (keepaliveTimer != TEST_KEEPALIVE_TIMEOUT_UNSET) { + ikeOptionsBuilder.setNattKeepAliveDelaySeconds(keepaliveTimer); + } return ikeOptionsBuilder.build(); }
diff --git a/tests/cts/netpermission/internetpermission/AndroidManifest.xml b/tests/cts/netpermission/internetpermission/AndroidManifest.xml index 45ef5bd..ae7de3f 100644 --- a/tests/cts/netpermission/internetpermission/AndroidManifest.xml +++ b/tests/cts/netpermission/internetpermission/AndroidManifest.xml
@@ -43,8 +43,6 @@ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.networkpermission.internetpermission.cts" android:label="CTS tests for INTERNET permissions"> - <meta-data android:name="listener" - android:value="com.android.cts.runner.CtsTestRunListener"/> </instrumentation> </manifest>
diff --git a/tests/cts/netpermission/updatestatspermission/AndroidManifest.xml b/tests/cts/netpermission/updatestatspermission/AndroidManifest.xml index 6babe8f..8a7e3f7 100644 --- a/tests/cts/netpermission/updatestatspermission/AndroidManifest.xml +++ b/tests/cts/netpermission/updatestatspermission/AndroidManifest.xml
@@ -51,8 +51,6 @@ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.networkpermission.updatestatspermission.cts" android:label="CTS tests for UPDATE_DEVICE_STATS permissions"> - <meta-data android:name="listener" - android:value="com.android.cts.runner.CtsTestRunListener"/> </instrumentation> </manifest>
diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 42949a4..4284f56 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp
@@ -46,6 +46,7 @@ // Change to system current when TetheringManager move to bootclass path. platform_apis: true, + host_required: ["net-tests-utils-host-common"], } // Tethering CTS tests that target the latest released SDK. These tests can be installed on release
diff --git a/tests/cts/tethering/AndroidManifest.xml b/tests/cts/tethering/AndroidManifest.xml index 911dbf2..bad722b 100644 --- a/tests/cts/tethering/AndroidManifest.xml +++ b/tests/cts/tethering/AndroidManifest.xml
@@ -27,8 +27,6 @@ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.tethering.cts" android:label="CTS tests of android.tethering"> - <meta-data android:name="listener" - android:value="com.android.cts.runner.CtsTestRunListener" /> </instrumentation> </manifest>
diff --git a/tests/cts/tethering/AndroidTestTemplate.xml b/tests/cts/tethering/AndroidTestTemplate.xml index 491b004..9b33afe 100644 --- a/tests/cts/tethering/AndroidTestTemplate.xml +++ b/tests/cts/tethering/AndroidTestTemplate.xml
@@ -25,6 +25,8 @@ <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="{MODULE}.apk" /> </target_preparer> + <target_preparer class="com.android.testutils.ConnectivityTestTargetPreparer"> + </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="android.tethering.cts" /> </test>
diff --git a/tests/integration/Android.bp b/tests/integration/Android.bp index e3d80a0..12919ae 100644 --- a/tests/integration/Android.bp +++ b/tests/integration/Android.bp
@@ -21,7 +21,10 @@ android_test { name: "FrameworksNetIntegrationTests", - defaults: ["framework-connectivity-internal-test-defaults"], + defaults: [ + "framework-connectivity-internal-test-defaults", + "NetworkStackApiShimSettingsForCurrentBranch", + ], platform_apis: true, certificate: "platform", srcs: [ @@ -33,6 +36,13 @@ "ServiceConnectivityResources", ], static_libs: [ + // It does not matter if NetworkStackApiStableLib or NetworkStackApiCurrentLib is used here, + // since the shims for the branch are already included via + // NetworkStackApiShimSettingsForCurrentBranch, and will be used in priority as they are + // first in the classpath. + // If the wrong shims are used for some reason, tests that use newer APIs fail. + // TODO: have NetworkStackApiStableLib link dynamically against the shims to remove this + // order-dependent setup. "NetworkStackApiStableLib", "androidx.test.ext.junit", "frameworks-net-integration-testutils",
diff --git a/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index 26b058d..67e1296 100644 --- a/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -25,7 +25,6 @@ import android.content.ServiceConnection import android.content.res.Resources import android.net.ConnectivityManager -import android.net.ConnectivityResources import android.net.IDnsResolver import android.net.INetd import android.net.LinkProperties @@ -37,7 +36,6 @@ import android.net.TestNetworkStackClient import android.net.Uri import android.net.metrics.IpConnectivityLog -import com.android.server.connectivity.MultinetworkPolicyTracker import android.os.ConditionVariable import android.os.IBinder import android.os.SystemConfigManager @@ -51,9 +49,15 @@ import com.android.server.ConnectivityService import com.android.server.NetworkAgentWrapper import com.android.server.TestNetIdManager +import com.android.server.connectivity.ConnectivityResources import com.android.server.connectivity.MockableSystemProperties +import com.android.server.connectivity.MultinetworkPolicyTracker import com.android.server.connectivity.ProxyTracker +import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged import com.android.testutils.TestableNetworkCallback +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import kotlin.test.fail import org.junit.After import org.junit.Before import org.junit.BeforeClass @@ -72,11 +76,6 @@ import org.mockito.Mockito.spy import org.mockito.MockitoAnnotations import org.mockito.Spy -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertNotNull -import kotlin.test.assertTrue -import kotlin.test.fail const val SERVICE_BIND_TIMEOUT_MS = 5_000L const val TEST_TIMEOUT_MS = 10_000L @@ -216,8 +215,8 @@ inv.getArgument(2), object : MultinetworkPolicyTracker.Dependencies() { override fun getResourcesForActiveSubId( - connResources: ConnectivityResources, - activeSubId: Int + connResources: ConnectivityResources, + activeSubId: Int ) = resources }) }.`when`(deps).makeMultinetworkPolicyTracker(any(), any(), any()) @@ -289,15 +288,16 @@ testCb.expectAvailableCallbacks(na.network, validated = false, tmt = TEST_TIMEOUT_MS) - val capportData = testCb.expectLinkPropertiesThat(na, TEST_TIMEOUT_MS) { - it.captivePortalData != null + val capportData = testCb.expect<LinkPropertiesChanged>(na, TEST_TIMEOUT_MS) { + it.lp.captivePortalData != null }.lp.captivePortalData - assertNotNull(capportData) assertTrue(capportData.isCaptive) assertEquals(Uri.parse("https://login.capport.android.com"), capportData.userPortalUrl) assertEquals(Uri.parse("https://venueinfo.capport.android.com"), capportData.venueInfoUrl) - val nc = testCb.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, na, TEST_TIMEOUT_MS) - assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED)) + testCb.expectCaps(na, TEST_TIMEOUT_MS) { + it.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) && + !it.hasCapability(NET_CAPABILITY_VALIDATED) + } } -} \ No newline at end of file +}
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp index aa5654a..c294e7b 100644 --- a/tests/mts/bpf_existence_test.cpp +++ b/tests/mts/bpf_existence_test.cpp
@@ -20,8 +20,6 @@ #include <set> #include <string> -#include <android/api-level.h> -#include <android-base/properties.h> #include <android-modules-utils/sdk_level.h> #include <bpf/BpfUtils.h> @@ -45,7 +43,7 @@ class BpfExistenceTest : public ::testing::Test { }; -// Part of Android R platform, but mainlined in S +// Part of Android R platform (for 4.9+), but mainlined in S static const set<string> PLATFORM_ONLY_IN_R = { PLATFORM "map_offload_tether_ingress_map", PLATFORM "map_offload_tether_limit_map", @@ -128,17 +126,18 @@ SHARED "prog_dscpPolicy_schedcls_set_dscp_ether", }; -void addAll(set<string>* a, const set<string>& b) { - a->insert(b.begin(), b.end()); +static void addAll(set<string>& a, const set<string>& b) { + a.insert(b.begin(), b.end()); } -#define DO_EXPECT(B, V) do { \ - if (B) addAll(expected, (V)); else addAll(unexpected, (V)); \ -} while (0) +#define DO_EXPECT(B, V) addAll((B) ? mustExist : mustNotExist, (V)) -void getFileLists(set<string>* expected, set<string>* unexpected) { - unexpected->clear(); - expected->clear(); +TEST_F(BpfExistenceTest, TestPrograms) { + // Only unconfined root is guaranteed to be able to access everything in /sys/fs/bpf. + ASSERT_EQ(0, getuid()) << "This test must run as root."; + + set<string> mustExist; + set<string> mustNotExist; // We do not actually check the platform P/Q (netd) and Q (clatd) things // and only verify the mainline module relevant R+ offload maps & progs. @@ -147,24 +146,23 @@ // and not to test the platform itself, which may have been modified by vendor or oems, // so we should only test for the removal of stuff that was mainline'd, // and for the presence of mainline stuff. - DO_EXPECT(IsAtLeastR() && !IsAtLeastS(), PLATFORM_ONLY_IN_R); + // R can potentially run on pre-4.9 kernel non-eBPF capable devices. + DO_EXPECT(IsAtLeastR() && !IsAtLeastS() && isAtLeastKernelVersion(4, 9, 0), PLATFORM_ONLY_IN_R); + + // S requires Linux Kernel 4.9+ and thus requires eBPF support. DO_EXPECT(IsAtLeastS(), MAINLINE_FOR_S_PLUS); DO_EXPECT(IsAtLeastS() && isAtLeastKernelVersion(5, 10, 0), MAINLINE_FOR_S_5_10_PLUS); // Nothing added or removed in SCv2. + // T still only requires Linux Kernel 4.9+. 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); -} -void checkFiles() { - set<string> mustExist; - set<string> mustNotExist; - - getFileLists(&mustExist, &mustNotExist); + // U requires Linux Kernel 4.14+, but nothing (as yet) added or removed in U. for (const auto& file : mustExist) { EXPECT_EQ(0, access(file.c_str(), R_OK)) << file << " does not exist"; @@ -178,19 +176,3 @@ } } } - -TEST_F(BpfExistenceTest, TestPrograms) { - SKIP_IF_BPF_NOT_SUPPORTED; - - // Pre-flight check to ensure test has been updated. - uint64_t buildVersionSdk = android_get_device_api_level(); - ASSERT_NE(0, buildVersionSdk) << "Unable to determine device SDK version"; - if (buildVersionSdk > __ANDROID_API_T__ && buildVersionSdk != __ANDROID_API_FUTURE__) { - FAIL() << "Unknown OS version " << buildVersionSdk << ", please update this test"; - } - - // Only unconfined root is guaranteed to be able to access everything in /sys/fs/bpf. - ASSERT_EQ(0, getuid()) << "This test must run as root."; - - checkFiles(); -}
diff --git a/tests/native/utilities/firewall.h b/tests/native/utilities/firewall.h index 185559b..1e7e987 100644 --- a/tests/native/utilities/firewall.h +++ b/tests/native/utilities/firewall.h
@@ -19,7 +19,7 @@ #include <android-base/thread_annotations.h> #include <bpf/BpfMap.h> -#include <bpf_shared.h> +#include "netd.h" using android::base::Result; using android::bpf::BpfMap;
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp index 8ed735a..8b286a0 100644 --- a/tests/unit/Android.bp +++ b/tests/unit/Android.bp
@@ -26,7 +26,6 @@ "libandroid_net_frameworktests_util_jni", "libbase", "libbinder", - "libbpf_bcc", "libc++", "libcrypto", "libcutils", @@ -69,11 +68,11 @@ "java/com/android/server/VpnManagerServiceTest.java", "java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java", "java/com/android/server/connectivity/IpConnectivityMetricsTest.java", + "java/com/android/server/connectivity/MetricsTestUtil.java", "java/com/android/server/connectivity/MultipathPolicyTrackerTest.java", "java/com/android/server/connectivity/NetdEventListenerServiceTest.java", "java/com/android/server/connectivity/VpnTest.java", "java/com/android/server/net/ipmemorystore/*.java", - "java/com/android/server/connectivity/mdns/**/*.java", ] } @@ -115,6 +114,7 @@ "service-connectivity-pre-jarjar", "service-connectivity-tiramisu-pre-jarjar", "services.core-vpn", + "testables", "cts-net-utils" ], libs: [ @@ -136,6 +136,37 @@ visibility: ["//packages/modules/Connectivity/tests:__subpackages__"], } +genrule { + name: "frameworks-net-tests-jarjar-rules", + defaults: ["jarjar-rules-combine-defaults"], + srcs: [ + ":frameworks-net-tests-lib-jarjar-gen", + // This is necessary because the tests use framework-connectivity-internal-test-defaults, + // which require the user to use connectivity jarjar rules. + ":connectivity-jarjar-rules", + ], + out: ["frameworks-net-tests-jarjar-rules.txt"], + visibility: ["//packages/modules/Connectivity/tests:__subpackages__"], +} + +java_genrule { + name: "frameworks-net-tests-lib-jarjar-gen", + tool_files: [ + ":FrameworksNetTestsLib{.jar}", + "jarjar-excludes.txt", + ], + tools: [ + "jarjar-rules-generator", + ], + out: ["frameworks-net-tests-lib-jarjar-rules.txt"], + cmd: "$(location jarjar-rules-generator) " + + "$(location :FrameworksNetTestsLib{.jar}) " + + "--prefix android.net.connectivity " + + "--excludes $(location jarjar-excludes.txt) " + + "--output $(out)", + visibility: ["//visibility:private"], +} + android_test { name: "FrameworksNetTests", enabled: enable_frameworks_net_tests, @@ -143,12 +174,11 @@ "FrameworksNetTestsDefaults", "FrameworksNetTests-jni-defaults", ], - jarjar_rules: ":connectivity-jarjar-rules", + jarjar_rules: ":frameworks-net-tests-jarjar-rules", test_suites: ["device-tests"], static_libs: [ "services.core", "services.net", - "service-mdns", ], jni_libs: [ "libandroid_net_connectivity_com_android_net_module_util_jni",
diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml index 5bac2dd..5d4bdf7 100644 --- a/tests/unit/AndroidManifest.xml +++ b/tests/unit/AndroidManifest.xml
@@ -63,7 +63,7 @@ <uses-library android:name="android.test.runner" /> <uses-library android:name="android.net.ipsec.ike" /> <activity - android:name="com.android.server.connectivity.NetworkNotificationManagerTest$TestDialogActivity"/> + android:name="android.net.connectivity.com.android.server.connectivity.NetworkNotificationManagerTest$TestDialogActivity"/> </application> <instrumentation
diff --git a/tests/unit/jarjar-excludes.txt b/tests/unit/jarjar-excludes.txt new file mode 100644 index 0000000..d2022bf --- /dev/null +++ b/tests/unit/jarjar-excludes.txt
@@ -0,0 +1,27 @@ +# Exclude some test prefixes, otherwise the classes reference below can't find +# them after jarjared. +android\.compat\..+ +androidx\.test\..+ +com\.android\.frameworks\.tests\..+ +com\.android\.testutils\..+ +com\.android\.dx\.mockito\..+ +com\.android\.internal\.compat\..+ +com\.android\.internal\.org\.bouncycastle\..+ +kotlin\.test\..+ +kotlin\.reflect\..+ +org\.junit\..+ +org\.mockito\..+ + +# Auto-jarjar-gen can't handle kotlin object expression, exclude the tests which use +# object expressions. +# +# For example: Illegal class access: +# 'android.net.connectivity.com.android.net.module.util.TrackRecordTest' attempting to access +# 'com.android.networkstack.tethering.util.TRTInterpreter' (declaration of +# 'android.net.connectivity.com.android.net.module.util.TrackRecordTest' ... +# +# In coverage test, TRTInterpreter don't be jarjar'ed to +# android.net.connectivity* by frameworks-net-tests-jarjar-rules instead it is +# jarjar'ed by follow up TetheringTestsJarJarRules. +# TODO(b/269259216): remove this after fixing Auto-jarjar-gen. +com\.android\.net\.module\.util\.TrackRecord.*
diff --git a/tests/unit/java/android/net/Ikev2VpnProfileTest.java b/tests/unit/java/android/net/Ikev2VpnProfileTest.java index 3b68120..e12e961 100644 --- a/tests/unit/java/android/net/Ikev2VpnProfileTest.java +++ b/tests/unit/java/android/net/Ikev2VpnProfileTest.java
@@ -492,6 +492,29 @@ } @Test + public void testAutomaticNattAndIpVersionConversionIsLossless() throws Exception { + final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); + builder.setAutomaticNattKeepaliveTimerEnabled(true); + builder.setAutomaticIpVersionSelectionEnabled(true); + + builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa); + final Ikev2VpnProfile ikeProfile = builder.build(); + + assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile())); + } + + @Test + public void testAutomaticNattAndIpVersionDefaults() throws Exception { + final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions(); + + builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa); + final Ikev2VpnProfile ikeProfile = builder.build(); + + assertEquals(false, ikeProfile.isAutomaticNattKeepaliveTimerEnabled()); + assertEquals(false, ikeProfile.isAutomaticIpVersionSelectionEnabled()); + } + + @Test public void testEquals() throws Exception { // Verify building without IkeTunnelConnectionParams final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
diff --git a/tests/unit/java/android/net/IpSecTransformTest.java b/tests/unit/java/android/net/IpSecTransformTest.java index c1bd719..8bc1bbd 100644 --- a/tests/unit/java/android/net/IpSecTransformTest.java +++ b/tests/unit/java/android/net/IpSecTransformTest.java
@@ -18,22 +18,92 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.content.Context; import android.os.Build; +import android.test.mock.MockContext; import androidx.test.filters.SmallTest; +import com.android.server.IpSecService; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.InetAddress; + /** Unit tests for {@link IpSecTransform}. */ @SmallTest @RunWith(DevSdkIgnoreRunner.class) @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) public class IpSecTransformTest { + @Rule public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); + + private static final int DROID_SPI = 0xD1201D; + private static final int TEST_RESOURCE_ID = 0x1234; + + private static final InetAddress SRC_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.200"); + private static final InetAddress DST_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.201"); + private static final InetAddress SRC_ADDRESS_V6 = + InetAddresses.parseNumericAddress("2001:db8::200"); + private static final InetAddress DST_ADDRESS_V6 = + InetAddresses.parseNumericAddress("2001:db8::201"); + + private MockContext mMockContext; + private IpSecService mMockIpSecService; + private IpSecManager mIpSecManager; + + @Before + public void setUp() throws Exception { + mMockIpSecService = mock(IpSecService.class); + mIpSecManager = new IpSecManager(mock(Context.class) /* unused */, mMockIpSecService); + + // Set up mMockContext since IpSecTransform needs an IpSecManager instance and a non-null + // package name to create transform + mMockContext = + new MockContext() { + @Override + public String getSystemServiceName(Class<?> serviceClass) { + if (serviceClass.equals(IpSecManager.class)) { + return Context.IPSEC_SERVICE; + } + throw new UnsupportedOperationException(); + } + + @Override + public Object getSystemService(String name) { + if (name.equals(Context.IPSEC_SERVICE)) { + return mIpSecManager; + } + throw new UnsupportedOperationException(); + } + + @Override + public String getOpPackageName() { + return "fooPackage"; + } + }; + + final IpSecSpiResponse spiResp = + new IpSecSpiResponse(IpSecManager.Status.OK, TEST_RESOURCE_ID, DROID_SPI); + when(mMockIpSecService.allocateSecurityParameterIndex(any(), anyInt(), any())) + .thenReturn(spiResp); + + final IpSecTransformResponse transformResp = + new IpSecTransformResponse(IpSecManager.Status.OK, TEST_RESOURCE_ID); + when(mMockIpSecService.createTransform(any(), any(), any())).thenReturn(transformResp); + } @Test public void testCreateTransformCopiesConfig() { @@ -64,4 +134,34 @@ assertEquals(config1, config2); } + + private IpSecTransform buildTestTransform() throws Exception { + final IpSecManager.SecurityParameterIndex spi = + mIpSecManager.allocateSecurityParameterIndex(DST_ADDRESS); + return new IpSecTransform.Builder(mMockContext).buildTunnelModeTransform(SRC_ADDRESS, spi); + } + + @Test + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testStartTransformMigration() throws Exception { + mIpSecManager.startTunnelModeTransformMigration( + buildTestTransform(), SRC_ADDRESS_V6, DST_ADDRESS_V6); + verify(mMockIpSecService) + .migrateTransform( + anyInt(), + eq(SRC_ADDRESS_V6.getHostAddress()), + eq(DST_ADDRESS_V6.getHostAddress()), + any()); + } + + @Test + @DevSdkIgnoreRule.IgnoreAfter(Build.VERSION_CODES.TIRAMISU) + public void testStartTransformMigrationOnSdkBeforeU() throws Exception { + try { + mIpSecManager.startTunnelModeTransformMigration( + buildTestTransform(), SRC_ADDRESS_V6, DST_ADDRESS_V6); + fail("Expect to fail since migration is not supported before U"); + } catch (UnsupportedOperationException expected) { + } + } }
diff --git a/tests/unit/java/android/net/NetworkStatsAccessTest.java b/tests/unit/java/android/net/NetworkStatsAccessTest.java index a74056b..8b86211 100644 --- a/tests/unit/java/android/net/NetworkStatsAccessTest.java +++ b/tests/unit/java/android/net/NetworkStatsAccessTest.java
@@ -78,6 +78,7 @@ setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false); setHasReadHistoryPermission(false); setHasNetworkStackPermission(false); + setHasMainlineNetworkStackPermission(false); } @After @@ -154,6 +155,10 @@ setHasNetworkStackPermission(false); assertEquals(NetworkStatsAccess.Level.DEFAULT, NetworkStatsAccess.checkAccessLevel(mContext, TEST_PID, TEST_UID, TEST_PKG)); + + setHasMainlineNetworkStackPermission(true); + assertEquals(NetworkStatsAccess.Level.DEVICE, + NetworkStatsAccess.checkAccessLevel(mContext, TEST_PID, TEST_UID, TEST_PKG)); } private void setHasCarrierPrivileges(boolean hasPrivileges) { @@ -189,4 +194,10 @@ TEST_PID, TEST_UID)).thenReturn(hasPermission ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED); } + + private void setHasMainlineNetworkStackPermission(boolean hasPermission) { + when(mContext.checkPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + TEST_PID, TEST_UID)).thenReturn(hasPermission ? PackageManager.PERMISSION_GRANTED + : PackageManager.PERMISSION_DENIED); + } }
diff --git a/tests/unit/java/android/net/NetworkTemplateTest.kt b/tests/unit/java/android/net/NetworkTemplateTest.kt index 3cf0228..2f6c76b 100644 --- a/tests/unit/java/android/net/NetworkTemplateTest.kt +++ b/tests/unit/java/android/net/NetworkTemplateTest.kt
@@ -34,10 +34,8 @@ import android.net.NetworkStats.ROAMING_ALL import android.net.NetworkTemplate.MATCH_CARRIER import android.net.NetworkTemplate.MATCH_MOBILE -import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD import android.net.NetworkTemplate.MATCH_TEST import android.net.NetworkTemplate.MATCH_WIFI -import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD import android.net.NetworkTemplate.NETWORK_TYPE_ALL import android.net.NetworkTemplate.OEM_MANAGED_ALL import android.net.NetworkTemplate.OEM_MANAGED_NO @@ -49,20 +47,20 @@ import android.net.wifi.WifiInfo import android.os.Build import android.telephony.TelephonyManager -import com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRunner import com.android.testutils.assertParcelSane +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotEquals +import kotlin.test.assertTrue import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertNotEquals -import kotlin.test.assertTrue private const val TEST_IMSI1 = "imsi1" private const val TEST_IMSI2 = "imsi2" @@ -73,6 +71,8 @@ @RunWith(DevSdkIgnoreRunner::class) @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) class NetworkTemplateTest { + @get:Rule + val ignoreRule = DevSdkIgnoreRule() private val mockContext = mock(Context::class.java) private val mockWifiInfo = mock(WifiInfo::class.java) @@ -133,10 +133,17 @@ mockContext, buildWifiNetworkState(null, TEST_WIFI_KEY1), true, 0) val identWifiImsi1Key1 = buildNetworkIdentity( mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_WIFI_KEY1), true, 0) + // This identity with a null wifiNetworkKey is to test matchesWifiNetworkKey won't crash + // the system when a null wifiNetworkKey is provided, which happens because of a bug in wifi + // and it should still match the wifi wildcard template. See b/266598304. + val identWifiNullKey = buildNetworkIdentity( + mockContext, buildWifiNetworkState(null /* subscriberId */, + null /* wifiNetworkKey */), true, 0) templateWifiWildcard.assertDoesNotMatch(identMobileImsi1) templateWifiWildcard.assertMatches(identWifiImsiNullKey1) templateWifiWildcard.assertMatches(identWifiImsi1Key1) + templateWifiWildcard.assertMatches(identWifiNullKey) } @Test @@ -151,6 +158,9 @@ .setWifiNetworkKeys(setOf(TEST_WIFI_KEY1)).build() val templateWifiKeyAllImsi1 = NetworkTemplate.Builder(MATCH_WIFI) .setSubscriberIds(setOf(TEST_IMSI1)).build() + val templateNullWifiKey = NetworkTemplate(MATCH_WIFI, + emptyArray<String>() /* subscriberIds */, arrayOf(null) /* wifiNetworkKeys */, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL) val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1), false, TelephonyManager.NETWORK_TYPE_UMTS) @@ -162,6 +172,12 @@ mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_WIFI_KEY1), true, 0) val identWifiImsi1Key2 = buildNetworkIdentity( mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_WIFI_KEY2), true, 0) + // This identity with a null wifiNetworkKey is to test the matchesWifiNetworkKey won't crash + // the system when a null wifiNetworkKey is provided, which would happen in some unknown + // cases, see b/266598304. + val identWifiNullKey = buildNetworkIdentity( + mockContext, buildWifiNetworkState(null /* subscriberId */, + null /* wifiNetworkKey */), true, 0) // Verify that template with WiFi Network Key only matches any subscriberId and // specific WiFi Network Key. @@ -194,6 +210,24 @@ templateWifiKeyAllImsi1.assertMatches(identWifiImsi1Key1) templateWifiKeyAllImsi1.assertDoesNotMatch(identWifiImsi2Key1) templateWifiKeyAllImsi1.assertMatches(identWifiImsi1Key2) + + // Test a network identity with null wifiNetworkKey won't crash. + // It should not match a template with wifiNetworkKeys is non-null. + // Also, it should not match a template with wifiNetworkKeys that contains null. + templateWifiKey1.assertDoesNotMatch(identWifiNullKey) + templateNullWifiKey.assertDoesNotMatch(identWifiNullKey) + } + + @DevSdkIgnoreRule.IgnoreAfter(Build.VERSION_CODES.TIRAMISU) + @Test + fun testBuildTemplateMobileAll_nullSubscriberId() { + val templateMobileAllWithNullImsi = buildTemplateMobileAll(null) + val setWithNull = HashSet<String?>().apply { + add(null) + } + val templateFromBuilder = NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES) + .setSubscriberIds(setWithNull).build() + assertEquals(templateFromBuilder, templateMobileAllWithNullImsi) } @Test @@ -232,7 +266,6 @@ val templateMobileWildcard = buildTemplateMobileWildcard() val templateMobileNullImsiWithRatType = NetworkTemplate.Builder(MATCH_MOBILE) .setRatType(TelephonyManager.NETWORK_TYPE_UMTS).build() - val mobileImsi1 = buildMobileNetworkState(TEST_IMSI1) val identMobile1 = buildNetworkIdentity(mockContext, mobileImsi1, false /* defaultNetwork */, TelephonyManager.NETWORK_TYPE_UMTS) @@ -447,20 +480,48 @@ } @Test + fun testEquals() { + val templateImsi1 = NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES) + .setSubscriberIds(setOf(TEST_IMSI1)).setRatType(TelephonyManager.NETWORK_TYPE_UMTS) + .build() + val dupTemplateImsi1 = NetworkTemplate(MATCH_MOBILE, arrayOf(TEST_IMSI1), + emptyArray<String>(), METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, + TelephonyManager.NETWORK_TYPE_UMTS, OEM_MANAGED_ALL) + val templateImsi2 = NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES) + .setSubscriberIds(setOf(TEST_IMSI2)).setRatType(TelephonyManager.NETWORK_TYPE_UMTS) + .build() + + assertEquals(templateImsi1, dupTemplateImsi1) + assertEquals(dupTemplateImsi1, templateImsi1) + assertNotEquals(templateImsi1, templateImsi2) + + val templateWifiKey1 = NetworkTemplate.Builder(MATCH_WIFI) + .setWifiNetworkKeys(setOf(TEST_WIFI_KEY1)).build() + val dupTemplateWifiKey1 = NetworkTemplate(MATCH_WIFI, emptyArray<String>(), + arrayOf(TEST_WIFI_KEY1), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, + NETWORK_TYPE_ALL, OEM_MANAGED_ALL) + val templateWifiKey2 = NetworkTemplate.Builder(MATCH_WIFI) + .setWifiNetworkKeys(setOf(TEST_WIFI_KEY2)).build() + + assertEquals(templateWifiKey1, dupTemplateWifiKey1) + assertEquals(dupTemplateWifiKey1, templateWifiKey1) + assertNotEquals(templateWifiKey1, templateWifiKey2) + } + + @Test fun testParcelUnparcel() { - val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, emptyArray<String>(), + val templateMobile = NetworkTemplate(MATCH_MOBILE, arrayOf(TEST_IMSI1), emptyArray<String>(), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, - TelephonyManager.NETWORK_TYPE_LTE, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT) - val templateWifi = NetworkTemplate(MATCH_WIFI, null, emptyArray<String>(), + TelephonyManager.NETWORK_TYPE_LTE, OEM_MANAGED_ALL) + val templateWifi = NetworkTemplate(MATCH_WIFI, emptyArray<String>(), arrayOf(TEST_WIFI_KEY1), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT) - val templateOem = NetworkTemplate(MATCH_MOBILE, null, emptyArray<String>(), + OEM_MANAGED_ALL) + val templateOem = NetworkTemplate(MATCH_MOBILE, emptyArray<String>(), emptyArray<String>(), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, - OEM_MANAGED_YES, SUBSCRIBER_ID_MATCH_RULE_EXACT) - assertParcelSane(templateMobile, 10) - assertParcelSane(templateWifi, 10) - assertParcelSane(templateOem, 10) + OEM_MANAGED_YES) + assertParcelSane(templateMobile, 8) + assertParcelSane(templateWifi, 8) + assertParcelSane(templateOem, 8) } // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with @@ -493,13 +554,14 @@ * @param matchType A match rule from {@code NetworkTemplate.MATCH_*} corresponding to the * networkType. * @param subscriberId To be populated with {@code TEST_IMSI*} only if networkType is - * {@code TYPE_MOBILE}. May be left as null when matchType is - * {@link NetworkTemplate.MATCH_MOBILE_WILDCARD}. - * @param templateWifiKey Top be populated with {@code TEST_WIFI_KEY*} only if networkType is - * {@code TYPE_WIFI}. May be left as null when matchType is - * {@link NetworkTemplate.MATCH_WIFI_WILDCARD}. - * @param identWifiKey If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide - * one of {@code TEST_WIFI_KEY*}. + * {@code TYPE_MOBILE}. Note that {@code MATCH_MOBILE} with an empty subscriberId list + * will match any subscriber ID. + * @param templateWifiKey To be populated with {@code TEST_WIFI_KEY*} only if networkType is + * {@code TYPE_WIFI}. Note that {@code MATCH_WIFI} with both an empty subscriberId list + * and an empty wifiNetworkKey list will match any subscriber ID and/or any wifi network + * key. + * @param identWifiKey If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. + * Provide one of {@code TEST_WIFI_KEY*}. */ private fun matchOemManagedIdent( networkType: Int, @@ -509,17 +571,17 @@ identWifiKey: String? = null ) { val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE) - val matchSubscriberIds = arrayOf(subscriberId) - val matchWifiNetworkKeys = arrayOf(templateWifiKey) + val matchSubscriberIds = + if (subscriberId == null) emptyArray<String>() else arrayOf(subscriberId) + val matchWifiNetworkKeys = + if (templateWifiKey == null) emptyArray<String>() else arrayOf(templateWifiKey) - val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, + val templateOemYes = NetworkTemplate(matchType, matchSubscriberIds, matchWifiNetworkKeys, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES, - SUBSCRIBER_ID_MATCH_RULE_EXACT) - val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES) + val templateOemAll = NetworkTemplate(matchType, matchSubscriberIds, matchWifiNetworkKeys, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT) + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL) for (identityOemManagedState in oemManagedStates) { val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType, @@ -528,10 +590,9 @@ // Create a template with each OEM managed type and match it against the NetworkIdentity for (templateOemManagedState in oemManagedStates) { - val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, + val template = NetworkTemplate(matchType, matchSubscriberIds, matchWifiNetworkKeys, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, templateOemManagedState, - SUBSCRIBER_ID_MATCH_RULE_EXACT) + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, templateOemManagedState) if (identityOemManagedState == templateOemManagedState) { template.assertMatches(ident) } else { @@ -552,11 +613,10 @@ @Test fun testOemManagedMatchesIdent() { matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE, subscriberId = TEST_IMSI1) - matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE_WILDCARD) + matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE) matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, templateWifiKey = TEST_WIFI_KEY1, identWifiKey = TEST_WIFI_KEY1) - matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI_WILDCARD, - identWifiKey = TEST_WIFI_KEY1) + matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, identWifiKey = TEST_WIFI_KEY1) } @Test
diff --git a/tests/unit/java/android/net/nsd/NsdManagerTest.java b/tests/unit/java/android/net/nsd/NsdManagerTest.java index 8a4932b..0965193 100644 --- a/tests/unit/java/android/net/nsd/NsdManagerTest.java +++ b/tests/unit/java/android/net/nsd/NsdManagerTest.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -32,6 +33,7 @@ import android.compat.testing.PlatformCompatChangeRule; import android.content.Context; +import android.net.connectivity.ConnectivityCompatChanges; import android.os.Build; import androidx.test.filters.SmallTest; @@ -72,79 +74,79 @@ public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - doReturn(mServiceConn).when(mService).connect(any()); + doReturn(mServiceConn).when(mService).connect(any(), anyBoolean()); mManager = new NsdManager(mContext, mService); final ArgumentCaptor<INsdManagerCallback> cbCaptor = ArgumentCaptor.forClass( INsdManagerCallback.class); - verify(mService).connect(cbCaptor.capture()); + verify(mService).connect(cbCaptor.capture(), anyBoolean()); mCallback = cbCaptor.getValue(); } @Test - @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) public void testResolveServiceS() throws Exception { verify(mServiceConn, never()).startDaemon(); doTestResolveService(); } @Test - @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) public void testResolveServicePreS() throws Exception { verify(mServiceConn).startDaemon(); doTestResolveService(); } @Test - @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) public void testDiscoverServiceS() throws Exception { verify(mServiceConn, never()).startDaemon(); doTestDiscoverService(); } @Test - @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) public void testDiscoverServicePreS() throws Exception { verify(mServiceConn).startDaemon(); doTestDiscoverService(); } @Test - @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) public void testParallelResolveServiceS() throws Exception { verify(mServiceConn, never()).startDaemon(); doTestParallelResolveService(); } @Test - @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) public void testParallelResolveServicePreS() throws Exception { verify(mServiceConn).startDaemon(); doTestParallelResolveService(); } @Test - @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) public void testInvalidCallsS() throws Exception { verify(mServiceConn, never()).startDaemon(); doTestInvalidCalls(); } @Test - @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) public void testInvalidCallsPreS() throws Exception { verify(mServiceConn).startDaemon(); doTestInvalidCalls(); } @Test - @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @EnableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) public void testRegisterServiceS() throws Exception { verify(mServiceConn, never()).startDaemon(); doTestRegisterService(); } @Test - @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @DisableCompatChanges(ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) public void testRegisterServicePreS() throws Exception { verify(mServiceConn).startDaemon(); doTestRegisterService();
diff --git a/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java b/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java index 64355ed..9ce0693 100644 --- a/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java +++ b/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.net.InetAddresses; import android.net.Network; import android.os.Build; import android.os.Bundle; @@ -38,6 +39,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; +import java.util.List; import java.util.Map; @RunWith(DevSdkIgnoreRunner.class) @@ -45,6 +47,8 @@ @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) public class NsdServiceInfoTest { + private static final InetAddress IPV4_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.1"); + private static final InetAddress IPV6_ADDRESS = InetAddresses.parseNumericAddress("2001:db8::"); public final static InetAddress LOCALHOST; static { // Because test. @@ -124,6 +128,7 @@ fullInfo.setServiceType("_kitten._tcp"); fullInfo.setPort(4242); fullInfo.setHost(LOCALHOST); + fullInfo.setHostAddresses(List.of(IPV4_ADDRESS)); fullInfo.setNetwork(new Network(123)); fullInfo.setInterfaceIndex(456); checkParcelable(fullInfo); @@ -139,6 +144,7 @@ attributedInfo.setServiceType("_kitten._tcp"); attributedInfo.setPort(4242); attributedInfo.setHost(LOCALHOST); + fullInfo.setHostAddresses(List.of(IPV6_ADDRESS, IPV4_ADDRESS)); attributedInfo.setAttribute("color", "pink"); attributedInfo.setAttribute("sound", (new String("にゃあ")).getBytes("UTF-8")); attributedInfo.setAttribute("adorable", (String) null);
diff --git a/tests/unit/java/android/net/util/KeepaliveUtilsTest.kt b/tests/unit/java/android/net/util/KeepaliveUtilsTest.kt index 9203f8f..cb3a315 100644 --- a/tests/unit/java/android/net/util/KeepaliveUtilsTest.kt +++ b/tests/unit/java/android/net/util/KeepaliveUtilsTest.kt
@@ -18,7 +18,6 @@ import android.content.Context import android.content.res.Resources -import android.net.ConnectivityResources import android.net.NetworkCapabilities import android.net.NetworkCapabilities.MAX_TRANSPORT import android.net.NetworkCapabilities.TRANSPORT_CELLULAR @@ -27,7 +26,9 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.os.Build import androidx.test.filters.SmallTest -import com.android.internal.R +import com.android.connectivity.resources.R +import com.android.server.connectivity.ConnectivityResources +import com.android.server.connectivity.KeepaliveResourceUtil import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRunner import org.junit.After @@ -37,7 +38,6 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.eq -import org.mockito.Mockito.any import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock @@ -53,14 +53,9 @@ class KeepaliveUtilsTest { // Prepare mocked context with given resource strings. - private fun getMockedContextWithStringArrayRes( - id: Int, - name: String, - res: Array<out String?>? - ): Context { + private fun getMockedContextWithStringArrayRes(id: Int, res: Array<out String?>?): Context { val mockRes = mock(Resources::class.java) doReturn(res).`when`(mockRes).getStringArray(eq(id)) - doReturn(id).`when`(mockRes).getIdentifier(eq(name), any(), any()) return mock(Context::class.java).apply { doReturn(mockRes).`when`(this).getResources() @@ -79,10 +74,10 @@ try { val mockContext = getMockedContextWithStringArrayRes( R.array.config_networkSupportedKeepaliveCount, - "config_networkSupportedKeepaliveCount", res) - KeepaliveUtils.getSupportedKeepalives(mockContext) + res) + KeepaliveResourceUtil.getSupportedKeepalives(mockContext) fail("Expected KeepaliveDeviceConfigurationException") - } catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) { + } catch (expected: KeepaliveResourceUtil.KeepaliveDeviceConfigurationException) { } } @@ -104,12 +99,12 @@ // Check valid customization generates expected array. val validRes = arrayOf("0,3", "1,0", "4,4") - val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0, 0) + val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0, 0, 0) val mockContext = getMockedContextWithStringArrayRes( R.array.config_networkSupportedKeepaliveCount, - "config_networkSupportedKeepaliveCount", validRes) - val actual = KeepaliveUtils.getSupportedKeepalives(mockContext) + validRes) + val actual = KeepaliveResourceUtil.getSupportedKeepalives(mockContext) assertArrayEquals(expectedValidRes, actual) }
diff --git a/tests/unit/java/com/android/internal/net/VpnProfileTest.java b/tests/unit/java/com/android/internal/net/VpnProfileTest.java index 0a6d2f2..b2dff2e 100644 --- a/tests/unit/java/com/android/internal/net/VpnProfileTest.java +++ b/tests/unit/java/com/android/internal/net/VpnProfileTest.java
@@ -20,6 +20,7 @@ import static android.net.cts.util.IkeSessionTestUtils.IKE_PARAMS_V4; import static com.android.modules.utils.build.SdkLevel.isAtLeastT; +import static com.android.modules.utils.build.SdkLevel.isAtLeastU; import static com.android.testutils.ParcelUtils.assertParcelSane; import static org.junit.Assert.assertEquals; @@ -55,6 +56,9 @@ private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24; private static final int ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE = 25; private static final int ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION = 26; + private static final int ENCODED_INDEX_IKE_TUN_CONN_PARAMS = 27; + private static final int ENCODED_INDEX_AUTOMATIC_NATT_KEEPALIVE_TIMER_ENABLED = 28; + private static final int ENCODED_INDEX_AUTOMATIC_IP_VERSION_SELECTION_ENABLED = 29; @Test public void testDefaults() throws Exception { @@ -85,12 +89,15 @@ assertFalse(p.isRestrictedToTestNetworks); assertFalse(p.excludeLocalRoutes); assertFalse(p.requiresInternetValidation); + assertFalse(p.automaticNattKeepaliveTimerEnabled); + assertFalse(p.automaticIpVersionSelectionEnabled); } private VpnProfile getSampleIkev2Profile(String key) { final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */, false /* excludesLocalRoutes */, true /* requiresPlatformValidation */, - null /* ikeTunConnParams */); + null /* ikeTunConnParams */, true /* mAutomaticNattKeepaliveTimerEnabled */, + true /* automaticIpVersionSelectionEnabled */); p.name = "foo"; p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS; @@ -128,7 +135,9 @@ private VpnProfile getSampleIkev2ProfileWithIkeTunConnParams(String key) { final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */, false /* excludesLocalRoutes */, true /* requiresPlatformValidation */, - new IkeTunnelConnectionParams(IKE_PARAMS_V4, CHILD_PARAMS)); + new IkeTunnelConnectionParams(IKE_PARAMS_V4, CHILD_PARAMS), + true /* mAutomaticNattKeepaliveTimerEnabled */, + true /* automaticIpVersionSelectionEnabled */); p.name = "foo"; p.server = "bar"; @@ -166,7 +175,11 @@ @Test public void testParcelUnparcel() { - if (isAtLeastT()) { + if (isAtLeastU()) { + // automaticNattKeepaliveTimerEnabled, automaticIpVersionSelectionEnabled added in U. + assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 28); + assertParcelSane(getSampleIkev2ProfileWithIkeTunConnParams(DUMMY_PROFILE_KEY), 28); + } else if (isAtLeastT()) { // excludeLocalRoutes, requiresPlatformValidation were added in T. assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 26); assertParcelSane(getSampleIkev2ProfileWithIkeTunConnParams(DUMMY_PROFILE_KEY), 26); @@ -221,16 +234,28 @@ ENCODED_INDEX_AUTH_PARAMS_INLINE, ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS, ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE, - ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */); + ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION, + ENCODED_INDEX_IKE_TUN_CONN_PARAMS, + ENCODED_INDEX_AUTOMATIC_NATT_KEEPALIVE_TIMER_ENABLED, + ENCODED_INDEX_AUTOMATIC_IP_VERSION_SELECTION_ENABLED + /* missingIndices */); assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes())); } + private String getEncodedDecodedIkev2ProfileWithtooFewValues() { + return getEncodedDecodedIkev2ProfileMissingValues( + ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS, + ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE, + ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION, + ENCODED_INDEX_IKE_TUN_CONN_PARAMS, + ENCODED_INDEX_AUTOMATIC_NATT_KEEPALIVE_TIMER_ENABLED, + ENCODED_INDEX_AUTOMATIC_IP_VERSION_SELECTION_ENABLED /* missingIndices */); + } + @Test public void testEncodeDecodeMissingIsRestrictedToTestNetworks() { - final String tooFewValues = - getEncodedDecodedIkev2ProfileMissingValues( - ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */); + final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues(); // Verify decoding without isRestrictedToTestNetworks defaults to false final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()); @@ -239,10 +264,7 @@ @Test public void testEncodeDecodeMissingExcludeLocalRoutes() { - final String tooFewValues = - getEncodedDecodedIkev2ProfileMissingValues( - ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE, - ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */); + final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues(); // Verify decoding without excludeLocalRoutes defaults to false final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()); @@ -251,9 +273,7 @@ @Test public void testEncodeDecodeMissingRequiresValidation() { - final String tooFewValues = - getEncodedDecodedIkev2ProfileMissingValues( - ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */); + final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues(); // Verify decoding without requiresValidation defaults to false final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()); @@ -261,6 +281,24 @@ } @Test + public void testEncodeDecodeMissingAutomaticNattKeepaliveTimerEnabled() { + final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues(); + + // Verify decoding without automaticNattKeepaliveTimerEnabled defaults to false + final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()); + assertFalse(decoded.automaticNattKeepaliveTimerEnabled); + } + + @Test + public void testEncodeDecodeMissingAutomaticIpVersionSelectionEnabled() { + final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues(); + + // Verify decoding without automaticIpVersionSelectionEnabled defaults to false + final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()); + assertFalse(decoded.automaticIpVersionSelectionEnabled); + } + + @Test public void testEncodeDecodeLoginsNotSaved() { final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY); profile.saveLogin = false;
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java index 0e17cd7..19fa41d 100644 --- a/tests/unit/java/com/android/server/BpfNetMapsTest.java +++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -66,6 +66,7 @@ import android.os.Build; import android.os.ServiceSpecificException; import android.system.ErrnoException; +import android.util.ArraySet; import android.util.IndentingPrintWriter; import androidx.test.filters.SmallTest; @@ -690,6 +691,80 @@ mBpfNetMaps.setUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID, FIREWALL_RULE_ALLOW)); } + private void doTestGetUidRule(final List<Integer> enableChains) throws Exception { + mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(0, getMatch(enableChains))); + + for (final int chain: FIREWALL_CHAINS) { + final String testCase = "EnabledChains: " + enableChains + " CheckedChain: " + chain; + if (enableChains.contains(chain)) { + final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain) + ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY; + assertEquals(testCase, expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID)); + } else { + final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain) + ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW; + assertEquals(testCase, expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID)); + } + } + } + + private void doTestGetUidRule(final int enableChain) throws Exception { + doTestGetUidRule(List.of(enableChain)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.S_V2) + public void testGetUidRule() throws Exception { + doTestGetUidRule(FIREWALL_CHAIN_DOZABLE); + doTestGetUidRule(FIREWALL_CHAIN_STANDBY); + doTestGetUidRule(FIREWALL_CHAIN_POWERSAVE); + doTestGetUidRule(FIREWALL_CHAIN_RESTRICTED); + doTestGetUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY); + doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_1); + doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_2); + doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_3); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.S_V2) + public void testGetUidRuleMultipleChainEnabled() throws Exception { + doTestGetUidRule(List.of( + FIREWALL_CHAIN_DOZABLE, + FIREWALL_CHAIN_STANDBY)); + doTestGetUidRule(List.of( + FIREWALL_CHAIN_DOZABLE, + FIREWALL_CHAIN_STANDBY, + FIREWALL_CHAIN_POWERSAVE, + FIREWALL_CHAIN_RESTRICTED)); + doTestGetUidRule(FIREWALL_CHAINS); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.S_V2) + public void testGetUidRuleNoEntry() throws Exception { + mUidOwnerMap.clear(); + for (final int chain: FIREWALL_CHAINS) { + final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain) + ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW; + assertEquals(expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID)); + } + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.S_V2) + public void testGetUidRuleInvalidChain() { + final Class<ServiceSpecificException> expected = ServiceSpecificException.class; + assertThrows(expected, () -> mBpfNetMaps.getUidRule(-1 /* childChain */, TEST_UID)); + assertThrows(expected, () -> mBpfNetMaps.getUidRule(1000 /* childChain */, TEST_UID)); + } + + @Test + @IgnoreAfter(Build.VERSION_CODES.S_V2) + public void testGetUidRuleBeforeT() { + assertThrows(UnsupportedOperationException.class, + () -> mBpfNetMaps.getUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID)); + } + @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2) public void testReplaceUidChain() throws Exception { @@ -1077,4 +1152,33 @@ mCookieTagMap.updateEntry(new CookieTagMapKey(123), new CookieTagMapValue(456, 0x789)); assertDumpContains(getDump(), "cookie=123 tag=0x789 uid=456"); } + + @Test + public void testGetUids() throws ErrnoException { + final int uid0 = TEST_UIDS[0]; + final int uid1 = TEST_UIDS[1]; + final long match0 = DOZABLE_MATCH | POWERSAVE_MATCH; + final long match1 = DOZABLE_MATCH | STANDBY_MATCH; + mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(NULL_IIF, match0)); + mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1)); + + assertEquals(new ArraySet<>(List.of(uid0, uid1)), + mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_DOZABLE)); + assertEquals(new ArraySet<>(List.of(uid0)), + mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_POWERSAVE)); + + assertEquals(new ArraySet<>(List.of(uid1)), + mBpfNetMaps.getUidsWithDenyRuleOnDenyListChain(FIREWALL_CHAIN_STANDBY)); + assertEquals(new ArraySet<>(), + mBpfNetMaps.getUidsWithDenyRuleOnDenyListChain(FIREWALL_CHAIN_OEM_DENY_1)); + } + + @Test + public void testGetUidsIllegalArgument() { + final Class<IllegalArgumentException> expected = IllegalArgumentException.class; + assertThrows(expected, + () -> mBpfNetMaps.getUidsWithDenyRuleOnDenyListChain(FIREWALL_CHAIN_DOZABLE)); + assertThrows(expected, + () -> mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_OEM_DENY_1)); + } }
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index 16f7039..904e4bd 100755 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -27,8 +27,11 @@ import static android.Manifest.permission.MANAGE_TEST_NETWORKS; import static android.Manifest.permission.NETWORK_FACTORY; import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.Manifest.permission.NETWORK_SETUP_WIZARD; import static android.Manifest.permission.NETWORK_STACK; import static android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD; +import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_FROZEN; +import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_UNFROZEN; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.content.Intent.ACTION_PACKAGE_ADDED; import static android.content.Intent.ACTION_PACKAGE_REMOVED; @@ -64,6 +67,7 @@ import static android.net.ConnectivityManager.FIREWALL_RULE_DENY; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE; +import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; @@ -137,6 +141,7 @@ import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST; import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY; import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED; +import static android.net.Proxy.PROXY_CHANGE_ACTION; import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED; @@ -145,11 +150,14 @@ import static android.os.Process.INVALID_UID; import static android.system.OsConstants.IPPROTO_TCP; +import static com.android.server.ConnectivityService.KEY_DESTROY_FROZEN_SOCKETS_VERSION; import static com.android.server.ConnectivityService.MAX_NETWORK_REQUESTS_PER_SYSTEM_UID; import static com.android.server.ConnectivityService.PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED; import static com.android.server.ConnectivityService.PREFERENCE_ORDER_OEM; import static com.android.server.ConnectivityService.PREFERENCE_ORDER_PROFILE; import static com.android.server.ConnectivityService.PREFERENCE_ORDER_VPN; +import static com.android.server.ConnectivityService.createDeliveryGroupKeyForConnectivityAction; +import static com.android.server.ConnectivityService.makeNflogPrefix; import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType; import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackRegister; import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister; @@ -159,6 +167,7 @@ import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2; import static com.android.testutils.FunctionalUtils.ignoreExceptions; +import static com.android.testutils.HandlerUtils.visibleOnHandlerThread; import static com.android.testutils.HandlerUtils.waitForIdleSerialExecutor; import static com.android.testutils.MiscAsserts.assertContainsAll; import static com.android.testutils.MiscAsserts.assertContainsExactly; @@ -167,8 +176,20 @@ import static com.android.testutils.MiscAsserts.assertRunsInAtMost; import static com.android.testutils.MiscAsserts.assertSameElements; import static com.android.testutils.MiscAsserts.assertThrows; +import static com.android.testutils.RecorderCallback.CallbackEntry.AVAILABLE; +import static com.android.testutils.RecorderCallback.CallbackEntry.BLOCKED_STATUS; +import static com.android.testutils.RecorderCallback.CallbackEntry.BLOCKED_STATUS_INT; +import static com.android.testutils.RecorderCallback.CallbackEntry.LINK_PROPERTIES_CHANGED; +import static com.android.testutils.RecorderCallback.CallbackEntry.LOSING; +import static com.android.testutils.RecorderCallback.CallbackEntry.LOST; +import static com.android.testutils.RecorderCallback.CallbackEntry.NETWORK_CAPS_UPDATED; +import static com.android.testutils.RecorderCallback.CallbackEntry.RESUMED; +import static com.android.testutils.RecorderCallback.CallbackEntry.SUSPENDED; +import static com.android.testutils.RecorderCallback.CallbackEntry.UNAVAILABLE; import static com.android.testutils.TestPermissionUtil.runAsShell; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -207,12 +228,16 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.ActivityManager.UidFrozenStateChangedCallback; import android.app.AlarmManager; import android.app.AppOpsManager; +import android.app.BroadcastOptions; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.app.usage.NetworkStatsManager; +import android.compat.testing.PlatformCompatChangeRule; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProvider; @@ -237,7 +262,6 @@ import android.net.ConnectivityManager.PacketKeepalive; import android.net.ConnectivityManager.PacketKeepaliveCallback; import android.net.ConnectivityManager.TooManyRequestsException; -import android.net.ConnectivityResources; import android.net.ConnectivitySettingsManager; import android.net.ConnectivityThread; import android.net.DataStallReportParcelable; @@ -297,6 +321,7 @@ import android.net.Uri; import android.net.VpnManager; import android.net.VpnTransportInfo; +import android.net.connectivity.ConnectivityCompatChanges; import android.net.metrics.IpConnectivityLog; import android.net.netd.aidl.NativeUidRangeConfig; import android.net.networkstack.NetworkStackClientBase; @@ -352,19 +377,24 @@ import com.android.internal.util.WakeupMessage; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; -import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.ArrayTrackRecord; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.LocationPermissionChecker; import com.android.net.module.util.NetworkMonitorUtils; import com.android.networkstack.apishim.ConstantsShim; import com.android.networkstack.apishim.NetworkAgentConfigShimImpl; +import com.android.networkstack.apishim.common.BroadcastOptionsShim; +import com.android.networkstack.apishim.common.UnsupportedApiLevelException; import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo; import com.android.server.ConnectivityService.NetworkRequestInfo; +import com.android.server.ConnectivityServiceTest.ConnectivityServiceDependencies.DestroySocketsWrapper; import com.android.server.ConnectivityServiceTest.ConnectivityServiceDependencies.ReportedInterfaces; +import com.android.server.connectivity.ApplicationSelfCertifiedNetworkCapabilities; +import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker; import com.android.server.connectivity.CarrierPrivilegeAuthenticator; import com.android.server.connectivity.ClatCoordinator; import com.android.server.connectivity.ConnectivityFlags; +import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.MultinetworkPolicyTracker; import com.android.server.connectivity.MultinetworkPolicyTrackerTestDependencies; import com.android.server.connectivity.Nat464Xlat; @@ -388,6 +418,9 @@ import com.android.testutils.TestableNetworkCallback; import com.android.testutils.TestableNetworkOfferCallback; +import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -457,6 +490,9 @@ @Rule public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); + @Rule + public final PlatformCompatChangeRule compatChangeRule = new PlatformCompatChangeRule(); + private static final int TIMEOUT_MS = 2_000; // Broadcasts can take a long time to be delivered. The test will not wait for that long unless // there is a failure, so use a long timeout. @@ -473,7 +509,7 @@ // complete before callbacks are verified. private static final int TEST_REQUEST_TIMEOUT_MS = 150; - private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000; + private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 2_000; private static final long TIMESTAMP = 1234L; @@ -504,6 +540,10 @@ private static final int TEST_PACKAGE_UID = 123; private static final int TEST_PACKAGE_UID2 = 321; private static final int TEST_PACKAGE_UID3 = 456; + + private static final int PACKET_WAKEUP_MASK = 0xffff0000; + private static final int PACKET_WAKEUP_MARK = 0x88880000; + private static final String ALWAYS_ON_PACKAGE = "com.android.test.alwaysonvpn"; private static final String INTERFACE_NAME = "interface"; @@ -523,11 +563,12 @@ private MockContext mServiceContext; private HandlerThread mCsHandlerThread; private ConnectivityServiceDependencies mDeps; + private AutomaticOnOffKeepaliveTrackerDependencies mAutoOnOffKeepaliveDependencies; private ConnectivityService mService; private WrappedConnectivityManager mCm; - private TestNetworkAgentWrapper mWiFiNetworkAgent; - private TestNetworkAgentWrapper mCellNetworkAgent; - private TestNetworkAgentWrapper mEthernetNetworkAgent; + private TestNetworkAgentWrapper mWiFiAgent; + private TestNetworkAgentWrapper mCellAgent; + private TestNetworkAgentWrapper mEthernetAgent; private MockVpn mMockVpn; private Context mContext; private NetworkPolicyCallback mPolicyCallback; @@ -573,6 +614,9 @@ @Mock BpfNetMaps mBpfNetMaps; @Mock CarrierPrivilegeAuthenticator mCarrierPrivilegeAuthenticator; @Mock TetheringManager mTetheringManager; + @Mock BroadcastOptionsShim mBroadcastOptionsShim; + @Mock ActivityManager mActivityManager; + @Mock DestroySocketsWrapper mDestroySocketsWrapper; // BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the // underlying binder calls. @@ -696,6 +740,7 @@ if (Context.BATTERY_STATS_SERVICE.equals(name)) return mBatteryStatsManager; if (Context.PAC_PROXY_SERVICE.equals(name)) return mPacProxyManager; if (Context.TETHERING_SERVICE.equals(name)) return mTetheringManager; + if (Context.ACTIVITY_SERVICE.equals(name)) return mActivityManager; return super.getSystemService(name); } @@ -820,6 +865,27 @@ // null should not pass the test return null; } + + @Override + public void sendStickyBroadcast(Intent intent, Bundle options) { + // Verify that delivery group policy APIs were used on U. + if (mDeps.isAtLeastU() && CONNECTIVITY_ACTION.equals(intent.getAction())) { + final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO, + NetworkInfo.class); + try { + verify(mBroadcastOptionsShim).setDeliveryGroupPolicy( + eq(ConstantsShim.DELIVERY_GROUP_POLICY_MOST_RECENT)); + verify(mBroadcastOptionsShim).setDeliveryGroupMatchingKey( + eq(CONNECTIVITY_ACTION), + eq(createDeliveryGroupKeyForConnectivityAction(ni))); + verify(mBroadcastOptionsShim).setDeferralPolicy( + eq(ConstantsShim.DEFERRAL_POLICY_UNTIL_ACTIVE)); + } catch (UnsupportedApiLevelException e) { + throw new RuntimeException(e); + } + } + super.sendStickyBroadcast(intent, options); + } } // This was only added in the T SDK, but this test needs to build against the R+S SDKs, too. @@ -850,9 +916,9 @@ private void waitForIdle() { HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); - waitForIdle(mCellNetworkAgent, TIMEOUT_MS); - waitForIdle(mWiFiNetworkAgent, TIMEOUT_MS); - waitForIdle(mEthernetNetworkAgent, TIMEOUT_MS); + waitForIdle(mCellAgent, TIMEOUT_MS); + waitForIdle(mWiFiAgent, TIMEOUT_MS); + waitForIdle(mEthernetAgent, TIMEOUT_MS); HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); HandlerUtils.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS); } @@ -875,15 +941,15 @@ // Bring up a network that we can use to send messages to ConnectivityService. ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); b.expectBroadcast(); - Network n = mWiFiNetworkAgent.getNetwork(); + Network n = mWiFiAgent.getNetwork(); assertNotNull(n); // Tests that calling waitForIdle waits for messages to be processed. for (int i = 0; i < attempts; i++) { - mWiFiNetworkAgent.setSignalStrength(i); + mWiFiAgent.setSignalStrength(i); waitForIdle(); assertEquals(i, mCm.getNetworkCapabilities(n).getSignalStrength()); } @@ -895,16 +961,16 @@ public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception { // Bring up a network that we can use to send messages to ConnectivityService. ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); b.expectBroadcast(); - Network n = mWiFiNetworkAgent.getNetwork(); + Network n = mWiFiAgent.getNetwork(); assertNotNull(n); // Ensure that not calling waitForIdle causes a race condition. final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng. for (int i = 0; i < attempts; i++) { - mWiFiNetworkAgent.setSignalStrength(i); + mWiFiAgent.setSignalStrength(i); if (i != mCm.getNetworkCapabilities(n).getSignalStrength()) { // We hit a race condition, as expected. Pass the test. return; @@ -1019,7 +1085,7 @@ } private void onValidationRequested() throws Exception { - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { verify(mNetworkMonitor).notifyNetworkConnectedParcel(any()); } else { verify(mNetworkMonitor).notifyNetworkConnected(any(), any()); @@ -1058,15 +1124,30 @@ * @param validated Indicate if network should pretend to be validated. */ public void connect(boolean validated) { - connect(validated, true, false /* isStrictMode */); + connect(validated, true, false /* privateDnsProbeSent */); } /** * Transition this NetworkAgent to CONNECTED state. + * * @param validated Indicate if network should pretend to be validated. + * Note that if this is true, this method will mock the NetworkMonitor + * probes to pretend the network is invalid after it validated once, + * so that subsequent attempts (with mNetworkMonitor.forceReevaluation) + * will fail unless setNetworkValid is called again manually. * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET. + * @param privateDnsProbeSent whether the private DNS probe should be considered to have + * been sent, assuming |validated| is true. + * If |validated| is false, |privateDnsProbeSent| is not used. + * If |validated| is true and |privateDnsProbeSent| is false, + * the probe has not been sent. + * If |validated| is true and |privateDnsProbeSent| is true, + * the probe has been sent and has succeeded. When the NM probes + * are mocked to be invalid, private DNS is the reason this + * network is invalid ; see @param |validated|. */ - public void connect(boolean validated, boolean hasInternet, boolean isStrictMode) { + public void connect(boolean validated, boolean hasInternet, + boolean privateDnsProbeSent) { final ConditionVariable validatedCv = new ConditionVariable(); final ConditionVariable capsChangedCv = new ConditionVariable(); final NetworkRequest request = new NetworkRequest.Builder() @@ -1074,7 +1155,7 @@ .clearCapabilities() .build(); if (validated) { - setNetworkValid(isStrictMode); + setNetworkValid(privateDnsProbeSent); } final NetworkCallback callback = new NetworkCallback() { public void onCapabilitiesChanged(Network network, @@ -1099,14 +1180,15 @@ if (validated) { // Wait for network to validate. waitFor(validatedCv); - setNetworkInvalid(isStrictMode); + setNetworkInvalid(privateDnsProbeSent); } mCm.unregisterNetworkCallback(callback); } - public void connectWithCaptivePortal(String redirectUrl, boolean isStrictMode) { - setNetworkPortal(redirectUrl, isStrictMode); - connect(false, true /* hasInternet */, isStrictMode); + public void connectWithCaptivePortal(String redirectUrl, + boolean privateDnsProbeSent) { + setNetworkPortal(redirectUrl, privateDnsProbeSent); + connect(false, true /* hasInternet */, privateDnsProbeSent); } public void connectWithPartialConnectivity() { @@ -1114,16 +1196,16 @@ connect(false); } - public void connectWithPartialValidConnectivity(boolean isStrictMode) { - setNetworkPartialValid(isStrictMode); - connect(false, true /* hasInternet */, isStrictMode); + public void connectWithPartialValidConnectivity(boolean privateDnsProbeSent) { + setNetworkPartialValid(privateDnsProbeSent); + connect(false, true /* hasInternet */, privateDnsProbeSent); } - void setNetworkValid(boolean isStrictMode) { + void setNetworkValid(boolean privateDnsProbeSent) { mNmValidationResult = NETWORK_VALIDATION_RESULT_VALID; mNmValidationRedirectUrl = null; int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS; - if (isStrictMode) { + if (privateDnsProbeSent) { probesSucceeded |= NETWORK_VALIDATION_PROBE_PRIVDNS; } // The probesCompleted equals to probesSucceeded for the case of valid network, so put @@ -1131,15 +1213,16 @@ setProbesStatus(probesSucceeded, probesSucceeded); } - void setNetworkInvalid(boolean isStrictMode) { + void setNetworkInvalid(boolean invalidBecauseOfPrivateDns) { mNmValidationResult = VALIDATION_RESULT_INVALID; mNmValidationRedirectUrl = null; int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS | NETWORK_VALIDATION_PROBE_HTTP; int probesSucceeded = 0; - // If the isStrictMode is true, it means the network is invalid when NetworkMonitor - // tried to validate the private DNS but failed. - if (isStrictMode) { + // If |invalidBecauseOfPrivateDns| is true, it means the network is invalid because + // NetworkMonitor tried to validate the private DNS but failed. Therefore it + // didn't get a chance to try the HTTP probe. + if (invalidBecauseOfPrivateDns) { probesCompleted &= ~NETWORK_VALIDATION_PROBE_HTTP; probesSucceeded = probesCompleted; probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS; @@ -1147,14 +1230,14 @@ setProbesStatus(probesCompleted, probesSucceeded); } - void setNetworkPortal(String redirectUrl, boolean isStrictMode) { - setNetworkInvalid(isStrictMode); + void setNetworkPortal(String redirectUrl, boolean privateDnsProbeSent) { + setNetworkInvalid(privateDnsProbeSent); mNmValidationRedirectUrl = redirectUrl; // Suppose the portal is found when NetworkMonitor probes NETWORK_VALIDATION_PROBE_HTTP // in the beginning, so the NETWORK_VALIDATION_PROBE_HTTPS hasn't probed yet. int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP; int probesSucceeded = VALIDATION_RESULT_INVALID; - if (isStrictMode) { + if (privateDnsProbeSent) { probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS; } setProbesStatus(probesCompleted, probesSucceeded); @@ -1169,7 +1252,7 @@ setProbesStatus(probesCompleted, probesSucceeded); } - void setNetworkPartialValid(boolean isStrictMode) { + void setNetworkPartialValid(boolean privateDnsProbeSent) { setNetworkPartial(); mNmValidationResult |= NETWORK_VALIDATION_RESULT_VALID; mNmValidationRedirectUrl = null; @@ -1178,7 +1261,7 @@ int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP; // Assume the partial network cannot pass the private DNS validation as well, so only // add NETWORK_VALIDATION_PROBE_DNS in probesCompleted but not probesSucceeded. - if (isStrictMode) { + if (privateDnsProbeSent) { probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS; } setProbesStatus(probesCompleted, probesSucceeded); @@ -1473,8 +1556,9 @@ registerAgent(false /* isAlwaysMetered */, uids, makeLinkProperties()); } - private void connect(boolean validated, boolean hasInternet, boolean isStrictMode) { - mMockNetworkAgent.connect(validated, hasInternet, isStrictMode); + private void connect(boolean validated, boolean hasInternet, + boolean privateDnsProbeSent) { + mMockNetworkAgent.connect(validated, hasInternet, privateDnsProbeSent); } private void connect(boolean validated) { @@ -1491,10 +1575,10 @@ } public void establish(LinkProperties lp, int uid, Set<UidRange> ranges, boolean validated, - boolean hasInternet, boolean isStrictMode) throws Exception { + boolean hasInternet, boolean privateDnsProbeSent) throws Exception { setOwnerAndAdminUid(uid); registerAgent(false, ranges, lp); - connect(validated, hasInternet, isStrictMode); + connect(validated, hasInternet, privateDnsProbeSent); waitForIdle(); } @@ -1507,11 +1591,11 @@ establish(lp, uid, uidRangesForUids(uid), true, true, false); } - public void establishForMyUid(boolean validated, boolean hasInternet, boolean isStrictMode) - throws Exception { + public void establishForMyUid(boolean validated, boolean hasInternet, + boolean privateDnsProbeSent) throws Exception { final int uid = Process.myUid(); establish(makeLinkProperties(), uid, uidRangesForUids(uid), validated, hasInternet, - isStrictMode); + privateDnsProbeSent); } public void establishForMyUid() throws Exception { @@ -1784,7 +1868,8 @@ doReturn(mResources).when(mockResContext).getResources(); ConnectivityResources.setResourcesContextForTest(mockResContext); mDeps = new ConnectivityServiceDependencies(mockResContext); - + mAutoOnOffKeepaliveDependencies = + new AutomaticOnOffKeepaliveTrackerDependencies(mServiceContext); mService = new ConnectivityService(mServiceContext, mMockDnsResolver, mock(IpConnectivityLog.class), @@ -1839,10 +1924,15 @@ doReturn(0).when(mResources).getInteger(R.integer.config_activelyPreferBadWifi); doReturn(true).when(mResources) .getBoolean(R.bool.config_cellular_radio_timesharing_capable); + doReturn(PACKET_WAKEUP_MASK).when(mResources).getInteger( + R.integer.config_networkWakeupPacketMask); + doReturn(PACKET_WAKEUP_MARK).when(mResources).getInteger( + R.integer.config_networkWakeupPacketMark); } class ConnectivityServiceDependencies extends ConnectivityService.Dependencies { final ConnectivityResources mConnRes; + final ArraySet<Pair<Long, Integer>> mEnabledChangeIds = new ArraySet<>(); ConnectivityServiceDependencies(final Context mockResContext) { mConnRes = new ConnectivityResources(mockResContext); @@ -1885,6 +1975,12 @@ } @Override + public AutomaticOnOffKeepaliveTracker makeAutomaticOnOffKeepaliveTracker(final Context c, + final Handler h) { + return new AutomaticOnOffKeepaliveTracker(c, h, mAutoOnOffKeepaliveDependencies); + } + + @Override public ConnectivityResources getResources(final Context ctx) { return mConnRes; } @@ -1902,7 +1998,7 @@ @Override public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator( @NonNull final Context context, @NonNull final TelephonyManager tm) { - return SdkLevel.isAtLeastT() ? mCarrierPrivilegeAuthenticator : null; + return mDeps.isAtLeastT() ? mCarrierPrivilegeAuthenticator : null; } @Override @@ -1990,15 +2086,72 @@ } @Override - public boolean isFeatureEnabled(Context context, String name, boolean defaultEnabled) { + public boolean isFeatureEnabled(Context context, String name) { switch (name) { case ConnectivityFlags.NO_REMATCH_ALL_REQUESTS_ON_REGISTER: return true; + case KEY_DESTROY_FROZEN_SOCKETS_VERSION: + return true; default: - return super.isFeatureEnabled(context, name, defaultEnabled); + return super.isFeatureEnabled(context, name); } } + public void setChangeIdEnabled(final boolean enabled, final long changeId, final int uid) { + final Pair<Long, Integer> data = new Pair<>(changeId, uid); + // mEnabledChangeIds is read on the handler thread and maybe the test thread, so + // make sure both threads see it before continuing. + visibleOnHandlerThread(mCsHandlerThread.getThreadHandler(), () -> { + if (enabled) { + mEnabledChangeIds.add(data); + } else { + mEnabledChangeIds.remove(data); + } + }); + } + + @Override + public boolean isChangeEnabled(final long changeId, final int uid) { + return mEnabledChangeIds.contains(new Pair<>(changeId, uid)); + } + + // In AOSP, build version codes are all over the place (e.g. at the time of this writing + // U == V). Define custom ones. + private static final int VERSION_UNMOCKED = -1; + private static final int VERSION_R = 1; + private static final int VERSION_S = 2; + private static final int VERSION_T = 3; + private static final int VERSION_U = 4; + private static final int VERSION_V = 5; + private static final int VERSION_MAX = VERSION_V; + private int mSdkLevel = VERSION_UNMOCKED; + + private void setBuildSdk(final int sdkLevel) { + if (sdkLevel > VERSION_MAX) { + throw new IllegalArgumentException("setBuildSdk must not be called with" + + " Build.VERSION constants but Dependencies.VERSION_* constants"); + } + visibleOnHandlerThread(mCsHandlerThread.getThreadHandler(), () -> mSdkLevel = sdkLevel); + } + + @Override + public boolean isAtLeastS() { + return mSdkLevel == VERSION_UNMOCKED ? super.isAtLeastS() + : mSdkLevel >= VERSION_S; + } + + @Override + public boolean isAtLeastT() { + return mSdkLevel == VERSION_UNMOCKED ? super.isAtLeastT() + : mSdkLevel >= VERSION_T; + } + + @Override + public boolean isAtLeastU() { + return mSdkLevel == VERSION_UNMOCKED ? super.isAtLeastU() + : mSdkLevel >= VERSION_U; + } + @Override public BpfNetMaps getBpfNetMaps(Context context, INetd netd) { return mBpfNetMaps; @@ -2034,6 +2187,86 @@ assertNotEquals(-1L, (long) mActiveRateLimit.getOrDefault(iface, -1L)); mActiveRateLimit.put(iface, -1L); } + + @Override + public BroadcastOptionsShim makeBroadcastOptionsShim(BroadcastOptions options) { + reset(mBroadcastOptionsShim); + return mBroadcastOptionsShim; + } + + @GuardedBy("this") + private boolean mForceDisableCompatChangeCheck = true; + + /** + * By default, the {@link #isChangeEnabled(long, String, UserHandle)} will always return + * true as the mForceDisableCompatChangeCheck is true and compat change check logic is + * never executed. The compat change check logic can be turned on by calling this method. + * If this method is called, the + * {@link libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges} or + * {@link libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges} must be + * used to turn on/off the compat change flag. + */ + private void enableCompatChangeCheck() { + synchronized (this) { + mForceDisableCompatChangeCheck = false; + } + } + + @Override + public boolean isChangeEnabled(long changeId, + @NonNull final String packageName, + @NonNull final UserHandle user) { + synchronized (this) { + if (mForceDisableCompatChangeCheck) { + return false; + } else { + return super.isChangeEnabled(changeId, packageName, user); + } + } + } + + // Class to be mocked and used to verify destroy sockets methods call + public class DestroySocketsWrapper { + public void destroyLiveTcpSockets(final Set<Range<Integer>> ranges, + final Set<Integer> exemptUids){} + public void destroyLiveTcpSocketsByOwnerUids(final Set<Integer> ownerUids){} + } + + @Override @SuppressWarnings("DirectInvocationOnMock") + public void destroyLiveTcpSockets(final Set<Range<Integer>> ranges, + final Set<Integer> exemptUids) { + // Call mocked destroyLiveTcpSockets so that test can verify this method call + mDestroySocketsWrapper.destroyLiveTcpSockets(ranges, exemptUids); + } + + @Override @SuppressWarnings("DirectInvocationOnMock") + public void destroyLiveTcpSocketsByOwnerUids(final Set<Integer> ownerUids) { + // Call mocked destroyLiveTcpSocketsByOwnerUids so that test can verify this method call + mDestroySocketsWrapper.destroyLiveTcpSocketsByOwnerUids(ownerUids); + } + + final ArrayTrackRecord<Long>.ReadHead mScheduledEvaluationTimeouts = + new ArrayTrackRecord<Long>().newReadHead(); + @Override + public void scheduleEvaluationTimeout(@NonNull Handler handler, + @NonNull final Network network, final long delayMs) { + mScheduledEvaluationTimeouts.add(delayMs); + super.scheduleEvaluationTimeout(handler, network, delayMs); + } + } + + private class AutomaticOnOffKeepaliveTrackerDependencies + extends AutomaticOnOffKeepaliveTracker.Dependencies { + AutomaticOnOffKeepaliveTrackerDependencies(Context context) { + super(context); + } + + @Override + public boolean isFeatureEnabled(@NonNull final String name, final boolean defaultEnabled) { + // Tests for enabling the feature are verified in AutomaticOnOffKeepaliveTrackerTest. + // Assuming enabled here to focus on ConnectivityService tests. + return true; + } } private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) { @@ -2067,17 +2300,17 @@ unregisterDefaultNetworkCallbacks(); maybeTearDownEnterpriseNetwork(); setAlwaysOnNetworks(false); - if (mCellNetworkAgent != null) { - mCellNetworkAgent.disconnect(); - mCellNetworkAgent = null; + if (mCellAgent != null) { + mCellAgent.disconnect(); + mCellAgent = null; } - if (mWiFiNetworkAgent != null) { - mWiFiNetworkAgent.disconnect(); - mWiFiNetworkAgent = null; + if (mWiFiAgent != null) { + mWiFiAgent.disconnect(); + mWiFiAgent = null; } - if (mEthernetNetworkAgent != null) { - mEthernetNetworkAgent.disconnect(); - mEthernetNetworkAgent = null; + if (mEthernetAgent != null) { + mEthernetAgent.disconnect(); + mEthernetAgent = null; } if (mQosCallbackMockHelper != null) { @@ -2091,7 +2324,9 @@ ConnectivityResources.setResourcesContextForTest(null); mCsHandlerThread.quitSafely(); + mCsHandlerThread.join(); mAlarmManagerThread.quitSafely(); + mAlarmManagerThread.join(); } private void mockDefaultPackages() throws Exception { @@ -2140,13 +2375,13 @@ } switch (transport) { case TRANSPORT_WIFI: - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); break; case TRANSPORT_CELLULAR: - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); break; case TRANSPORT_ETHERNET: - assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mEthernetAgent.getNetwork(), mCm.getActiveNetwork()); break; default: break; @@ -2214,22 +2449,15 @@ } } - /** Expects that {@code count} CONNECTIVITY_ACTION broadcasts are received. */ - private ExpectedBroadcast registerConnectivityBroadcast(final int count) { - return registerConnectivityBroadcastThat(count, intent -> true); - } - - private ExpectedBroadcast registerConnectivityBroadcastThat(final int count, + private ExpectedBroadcast registerBroadcastReceiverThat(final String action, final int count, @NonNull final Predicate<Intent> filter) { - final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION); + final IntentFilter intentFilter = new IntentFilter(action); // AtomicReference allows receiver to access expected even though it is constructed later. final AtomicReference<ExpectedBroadcast> expectedRef = new AtomicReference<>(); final BroadcastReceiver receiver = new BroadcastReceiver() { private int mRemaining = count; public void onReceive(Context context, Intent intent) { - final int type = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1); - final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO); - Log.d(TAG, "Received CONNECTIVITY_ACTION type=" + type + " ni=" + ni); + logIntent(intent); if (!filter.test(intent)) return; if (--mRemaining == 0) { expectedRef.get().complete(intent); @@ -2242,39 +2470,49 @@ return expected; } + private void logIntent(Intent intent) { + final String action = intent.getAction(); + if (CONNECTIVITY_ACTION.equals(action)) { + final int type = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1); + final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO); + Log.d(TAG, "Received " + action + ", type=" + type + " ni=" + ni); + } else if (PROXY_CHANGE_ACTION.equals(action)) { + final ProxyInfo proxy = (ProxyInfo) intent.getExtra( + Proxy.EXTRA_PROXY_INFO, ProxyInfo.buildPacProxy(Uri.EMPTY)); + Log.d(TAG, "Received " + action + ", proxy = " + proxy); + } else { + throw new IllegalArgumentException("Unsupported logging " + action); + } + } + + /** Expects that {@code count} CONNECTIVITY_ACTION broadcasts are received. */ + private ExpectedBroadcast expectConnectivityAction(final int count) { + return registerBroadcastReceiverThat(CONNECTIVITY_ACTION, count, intent -> true); + } + + private ExpectedBroadcast expectConnectivityAction(int type, NetworkInfo.DetailedState state) { + return registerBroadcastReceiverThat(CONNECTIVITY_ACTION, 1, intent -> { + final int actualType = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1); + final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO); + return type == actualType + && state == ni.getDetailedState() + && extraInfoInBroadcastHasExpectedNullness(ni); + }); + } + + /** Expects that PROXY_CHANGE_ACTION broadcast is received. */ + private ExpectedBroadcast expectProxyChangeAction() { + return registerBroadcastReceiverThat(PROXY_CHANGE_ACTION, 1, intent -> true); + } + private ExpectedBroadcast expectProxyChangeAction(ProxyInfo proxy) { - return registerPacProxyBroadcastThat(intent -> { + return registerBroadcastReceiverThat(PROXY_CHANGE_ACTION, 1, intent -> { final ProxyInfo actualProxy = (ProxyInfo) intent.getExtra(Proxy.EXTRA_PROXY_INFO, ProxyInfo.buildPacProxy(Uri.EMPTY)); return proxy.equals(actualProxy); }); } - private ExpectedBroadcast registerPacProxyBroadcast() { - return registerPacProxyBroadcastThat(intent -> true); - } - - private ExpectedBroadcast registerPacProxyBroadcastThat( - @NonNull final Predicate<Intent> filter) { - final IntentFilter intentFilter = new IntentFilter(Proxy.PROXY_CHANGE_ACTION); - // AtomicReference allows receiver to access expected even though it is constructed later. - final AtomicReference<ExpectedBroadcast> expectedRef = new AtomicReference<>(); - final BroadcastReceiver receiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - final ProxyInfo proxy = (ProxyInfo) intent.getExtra( - Proxy.EXTRA_PROXY_INFO, ProxyInfo.buildPacProxy(Uri.EMPTY)); - Log.d(TAG, "Receive PROXY_CHANGE_ACTION, proxy = " + proxy); - if (filter.test(intent)) { - expectedRef.get().complete(intent); - } - } - }; - final ExpectedBroadcast expected = new ExpectedBroadcast(receiver); - expectedRef.set(expected); - mServiceContext.registerReceiver(receiver, intentFilter); - return expected; - } - private boolean extraInfoInBroadcastHasExpectedNullness(NetworkInfo ni) { final DetailedState state = ni.getDetailedState(); if (state == DetailedState.CONNECTED && ni.getExtraInfo() == null) return false; @@ -2290,16 +2528,6 @@ return true; } - private ExpectedBroadcast expectConnectivityAction(int type, NetworkInfo.DetailedState state) { - return registerConnectivityBroadcastThat(1, intent -> { - final int actualType = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1); - final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO); - return type == actualType - && state == ni.getDetailedState() - && extraInfoInBroadcastHasExpectedNullness(ni); - }); - } - @Test public void testNetworkTypes() { // Ensure that our mocks for the networkAttributes config variable work as expected. If they @@ -2320,10 +2548,10 @@ @Test public void testNetworkFeature() throws Exception { // Connect the cell agent and wait for the connected broadcast. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.addCapability(NET_CAPABILITY_SUPL); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.addCapability(NET_CAPABILITY_SUPL); ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED); - mCellNetworkAgent.connect(true); + mCellAgent.connect(true); b.expectBroadcast(); // Build legacy request for SUPL. @@ -2334,56 +2562,56 @@ ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST); // File request, withdraw it and make sure no broadcast is sent - b = registerConnectivityBroadcast(1); + b = expectConnectivityAction(1); final TestNetworkCallback callback = new TestNetworkCallback(); mCm.requestNetwork(legacyRequest, callback); - callback.expect(CallbackEntry.AVAILABLE, mCellNetworkAgent); + callback.expect(AVAILABLE, mCellAgent); mCm.unregisterNetworkCallback(callback); b.expectNoBroadcast(800); // 800ms long enough to at least flake if this is sent // Disconnect the network and expect mobile disconnected broadcast. b = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED); - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); b.expectBroadcast(); } @Test public void testLingering() throws Exception { verifyNoNetwork(); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); assertNull(mCm.getActiveNetworkInfo()); assertNull(mCm.getActiveNetwork()); // Test bringing up validated cellular. ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED); - mCellNetworkAgent.connect(true); + mCellAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_CELLULAR); assertLength(2, mCm.getAllNetworks()); - assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) || - mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork())); - assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) || - mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork())); + assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) + || mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork())); + assertTrue(mCm.getAllNetworks()[0].equals(mWiFiAgent.getNetwork()) + || mCm.getAllNetworks()[1].equals(mWiFiAgent.getNetwork())); // Test bringing up validated WiFi. - b = registerConnectivityBroadcast(2); - mWiFiNetworkAgent.connect(true); + b = expectConnectivityAction(2); + mWiFiAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); assertLength(2, mCm.getAllNetworks()); - assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) || - mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork())); - assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) || - mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork())); + assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) + || mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork())); + assertTrue(mCm.getAllNetworks()[0].equals(mCellAgent.getNetwork()) + || mCm.getAllNetworks()[1].equals(mCellAgent.getNetwork())); // Test cellular linger timeout. - mCellNetworkAgent.expectDisconnected(); + mCellAgent.expectDisconnected(); waitForIdle(); assertLength(1, mCm.getAllNetworks()); verifyActiveNetwork(TRANSPORT_WIFI); assertLength(1, mCm.getAllNetworks()); assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork()); // Test WiFi disconnect. - b = registerConnectivityBroadcast(1); - mWiFiNetworkAgent.disconnect(); + b = expectConnectivityAction(1); + mWiFiAgent.disconnect(); b.expectBroadcast(); verifyNoNetwork(); } @@ -2400,43 +2628,43 @@ // 1. Create a network that is not requested by anyone, and does not satisfy any of the // default requests. Verify that the network will be inactive instead of torn down. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithoutInternet(); - listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connectWithoutInternet(); + listenCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); listenCallback.assertNoCallback(); // Verify that the network will be torn down after nascent expiry. A small period of time // is added in case of flakiness. final int nascentTimeoutMs = mService.mNascentDelayMs + mService.mNascentDelayMs / 4; - listenCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent, nascentTimeoutMs); + listenCallback.expect(LOST, mWiFiAgent, nascentTimeoutMs); // 2. Create a network that is satisfied by a request comes later. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithoutInternet(); - listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connectWithoutInternet(); + listenCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); final NetworkRequest wifiRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_WIFI).build(); final TestNetworkCallback wifiCallback = new TestNetworkCallback(); mCm.requestNetwork(wifiRequest, wifiCallback); - wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // Verify that the network will be kept since the request is still satisfied. And is able // to get disconnected as usual if the request is released after the nascent timer expires. listenCallback.assertNoCallback(nascentTimeoutMs); mCm.unregisterNetworkCallback(wifiCallback); - listenCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + listenCallback.expect(LOST, mWiFiAgent); // 3. Create a network that is satisfied by a request comes later. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithoutInternet(); - listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connectWithoutInternet(); + listenCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); mCm.requestNetwork(wifiRequest, wifiCallback); - wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // Verify that the network will still be torn down after the request gets removed. mCm.unregisterNetworkCallback(wifiCallback); - listenCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + listenCallback.expect(LOST, mWiFiAgent); // There is no need to ensure that LOSING is never sent in the common case that the // network immediately satisfies a request that was already present, because it is already @@ -2469,20 +2697,20 @@ .addCapability(NET_CAPABILITY_FOREGROUND).build(), fgMobileListenCallback); // Connect wifi, which satisfies default request. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - wifiListenCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + wifiListenCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent); // Connect a cellular network, verify that satisfies only the background callback. setAlwaysOnNetworks(true); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - bgMobileListenCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + bgMobileListenCallback.expectAvailableThenValidatedCallbacks(mCellAgent); fgMobileListenCallback.assertNoCallback(); - assertFalse(isForegroundNetwork(mCellNetworkAgent)); + assertFalse(isForegroundNetwork(mCellAgent)); - mCellNetworkAgent.disconnect(); - bgMobileListenCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + bgMobileListenCallback.expect(LOST, mCellAgent); fgMobileListenCallback.assertNoCallback(); mCm.unregisterNetworkCallback(wifiListenCallback); @@ -2547,34 +2775,34 @@ final boolean cellRadioTimesharingCapable) throws Exception { mService.mCellularRadioTimesharingCapable = cellRadioTimesharingCapable; // Test bringing up unvalidated WiFi - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - ExpectedBroadcast b = registerConnectivityBroadcast(1); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + ExpectedBroadcast b = expectConnectivityAction(1); + mWiFiAgent.connect(false); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); // Test bringing up unvalidated cellular - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(false); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(false); waitForIdle(); verifyActiveNetwork(TRANSPORT_WIFI); // Test cellular disconnect. - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); waitForIdle(); verifyActiveNetwork(TRANSPORT_WIFI); // Test bringing up validated cellular - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - b = registerConnectivityBroadcast(2); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + b = expectConnectivityAction(2); + mCellAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test cellular disconnect. - b = registerConnectivityBroadcast(2); - mCellNetworkAgent.disconnect(); + b = expectConnectivityAction(2); + mCellAgent.disconnect(); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); // Test WiFi disconnect. - b = registerConnectivityBroadcast(1); - mWiFiNetworkAgent.disconnect(); + b = expectConnectivityAction(1); + mWiFiAgent.disconnect(); b.expectBroadcast(); verifyNoNetwork(); } @@ -2595,25 +2823,25 @@ final boolean cellRadioTimesharingCapable) throws Exception { mService.mCellularRadioTimesharingCapable = cellRadioTimesharingCapable; // Test bringing up unvalidated cellular. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - ExpectedBroadcast b = registerConnectivityBroadcast(1); - mCellNetworkAgent.connect(false); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + ExpectedBroadcast b = expectConnectivityAction(1); + mCellAgent.connect(false); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test bringing up unvalidated WiFi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - b = registerConnectivityBroadcast(2); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + b = expectConnectivityAction(2); + mWiFiAgent.connect(false); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); // Test WiFi disconnect. - b = registerConnectivityBroadcast(2); - mWiFiNetworkAgent.disconnect(); + b = expectConnectivityAction(2); + mWiFiAgent.disconnect(); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test cellular disconnect. - b = registerConnectivityBroadcast(1); - mCellNetworkAgent.disconnect(); + b = expectConnectivityAction(1); + mCellAgent.disconnect(); b.expectBroadcast(); verifyNoNetwork(); } @@ -2634,28 +2862,28 @@ final boolean cellRadioTimesharingCapable) throws Exception { mService.mCellularRadioTimesharingCapable = cellRadioTimesharingCapable; // Test bringing up unvalidated WiFi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - ExpectedBroadcast b = registerConnectivityBroadcast(1); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + ExpectedBroadcast b = expectConnectivityAction(1); + mWiFiAgent.connect(false); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); - assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability( + assertFalse(mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); // Test bringing up validated cellular. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - b = registerConnectivityBroadcast(2); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + b = expectConnectivityAction(2); + mCellAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_CELLULAR); - assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability( + assertFalse(mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); // Test cellular disconnect. - b = registerConnectivityBroadcast(2); - mCellNetworkAgent.disconnect(); + b = expectConnectivityAction(2); + mCellAgent.disconnect(); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); // Unlingering a network should not cause it to be marked as validated. - assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability( + assertFalse(mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); } @@ -2712,7 +2940,7 @@ if (expectLingering) { generalCb.expectLosing(net1); } - generalCb.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, net2); + generalCb.expectCaps(net2, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); defaultCb.expectAvailableDoubleValidatedCallbacks(net2); // Make sure cell 1 is unwanted immediately if the radio can't time share, but only @@ -2727,7 +2955,7 @@ net1.expectDisconnected(TEST_CALLBACK_TIMEOUT_MS); } net1.disconnect(); - generalCb.expect(CallbackEntry.LOST, net1); + generalCb.expect(LOST, net1); // Remove primary from net 2 net2.setScore(new NetworkScore.Builder().build()); @@ -2757,13 +2985,14 @@ // for any other request. generalCb.expectLosing(net2); net2.assertNotDisconnected(TEST_CALLBACK_TIMEOUT_MS); - generalCb.assertNoCallback(); + // Timeout 0 because after a while LOST will actually arrive + generalCb.assertNoCallback(0 /* timeoutMs */); net2.expectDisconnected(UNREASONABLY_LONG_ALARM_WAIT_MS); } else { net2.expectDisconnected(TEST_CALLBACK_TIMEOUT_MS); } net2.disconnect(); - generalCb.expect(CallbackEntry.LOST, net2); + generalCb.expect(LOST, net2); defaultCb.assertNoCallback(); net3.disconnect(); @@ -2788,25 +3017,25 @@ final boolean cellRadioTimesharingCapable) throws Exception { mService.mCellularRadioTimesharingCapable = cellRadioTimesharingCapable; // Test bringing up validated cellular. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - ExpectedBroadcast b = registerConnectivityBroadcast(1); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + ExpectedBroadcast b = expectConnectivityAction(1); + mCellAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test bringing up validated WiFi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - b = registerConnectivityBroadcast(2); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + b = expectConnectivityAction(2); + mWiFiAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); // Test WiFi getting really weak. - b = registerConnectivityBroadcast(2); - mWiFiNetworkAgent.adjustScore(-11); + b = expectConnectivityAction(2); + mWiFiAgent.adjustScore(-11); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test WiFi restoring signal strength. - b = registerConnectivityBroadcast(2); - mWiFiNetworkAgent.adjustScore(11); + b = expectConnectivityAction(2); + mWiFiAgent.adjustScore(11); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); } @@ -2828,29 +3057,29 @@ mService.mCellularRadioTimesharingCapable = cellRadioTimesharingCapable; // Test bringing up WiFi without NET_CAPABILITY_INTERNET. // Expect it to be torn down immediately because it satisfies no requests. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithoutInternet(); - mWiFiNetworkAgent.expectDisconnected(); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connectWithoutInternet(); + mWiFiAgent.expectDisconnected(); // Test bringing up cellular without NET_CAPABILITY_INTERNET. // Expect it to be torn down immediately because it satisfies no requests. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mCellNetworkAgent.connectWithoutInternet(); - mCellNetworkAgent.expectDisconnected(); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mCellAgent.connectWithoutInternet(); + mCellAgent.expectDisconnected(); // Test bringing up validated WiFi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED); - mWiFiNetworkAgent.connect(true); + mWiFiAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); // Test bringing up unvalidated cellular. // Expect it to be torn down because it could never be the highest scoring network // satisfying the default request even if it validated. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(false); - mCellNetworkAgent.expectDisconnected(); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(false); + mCellAgent.expectDisconnected(); verifyActiveNetwork(TRANSPORT_WIFI); - mWiFiNetworkAgent.disconnect(); - mWiFiNetworkAgent.expectDisconnected(); + mWiFiAgent.disconnect(); + mWiFiAgent.expectDisconnected(); } // TODO : migrate to @Parameterized @@ -2869,37 +3098,37 @@ final boolean cellRadioTimesharingCapable) throws Exception { mService.mCellularRadioTimesharingCapable = cellRadioTimesharingCapable; // Test bringing up validated cellular. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - ExpectedBroadcast b = registerConnectivityBroadcast(1); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + ExpectedBroadcast b = expectConnectivityAction(1); + mCellAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test bringing up validated WiFi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - b = registerConnectivityBroadcast(2); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + b = expectConnectivityAction(2); + mWiFiAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); // Reevaluate WiFi (it'll instantly fail DNS). - b = registerConnectivityBroadcast(2); - assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability( + b = expectConnectivityAction(2); + assertTrue(mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); - mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork()); + mCm.reportBadNetwork(mWiFiAgent.getNetwork()); // Should quickly fall back to Cellular. b.expectBroadcast(); - assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability( + assertFalse(mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); verifyActiveNetwork(TRANSPORT_CELLULAR); // Reevaluate cellular (it'll instantly fail DNS). - b = registerConnectivityBroadcast(2); - assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability( + b = expectConnectivityAction(2); + assertTrue(mCm.getNetworkCapabilities(mCellAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); - mCm.reportBadNetwork(mCellNetworkAgent.getNetwork()); + mCm.reportBadNetwork(mCellAgent.getNetwork()); // Should quickly fall back to WiFi. b.expectBroadcast(); - assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability( + assertFalse(mCm.getNetworkCapabilities(mCellAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); - assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability( + assertFalse(mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); verifyActiveNetwork(TRANSPORT_WIFI); } @@ -2920,25 +3149,25 @@ final boolean cellRadioTimesharingCapable) throws Exception { mService.mCellularRadioTimesharingCapable = cellRadioTimesharingCapable; // Test bringing up unvalidated WiFi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - ExpectedBroadcast b = registerConnectivityBroadcast(1); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + ExpectedBroadcast b = expectConnectivityAction(1); + mWiFiAgent.connect(false); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); // Test bringing up validated cellular. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - b = registerConnectivityBroadcast(2); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + b = expectConnectivityAction(2); + mCellAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_CELLULAR); // Reevaluate cellular (it'll instantly fail DNS). - b = registerConnectivityBroadcast(2); - assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability( + b = expectConnectivityAction(2); + assertTrue(mCm.getNetworkCapabilities(mCellAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); - mCm.reportBadNetwork(mCellNetworkAgent.getNetwork()); + mCm.reportBadNetwork(mCellAgent.getNetwork()); // Should quickly fall back to WiFi. b.expectBroadcast(); - assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability( + assertFalse(mCm.getNetworkCapabilities(mCellAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); verifyActiveNetwork(TRANSPORT_WIFI); } @@ -2957,18 +3186,16 @@ */ private class TestNetworkCallback extends TestableNetworkCallback { TestNetworkCallback() { - super(TEST_CALLBACK_TIMEOUT_MS); - } - - @Override - public void assertNoCallback() { - // TODO: better support this use case in TestableNetworkCallback - waitForIdle(); - assertNoCallback(0 /* timeout */); + // In the context of this test, the testable network callbacks should use waitForIdle + // before calling assertNoCallback in an effort to detect issues where a callback is + // not yet sent but a message currently in the queue of a handler will cause it to + // be sent soon. + super(TEST_CALLBACK_TIMEOUT_MS, TEST_CALLBACK_TIMEOUT_MS, + ConnectivityServiceTest.this::waitForIdle); } public CallbackEntry.Losing expectLosing(final HasNetwork n, final long timeoutMs) { - final CallbackEntry.Losing losing = expect(CallbackEntry.LOSING, n, timeoutMs); + final CallbackEntry.Losing losing = expect(LOSING, n, timeoutMs); final int maxMsToLive = losing.getMaxMsToLive(); if (maxMsToLive < 0 || maxMsToLive > mService.mLingerDelayMs) { // maxMsToLive is the value that was received in the onLosing callback. That must @@ -2990,27 +3217,32 @@ // Can't be part of TestNetworkCallback because "cannot be declared static; static methods can // only be declared in a static or top level type". + static void assertNoCallbacks(final long timeoutMs, TestNetworkCallback ... callbacks) { + for (TestNetworkCallback c : callbacks) { + c.assertNoCallback(timeoutMs); + } + } + static void assertNoCallbacks(TestNetworkCallback ... callbacks) { for (TestNetworkCallback c : callbacks) { - c.assertNoCallback(); + c.assertNoCallback(); // each callback uses its own timeout } } static void expectOnLost(TestNetworkAgentWrapper network, TestNetworkCallback ... callbacks) { for (TestNetworkCallback c : callbacks) { - c.expect(CallbackEntry.LOST, network); + c.expect(LOST, network); } } static void expectAvailableCallbacksUnvalidatedWithSpecifier(TestNetworkAgentWrapper network, NetworkSpecifier specifier, TestNetworkCallback ... callbacks) { for (TestNetworkCallback c : callbacks) { - c.expect(CallbackEntry.AVAILABLE, network); - c.expectCapabilitiesThat(network, (nc) -> - !nc.hasCapability(NET_CAPABILITY_VALIDATED) - && Objects.equals(specifier, nc.getNetworkSpecifier())); - c.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, network); - c.expect(CallbackEntry.BLOCKED_STATUS, network); + c.expect(AVAILABLE, network); + c.expectCaps(network, cb -> !cb.hasCapability(NET_CAPABILITY_VALIDATED) + && Objects.equals(specifier, cb.getNetworkSpecifier())); + c.expect(LINK_PROPERTIES_CHANGED, network); + c.expect(BLOCKED_STATUS, network); } } @@ -3020,12 +3252,12 @@ final NetworkRequest wifiRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_WIFI).build(); mCm.requestNetwork(wifiRequest, cb); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); // Updating the score triggers a rematch. - mWiFiNetworkAgent.setScore(new NetworkScore.Builder().build()); + mWiFiAgent.setScore(new NetworkScore.Builder().build()); cb.assertNoCallback(); - mWiFiNetworkAgent.connect(false); - cb.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent.connect(false); + cb.expectAvailableCallbacksUnvalidated(mWiFiAgent); cb.assertNoCallback(); mCm.unregisterNetworkCallback(cb); } @@ -3036,13 +3268,13 @@ final NetworkRequest wifiRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_WIFI).build(); mCm.registerNetworkCallback(wifiRequest, cb); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - final NetworkCapabilities nc = mWiFiNetworkAgent.getNetworkCapabilities(); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + final NetworkCapabilities nc = mWiFiAgent.getNetworkCapabilities(); nc.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); - mWiFiNetworkAgent.setNetworkCapabilities(nc, true /* sendToConnectivityService */); + mWiFiAgent.setNetworkCapabilities(nc, true /* sendToConnectivityService */); cb.assertNoCallback(); - mWiFiNetworkAgent.connect(false); - cb.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent.connect(false); + cb.expectAvailableCallbacksUnvalidated(mWiFiAgent); final CallbackEntry found = CollectionUtils.findLast(cb.getHistory(), it -> it instanceof CallbackEntry.CapabilitiesChanged); assertTrue(((CallbackEntry.CapabilitiesChanged) found).getCaps() @@ -3067,77 +3299,81 @@ mCm.registerNetworkCallback(cellRequest, cellNetworkCallback); // Test unvalidated networks - ExpectedBroadcast b = registerConnectivityBroadcast(1); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(false); - genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); - cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + ExpectedBroadcast b = expectConnectivityAction(1); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(false); + genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellAgent); + cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellAgent); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); b.expectBroadcast(); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); // This should not trigger spurious onAvailable() callbacks, b/21762680. - mCellNetworkAgent.adjustScore(-1); + mCellAgent.adjustScore(-1); waitForIdle(); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); - b = registerConnectivityBroadcast(2); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); - genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + b = expectConnectivityAction(2); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); + genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); b.expectBroadcast(); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); - b = registerConnectivityBroadcast(2); - mWiFiNetworkAgent.disconnect(); - genericNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - wifiNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + b = expectConnectivityAction(2); + mWiFiAgent.disconnect(); + genericNetworkCallback.expect(CallbackEntry.LOST, mWiFiAgent); + wifiNetworkCallback.expect(CallbackEntry.LOST, mWiFiAgent); cellNetworkCallback.assertNoCallback(); b.expectBroadcast(); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); - b = registerConnectivityBroadcast(1); - mCellNetworkAgent.disconnect(); - genericNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); - cellNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + b = expectConnectivityAction(1); + mCellAgent.disconnect(); + genericNetworkCallback.expect(CallbackEntry.LOST, mCellAgent); + cellNetworkCallback.expect(CallbackEntry.LOST, mCellAgent); b.expectBroadcast(); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); // Test validated networks - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); // This should not trigger spurious onAvailable() callbacks, b/21762680. - mCellNetworkAgent.adjustScore(-1); + mCellAgent.adjustScore(-1); waitForIdle(); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - genericNetworkCallback.expectLosing(mCellNetworkAgent); - genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - cellNetworkCallback.expectLosing(mCellNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + genericNetworkCallback.expectLosing(mCellAgent); + genericNetworkCallback.expectCaps(mWiFiAgent, + c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent); + cellNetworkCallback.expectLosing(mCellAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); + // Cell will disconnect after the lingering period. Before that elapses check that + // there have been no callbacks. + assertNoCallbacks(0 /* timeoutMs */, + genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); + + mWiFiAgent.disconnect(); + genericNetworkCallback.expect(LOST, mWiFiAgent); + wifiNetworkCallback.expect(LOST, mWiFiAgent); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); - mWiFiNetworkAgent.disconnect(); - genericNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - wifiNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); - - mCellNetworkAgent.disconnect(); - genericNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); - cellNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + genericNetworkCallback.expect(LOST, mCellAgent); + cellNetworkCallback.expect(LOST, mCellAgent); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); } @@ -3149,10 +3385,10 @@ mCm.registerNetworkCallback(wifiRequest, callback); mCm.registerDefaultNetworkCallback(defaultCallback); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); final LinkProperties newLp = new LinkProperties(); final Uri capportUrl = Uri.parse("https://capport.example.com/api"); @@ -3161,20 +3397,20 @@ final Uri expectedCapportUrl = sanitized ? null : capportUrl; newLp.setCaptivePortalApiUrl(capportUrl); - mWiFiNetworkAgent.sendLinkProperties(newLp); - callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> - Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl())); - defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> - Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl())); + mWiFiAgent.sendLinkProperties(newLp); + callback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, cb -> + Objects.equals(expectedCapportUrl, cb.getLp().getCaptivePortalApiUrl())); + defaultCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, cb -> + Objects.equals(expectedCapportUrl, cb.getLp().getCaptivePortalApiUrl())); final CaptivePortalData expectedCapportData = sanitized ? null : capportData; - mWiFiNetworkAgent.notifyCapportApiDataChanged(capportData); - callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> - Objects.equals(expectedCapportData, lp.getCaptivePortalData())); - defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> - Objects.equals(expectedCapportData, lp.getCaptivePortalData())); + mWiFiAgent.notifyCapportApiDataChanged(capportData); + callback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, cb -> + Objects.equals(expectedCapportData, cb.getLp().getCaptivePortalData())); + defaultCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, cb -> + Objects.equals(expectedCapportData, cb.getLp().getCaptivePortalData())); - final LinkProperties lp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork()); + final LinkProperties lp = mCm.getLinkProperties(mWiFiAgent.getNetwork()); assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl()); assertEquals(expectedCapportData, lp.getCaptivePortalData()); } @@ -3209,19 +3445,18 @@ final int originalOwnerUid = Process.myUid(); ncTemplate.setOwnerUid(originalOwnerUid); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), - ncTemplate); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), ncTemplate); + mWiFiAgent.connect(false); waitForIdle(); - // Send ConnectivityService an update to the mWiFiNetworkAgent's capabilities that changes + // Send ConnectivityService an update to the mWiFiAgent's capabilities that changes // the owner UID and an unrelated capability. - NetworkCapabilities agentCapabilities = mWiFiNetworkAgent.getNetworkCapabilities(); + NetworkCapabilities agentCapabilities = mWiFiAgent.getNetworkCapabilities(); assertEquals(originalOwnerUid, agentCapabilities.getOwnerUid()); agentCapabilities.setOwnerUid(42); assertFalse(agentCapabilities.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); agentCapabilities.addCapability(NET_CAPABILITY_NOT_CONGESTED); - mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true); + mWiFiAgent.setNetworkCapabilities(agentCapabilities, true); waitForIdle(); // Owner UIDs are not visible without location permission. @@ -3229,7 +3464,7 @@ Manifest.permission.ACCESS_FINE_LOCATION); // Check that the capability change has been applied but the owner UID is not modified. - NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()); + NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()); assertEquals(originalOwnerUid, nc.getOwnerUid()); assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); } @@ -3239,8 +3474,10 @@ // This test would be flaky with the default 120ms timer: that is short enough that // lingered networks are torn down before assertions can be run. We don't want to mock the // lingering timer to keep the WakeupMessage logic realistic: this has already proven useful - // in detecting races. - mService.mLingerDelayMs = 300; + // in detecting races. Furthermore, sometimes the test is running while Phenotype is running + // so hot that the test doesn't get the CPU for multiple hundreds of milliseconds, so this + // needs to be suitably long. + mService.mLingerDelayMs = 2_000; NetworkRequest request = new NetworkRequest.Builder() .clearCapabilities().addCapability(NET_CAPABILITY_NOT_METERED) @@ -3251,56 +3488,56 @@ TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mEthernetAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); - mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mCellAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mEthernetAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mCellNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + mCellAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - mWiFiNetworkAgent.connect(true); + mWiFiAgent.connect(true); // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request. // We then get LOSING when wifi validates and cell is outscored. - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // TODO: Investigate sending validated before losing. - callback.expectLosing(mCellNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + callback.expectLosing(mCellAgent); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - mEthernetNetworkAgent.connect(true); - callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent); + mEthernetAgent.connect(true); + callback.expectAvailableCallbacksUnvalidated(mEthernetAgent); // TODO: Investigate sending validated before losing. - callback.expectLosing(mWiFiNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent); - defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent); - assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + callback.expectLosing(mWiFiAgent); + callback.expectCaps(mEthernetAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetAgent); + assertEquals(mEthernetAgent.getNetwork(), mCm.getActiveNetwork()); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - mEthernetNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mEthernetNetworkAgent); - defaultCallback.expect(CallbackEntry.LOST, mEthernetNetworkAgent); - defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); + mEthernetAgent.disconnect(); + callback.expect(LOST, mEthernetAgent); + defaultCallback.expect(LOST, mEthernetAgent); + defaultCallback.expectAvailableCallbacksValidated(mWiFiAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); for (int i = 0; i < 4; i++) { TestNetworkAgentWrapper oldNetwork, newNetwork; if (i % 2 == 0) { - mWiFiNetworkAgent.adjustScore(-15); - oldNetwork = mWiFiNetworkAgent; - newNetwork = mCellNetworkAgent; + mWiFiAgent.adjustScore(-15); + oldNetwork = mWiFiAgent; + newNetwork = mCellAgent; } else { - mWiFiNetworkAgent.adjustScore(15); - oldNetwork = mCellNetworkAgent; - newNetwork = mWiFiNetworkAgent; + mWiFiAgent.adjustScore(15); + oldNetwork = mCellAgent; + newNetwork = mWiFiAgent; } callback.expectLosing(oldNetwork); @@ -3309,28 +3546,28 @@ defaultCallback.expectAvailableCallbacksValidated(newNetwork); assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork()); } - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); // Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even // if the network is still up. - mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.removeCapability(NET_CAPABILITY_NOT_METERED); // We expect a notification about the capabilities change, and nothing else. - defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent); + defaultCallback.expectCaps(mWiFiAgent, c -> !c.hasCapability(NET_CAPABILITY_NOT_METERED)); defaultCallback.assertNoCallback(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + callback.expect(LOST, mWiFiAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Wifi no longer satisfies our listen, which is for an unmetered network. // But because its score is 55, it's still up (and the default network). - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); // Disconnect our test networks. - mWiFiNetworkAgent.disconnect(); - defaultCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + mWiFiAgent.disconnect(); + defaultCallback.expect(LOST, mWiFiAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - mCellNetworkAgent.disconnect(); - defaultCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + defaultCallback.expect(LOST, mCellAgent); waitForIdle(); assertEquals(null, mCm.getActiveNetwork()); @@ -3344,64 +3581,64 @@ mCm.registerNetworkCallback(request, callback); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(false); // Score: 10 - callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); - defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(false); // Score: 10 + callback.expectAvailableCallbacksUnvalidated(mCellAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mCellAgent); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up wifi with a score of 20. // Cell stays up because it would satisfy the default request if it validated. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); // Score: 20 - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); // Score: 20 + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - defaultCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); + defaultCallback.expect(LOST, mWiFiAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mCellAgent); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but // it's arguably correct to linger it, since it was the default network before it validated. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // TODO: Investigate sending validated before losing. - callback.expectLosing(mCellNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + callback.expectLosing(mCellAgent); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - defaultCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); - mCellNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mCellNetworkAgent); - defaultCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); + defaultCallback.expect(LOST, mWiFiAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mCellAgent); + mCellAgent.disconnect(); + callback.expect(LOST, mCellAgent); + defaultCallback.expect(LOST, mCellAgent); waitForIdle(); assertEquals(null, mCm.getActiveNetwork()); // If a network is lingering, and we add and remove a request from it, resume lingering. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mCellAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // TODO: Investigate sending validated before losing. - callback.expectLosing(mCellNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + callback.expectLosing(mCellAgent); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); NetworkRequest cellRequest = new NetworkRequest.Builder() @@ -3411,14 +3648,14 @@ // TODO: should this cause an AVAILABLE callback, to indicate that the network is no longer // lingering? mCm.unregisterNetworkCallback(noopCallback); - callback.expectLosing(mCellNetworkAgent); + callback.expectLosing(mCellAgent); // Similar to the above: lingering can start even after the lingered request is removed. // Disconnect wifi and switch to cell. - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - defaultCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); + defaultCallback.expect(LOST, mWiFiAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Cell is now the default network. Pin it with a cell-specific request. @@ -3426,44 +3663,44 @@ mCm.requestNetwork(cellRequest, noopCallback); // Now connect wifi, and expect it to become the default network. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mWiFiAgent); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // The default request is lingering on cell, but nothing happens to cell, and we send no // callbacks for it, because it's kept up by cellRequest. callback.assertNoCallback(); // Now unregister cellRequest and expect cell to start lingering. mCm.unregisterNetworkCallback(noopCallback); - callback.expectLosing(mCellNetworkAgent); + callback.expectLosing(mCellAgent); // Let linger run its course. - callback.assertNoCallback(); + callback.assertNoCallback(0 /* timeoutMs */); final int lingerTimeoutMs = mService.mLingerDelayMs + mService.mLingerDelayMs / 4; - callback.expect(CallbackEntry.LOST, mCellNetworkAgent, lingerTimeoutMs); + callback.expect(LOST, mCellAgent, lingerTimeoutMs); // Register a TRACK_DEFAULT request and check that it does not affect lingering. TestNetworkCallback trackDefaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(trackDefaultCallback); - trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); - mEthernetNetworkAgent.connect(true); - callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent); - callback.expectLosing(mWiFiNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent); - trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent); - defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent); + trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiAgent); + mEthernetAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); + mEthernetAgent.connect(true); + callback.expectAvailableCallbacksUnvalidated(mEthernetAgent); + callback.expectLosing(mWiFiAgent); + callback.expectCaps(mEthernetAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetAgent); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Let linger run its course. - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent, lingerTimeoutMs); + callback.expect(LOST, mWiFiAgent, lingerTimeoutMs); // Clean up. - mEthernetNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mEthernetNetworkAgent); - defaultCallback.expect(CallbackEntry.LOST, mEthernetNetworkAgent); - trackDefaultCallback.expect(CallbackEntry.LOST, mEthernetNetworkAgent); + mEthernetAgent.disconnect(); + callback.expect(LOST, mEthernetAgent); + defaultCallback.expect(LOST, mEthernetAgent); + trackDefaultCallback.expect(LOST, mEthernetAgent); mCm.unregisterNetworkCallback(callback); mCm.unregisterNetworkCallback(defaultCallback); @@ -3499,19 +3736,19 @@ TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mCellNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mCellAgent); // Wifi comes up and cell lingers. - mWiFiNetworkAgent.connect(true); - defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - callback.expectLosing(mCellNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + mWiFiAgent.connect(true); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + callback.expectLosing(mCellAgent); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); // File a request for cellular, then release it. NetworkRequest cellRequest = new NetworkRequest.Builder() @@ -3519,13 +3756,13 @@ NetworkCallback noopCallback = new NetworkCallback(); mCm.requestNetwork(cellRequest, noopCallback); mCm.unregisterNetworkCallback(noopCallback); - callback.expectLosing(mCellNetworkAgent); + callback.expectLosing(mCellAgent); // Let linger run its course. callback.assertNoCallback(); final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4; - callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent, - lingerTimeoutMs); + callback.expectCaps(mCellAgent, lingerTimeoutMs, + c -> !c.hasCapability(NET_CAPABILITY_FOREGROUND)); // Clean up. mCm.unregisterNetworkCallback(defaultCallback); @@ -3580,7 +3817,7 @@ private void expectDisconnectAndClearNotifications(TestNetworkCallback callback, TestNetworkAgentWrapper agent, NotificationType type) { - callback.expect(CallbackEntry.LOST, agent); + callback.expect(LOST, agent); expectClearNotification(agent, type); } @@ -3651,7 +3888,13 @@ final NetworkAgentWrapper.Callbacks callbacks = new NetworkAgentWrapper.Callbacks( onNetworkCreated, onNetworkUnwanted, onNetworkDisconnected); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, callbacks); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, callbacks); + + if (mService.shouldCreateNetworksImmediately()) { + assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } else { + assertNull(eventOrder.poll()); + } // Connect a network, and file a request for it after it has come up, to ensure the nascent // timer is cleared and the test does not have to wait for it. Filing the request after the @@ -3659,13 +3902,18 @@ // nascent timer if the first request satisfied by the network was filed before the network // connected. // TODO: fix this bug, file the request before connecting, and remove the waitForIdle. - mWiFiNetworkAgent.connectWithoutInternet(); - waitForIdle(); + mWiFiAgent.connectWithoutInternet(); + if (!mService.shouldCreateNetworksImmediately()) { + assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } else { + waitForIdle(); + assertNull(eventOrder.poll()); + } mCm.requestNetwork(request, callback); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // Set teardown delay and make sure CS has processed it. - mWiFiNetworkAgent.getNetworkAgent().setTeardownDelayMillis(300); + mWiFiAgent.getNetworkAgent().setTeardownDelayMillis(300); waitForIdle(); // Post the duringTeardown lambda to the handler so it fires while teardown is in progress. @@ -3673,11 +3921,10 @@ // down the network and started the teardown timer, and short enough that the lambda is // scheduled to run before the teardown timer. final Handler h = new Handler(mCsHandlerThread.getLooper()); - h.postDelayed(() -> duringTeardown.accept(mWiFiNetworkAgent.getNetwork()), 150); + h.postDelayed(() -> duringTeardown.accept(mWiFiAgent.getNetwork()), 150); // Disconnect the network and check that events happened in the right order. mCm.unregisterNetworkCallback(callback); - assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals("onNetworkUnwanted", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals("timePasses", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals("onNetworkDisconnected", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); @@ -3687,113 +3934,118 @@ @Test public void testExplicitlySelected() throws Exception { - NetworkRequest request = new NetworkRequest.Builder() + final NetworkRequest request = new NetworkRequest.Builder() .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET) .build(); - TestNetworkCallback callback = new TestNetworkCallback(); + final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(request, callback); - // Bring up validated cell. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + // Bring up validated cell + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellAgent); // Bring up unvalidated wifi with explicitlySelected=true. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.explicitlySelected(true, false); - mWiFiNetworkAgent.connect(false); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.explicitlySelected(true, false); + mWiFiAgent.connect(false); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // Cell remains the default. - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); // Expect a high-priority NO_INTERNET notification. - expectUnvalidationCheckWillNotify(mWiFiNetworkAgent, NotificationType.NO_INTERNET); + expectUnvalidationCheckWillNotify(mWiFiAgent, NotificationType.NO_INTERNET); // Lower WiFi's score to lower than cell, and check that it doesn't disconnect because // it's explicitly selected. - mWiFiNetworkAgent.adjustScore(-40); - mWiFiNetworkAgent.adjustScore(40); + mWiFiAgent.adjustScore(-40); + mWiFiAgent.adjustScore(40); callback.assertNoCallback(); // If the user chooses yes on the "No Internet access, stay connected?" dialog, we switch to // wifi even though it's unvalidated. - mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), true, false); - callback.expectLosing(mCellNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + mCm.setAcceptUnvalidated(mWiFiAgent.getNetwork(), true, false); + callback.expectLosing(mCellAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); // Disconnect wifi, and then reconnect, again with explicitlySelected=true. - mWiFiNetworkAgent.disconnect(); - expectDisconnectAndClearNotifications(callback, mWiFiNetworkAgent, - NotificationType.NO_INTERNET); + mWiFiAgent.disconnect(); + expectDisconnectAndClearNotifications(callback, mWiFiAgent, NotificationType.NO_INTERNET); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.explicitlySelected(true, false); - mWiFiNetworkAgent.connect(false); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.explicitlySelected(true, false); + mWiFiAgent.connect(false); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // Expect a high-priority NO_INTERNET notification. - expectUnvalidationCheckWillNotify(mWiFiNetworkAgent, NotificationType.NO_INTERNET); + expectUnvalidationCheckWillNotify(mWiFiAgent, NotificationType.NO_INTERNET); // If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the // network to disconnect. - mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), false, false); - expectDisconnectAndClearNotifications(callback, mWiFiNetworkAgent, - NotificationType.NO_INTERNET); + mCm.setAcceptUnvalidated(mWiFiAgent.getNetwork(), false, false); + expectDisconnectAndClearNotifications(callback, mWiFiAgent, NotificationType.NO_INTERNET); reset(mNotificationManager); // Reconnect, again with explicitlySelected=true, but this time validate. // Expect no notifications. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.explicitlySelected(true, false); - mWiFiNetworkAgent.connect(true); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - callback.expectLosing(mCellNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); - expectUnvalidationCheckWillNotNotify(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.explicitlySelected(true, false); + mWiFiAgent.connect(true); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + callback.expectLosing(mCellAgent); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); + expectUnvalidationCheckWillNotNotify(mWiFiAgent); - mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); - mEthernetNetworkAgent.connect(true); - callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent); - callback.expectLosing(mWiFiNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent); - assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + // Now request cell so it doesn't disconnect during the test + final NetworkRequest cellRequest = new NetworkRequest.Builder() + .clearCapabilities().addTransportType(TRANSPORT_CELLULAR).build(); + final TestNetworkCallback cellCallback = new TestNetworkCallback(); + mCm.requestNetwork(cellRequest, cellCallback); + + mEthernetAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); + mEthernetAgent.connect(true); + callback.expectAvailableCallbacksUnvalidated(mEthernetAgent); + callback.expectLosing(mWiFiAgent); + callback.expectCaps(mEthernetAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + assertEquals(mEthernetAgent.getNetwork(), mCm.getActiveNetwork()); callback.assertNoCallback(); // Disconnect wifi, and then reconnect as if the user had selected "yes, don't ask again" // (i.e., with explicitlySelected=true and acceptUnvalidated=true). Expect to switch to // wifi immediately. - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.explicitlySelected(true, true); - mWiFiNetworkAgent.connect(false); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - callback.expectLosing(mEthernetNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); - mEthernetNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mEthernetNetworkAgent); - expectUnvalidationCheckWillNotNotify(mWiFiNetworkAgent); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.explicitlySelected(true, true); + mWiFiAgent.connect(false); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + callback.expectLosing(mEthernetAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); + mEthernetAgent.disconnect(); + callback.expect(LOST, mEthernetAgent); + expectUnvalidationCheckWillNotNotify(mWiFiAgent); // Disconnect and reconnect with explicitlySelected=false and acceptUnvalidated=true. // Check that the network is not scored specially and that the device prefers cell data. - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.explicitlySelected(false, true); - mWiFiNetworkAgent.connect(false); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); - expectUnvalidationCheckWillNotNotify(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.explicitlySelected(false, true); + mWiFiAgent.connect(false); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); + expectUnvalidationCheckWillNotNotify(mWiFiAgent); // Clean up. - mWiFiNetworkAgent.disconnect(); - mCellNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); + mCellAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - callback.expect(CallbackEntry.LOST, mCellNetworkAgent); + callback.expect(LOST, mWiFiAgent); + callback.expect(LOST, mCellAgent); + mCm.unregisterNetworkCallback(cellCallback); } private void doTestFirstEvaluation( @@ -3807,36 +4059,36 @@ TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(request, callback); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - doConnect.accept(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + doConnect.accept(mWiFiAgent); // Expect the available callbacks, but don't require specific values for their arguments // since this method doesn't know how the network was connected. - callback.expect(CallbackEntry.AVAILABLE, mWiFiNetworkAgent); - callback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, mWiFiNetworkAgent); - callback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mWiFiNetworkAgent); - callback.expect(CallbackEntry.BLOCKED_STATUS, mWiFiNetworkAgent); + callback.expect(AVAILABLE, mWiFiAgent); + callback.expect(NETWORK_CAPS_UPDATED, mWiFiAgent); + callback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent); + callback.expect(BLOCKED_STATUS, mWiFiAgent); if (waitForSecondCaps) { // This is necessary because of b/245893397, the same bug that happens where we use // expectAvailableDoubleValidatedCallbacks. - callback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, mWiFiNetworkAgent); + callback.expect(NETWORK_CAPS_UPDATED, mWiFiAgent); } final NetworkAgentInfo nai = - mService.getNetworkAgentInfoForNetwork(mWiFiNetworkAgent.getNetwork()); + mService.getNetworkAgentInfoForNetwork(mWiFiAgent.getNetwork()); final long firstEvaluation = nai.getFirstEvaluationConcludedTime(); if (evaluatedByValidation) { assertNotEquals(0L, firstEvaluation); } else { assertEquals(0L, firstEvaluation); } - mService.scheduleEvaluationTimeout(mWiFiNetworkAgent.getNetwork(), 0L /* timeout */); + mService.scheduleEvaluationTimeout(mWiFiAgent.getNetwork(), 0L /* timeout */); waitForIdle(); if (evaluatedByValidation) { assertEquals(firstEvaluation, nai.getFirstEvaluationConcludedTime()); } else { assertNotEquals(0L, nai.getFirstEvaluationConcludedTime()); } - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); mCm.unregisterNetworkCallback(callback); } @@ -4005,9 +4257,9 @@ @Test public void testRegisterIgnoringScore() throws Exception { - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(90).build()); - mWiFiNetworkAgent.connect(true /* validated */); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.setScore(new NetworkScore.Builder().setLegacyInt(90).build()); + mWiFiAgent.connect(true /* validated */); // Make sure the factory sees the default network final NetworkCapabilities filter = new NetworkCapabilities(); @@ -4030,13 +4282,13 @@ testFactoryAll.expectRequestAdd(); // The legacy int will be ignored anyway, set the only other knob to true - mWiFiNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(110) + mWiFiAgent.setScore(new NetworkScore.Builder().setLegacyInt(110) .setTransportPrimary(true).build()); expectNoRequestChanged(testFactory); // still not seeing the request expectNoRequestChanged(testFactoryAll); // still seeing the request - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); } @Test @@ -4124,18 +4376,18 @@ @Test public void testMMSonWiFi() throws Exception { // Test bringing up cellular without MMS NetworkRequest gets reaped - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS); - mCellNetworkAgent.connectWithoutInternet(); - mCellNetworkAgent.expectDisconnected(); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.addCapability(NET_CAPABILITY_MMS); + mCellAgent.connectWithoutInternet(); + mCellAgent.expectDisconnected(); waitForIdle(); assertEmpty(mCm.getAllNetworks()); verifyNoNetwork(); // Test bringing up validated WiFi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED); - mWiFiNetworkAgent.connect(true); + mWiFiAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); @@ -4146,24 +4398,24 @@ mCm.requestNetwork(builder.build(), networkCallback); // Test bringing up unvalidated cellular with MMS - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS); - mCellNetworkAgent.connectWithoutInternet(); - networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.addCapability(NET_CAPABILITY_MMS); + mCellAgent.connectWithoutInternet(); + networkCallback.expectAvailableCallbacksUnvalidated(mCellAgent); verifyActiveNetwork(TRANSPORT_WIFI); // Test releasing NetworkRequest disconnects cellular with MMS mCm.unregisterNetworkCallback(networkCallback); - mCellNetworkAgent.expectDisconnected(); + mCellAgent.expectDisconnected(); verifyActiveNetwork(TRANSPORT_WIFI); } @Test public void testMMSonCell() throws Exception { // Test bringing up cellular without MMS - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED); - mCellNetworkAgent.connect(false); + mCellAgent.connect(false); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_CELLULAR); @@ -4197,142 +4449,139 @@ mCm.registerNetworkCallback(request, callback); // Bring up validated mobile data. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellAgent); // Bring up wifi with partial connectivity. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithPartialConnectivity(); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connectWithPartialConnectivity(); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)); // Mobile data should be the default network. - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); callback.assertNoCallback(); // Expect a PARTIAL_CONNECTIVITY notification. The notification appears as soon as partial // connectivity is detected, and is low priority because the network was not explicitly // selected by the user. This happens if we reconnect to a network where the user previously // accepted partial connectivity without checking "always". - expectNotification(mWiFiNetworkAgent, NotificationType.PARTIAL_CONNECTIVITY); + expectNotification(mWiFiAgent, NotificationType.PARTIAL_CONNECTIVITY); // With HTTPS probe disabled, NetworkMonitor should pass the network validation with http // probe. - mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */); + mWiFiAgent.setNetworkPartialValid(false /* privateDnsProbeSent */); // If the user chooses yes to use this partial connectivity wifi, switch the default // network to wifi and check if wifi becomes valid or not. - mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */, + mCm.setAcceptPartialConnectivity(mWiFiAgent.getNetwork(), true /* accept */, false /* always */); // If user accepts partial connectivity network, // NetworkMonitor#setAcceptPartialConnectivity() should be called too. waitForIdle(); - verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); + verify(mWiFiAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); // Need a trigger point to let NetworkMonitor tell ConnectivityService that the network is // validated. - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); - callback.expectLosing(mCellNetworkAgent); - NetworkCapabilities nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, - mWiFiNetworkAgent); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true); + callback.expectLosing(mCellAgent); + NetworkCapabilities nc = + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); assertTrue(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); // Once the network validates, the notification disappears. - expectClearNotification(mWiFiNetworkAgent, NotificationType.PARTIAL_CONNECTIVITY); + expectClearNotification(mWiFiAgent, NotificationType.PARTIAL_CONNECTIVITY); // Disconnect and reconnect wifi with partial connectivity again. - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithPartialConnectivity(); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connectWithPartialConnectivity(); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)); // Mobile data should be the default network. - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); waitForIdle(); // Expect a low-priority PARTIAL_CONNECTIVITY notification as soon as partial connectivity // is detected. - expectNotification(mWiFiNetworkAgent, NotificationType.PARTIAL_CONNECTIVITY); + expectNotification(mWiFiAgent, NotificationType.PARTIAL_CONNECTIVITY); // If the user chooses no, disconnect wifi immediately. - mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), false /* accept */, + mCm.setAcceptPartialConnectivity(mWiFiAgent.getNetwork(), false /* accept */, false /* always */); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - expectClearNotification(mWiFiNetworkAgent, NotificationType.PARTIAL_CONNECTIVITY); + callback.expect(LOST, mWiFiAgent); + expectClearNotification(mWiFiAgent, NotificationType.PARTIAL_CONNECTIVITY); reset(mNotificationManager); // If the user accepted partial connectivity before, and the device connects to that network // again, but now the network has full connectivity, then the network shouldn't contain // NET_CAPABILITY_PARTIAL_CONNECTIVITY. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); // acceptUnvalidated is also used as setting for accepting partial networks. - mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */, - true /* acceptUnvalidated */); - mWiFiNetworkAgent.connect(true); - expectUnvalidationCheckWillNotNotify(mWiFiNetworkAgent); + mWiFiAgent.explicitlySelected(true /* explicitlySelected */, true /* acceptUnvalidated */); + mWiFiAgent.connect(true); + expectUnvalidationCheckWillNotNotify(mWiFiAgent); // If user accepted partial connectivity network before, // NetworkMonitor#setAcceptPartialConnectivity() will be called in // ConnectivityService#updateNetworkInfo(). - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); - callback.expectLosing(mCellNetworkAgent); - nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + verify(mWiFiAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); + callback.expectLosing(mCellAgent); + nc = callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); assertFalse(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)); // Wifi should be the default network. - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); // The user accepted partial connectivity and selected "don't ask again". Now the user // reconnects to the partial connectivity network. Switch to wifi as soon as partial // connectivity is detected. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */, - true /* acceptUnvalidated */); - mWiFiNetworkAgent.connectWithPartialConnectivity(); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.explicitlySelected(true /* explicitlySelected */, true /* acceptUnvalidated */); + mWiFiAgent.connectWithPartialConnectivity(); // If user accepted partial connectivity network before, // NetworkMonitor#setAcceptPartialConnectivity() will be called in // ConnectivityService#updateNetworkInfo(). - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); - callback.expectLosing(mCellNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); - callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent); - expectUnvalidationCheckWillNotNotify(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + verify(mWiFiAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); + callback.expectLosing(mCellAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)); + expectUnvalidationCheckWillNotNotify(mWiFiAgent); - mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */); + mWiFiAgent.setNetworkValid(false /* privateDnsProbeSent */); // Need a trigger point to let NetworkMonitor tell ConnectivityService that the network is // validated. - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); // If the user accepted partial connectivity, and the device auto-reconnects to the partial // connectivity network, it should contain both PARTIAL_CONNECTIVITY and VALIDATED. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.explicitlySelected(false /* explicitlySelected */, - true /* acceptUnvalidated */); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.explicitlySelected(false /* explicitlySelected */, true /* acceptUnvalidated */); // NetworkMonitor will immediately (once the HTTPS probe fails...) report the network as // valid, because ConnectivityService calls setAcceptPartialConnectivity before it calls // notifyNetworkConnected. - mWiFiNetworkAgent.connectWithPartialValidConnectivity(false /* isStrictMode */); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); - callback.expectLosing(mCellNetworkAgent); - callback.expectCapabilitiesWith( - NET_CAPABILITY_PARTIAL_CONNECTIVITY | NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - expectUnvalidationCheckWillNotNotify(mWiFiNetworkAgent); - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.connectWithPartialValidConnectivity(false /* privateDnsProbeSent */); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + verify(mWiFiAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); + callback.expectLosing(mCellAgent); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY) + && c.hasCapability(NET_CAPABILITY_VALIDATED)); + expectUnvalidationCheckWillNotNotify(mWiFiAgent); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); verifyNoMoreInteractions(mNotificationManager); } @@ -4351,42 +4600,40 @@ // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); String redirectUrl = "http://android.com/path"; - mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */); - wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), redirectUrl); + mWiFiAgent.connectWithCaptivePortal(redirectUrl, false /* privateDnsProbeSent */); + wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + assertEquals(mWiFiAgent.waitForRedirectUrl(), redirectUrl); // This is necessary because of b/245893397, the same bug that happens where we use // expectAvailableDoubleValidatedCallbacks. // TODO : fix b/245893397 and remove this. - wifiCallback.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, mWiFiNetworkAgent); + wifiCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)); // Check that startCaptivePortalApp sends the expected command to NetworkMonitor. - mCm.startCaptivePortalApp(mWiFiNetworkAgent.getNetwork()); - verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1)) - .launchCaptivePortalApp(); + mCm.startCaptivePortalApp(mWiFiAgent.getNetwork()); + verify(mWiFiAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1)).launchCaptivePortalApp(); // Report that the captive portal is dismissed with partial connectivity, and check that // callbacks are fired with PARTIAL and without CAPTIVE_PORTAL. - mWiFiNetworkAgent.setNetworkPartial(); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); + mWiFiAgent.setNetworkPartial(); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true); waitForIdle(); - wifiCallback.expectCapabilitiesThat( - mWiFiNetworkAgent, nc -> - nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY) - && !nc.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)); + wifiCallback.expectCaps(mWiFiAgent, + c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY) + && !c.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)); // Report partial connectivity is accepted. - mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */); - mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */, + mWiFiAgent.setNetworkPartialValid(false /* privateDnsProbeSent */); + mCm.setAcceptPartialConnectivity(mWiFiAgent.getNetwork(), true /* accept */, false /* always */); waitForIdle(); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); - wifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, - mWiFiNetworkAgent); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true); + wifiCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + validatedCallback.expectAvailableCallbacksValidated(mWiFiAgent); + validatedCallback.expectCaps(mWiFiAgent, + c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)); mCm.unregisterNetworkCallback(wifiCallback); mCm.unregisterNetworkCallback(validatedCallback); @@ -4406,39 +4653,39 @@ // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); String firstRedirectUrl = "http://example.com/firstPath"; - mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */); - captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl); + mWiFiAgent.connectWithCaptivePortal(firstRedirectUrl, false /* privateDnsProbeSent */); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + assertEquals(mWiFiAgent.waitForRedirectUrl(), firstRedirectUrl); // Take down network. // Expect onLost callback. - mWiFiNetworkAgent.disconnect(); - captivePortalCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.disconnect(); + captivePortalCallback.expect(LOST, mWiFiAgent); // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); String secondRedirectUrl = "http://example.com/secondPath"; - mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl, false /* isStrictMode */); - captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl); + mWiFiAgent.connectWithCaptivePortal(secondRedirectUrl, false /* privateDnsProbeSent */); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + assertEquals(mWiFiAgent.waitForRedirectUrl(), secondRedirectUrl); // Make captive portal disappear then revalidate. // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL. - mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); - captivePortalCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.setNetworkValid(false /* privateDnsProbeSent */); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true); + captivePortalCallback.expect(LOST, mWiFiAgent); // Expect NET_CAPABILITY_VALIDATED onAvailable callback. - validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); // Break network connectivity. // Expect NET_CAPABILITY_VALIDATED onLost callback. - mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false); - validatedCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.setNetworkInvalid(false /* invalidBecauseOfPrivateDns */); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), false); + validatedCallback.expect(LOST, mWiFiAgent); } private Intent startCaptivePortalApp(TestNetworkAgentWrapper networkAgent) throws Exception { @@ -4475,36 +4722,35 @@ mCm.registerNetworkCallback(validatedRequest, validatedCallback); // Bring up wifi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - Network wifiNetwork = mWiFiNetworkAgent.getNetwork(); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + Network wifiNetwork = mWiFiAgent.getNetwork(); // Check that calling startCaptivePortalApp does nothing. final int fastTimeoutMs = 100; mCm.startCaptivePortalApp(wifiNetwork); waitForIdle(); - verify(mWiFiNetworkAgent.mNetworkMonitor, never()).launchCaptivePortalApp(); + verify(mWiFiAgent.mNetworkMonitor, never()).launchCaptivePortalApp(); mServiceContext.expectNoStartActivityIntent(fastTimeoutMs); // Turn into a captive portal. - mWiFiNetworkAgent.setNetworkPortal("http://example.com", false /* isStrictMode */); + mWiFiAgent.setNetworkPortal("http://example.com", false /* privateDnsProbeSent */); mCm.reportNetworkConnectivity(wifiNetwork, false); - captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - validatedCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + validatedCallback.expect(LOST, mWiFiAgent); // This is necessary because of b/245893397, the same bug that happens where we use // expectAvailableDoubleValidatedCallbacks. // TODO : fix b/245893397 and remove this. - captivePortalCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, - mWiFiNetworkAgent); + captivePortalCallback.expectCaps(mWiFiAgent); - startCaptivePortalApp(mWiFiNetworkAgent); + startCaptivePortalApp(mWiFiAgent); // Report that the captive portal is dismissed, and check that callbacks are fired - mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */); - mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); - validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - captivePortalCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.setNetworkValid(false /* privateDnsProbeSent */); + mWiFiAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); + validatedCallback.expectAvailableCallbacksValidated(mWiFiAgent); + captivePortalCallback.expect(LOST, mWiFiAgent); mCm.unregisterNetworkCallback(validatedCallback); mCm.unregisterNetworkCallback(captivePortalCallback); @@ -4517,11 +4763,11 @@ .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build(); mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithCaptivePortal(TEST_REDIRECT_URL, false); - captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connectWithCaptivePortal(TEST_REDIRECT_URL, false); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); - final Intent signInIntent = startCaptivePortalApp(mWiFiNetworkAgent); + final Intent signInIntent = startCaptivePortalApp(mWiFiAgent); final CaptivePortal captivePortal = signInIntent .getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL); @@ -4529,14 +4775,14 @@ waitForIdle(); // Since network will disconnect, ensure no notification of response to NetworkMonitor - verify(mWiFiNetworkAgent.mNetworkMonitor, never()) + verify(mWiFiAgent.mNetworkMonitor, never()) .notifyCaptivePortalAppFinished(CaptivePortal.APP_RETURN_UNWANTED); // Report that the network is disconnected - mWiFiNetworkAgent.expectDisconnected(); - mWiFiNetworkAgent.expectPreventReconnectReceived(); - verify(mWiFiNetworkAgent.mNetworkMonitor).notifyNetworkDisconnected(); - captivePortalCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.expectDisconnected(); + mWiFiAgent.expectPreventReconnectReceived(); + verify(mWiFiAgent.mNetworkMonitor).notifyNetworkDisconnected(); + captivePortalCallback.expect(LOST, mWiFiAgent); mCm.unregisterNetworkCallback(captivePortalCallback); } @@ -4556,12 +4802,12 @@ setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID); // Bring up a network with a captive portal. // Expect it to fail to connect and not result in any callbacks. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - String firstRedirectUrl = "http://example.com/firstPath"; + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + final String firstRedirectUrl = "http://example.com/firstPath"; - mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */); - mWiFiNetworkAgent.expectDisconnected(); - mWiFiNetworkAgent.expectPreventReconnectReceived(); + mWiFiAgent.connectWithCaptivePortal(firstRedirectUrl, false /* privateDnsProbeSent */); + mWiFiAgent.expectDisconnected(); + mWiFiAgent.expectPreventReconnectReceived(); assertNoCallbacks(captivePortalCallback, validatedCallback); } @@ -4575,28 +4821,30 @@ .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build(); mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); final String redirectUrl = "http://example.com/firstPath"; - mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */); - captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent.connectWithCaptivePortal(redirectUrl, + false /* privateDnsProbeSent */); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); final CaptivePortalData testData = new CaptivePortalData.Builder() .setUserPortalUrl(Uri.parse(redirectUrl)) .setBytesRemaining(12345L) .build(); - mWiFiNetworkAgent.notifyCapportApiDataChanged(testData); + mWiFiAgent.notifyCapportApiDataChanged(testData); - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> testData.equals(lp.getCaptivePortalData())); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> testData.equals(cb.getLp().getCaptivePortalData())); final LinkProperties newLps = new LinkProperties(); newLps.setMtu(1234); - mWiFiNetworkAgent.sendLinkProperties(newLps); + mWiFiAgent.sendLinkProperties(newLps); // CaptivePortalData is not lost and unchanged when LPs are received from the NetworkAgent - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> testData.equals(lp.getCaptivePortalData()) && lp.getMtu() == 1234); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> testData.equals(cb.getLp().getCaptivePortalData()) + && cb.getLp().getMtu() == 1234); } private TestNetworkCallback setupNetworkCallbackAndConnectToWifi() throws Exception { @@ -4609,10 +4857,11 @@ .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build(); mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithCaptivePortal(TEST_REDIRECT_URL, false /* isStrictMode */); - captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent.connectWithCaptivePortal(TEST_REDIRECT_URL, + false /* privateDnsProbeSent */); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); return captivePortalCallback; } @@ -4687,53 +4936,54 @@ final CaptivePortalTestData captivePortalTestData = setupCaptivePortalData(); // Baseline capport data - mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData); + mWiFiAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData); - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData())); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> captivePortalTestData.mCapportData.equals(cb.getLp().getCaptivePortalData())); // Venue URL, T&C URL and friendly name from Network agent with Passpoint source, confirm // that API data gets precedence on the bytes remaining. final LinkProperties linkProperties = new LinkProperties(); linkProperties.setCaptivePortalData(captivePortalTestData.mNaPasspointData); - mWiFiNetworkAgent.sendLinkProperties(linkProperties); + mWiFiAgent.sendLinkProperties(linkProperties); // Make sure that the capport data is merged - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> captivePortalTestData.mExpectedMergedPasspointData - .equals(lp.getCaptivePortalData())); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> captivePortalTestData.mExpectedMergedPasspointData.equals( + cb.getLp().getCaptivePortalData())); // Now send this information from non-Passpoint source, confirm that Capport data takes // precedence linkProperties.setCaptivePortalData(captivePortalTestData.mNaOtherData); - mWiFiNetworkAgent.sendLinkProperties(linkProperties); + mWiFiAgent.sendLinkProperties(linkProperties); // Make sure that the capport data is merged - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> captivePortalTestData.mExpectedMergedOtherData - .equals(lp.getCaptivePortalData())); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> captivePortalTestData.mExpectedMergedOtherData.equals( + cb.getLp().getCaptivePortalData())); // Create a new LP with no Network agent capport data final LinkProperties newLps = new LinkProperties(); newLps.setMtu(1234); - mWiFiNetworkAgent.sendLinkProperties(newLps); + mWiFiAgent.sendLinkProperties(newLps); // CaptivePortalData is not lost and has the original values when LPs are received from the // NetworkAgent - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()) - && lp.getMtu() == 1234); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> captivePortalTestData.mCapportData.equals(cb.getLp().getCaptivePortalData()) + && cb.getLp().getMtu() == 1234); // Now send capport data only from the Network agent - mWiFiNetworkAgent.notifyCapportApiDataChanged(null); - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> lp.getCaptivePortalData() == null); + mWiFiAgent.notifyCapportApiDataChanged(null); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> cb.getLp().getCaptivePortalData() == null); newLps.setCaptivePortalData(captivePortalTestData.mNaPasspointData); - mWiFiNetworkAgent.sendLinkProperties(newLps); + mWiFiAgent.sendLinkProperties(newLps); // Make sure that only the network agent capport data is available - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData())); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> captivePortalTestData.mNaPasspointData.equals( + cb.getLp().getCaptivePortalData())); } @Test @@ -4745,28 +4995,29 @@ // on the bytes remaining. final LinkProperties linkProperties = new LinkProperties(); linkProperties.setCaptivePortalData(captivePortalTestData.mNaPasspointData); - mWiFiNetworkAgent.sendLinkProperties(linkProperties); + mWiFiAgent.sendLinkProperties(linkProperties); // Make sure that the data is saved correctly - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData())); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> captivePortalTestData.mNaPasspointData.equals( + cb.getLp().getCaptivePortalData())); // Expected merged data: Network agent data is preferred, and values that are not used by // it are merged from capport data - mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData); + mWiFiAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData); // Make sure that the Capport data is merged correctly - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> captivePortalTestData.mExpectedMergedPasspointData.equals( - lp.getCaptivePortalData())); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> captivePortalTestData.mExpectedMergedPasspointData.equals( + cb.getLp().getCaptivePortalData())); // Now set the naData to null linkProperties.setCaptivePortalData(null); - mWiFiNetworkAgent.sendLinkProperties(linkProperties); + mWiFiAgent.sendLinkProperties(linkProperties); // Make sure that the Capport data is retained correctly - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData())); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> captivePortalTestData.mCapportData.equals(cb.getLp().getCaptivePortalData())); } @Test @@ -4779,20 +5030,20 @@ // on the bytes remaining. final LinkProperties linkProperties = new LinkProperties(); linkProperties.setCaptivePortalData(captivePortalTestData.mNaOtherData); - mWiFiNetworkAgent.sendLinkProperties(linkProperties); + mWiFiAgent.sendLinkProperties(linkProperties); // Make sure that the data is saved correctly - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> captivePortalTestData.mNaOtherData.equals(lp.getCaptivePortalData())); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> captivePortalTestData.mNaOtherData.equals(cb.getLp().getCaptivePortalData())); // Expected merged data: Network agent data is preferred, and values that are not used by // it are merged from capport data - mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData); + mWiFiAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData); // Make sure that the Capport data is merged correctly - captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, - lp -> captivePortalTestData.mExpectedMergedOtherData.equals( - lp.getCaptivePortalData())); + captivePortalCallback.expect(LINK_PROPERTIES_CHANGED, mWiFiAgent, + cb -> captivePortalTestData.mExpectedMergedOtherData.equals( + cb.getLp().getCaptivePortalData())); } private NetworkRequest.Builder newWifiRequestBuilder() { @@ -4912,51 +5163,50 @@ LocalStringNetworkSpecifier nsFoo = new LocalStringNetworkSpecifier("foo"); LocalStringNetworkSpecifier nsBar = new LocalStringNetworkSpecifier("bar"); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); - expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, null /* specifier */, + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); + expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiAgent, null /* specifier */, cEmpty1, cEmpty2, cEmpty3, cEmpty4); assertNoCallbacks(cFoo, cBar); - mWiFiNetworkAgent.disconnect(); - expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4); + mWiFiAgent.disconnect(); + expectOnLost(mWiFiAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.setNetworkSpecifier(nsFoo); - mWiFiNetworkAgent.connect(false); - expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, nsFoo, + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.setNetworkSpecifier(nsFoo); + mWiFiAgent.connect(false); + expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiAgent, nsFoo, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo); cBar.assertNoCallback(); assertEquals(nsFoo, - mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier()); + mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()).getNetworkSpecifier()); assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo); - mWiFiNetworkAgent.disconnect(); - expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo); + mWiFiAgent.disconnect(); + expectOnLost(mWiFiAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.setNetworkSpecifier(nsBar); - mWiFiNetworkAgent.connect(false); - expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, nsBar, + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.setNetworkSpecifier(nsBar); + mWiFiAgent.connect(false); + expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiAgent, nsBar, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cBar); cFoo.assertNoCallback(); assertEquals(nsBar, - mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier()); + mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()).getNetworkSpecifier()); - mWiFiNetworkAgent.disconnect(); - expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cBar); + mWiFiAgent.disconnect(); + expectOnLost(mWiFiAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cBar); cFoo.assertNoCallback(); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier()); - mWiFiNetworkAgent.connect(false); - expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, null /* specifier */, + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier()); + mWiFiAgent.connect(false); + expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiAgent, null /* specifier */, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar); - assertNull( - mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier()); + assertNull(mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()).getNetworkSpecifier()); - mWiFiNetworkAgent.disconnect(); - expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar); + mWiFiAgent.disconnect(); + expectOnLost(mWiFiAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar); } /** @@ -5035,8 +5285,8 @@ @Test public void testNetworkRequestUidSpoofSecurityException() throws Exception { - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); NetworkRequest networkRequest = newWifiRequestBuilder().build(); TestNetworkCallback networkCallback = new TestNetworkCallback(); doThrow(new SecurityException()).when(mAppOpsManager).checkPackage(anyInt(), anyString()); @@ -5091,35 +5341,35 @@ cellNetworkCallback.assertNoCallback(); // Bring up cell and expect CALLBACK_AVAILABLE. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - systemDefaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + systemDefaultCallback.expectAvailableThenValidatedCallbacks(mCellAgent); assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up wifi and expect CALLBACK_AVAILABLE. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); cellNetworkCallback.assertNoCallback(); - defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - systemDefaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + systemDefaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring down cell. Expect no default network callback, since it wasn't the default. - mCellNetworkAgent.disconnect(); - cellNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + cellNetworkCallback.expect(LOST, mCellAgent); defaultNetworkCallback.assertNoCallback(); systemDefaultCallback.assertNoCallback(); assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up cell. Expect no default network callback, since it won't be the default. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); defaultNetworkCallback.assertNoCallback(); systemDefaultCallback.assertNoCallback(); assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); @@ -5127,16 +5377,16 @@ // Bring down wifi. Expect the default network callback to notified of LOST wifi // followed by AVAILABLE cell. - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); cellNetworkCallback.assertNoCallback(); - defaultNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); - systemDefaultCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - systemDefaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); - mCellNetworkAgent.disconnect(); - cellNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); - defaultNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); - systemDefaultCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + defaultNetworkCallback.expect(LOST, mWiFiAgent); + defaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); + systemDefaultCallback.expect(LOST, mWiFiAgent); + systemDefaultCallback.expectAvailableCallbacksValidated(mCellAgent); + mCellAgent.disconnect(); + cellNetworkCallback.expect(LOST, mCellAgent); + defaultNetworkCallback.expect(LOST, mCellAgent); + systemDefaultCallback.expect(LOST, mCellAgent); waitForIdle(); assertEquals(null, mCm.getActiveNetwork()); @@ -5148,7 +5398,7 @@ assertEquals(null, systemDefaultCallback.getLastAvailableNetwork()); mMockVpn.disconnect(); - defaultNetworkCallback.expect(CallbackEntry.LOST, mMockVpn); + defaultNetworkCallback.expect(LOST, mMockVpn); systemDefaultCallback.assertNoCallback(); waitForIdle(); assertEquals(null, mCm.getActiveNetwork()); @@ -5163,29 +5413,28 @@ mCm.requestNetwork(cellRequest, cellNetworkCallback); // Bring up the mobile network. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); // We should get onAvailable(), onCapabilitiesChanged(), and // onLinkPropertiesChanged() in rapid succession. Additionally, we // should get onCapabilitiesChanged() when the mobile network validates. - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); cellNetworkCallback.assertNoCallback(); // Update LinkProperties. final LinkProperties lp = new LinkProperties(); lp.setInterfaceName("foonet_data0"); - mCellNetworkAgent.sendLinkProperties(lp); + mCellAgent.sendLinkProperties(lp); // We should get onLinkPropertiesChanged(). - cellNetworkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, - mCellNetworkAgent); + cellNetworkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); cellNetworkCallback.assertNoCallback(); // Suspend the network. - mCellNetworkAgent.suspend(); - cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED, - mCellNetworkAgent); - cellNetworkCallback.expect(CallbackEntry.SUSPENDED, mCellNetworkAgent); + mCellAgent.suspend(); + cellNetworkCallback.expectCaps(mCellAgent, + c -> !c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + cellNetworkCallback.expect(SUSPENDED, mCellAgent); cellNetworkCallback.assertNoCallback(); assertEquals(NetworkInfo.State.SUSPENDED, mCm.getActiveNetworkInfo().getState()); @@ -5194,21 +5443,21 @@ mCm.registerDefaultNetworkCallback(dfltNetworkCallback); // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(), // as well as onNetworkSuspended() in rapid succession. - dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent, true); + dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellAgent, true); dfltNetworkCallback.assertNoCallback(); mCm.unregisterNetworkCallback(dfltNetworkCallback); - mCellNetworkAgent.resume(); - cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED, - mCellNetworkAgent); - cellNetworkCallback.expect(CallbackEntry.RESUMED, mCellNetworkAgent); + mCellAgent.resume(); + cellNetworkCallback.expectCaps(mCellAgent, + c -> c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + cellNetworkCallback.expect(RESUMED, mCellAgent); cellNetworkCallback.assertNoCallback(); assertEquals(NetworkInfo.State.CONNECTED, mCm.getActiveNetworkInfo().getState()); dfltNetworkCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(dfltNetworkCallback); // This time onNetworkSuspended should not be called. - dfltNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + dfltNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); dfltNetworkCallback.assertNoCallback(); mCm.unregisterNetworkCallback(dfltNetworkCallback); @@ -5217,8 +5466,8 @@ @Test public void testRegisterPrivilegedDefaultCallbacksRequirePermissions() throws Exception { - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(false /* validated */); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(false /* validated */); mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_DENIED); final Handler handler = new Handler(ConnectivityThread.getInstanceLooper()); @@ -5233,16 +5482,23 @@ mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_GRANTED); mCm.registerSystemDefaultNetworkCallback(callback, handler); mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_DENIED); - callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mCellAgent); mCm.unregisterNetworkCallback(callback); mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED); mCm.registerSystemDefaultNetworkCallback(callback, handler); - callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mCellAgent); mCm.unregisterNetworkCallback(callback); + mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED); + mServiceContext.setPermission(NETWORK_SETUP_WIZARD, PERMISSION_GRANTED); + mCm.registerSystemDefaultNetworkCallback(callback, handler); + callback.expectAvailableCallbacksUnvalidated(mCellAgent); + mCm.unregisterNetworkCallback(callback); + + mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED); mCm.registerDefaultNetworkCallbackForUid(APP1_UID, callback, handler); - callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mCellAgent); mCm.unregisterNetworkCallback(callback); } @@ -5273,15 +5529,15 @@ mCm.registerNetworkCallback(includeOtherUidsRequest, includeOtherUidsCallback); // Both callbacks see a network with no specifier that applies to their UID. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false /* validated */); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - otherUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - includeOtherUidsCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - otherUidCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - includeOtherUidsCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false /* validated */); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + otherUidCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + includeOtherUidsCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); + otherUidCallback.expect(LOST, mWiFiAgent); + includeOtherUidsCallback.expect(LOST, mWiFiAgent); // Only the includeOtherUidsCallback sees a VPN that does not apply to its UID. final UidRange range = UidRange.createForUser(UserHandle.of(RESTRICTED_USER)); @@ -5292,7 +5548,7 @@ otherUidCallback.assertNoCallback(); mMockVpn.disconnect(); - includeOtherUidsCallback.expect(CallbackEntry.LOST, mMockVpn); + includeOtherUidsCallback.expect(LOST, mMockVpn); callback.assertNoCallback(); otherUidCallback.assertNoCallback(); } @@ -5357,10 +5613,10 @@ final NetworkCapabilities ncTemplate = new NetworkCapabilities() .addTransportType(TRANSPORT_WIFI) .setNetworkSpecifier(specifier); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, emptyLp, ncTemplate); - mWiFiNetworkAgent.connect(false /* validated */); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - otherUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, emptyLp, ncTemplate); + mWiFiAgent.connect(false /* validated */); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + otherUidCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); includeOtherUidsCallback.assertNoCallback(); } @@ -5415,63 +5671,63 @@ mCm.registerNetworkCallback(request, callback); mCm.registerNetworkCallback(fgRequest, fgCallback); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - assertTrue(isForegroundNetwork(mCellNetworkAgent)); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellAgent); + fgCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + assertTrue(isForegroundNetwork(mCellAgent)); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); // When wifi connects, cell lingers. - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - callback.expectLosing(mCellNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - fgCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - fgCallback.expectLosing(mCellNetworkAgent); - fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - assertTrue(isForegroundNetwork(mCellNetworkAgent)); - assertTrue(isForegroundNetwork(mWiFiNetworkAgent)); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + callback.expectLosing(mCellAgent); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + fgCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + fgCallback.expectLosing(mCellAgent); + fgCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + assertTrue(isForegroundNetwork(mCellAgent)); + assertTrue(isForegroundNetwork(mWiFiAgent)); // When lingering is complete, cell is still there but is now in the background. waitForIdle(); int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4; - fgCallback.expect(CallbackEntry.LOST, mCellNetworkAgent, timeoutMs); + fgCallback.expect(LOST, mCellAgent, timeoutMs); // Expect a network capabilities update sans FOREGROUND. - callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent); - assertFalse(isForegroundNetwork(mCellNetworkAgent)); - assertTrue(isForegroundNetwork(mWiFiNetworkAgent)); + callback.expectCaps(mCellAgent, c -> !c.hasCapability(NET_CAPABILITY_FOREGROUND)); + assertFalse(isForegroundNetwork(mCellAgent)); + assertTrue(isForegroundNetwork(mWiFiAgent)); // File a cell request and check that cell comes into the foreground. final NetworkRequest cellRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_CELLULAR).build(); final TestNetworkCallback cellCallback = new TestNetworkCallback(); mCm.requestNetwork(cellRequest, cellCallback); - cellCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); - fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + cellCallback.expectAvailableCallbacksValidated(mCellAgent); + fgCallback.expectAvailableCallbacksValidated(mCellAgent); // Expect a network capabilities update with FOREGROUND, because the most recent // request causes its state to change. - cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent); - assertTrue(isForegroundNetwork(mCellNetworkAgent)); - assertTrue(isForegroundNetwork(mWiFiNetworkAgent)); + cellCallback.expectCaps(mCellAgent, c -> c.hasCapability(NET_CAPABILITY_FOREGROUND)); + callback.expectCaps(mCellAgent, c -> c.hasCapability(NET_CAPABILITY_FOREGROUND)); + assertTrue(isForegroundNetwork(mCellAgent)); + assertTrue(isForegroundNetwork(mWiFiAgent)); // Release the request. The network immediately goes into the background, since it was not // lingering. mCm.unregisterNetworkCallback(cellCallback); - fgCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + fgCallback.expect(LOST, mCellAgent); // Expect a network capabilities update sans FOREGROUND. - callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent); - assertFalse(isForegroundNetwork(mCellNetworkAgent)); - assertTrue(isForegroundNetwork(mWiFiNetworkAgent)); + callback.expectCaps(mCellAgent, c -> !c.hasCapability(NET_CAPABILITY_FOREGROUND)); + assertFalse(isForegroundNetwork(mCellAgent)); + assertTrue(isForegroundNetwork(mWiFiAgent)); // Disconnect wifi and check that cell is foreground again. - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - fgCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); - assertTrue(isForegroundNetwork(mCellNetworkAgent)); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); + fgCallback.expect(LOST, mWiFiAgent); + fgCallback.expectAvailableCallbacksValidated(mCellAgent); + assertTrue(isForegroundNetwork(mCellAgent)); mCm.unregisterNetworkCallback(callback); mCm.unregisterNetworkCallback(fgCallback); @@ -5512,11 +5768,11 @@ } }); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); // Don't request that the network validate, because otherwise connect() will block until // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired, // and we won't actually measure anything. - mCellNetworkAgent.connect(false); + mCellAgent.connect(false); long onAvailableDispatchingDuration = durationOf(() -> { await(availableLatch, 10 * CONNECT_TIME_LIMIT_MS); @@ -5529,9 +5785,9 @@ onAvailableDispatchingDuration <= CONNECT_TIME_LIMIT_MS); // Give wifi a high enough score that we'll linger cell when wifi comes up. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.adjustScore(40); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.adjustScore(40); + mWiFiAgent.connect(false); long onLostDispatchingDuration = durationOf(() -> { await(losingLatch, 10 * SWITCH_TIME_LIMIT_MS); @@ -5577,9 +5833,9 @@ assertTrue(testFactory.getMyStartRequested()); // Bring up wifi. The factory stops looking for a network. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); // Score 60 - 40 penalty for not validated yet, then 60 when it validates - mWiFiNetworkAgent.connect(true); + mWiFiAgent.connect(true); // The network connects with a low score, so the offer can still beat it and // nothing happens. Then the network validates, and the offer with its filter score // of 40 can no longer beat it and the request is removed. @@ -5598,9 +5854,9 @@ // Bring up cell data and check that the factory stops looking. assertLength(1, mCm.getAllNetworks()); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(false); - cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent, false, false, false, + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(false); + cellNetworkCallback.expectAvailableCallbacks(mCellAgent, false, false, false, TEST_CALLBACK_TIMEOUT_MS); // When cell connects, it will satisfy the "mobile always on request" right away // by virtue of being the only network that can satisfy the request. However, its @@ -5610,11 +5866,12 @@ // Next, cell validates. This gives it a score of 50 and the test factory can't // hope to beat that according to its filters. It will see the message that its // offer is now unnecessary. - mCellNetworkAgent.setNetworkValid(true); + mCellAgent.setNetworkValid(true); // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is // validated – see testPartialConnectivity. - mCm.reportNetworkConnectivity(mCellNetworkAgent.getNetwork(), true); - cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent); + mCm.reportNetworkConnectivity(mCellAgent.getNetwork(), true); + cellNetworkCallback.expectCaps(mCellAgent, + c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); testFactory.expectRequestRemove(); testFactory.assertRequestCountEquals(0); // Accordingly, the factory shouldn't be started. @@ -5627,8 +5884,8 @@ // Cell disconnects. There is still the "mobile data always on" request outstanding, // and the test factory should see it now that it isn't hopelessly outscored. - mCellNetworkAgent.disconnect(); - cellNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + cellNetworkCallback.expect(LOST, mCellAgent); // Wait for the network to be removed from internal structures before // calling synchronous getter waitForIdle(); @@ -5639,9 +5896,9 @@ // Reconnect cell validated, see the request disappear again. Then withdraw the // mobile always on request. This will tear down cell, and there shouldn't be a // blip where the test factory briefly sees the request or anything. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); waitForIdle(); assertLength(2, mCm.getAllNetworks()); testFactory.expectRequestRemove(); @@ -5651,7 +5908,7 @@ testFactory.assertRequestCountEquals(0); assertFalse(testFactory.getMyStartRequested()); // ... and cell data to be torn down immediately since it is no longer nascent. - cellNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + cellNetworkCallback.expect(LOST, mCellAgent); waitForIdle(); assertLength(1, mCm.getAllNetworks()); testFactory.terminate(); @@ -5732,7 +5989,7 @@ doReturn(0).when(mResources).getInteger(R.integer.config_activelyPreferBadWifi); mPolicyTracker.reevaluate(); waitForIdle(); - if (SdkLevel.isAtLeastU()) { + if (mDeps.isAtLeastU()) { // U+ ignore the setting and always actively prefers bad wifi assertTrue(mService.mNetworkRanker.getConfiguration().activelyPreferBadWifi()); } else { @@ -5796,39 +6053,40 @@ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback); // Cell connects and validates. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), null /* ncTemplate */, cellProvider); - mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent.connect(true); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); cellCallback.assertNoCallback(); wifiCallback.assertNoCallback(); // Bring up wifi. At first it's invalidated, so cell is still needed. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), null /* ncTemplate */, wifiProvider); - mWiFiNetworkAgent.connect(false); - wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent.connect(false); + wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); cellCallback.assertNoCallback(); wifiCallback.assertNoCallback(); // Wifi validates. Cell is no longer needed, because it's outscored. - mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */); + mWiFiAgent.setNetworkValid(true /* privateDnsProbeSent */); // Have CS reconsider the network (see testPartialConnectivity) - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); - wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true); + wifiNetworkCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); cellCallback.expectOnNetworkUnneeded(defaultCaps); wifiCallback.assertNoCallback(); // Wifi is no longer validated. Cell is needed again. - mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false); - wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + mWiFiAgent.setNetworkInvalid(true /* invalidBecauseOfPrivateDns */); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), false); + wifiNetworkCallback.expectCaps(mWiFiAgent, + c -> !c.hasCapability(NET_CAPABILITY_VALIDATED)); cellCallback.expectOnNetworkNeeded(defaultCaps); wifiCallback.assertNoCallback(); // Disconnect wifi and pretend the carrier restricts moving away from bad wifi. - mWiFiNetworkAgent.disconnect(); - wifiNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.disconnect(); + wifiNetworkCallback.expect(LOST, mWiFiAgent); // This has getAvoidBadWifi return false. This test doesn't change the value of the // associated setting. doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi); @@ -5836,31 +6094,36 @@ waitForIdle(); // Connect wifi again, cell is needed until wifi validates. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), null /* ncTemplate */, wifiProvider); - mWiFiNetworkAgent.connect(false); - wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent.connect(false); + wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); cellCallback.assertNoCallback(); wifiCallback.assertNoCallback(); - mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); - wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + mWiFiAgent.setNetworkValid(true /* privateDnsProbeSent */); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true); + wifiNetworkCallback.expectCaps(mWiFiAgent, + c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); cellCallback.expectOnNetworkUnneeded(defaultCaps); wifiCallback.assertNoCallback(); // Wifi loses validation. Because the device doesn't avoid bad wifis, cell is // not needed. - mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false); - wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + mWiFiAgent.setNetworkInvalid(true /* invalidBecauseOfPrivateDns */); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), false); + wifiNetworkCallback.expectCaps(mWiFiAgent, + c -> !c.hasCapability(NET_CAPABILITY_VALIDATED)); cellCallback.assertNoCallback(); wifiCallback.assertNoCallback(); } - public void doTestPreferBadWifi(final boolean preferBadWifi) throws Exception { + public void doTestPreferBadWifi(final boolean avoidBadWifi, + final boolean preferBadWifi, + @NonNull Predicate<Long> checkUnvalidationTimeout) throws Exception { // Pretend we're on a carrier that restricts switching away from bad wifi, and // depending on the parameter one that may indeed prefer bad wifi. - doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi); + doReturn(avoidBadWifi ? 1 : 0).when(mResources) + .getInteger(R.integer.config_networkAvoidBadWifi); doReturn(preferBadWifi ? 1 : 0).when(mResources) .getInteger(R.integer.config_activelyPreferBadWifi); mPolicyTracker.reevaluate(); @@ -5870,37 +6133,55 @@ .clearCapabilities() .addTransportType(TRANSPORT_WIFI) .build(); - final TestableNetworkCallback wifiCallback = new TestableNetworkCallback(); + final TestNetworkCallback wifiCallback = new TestNetworkCallback(); mCm.registerNetworkCallback(wifiRequest, wifiCallback); // Bring up validated cell and unvalidated wifi. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); - wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); + wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); - if (preferBadWifi) { - expectUnvalidationCheckWillNotify(mWiFiNetworkAgent, NotificationType.LOST_INTERNET); - mDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mDeps.mScheduledEvaluationTimeouts.poll(TIMEOUT_MS, t -> checkUnvalidationTimeout.test(t)); + + if (!avoidBadWifi && preferBadWifi) { + expectUnvalidationCheckWillNotify(mWiFiAgent, NotificationType.LOST_INTERNET); + mDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); } else { - expectUnvalidationCheckWillNotNotify(mWiFiNetworkAgent); + expectUnvalidationCheckWillNotNotify(mWiFiAgent); mDefaultNetworkCallback.assertNoCallback(); } } @Test - public void testPreferBadWifi_doNotPrefer() throws Exception { + public void testPreferBadWifi_doNotAvoid_doNotPrefer() throws Exception { // Starting with U this mode is no longer supported and can't actually be tested - assumeFalse(SdkLevel.isAtLeastU()); - doTestPreferBadWifi(false /* preferBadWifi */); + assumeFalse(mDeps.isAtLeastU()); + doTestPreferBadWifi(false /* avoidBadWifi */, false /* preferBadWifi */, + timeout -> timeout < 14_000); } @Test - public void testPreferBadWifi_doPrefer() throws Exception { - doTestPreferBadWifi(true /* preferBadWifi */); + public void testPreferBadWifi_doNotAvoid_doPrefer() throws Exception { + doTestPreferBadWifi(false /* avoidBadWifi */, true /* preferBadWifi */, + timeout -> timeout > 14_000); + } + + @Test + public void testPreferBadWifi_doAvoid_doNotPrefer() throws Exception { + // If avoidBadWifi=true, then preferBadWifi should be irrelevant. Test anyway. + doTestPreferBadWifi(true /* avoidBadWifi */, false /* preferBadWifi */, + timeout -> timeout < 14_000); + } + + @Test + public void testPreferBadWifi_doAvoid_doPrefer() throws Exception { + // If avoidBadWifi=true, then preferBadWifi should be irrelevant. Test anyway. + doTestPreferBadWifi(true /* avoidBadWifi */, true /* preferBadWifi */, + timeout -> timeout < 14_000); } @Test @@ -5931,25 +6212,25 @@ mPolicyTracker.reevaluate(); // Bring up validated cell. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - Network cellNetwork = mCellNetworkAgent.getNetwork(); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + Network cellNetwork = mCellAgent.getNetwork(); // Bring up validated wifi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - Network wifiNetwork = mWiFiNetworkAgent.getNetwork(); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + Network wifiNetwork = mWiFiAgent.getNetwork(); // Fail validation on wifi. - mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */); + mWiFiAgent.setNetworkInvalid(false /* invalidBecauseOfPrivateDns */); mCm.reportNetworkConnectivity(wifiNetwork, false); - defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - validatedWifiCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - expectNotification(mWiFiNetworkAgent, NotificationType.LOST_INTERNET); + defaultCallback.expectCaps(mWiFiAgent, c -> !c.hasCapability(NET_CAPABILITY_VALIDATED)); + validatedWifiCallback.expect(LOST, mWiFiAgent); + expectNotification(mWiFiAgent, NotificationType.LOST_INTERNET); // Because avoid bad wifi is off, we don't switch to cellular. defaultCallback.assertNoCallback(); @@ -5963,24 +6244,24 @@ // that we switch back to cell. doReturn(1).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi); mPolicyTracker.reevaluate(); - defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellAgent); assertEquals(mCm.getActiveNetwork(), cellNetwork); - expectClearNotification(mWiFiNetworkAgent, NotificationType.LOST_INTERNET); + expectClearNotification(mWiFiAgent, NotificationType.LOST_INTERNET); // Switch back to a restrictive carrier. doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi); mPolicyTracker.reevaluate(); - defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); assertEquals(mCm.getActiveNetwork(), wifiNetwork); // A notification was already shown for this very network. - expectNoNotification(mWiFiNetworkAgent); + expectNoNotification(mWiFiAgent); // Simulate the user selecting "switch" on the dialog, and check that we switch to cell. // In principle this is a little bit unrealistic because the switch to a less restrictive // carrier above should have remove the notification but this doesn't matter for the // purposes of this test. mCm.setAvoidUnvalidated(wifiNetwork); - defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellAgent); assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability( NET_CAPABILITY_VALIDATED)); assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability( @@ -5988,54 +6269,54 @@ assertEquals(mCm.getActiveNetwork(), cellNetwork); // Disconnect and reconnect wifi to clear the one-time switch above. - mWiFiNetworkAgent.disconnect(); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - wifiNetwork = mWiFiNetworkAgent.getNetwork(); + mWiFiAgent.disconnect(); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + wifiNetwork = mWiFiAgent.getNetwork(); // Fail validation on wifi and expect the dialog to appear. - mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */); + mWiFiAgent.setNetworkInvalid(false /* invalidBecauseOfPrivateDns */); mCm.reportNetworkConnectivity(wifiNetwork, false); - defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - validatedWifiCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - expectNotification(mWiFiNetworkAgent, NotificationType.LOST_INTERNET); + defaultCallback.expectCaps(mWiFiAgent, c -> !c.hasCapability(NET_CAPABILITY_VALIDATED)); + validatedWifiCallback.expect(LOST, mWiFiAgent); + expectNotification(mWiFiAgent, NotificationType.LOST_INTERNET); // Simulate the user selecting "switch" and checking the don't ask again checkbox. Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1); mPolicyTracker.reevaluate(); // We now switch to cell. - defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellAgent); assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability( NET_CAPABILITY_VALIDATED)); assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability( NET_CAPABILITY_VALIDATED)); assertEquals(mCm.getActiveNetwork(), cellNetwork); - expectClearNotification(mWiFiNetworkAgent, NotificationType.LOST_INTERNET); + expectClearNotification(mWiFiAgent, NotificationType.LOST_INTERNET); // Simulate the user turning the cellular fallback setting off and then on. // We switch to wifi and then to cell. Settings.Global.putString(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, null); mPolicyTracker.reevaluate(); - defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); assertEquals(mCm.getActiveNetwork(), wifiNetwork); // Notification is cleared again because CS doesn't particularly remember that it has // cleared it before, and if it hasn't cleared it before then it should do so now. - expectClearNotification(mWiFiNetworkAgent, NotificationType.LOST_INTERNET); + expectClearNotification(mWiFiAgent, NotificationType.LOST_INTERNET); Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1); mPolicyTracker.reevaluate(); - defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellAgent); assertEquals(mCm.getActiveNetwork(), cellNetwork); // If cell goes down, we switch to wifi. - mCellNetworkAgent.disconnect(); - defaultCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); - defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mCellAgent.disconnect(); + defaultCallback.expect(LOST, mCellAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); validatedWifiCallback.assertNoCallback(); // Notification is cleared yet again because the device switched to wifi. - expectClearNotification(mWiFiNetworkAgent, NotificationType.LOST_INTERNET); + expectClearNotification(mWiFiAgent, NotificationType.LOST_INTERNET); mCm.unregisterNetworkCallback(cellNetworkCallback); mCm.unregisterNetworkCallback(validatedWifiCallback); @@ -6072,9 +6353,9 @@ final TestNetworkCallback networkCallback = new TestNetworkCallback(); mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); - networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false, + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); + networkCallback.expectAvailableCallbacks(mWiFiAgent, false, false, false, TEST_CALLBACK_TIMEOUT_MS); // pass timeout and validate that UNAVAILABLE is not called @@ -6092,12 +6373,12 @@ final TestNetworkCallback networkCallback = new TestNetworkCallback(); mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); - networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false, + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); + networkCallback.expectAvailableCallbacks(mWiFiAgent, false, false, false, TEST_CALLBACK_TIMEOUT_MS); - mWiFiNetworkAgent.disconnect(); - networkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.disconnect(); + networkCallback.expect(LOST, mWiFiAgent); // Validate that UNAVAILABLE is not called networkCallback.assertNoCallback(); @@ -6117,11 +6398,11 @@ mCm.requestNetwork(nr, networkCallback, timeoutMs); // pass timeout and validate that UNAVAILABLE is called - networkCallback.expect(CallbackEntry.UNAVAILABLE); + networkCallback.expect(UNAVAILABLE); // create a network satisfying request - validate that request not triggered - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); networkCallback.assertNoCallback(); } @@ -6143,8 +6424,8 @@ networkCallback.assertNoCallback(); // create a network satisfying request - validate that request not triggered - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); networkCallback.assertNoCallback(); } @@ -6201,7 +6482,7 @@ // onUnavailable! testFactory.triggerUnfulfillable(newRequest); - networkCallback.expect(CallbackEntry.UNAVAILABLE); + networkCallback.expect(UNAVAILABLE); // Declaring a request unfulfillable releases it automatically. testFactory.expectRequestRemove(); @@ -6219,6 +6500,142 @@ } } + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @DisableCompatChanges(ConnectivityCompatChanges.ENABLE_SELF_CERTIFIED_CAPABILITIES_DECLARATION) + public void testSelfCertifiedCapabilitiesDisabled() + throws Exception { + mDeps.enableCompatChangeCheck(); + final NetworkRequest networkRequest = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + .build(); + final TestNetworkCallback cb = new TestNetworkCallback(); + mCm.requestNetwork(networkRequest, cb); + mCm.unregisterNetworkCallback(cb); + } + + /** Set the networkSliceResourceId to 0 will result in NameNotFoundException be thrown. */ + private void setupMockForNetworkCapabilitiesResources(int networkSliceResourceId) + throws PackageManager.NameNotFoundException { + if (networkSliceResourceId == 0) { + doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getProperty( + ConstantsShim.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES, + mContext.getPackageName()); + } else { + final PackageManager.Property property = new PackageManager.Property( + ConstantsShim.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES, + networkSliceResourceId, + true /* isResource */, + mContext.getPackageName(), + "dummyClass" + ); + doReturn(property).when(mPackageManager).getProperty( + ConstantsShim.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES, + mContext.getPackageName()); + doReturn(mContext.getResources()).when(mPackageManager).getResourcesForApplication( + mContext.getPackageName()); + } + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @EnableCompatChanges(ConnectivityCompatChanges.ENABLE_SELF_CERTIFIED_CAPABILITIES_DECLARATION) + public void requestNetwork_withoutPrioritizeBandwidthDeclaration_shouldThrowException() + throws Exception { + mDeps.enableCompatChangeCheck(); + setupMockForNetworkCapabilitiesResources( + com.android.frameworks.tests.net.R.xml.self_certified_capabilities_latency); + final NetworkRequest networkRequest = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + .build(); + final TestNetworkCallback cb = new TestNetworkCallback(); + final Exception e = assertThrows(SecurityException.class, + () -> mCm.requestNetwork(networkRequest, cb)); + assertThat(e.getMessage(), + containsString(ApplicationSelfCertifiedNetworkCapabilities.PRIORITIZE_BANDWIDTH)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @EnableCompatChanges(ConnectivityCompatChanges.ENABLE_SELF_CERTIFIED_CAPABILITIES_DECLARATION) + public void requestNetwork_withoutPrioritizeLatencyDeclaration_shouldThrowException() + throws Exception { + mDeps.enableCompatChangeCheck(); + setupMockForNetworkCapabilitiesResources( + com.android.frameworks.tests.net.R.xml.self_certified_capabilities_bandwidth); + final NetworkRequest networkRequest = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) + .build(); + final TestNetworkCallback cb = new TestNetworkCallback(); + final Exception e = assertThrows(SecurityException.class, + () -> mCm.requestNetwork(networkRequest, cb)); + assertThat(e.getMessage(), + containsString(ApplicationSelfCertifiedNetworkCapabilities.PRIORITIZE_LATENCY)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @EnableCompatChanges(ConnectivityCompatChanges.ENABLE_SELF_CERTIFIED_CAPABILITIES_DECLARATION) + public void requestNetwork_withoutNetworkSliceProperty_shouldThrowException() throws Exception { + mDeps.enableCompatChangeCheck(); + setupMockForNetworkCapabilitiesResources(0 /* networkSliceResourceId */); + final NetworkRequest networkRequest = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + .build(); + final TestNetworkCallback cb = new TestNetworkCallback(); + final Exception e = assertThrows(SecurityException.class, + () -> mCm.requestNetwork(networkRequest, cb)); + assertThat(e.getMessage(), + containsString(ConstantsShim.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES)); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @EnableCompatChanges(ConnectivityCompatChanges.ENABLE_SELF_CERTIFIED_CAPABILITIES_DECLARATION) + public void requestNetwork_withNetworkSliceDeclaration_shouldSucceed() throws Exception { + mDeps.enableCompatChangeCheck(); + setupMockForNetworkCapabilitiesResources( + com.android.frameworks.tests.net.R.xml.self_certified_capabilities_both); + + final NetworkRequest networkRequest = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + .build(); + final TestNetworkCallback cb = new TestNetworkCallback(); + mCm.requestNetwork(networkRequest, cb); + mCm.unregisterNetworkCallback(cb); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @EnableCompatChanges(ConnectivityCompatChanges.ENABLE_SELF_CERTIFIED_CAPABILITIES_DECLARATION) + public void requestNetwork_withNetworkSliceDeclaration_shouldUseCache() throws Exception { + mDeps.enableCompatChangeCheck(); + setupMockForNetworkCapabilitiesResources( + com.android.frameworks.tests.net.R.xml.self_certified_capabilities_both); + + final NetworkRequest networkRequest = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) + .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + .build(); + final TestNetworkCallback cb = new TestNetworkCallback(); + mCm.requestNetwork(networkRequest, cb); + mCm.unregisterNetworkCallback(cb); + + // Second call should use caches + mCm.requestNetwork(networkRequest, cb); + mCm.unregisterNetworkCallback(cb); + + // PackageManager's API only called once because the second call is using cache. + verify(mPackageManager, times(1)).getProperty( + ConstantsShim.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES, + mContext.getPackageName()); + verify(mPackageManager, times(1)).getResourcesForApplication( + mContext.getPackageName()); + } + /** * Validate the service throws if request with CBS but without carrier privilege. */ @@ -6382,18 +6799,18 @@ private Network connectKeepaliveNetwork(LinkProperties lp) throws Exception { // Ensure the network is disconnected before anything else occurs - if (mWiFiNetworkAgent != null) { - assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork())); + if (mWiFiAgent != null) { + assertNull(mCm.getNetworkCapabilities(mWiFiAgent.getNetwork())); } - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED); - mWiFiNetworkAgent.connect(true); + mWiFiAgent.connect(true); b.expectBroadcast(); verifyActiveNetwork(TRANSPORT_WIFI); - mWiFiNetworkAgent.sendLinkProperties(lp); + mWiFiAgent.sendLinkProperties(lp); waitForIdle(); - return mWiFiNetworkAgent.getNetwork(); + return mWiFiAgent.getNetwork(); } @Test @@ -6450,10 +6867,10 @@ callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED); // Check that a started keepalive can be stopped. - mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS); + mWiFiAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS); ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectStarted(); - mWiFiNetworkAgent.setStopKeepaliveEvent(PacketKeepalive.SUCCESS); + mWiFiAgent.setStopKeepaliveEvent(PacketKeepalive.SUCCESS); ka.stop(); callback.expectStopped(); @@ -6463,15 +6880,15 @@ callback.expectStarted(); bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25)); bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25)); - mWiFiNetworkAgent.sendLinkProperties(bogusLp); + mWiFiAgent.sendLinkProperties(bogusLp); callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS); - mWiFiNetworkAgent.sendLinkProperties(lp); + mWiFiAgent.sendLinkProperties(lp); // Check that a started keepalive is stopped correctly when the network disconnects. ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectStarted(); - mWiFiNetworkAgent.disconnect(); - mWiFiNetworkAgent.expectDisconnected(); + mWiFiAgent.disconnect(); + mWiFiAgent.expectDisconnected(); callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK); // ... and that stopping it after that has no adverse effects. @@ -6482,15 +6899,15 @@ // Reconnect. myNet = connectKeepaliveNetwork(lp); - mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS); + mWiFiAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS); // Check that keepalive slots start from 1 and increment. The first one gets slot 1. - mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); + mWiFiAgent.setExpectedKeepaliveSlot(1); ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectStarted(); // The second one gets slot 2. - mWiFiNetworkAgent.setExpectedKeepaliveSlot(2); + mWiFiAgent.setExpectedKeepaliveSlot(2); TestKeepaliveCallback callback2 = new TestKeepaliveCallback(); PacketKeepalive ka2 = mCm.startNattKeepalive( myNet, validKaInterval, callback2, myIPv4, 6789, dstIPv4); @@ -6500,7 +6917,7 @@ ka.stop(); callback.expectStopped(); - mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); + mWiFiAgent.setExpectedKeepaliveSlot(1); TestKeepaliveCallback callback3 = new TestKeepaliveCallback(); PacketKeepalive ka3 = mCm.startNattKeepalive( myNet, validKaInterval, callback3, myIPv4, 9876, dstIPv4); @@ -6602,12 +7019,12 @@ } // Check that a started keepalive can be stopped. - mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); + mWiFiAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); try (SocketKeepalive ka = mCm.createSocketKeepalive( myNet, testSocket, myIPv4, dstIPv4, executor, callback)) { ka.start(validKaInterval); callback.expectStarted(); - mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS); + mWiFiAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS); ka.stop(); callback.expectStopped(); @@ -6636,9 +7053,9 @@ callback.expectStarted(); bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25)); bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25)); - mWiFiNetworkAgent.sendLinkProperties(bogusLp); + mWiFiAgent.sendLinkProperties(bogusLp); callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS); - mWiFiNetworkAgent.sendLinkProperties(lp); + mWiFiAgent.sendLinkProperties(lp); } // Check that a started keepalive is stopped correctly when the network disconnects. @@ -6646,21 +7063,20 @@ myNet, testSocket, myIPv4, dstIPv4, executor, callback)) { ka.start(validKaInterval); callback.expectStarted(); - mWiFiNetworkAgent.disconnect(); - mWiFiNetworkAgent.expectDisconnected(); + mWiFiAgent.disconnect(); + mWiFiAgent.expectDisconnected(); callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK); // ... and that stopping it after that has no adverse effects. waitForIdle(); - final Network myNetAlias = myNet; - assertNull(mCm.getNetworkCapabilities(myNetAlias)); + assertNull(mCm.getNetworkCapabilities(myNet)); ka.stop(); callback.assertNoCallback(); } // Reconnect. myNet = connectKeepaliveNetwork(lp); - mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); + mWiFiAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); // Check that a stop followed by network disconnects does not result in crash. try (SocketKeepalive ka = mCm.createSocketKeepalive( @@ -6669,7 +7085,7 @@ callback.expectStarted(); // Delay the response of keepalive events in networkAgent long enough to make sure // the follow-up network disconnection will be processed first. - mWiFiNetworkAgent.setKeepaliveResponseDelay(3 * TIMEOUT_MS); + mWiFiAgent.setKeepaliveResponseDelay(3 * TIMEOUT_MS); ka.stop(); // Call stop() twice shouldn't result in crash, b/182586681. ka.stop(); @@ -6679,8 +7095,8 @@ waitForIdleSerialExecutor(executor, TIMEOUT_MS); waitForIdle(); - mWiFiNetworkAgent.disconnect(); - mWiFiNetworkAgent.expectDisconnected(); + mWiFiAgent.disconnect(); + mWiFiAgent.expectDisconnected(); callback.expectStopped(); callback.assertNoCallback(); } @@ -6688,20 +7104,18 @@ // Reconnect. waitForIdle(); myNet = connectKeepaliveNetwork(lp); - mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); + mWiFiAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); // Check that keepalive slots start from 1 and increment. The first one gets slot 1. - mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); - int srcPort2 = 0; + mWiFiAgent.setExpectedKeepaliveSlot(1); try (SocketKeepalive ka = mCm.createSocketKeepalive( myNet, testSocket, myIPv4, dstIPv4, executor, callback)) { ka.start(validKaInterval); callback.expectStarted(); // The second one gets slot 2. - mWiFiNetworkAgent.setExpectedKeepaliveSlot(2); + mWiFiAgent.setExpectedKeepaliveSlot(2); final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket(); - srcPort2 = testSocket2.getPort(); TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback(executor); try (SocketKeepalive ka2 = mCm.createSocketKeepalive( myNet, testSocket2, myIPv4, dstIPv4, executor, callback2)) { @@ -6724,9 +7138,9 @@ // assertFalse(isUdpPortInUse(srcPort)); // assertFalse(isUdpPortInUse(srcPort2)); - mWiFiNetworkAgent.disconnect(); - mWiFiNetworkAgent.expectDisconnected(); - mWiFiNetworkAgent = null; + mWiFiAgent.disconnect(); + mWiFiAgent.expectDisconnected(); + mWiFiAgent = null; } @Test @@ -6800,9 +7214,9 @@ testSocketV4.close(); testSocketV6.close(); - mWiFiNetworkAgent.disconnect(); - mWiFiNetworkAgent.expectDisconnected(); - mWiFiNetworkAgent = null; + mWiFiAgent.disconnect(); + mWiFiAgent.expectDisconnected(); + mWiFiAgent = null; } private void doTestNattSocketKeepalivesFdWithExecutor(Executor executor) throws Exception { @@ -6817,8 +7231,8 @@ lp.addLinkAddress(new LinkAddress(myIPv4, 25)); lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254"))); Network myNet = connectKeepaliveNetwork(lp); - mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); - mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS); + mWiFiAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); + mWiFiAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS); TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor); @@ -6853,9 +7267,9 @@ // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7. // assertFalse(isUdpPortInUse(srcPort)); - mWiFiNetworkAgent.disconnect(); - mWiFiNetworkAgent.expectDisconnected(); - mWiFiNetworkAgent = null; + mWiFiAgent.disconnect(); + mWiFiAgent.expectDisconnected(); + mWiFiAgent = null; } private static boolean isUdpPortInUse(int port) { @@ -6893,18 +7307,18 @@ } private void assertPinnedToWifiWithCellDefault() { - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess()); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getBoundNetworkForProcess()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); } private void assertPinnedToWifiWithWifiDefault() { - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess()); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getBoundNetworkForProcess()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); } private void assertNotPinnedToWifi() { assertNull(mCm.getBoundNetworkForProcess()); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); } @Test @@ -6917,23 +7331,23 @@ TestNetworkPinner.pin(mServiceContext, wifiRequest); assertNull(mCm.getBoundNetworkForProcess()); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); // When wi-fi connects, expect to be pinned. assertTrue(TestNetworkPinner.awaitPin(100)); assertPinnedToWifiWithCellDefault(); // Disconnect and expect the pin to drop. - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); assertTrue(TestNetworkPinner.awaitUnpin(100)); assertNotPinnedToWifi(); // Reconnecting does not cause the pin to come back. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); assertFalse(TestNetworkPinner.awaitPin(100)); assertNotPinnedToWifi(); @@ -6947,22 +7361,22 @@ assertNotPinnedToWifi(); // Disconnect cell and wifi. - ExpectedBroadcast b = registerConnectivityBroadcast(3); // cell down, wifi up, wifi down. - mCellNetworkAgent.disconnect(); - mWiFiNetworkAgent.disconnect(); + ExpectedBroadcast b = expectConnectivityAction(3); // cell down, wifi up, wifi down. + mCellAgent.disconnect(); + mWiFiAgent.disconnect(); b.expectBroadcast(); // Pinning takes effect even if the pinned network is the default when the pin is set... TestNetworkPinner.pin(mServiceContext, wifiRequest); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); assertTrue(TestNetworkPinner.awaitPin(100)); assertPinnedToWifiWithWifiDefault(); // ... and is maintained even when that network is no longer the default. - b = registerConnectivityBroadcast(1); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mCellNetworkAgent.connect(true); + b = expectConnectivityAction(1); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mCellAgent.connect(true); b.expectBroadcast(); assertPinnedToWifiWithCellDefault(); } @@ -7137,7 +7551,7 @@ @Test public void testNetworkInfoOfTypeNone() throws Exception { - ExpectedBroadcast b = registerConnectivityBroadcast(1); + ExpectedBroadcast b = expectConnectivityAction(1); verifyNoNetwork(); TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE); @@ -7155,7 +7569,7 @@ mCm.registerNetworkCallback(request, callback); // Bring up wifi aware network. - wifiAware.connect(false, false, false /* isStrictMode */); + wifiAware.connect(false, false, false /* privateDnsProbeSent */); callback.expectAvailableCallbacksUnvalidated(wifiAware); assertNull(mCm.getActiveNetworkInfo()); @@ -7166,7 +7580,7 @@ // Disconnect wifi aware network. wifiAware.disconnect(); - callback.expect(CallbackEntry.LOST, TIMEOUT_MS); + callback.expect(LOST, TIMEOUT_MS); mCm.unregisterNetworkCallback(callback); verifyNoNetwork(); @@ -7213,13 +7627,12 @@ // ConnectivityService. TestNetworkAgentWrapper networkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); networkAgent.connect(true); - networkCallback.expect(CallbackEntry.AVAILABLE, networkAgent); - networkCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, networkAgent); + networkCallback.expect(AVAILABLE, networkAgent); + networkCallback.expect(NETWORK_CAPS_UPDATED, networkAgent); CallbackEntry.LinkPropertiesChanged cbi = - networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, - networkAgent); - networkCallback.expect(CallbackEntry.BLOCKED_STATUS, networkAgent); - networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent); + networkCallback.expect(LINK_PROPERTIES_CHANGED, networkAgent); + networkCallback.expect(BLOCKED_STATUS, networkAgent); + networkCallback.expectCaps(networkAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); networkCallback.assertNoCallback(); checkDirectlyConnectedRoutes(cbi.getLp(), asList(myIpv4Address), asList(myIpv4DefaultRoute)); @@ -7233,7 +7646,7 @@ newLp.addLinkAddress(myIpv6Address1); newLp.addLinkAddress(myIpv6Address2); networkAgent.sendLinkProperties(newLp); - cbi = networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, networkAgent); + cbi = networkCallback.expect(LINK_PROPERTIES_CHANGED, networkAgent); networkCallback.assertNoCallback(); checkDirectlyConnectedRoutes(cbi.getLp(), asList(myIpv4Address, myIpv6Address1, myIpv6Address2), @@ -7294,15 +7707,15 @@ } private List<Network> onlyCell() { - return List.of(mCellNetworkAgent.getNetwork()); + return List.of(mCellAgent.getNetwork()); } private List<Network> onlyWifi() { - return List.of(mWiFiNetworkAgent.getNetwork()); + return List.of(mWiFiAgent.getNetwork()); } private List<Network> cellAndWifi() { - return List.of(mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()); + return List.of(mCellAgent.getNetwork(), mWiFiAgent.getNetwork()); } @Test @@ -7312,13 +7725,15 @@ LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); // Simple connection with initial LP should have updated ifaces. - mCellNetworkAgent.connect(false); + mCellAgent.connect(false); waitForIdle(); - expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME); + List<Network> allNetworks = mService.shouldCreateNetworksImmediately() + ? cellAndWifi() : onlyCell(); + expectNotifyNetworkStatus(allNetworks, onlyCell(), MOBILE_IFNAME); reset(mStatsManager); // Verify change fields other than interfaces does not trigger a notification to NSS. @@ -7326,13 +7741,13 @@ 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); + mCellAgent.sendLinkProperties(cellLp); verifyNoMoreInteractions(mStatsManager); reset(mStatsManager); // Default network switch should update ifaces. - mWiFiNetworkAgent.connect(false); - mWiFiNetworkAgent.sendLinkProperties(wifiLp); + mWiFiAgent.connect(false); + mWiFiAgent.sendLinkProperties(wifiLp); waitForIdle(); assertEquals(wifiLp, mService.getActiveLinkProperties()); expectNotifyNetworkStatus(cellAndWifi(), onlyWifi(), WIFI_IFNAME); @@ -7344,52 +7759,52 @@ // 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(); + mCellAgent.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); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent.connect(false); waitForIdle(); expectNotifyNetworkStatus(cellAndWifi(), onlyWifi(), WIFI_IFNAME); reset(mStatsManager); // Disconnect should update ifaces. - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); waitForIdle(); expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME); reset(mStatsManager); // Metered change should update ifaces - mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + mCellAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME); reset(mStatsManager); - mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + mCellAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME); reset(mStatsManager); // Temp metered change shouldn't update ifaces - mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); + mCellAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); waitForIdle(); verify(mStatsManager, never()).notifyNetworkStatus(eq(onlyCell()), any(List.class), eq(MOBILE_IFNAME), any(List.class)); reset(mStatsManager); // Congested change shouldn't update ifaces - mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); + mCellAgent.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); + mCellAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); waitForIdle(); expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME); reset(mStatsManager); @@ -7401,25 +7816,22 @@ mMockVpn.establishForMyUid(lp); assertUidRangesUpdatedForMyUid(true); - final List<Network> cellAndVpn = - List.of(mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()); + final List<Network> cellAndVpn = List.of(mCellAgent.getNetwork(), mMockVpn.getNetwork()); // A VPN with default (null) underlying networks sets the underlying network's interfaces... 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); - mWiFiNetworkAgent.connect(false); - mWiFiNetworkAgent.sendLinkProperties(wifiLp); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); + mWiFiAgent.sendLinkProperties(wifiLp); final Network[] onlyNull = new Network[]{null}; - final List<Network> wifiAndVpn = - List.of(mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork()); - final List<Network> cellWifiAndVpn = - List.of(mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork(), - mMockVpn.getNetwork()); + final List<Network> wifiAndVpn = List.of(mWiFiAgent.getNetwork(), mMockVpn.getNetwork()); + final List<Network> cellWifiAndVpn = List.of(mCellAgent.getNetwork(), + mWiFiAgent.getNetwork(), mMockVpn.getNetwork()); final Network[] cellNullAndWifi = - new Network[]{mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()}; + new Network[] { mCellAgent.getNetwork(), null, mWiFiAgent.getNetwork() }; waitForIdle(); assertEquals(wifiLp, mService.getActiveLinkProperties()); @@ -7459,9 +7871,9 @@ // could result in incorrect data usage measurements if the interface used by the // disconnected network is reused by a system component that does not register an agent for // it (e.g., tethering). - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); waitForIdle(); - assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork())); + assertNull(mService.getLinkProperties(mCellAgent.getNetwork())); expectNotifyNetworkStatus(cellWifiAndVpn, wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, List.of(MOBILE_IFNAME, WIFI_IFNAME)); @@ -7477,16 +7889,16 @@ // ... but if something else happens that causes notifyIfacesChangedForNetworkStats to be // called again, it does. For example, connect Ethernet, but with a low score, such that it // does not become the default network. - mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); - mEthernetNetworkAgent.setScore( + mEthernetAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); + mEthernetAgent.setScore( new NetworkScore.Builder().setLegacyInt(30).setExiting(true).build()); - mEthernetNetworkAgent.connect(false); + mEthernetAgent.connect(false); waitForIdle(); verify(mStatsManager).notifyNetworkStatus(any(List.class), any(List.class), any() /* anyString() doesn't match null */, argThat(vpnInfos -> vpnInfos.get(0).getUnderlyingInterfaces().size() == 1 && WIFI_IFNAME.equals(vpnInfos.get(0).getUnderlyingInterfaces().get(0)))); - mEthernetNetworkAgent.disconnect(); + mEthernetAgent.disconnect(); waitForIdle(); reset(mStatsManager); @@ -7526,18 +7938,17 @@ final int[] adminUids = new int[] {Process.myUid() + 1}; final NetworkCapabilities ncTemplate = new NetworkCapabilities(); ncTemplate.setAdministratorUids(adminUids); - mCellNetworkAgent = + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), ncTemplate); - mCellNetworkAgent.connect(false /* validated */); + mCellAgent.connect(false /* validated */); // Verify case where caller has permission mServiceContext.setPermission( NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_GRANTED); TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(callback); - callback.expect(CallbackEntry.AVAILABLE, mCellNetworkAgent); - callback.expectCapabilitiesThat( - mCellNetworkAgent, nc -> Arrays.equals(adminUids, nc.getAdministratorUids())); + callback.expect(AVAILABLE, mCellAgent); + callback.expectCaps(mCellAgent, c -> Arrays.equals(adminUids, c.getAdministratorUids())); mCm.unregisterNetworkCallback(callback); // Verify case where caller does NOT have permission @@ -7546,9 +7957,8 @@ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED); callback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(callback); - callback.expect(CallbackEntry.AVAILABLE, mCellNetworkAgent); - callback.expectCapabilitiesThat( - mCellNetworkAgent, nc -> nc.getAdministratorUids().length == 0); + callback.expect(AVAILABLE, mCellAgent); + callback.expectCaps(mCellAgent, c -> c.getAdministratorUids().length == 0); } @Test @@ -7565,10 +7975,10 @@ // Connect a VCN-managed wifi network. final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); - mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_VCN_MANAGED); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.connect(true /* validated */); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + mWiFiAgent.removeCapability(NET_CAPABILITY_NOT_VCN_MANAGED); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.connect(true /* validated */); final List<Network> none = List.of(); expectNotifyNetworkStatus(onlyWifi(), none, null); // Wifi is not the default network @@ -7583,7 +7993,7 @@ final LinkProperties lp = new LinkProperties(); lp.setInterfaceName(vcnIface); final TestNetworkAgentWrapper vcn = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, lp, nc); - vcn.setUnderlyingNetworks(List.of(mWiFiNetworkAgent.getNetwork())); + vcn.setUnderlyingNetworks(List.of(mWiFiAgent.getNetwork())); vcn.connect(false /* validated */); final TestNetworkCallback callback = new TestNetworkCallback(); @@ -7596,12 +8006,12 @@ assertFalse(nc.hasTransport(TRANSPORT_WIFI)); assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED)); final List<Network> onlyVcn = List.of(vcn.getNetwork()); - final List<Network> vcnAndWifi = List.of(vcn.getNetwork(), mWiFiNetworkAgent.getNetwork()); + final List<Network> vcnAndWifi = List.of(vcn.getNetwork(), mWiFiAgent.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); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); callback.assertNoCallback(); nc = mCm.getNetworkCapabilities(vcn.getNetwork()); assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED)); @@ -7609,11 +8019,11 @@ // Switch underlying networks. final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); - mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_VCN_MANAGED); - mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_ROAMING); - mCellNetworkAgent.connect(false /* validated */); - vcn.setUnderlyingNetworks(List.of(mCellNetworkAgent.getNetwork())); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent.removeCapability(NET_CAPABILITY_NOT_VCN_MANAGED); + mCellAgent.addCapability(NET_CAPABILITY_NOT_ROAMING); + mCellAgent.connect(false /* validated */); + vcn.setUnderlyingNetworks(List.of(mCellAgent.getNetwork())); // The underlying capability changes do not propagate to the virtual network, but // NetworkStatsService is informed of the new underlying interface. @@ -7622,7 +8032,7 @@ assertFalse(nc.hasTransport(TRANSPORT_WIFI)); assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_ROAMING)); final List<Network> vcnWifiAndCell = List.of(vcn.getNetwork(), - mWiFiNetworkAgent.getNetwork(), mCellNetworkAgent.getNetwork()); + mWiFiAgent.getNetwork(), mCellAgent.getNetwork()); expectNotifyNetworkStatus(vcnWifiAndCell, onlyVcn, vcnIface, ownerUid, vcnIface, List.of(MOBILE_IFNAME)); } @@ -7631,10 +8041,14 @@ public void testBasicDnsConfigurationPushed() throws Exception { setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + final int netId = mCellAgent.getNetwork().netId; waitForIdle(); - verify(mMockDnsResolver, never()).setResolverConfiguration(any()); - verifyNoMoreInteractions(mMockDnsResolver); + if (mService.shouldCreateNetworksImmediately()) { + verify(mMockDnsResolver, times(1)).createNetworkCache(netId); + } else { + verify(mMockDnsResolver, never()).setResolverConfiguration(any()); + } final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); @@ -7647,18 +8061,20 @@ cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64")); cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"), MOBILE_IFNAME)); - mCellNetworkAgent.sendLinkProperties(cellLp); - mCellNetworkAgent.connect(false); + mCellAgent.sendLinkProperties(cellLp); + mCellAgent.connect(false); waitForIdle(); - - verify(mMockDnsResolver, times(1)).createNetworkCache( - eq(mCellNetworkAgent.getNetwork().netId)); - // CS tells dnsresolver about the empty DNS config for this network. + if (!mService.shouldCreateNetworksImmediately()) { + // CS tells dnsresolver about the empty DNS config for this network. + verify(mMockDnsResolver, times(1)).createNetworkCache(netId); + } verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any()); + + verifyNoMoreInteractions(mMockDnsResolver); reset(mMockDnsResolver); cellLp.addDnsServer(InetAddress.getByName("2001:db8::1")); - mCellNetworkAgent.sendLinkProperties(cellLp); + mCellAgent.sendLinkProperties(cellLp); waitForIdle(); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( mResolverParamsParcelCaptor.capture()); @@ -7670,7 +8086,7 @@ reset(mMockDnsResolver); cellLp.addDnsServer(InetAddress.getByName("192.0.2.1")); - mCellNetworkAgent.sendLinkProperties(cellLp); + mCellAgent.sendLinkProperties(cellLp); waitForIdle(); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( mResolverParamsParcelCaptor.capture()); @@ -7688,7 +8104,7 @@ final String TLS_SERVER6 = "2001:db8:53::53"; final InetAddress[] TLS_IPS = new InetAddress[]{ InetAddress.getByName(TLS_SERVER6) }; final String[] TLS_SERVERS = new String[]{ TLS_SERVER6 }; - mCellNetworkAgent.mNmCallbacks.notifyPrivateDnsConfigResolved( + mCellAgent.mNmCallbacks.notifyPrivateDnsConfigResolved( new PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS).toParcel()); waitForIdle(); @@ -7709,11 +8125,10 @@ final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(request, callback); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - verify(mMockDnsResolver, times(1)).createNetworkCache( - eq(mWiFiNetworkAgent.getNetwork().netId)); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + verify(mMockDnsResolver, times(1)).createNetworkCache(eq(mWiFiAgent.getNetwork().netId)); verify(mMockDnsResolver, times(2)).setResolverConfiguration( mResolverParamsParcelCaptor.capture()); final ResolverParamsParcel resolverParams = mResolverParamsParcelCaptor.getValue(); @@ -7729,31 +8144,31 @@ TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(request, callback); // Bring up wifi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // Private DNS resolution failed, checking if the notification will be shown or not. - mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */); - mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); + mWiFiAgent.setNetworkInvalid(true /* invalidBecauseOfPrivateDns */); + mWiFiAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); waitForIdle(); // If network validation failed, NetworkMonitor will re-evaluate the network. // ConnectivityService should filter the redundant notification. This part is trying to // simulate that situation and check if ConnectivityService could filter that case. - mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); + mWiFiAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); waitForIdle(); verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).notify(anyString(), eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any()); // If private DNS resolution successful, the PRIVATE_DNS_BROKEN notification shouldn't be // shown. - mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */); - mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); + mWiFiAgent.setNetworkValid(true /* privateDnsProbeSent */); + mWiFiAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); waitForIdle(); verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).cancel(anyString(), eq(NotificationType.PRIVATE_DNS_BROKEN.eventId)); // If private DNS resolution failed again, the PRIVATE_DNS_BROKEN notification should be // shown again. - mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */); - mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); + mWiFiAgent.setNetworkInvalid(true /* invalidBecauseOfPrivateDns */); + mWiFiAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); waitForIdle(); verify(mNotificationManager, timeout(TIMEOUT_MS).times(2)).notify(anyString(), eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any()); @@ -7769,11 +8184,14 @@ .addTransportType(TRANSPORT_CELLULAR).build(); mCm.requestNetwork(cellRequest, cellNetworkCallback); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + final int netId = mCellAgent.getNetwork().netId; waitForIdle(); - // CS tells netd about the empty DNS config for this network. - verify(mMockDnsResolver, never()).setResolverConfiguration(any()); - verifyNoMoreInteractions(mMockDnsResolver); + if (mService.shouldCreateNetworksImmediately()) { + verify(mMockDnsResolver, times(1)).createNetworkCache(netId); + } else { + verify(mMockDnsResolver, never()).setResolverConfiguration(any()); + } final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); @@ -7789,11 +8207,12 @@ cellLp.addDnsServer(InetAddress.getByName("2001:db8::1")); cellLp.addDnsServer(InetAddress.getByName("192.0.2.1")); - mCellNetworkAgent.sendLinkProperties(cellLp); - mCellNetworkAgent.connect(false); + mCellAgent.sendLinkProperties(cellLp); + mCellAgent.connect(false); waitForIdle(); - verify(mMockDnsResolver, times(1)).createNetworkCache( - eq(mCellNetworkAgent.getNetwork().netId)); + if (!mService.shouldCreateNetworksImmediately()) { + verify(mMockDnsResolver, times(1)).createNetworkCache(netId); + } verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( mResolverParamsParcelCaptor.capture()); ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue(); @@ -7804,13 +8223,13 @@ assertEquals(2, resolvrParams.tlsServers.length); assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll( asList("2001:db8::1", "192.0.2.1"))); + verifyNoMoreInteractions(mMockDnsResolver); reset(mMockDnsResolver); - cellNetworkCallback.expect(CallbackEntry.AVAILABLE, mCellNetworkAgent); - cellNetworkCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, - mCellNetworkAgent); + cellNetworkCallback.expect(AVAILABLE, mCellAgent); + cellNetworkCallback.expect(NETWORK_CAPS_UPDATED, mCellAgent); CallbackEntry.LinkPropertiesChanged cbi = cellNetworkCallback.expect( - CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); - cellNetworkCallback.expect(CallbackEntry.BLOCKED_STATUS, mCellNetworkAgent); + LINK_PROPERTIES_CHANGED, mCellAgent); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent); cellNetworkCallback.assertNoCallback(); assertFalse(cbi.getLp().isPrivateDnsActive()); assertNull(cbi.getLp().getPrivateDnsServerName()); @@ -7841,8 +8260,7 @@ setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com"); // Can't test dns configuration for strict mode without properly mocking // out the DNS lookups, but can test that LinkProperties is updated. - cbi = cellNetworkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, - mCellNetworkAgent); + cbi = cellNetworkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); cellNetworkCallback.assertNoCallback(); assertTrue(cbi.getLp().isPrivateDnsActive()); assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName()); @@ -7868,18 +8286,17 @@ .addTransportType(TRANSPORT_CELLULAR).build(); mCm.requestNetwork(cellRequest, cellNetworkCallback); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); waitForIdle(); LinkProperties lp = new LinkProperties(); - mCellNetworkAgent.sendLinkProperties(lp); - mCellNetworkAgent.connect(false); + mCellAgent.sendLinkProperties(lp); + mCellAgent.connect(false); waitForIdle(); - cellNetworkCallback.expect(CallbackEntry.AVAILABLE, mCellNetworkAgent); - cellNetworkCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, - mCellNetworkAgent); + cellNetworkCallback.expect(AVAILABLE, mCellAgent); + cellNetworkCallback.expect(NETWORK_CAPS_UPDATED, mCellAgent); CallbackEntry.LinkPropertiesChanged cbi = cellNetworkCallback.expect( - CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); - cellNetworkCallback.expect(CallbackEntry.BLOCKED_STATUS, mCellNetworkAgent); + LINK_PROPERTIES_CHANGED, mCellAgent); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent); cellNetworkCallback.assertNoCallback(); assertFalse(cbi.getLp().isPrivateDnsActive()); assertNull(cbi.getLp().getPrivateDnsServerName()); @@ -7889,16 +8306,15 @@ // Send a validation event for a server that is not part of the current // resolver config. The validation event should be ignored. mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent( - makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, "", + makePrivateDnsValidationEvent(mCellAgent.getNetwork().netId, "", "145.100.185.18", VALIDATION_RESULT_SUCCESS)); cellNetworkCallback.assertNoCallback(); // Add a dns server to the LinkProperties. LinkProperties lp2 = new LinkProperties(lp); lp2.addDnsServer(InetAddress.getByName("145.100.185.16")); - mCellNetworkAgent.sendLinkProperties(lp2); - cbi = cellNetworkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, - mCellNetworkAgent); + mCellAgent.sendLinkProperties(lp2); + cbi = cellNetworkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); cellNetworkCallback.assertNoCallback(); assertFalse(cbi.getLp().isPrivateDnsActive()); assertNull(cbi.getLp().getPrivateDnsServerName()); @@ -7908,13 +8324,13 @@ // Send a validation event containing a hostname that is not part of // the current resolver config. The validation event should be ignored. mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent( - makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, + makePrivateDnsValidationEvent(mCellAgent.getNetwork().netId, "145.100.185.16", "hostname", VALIDATION_RESULT_SUCCESS)); cellNetworkCallback.assertNoCallback(); // Send a validation event where validation failed. mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent( - makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, + makePrivateDnsValidationEvent(mCellAgent.getNetwork().netId, "145.100.185.16", "", VALIDATION_RESULT_FAILURE)); cellNetworkCallback.assertNoCallback(); @@ -7922,10 +8338,9 @@ // the current resolver config. A LinkProperties callback with updated // private dns fields should be sent. mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent( - makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, + makePrivateDnsValidationEvent(mCellAgent.getNetwork().netId, "145.100.185.16", "", VALIDATION_RESULT_SUCCESS)); - cbi = cellNetworkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, - mCellNetworkAgent); + cbi = cellNetworkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); cellNetworkCallback.assertNoCallback(); assertTrue(cbi.getLp().isPrivateDnsActive()); assertNull(cbi.getLp().getPrivateDnsServerName()); @@ -7935,9 +8350,8 @@ // the network agent sends unrelated changes. LinkProperties lp3 = new LinkProperties(lp2); lp3.setMtu(1300); - mCellNetworkAgent.sendLinkProperties(lp3); - cbi = cellNetworkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, - mCellNetworkAgent); + mCellAgent.sendLinkProperties(lp3); + cbi = cellNetworkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); cellNetworkCallback.assertNoCallback(); assertTrue(cbi.getLp().isPrivateDnsActive()); assertNull(cbi.getLp().getPrivateDnsServerName()); @@ -7948,9 +8362,8 @@ // fields in LinkProperties. LinkProperties lp4 = new LinkProperties(lp3); lp4.removeDnsServer(InetAddress.getByName("145.100.185.16")); - mCellNetworkAgent.sendLinkProperties(lp4); - cbi = cellNetworkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, - mCellNetworkAgent); + mCellAgent.sendLinkProperties(lp4); + cbi = cellNetworkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); cellNetworkCallback.assertNoCallback(); assertFalse(cbi.getLp().isPrivateDnsActive()); assertNull(cbi.getLp().getPrivateDnsServerName()); @@ -7985,10 +8398,10 @@ @Test public void testApplyUnderlyingCapabilities() throws Exception { - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mCellNetworkAgent.connect(false /* validated */); - mWiFiNetworkAgent.connect(false /* validated */); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mCellAgent.connect(false /* validated */); + mWiFiAgent.connect(false /* validated */); final NetworkCapabilities cellNc = new NetworkCapabilities() .addTransportType(TRANSPORT_CELLULAR) @@ -8005,12 +8418,12 @@ .addCapability(NET_CAPABILITY_NOT_SUSPENDED) .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) .setLinkUpstreamBandwidthKbps(20); - mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */); - mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */); + mCellAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */); + mWiFiAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */); waitForIdle(); - final Network mobile = mCellNetworkAgent.getNetwork(); - final Network wifi = mWiFiNetworkAgent.getNetwork(); + final Network mobile = mCellAgent.getNetwork(); + final Network wifi = mWiFiAgent.getNetwork(); final NetworkCapabilities initialCaps = new NetworkCapabilities(); initialCaps.addTransportType(TRANSPORT_VPN); @@ -8141,9 +8554,7 @@ mMockVpn.setUnderlyingNetworks(new Network[]{wifiNetwork}); // onCapabilitiesChanged() should be called because // NetworkCapabilities#mUnderlyingNetworks is updated. - CallbackEntry ce = callback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, - mMockVpn); - final NetworkCapabilities vpnNc1 = ((CallbackEntry.CapabilitiesChanged) ce).getCaps(); + final NetworkCapabilities vpnNc1 = callback.expectCaps(mMockVpn); // Since the wifi network hasn't brought up, // ConnectivityService#applyUnderlyingCapabilities cannot find it. Update // NetworkCapabilities#mUnderlyingNetworks to an empty array, and it will be updated to @@ -8165,9 +8576,9 @@ // Make that underlying network connect, and expect to see its capabilities immediately // reflected in the VPN's capabilities. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - assertEquals(wifiNetwork, mWiFiNetworkAgent.getNetwork()); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + assertEquals(wifiNetwork, mWiFiAgent.getNetwork()); + mWiFiAgent.connect(false); // TODO: the callback for the VPN happens before any callbacks are called for the wifi // network that has just connected. There appear to be two issues here: // 1. The VPN code will accept an underlying network as soon as getNetworkCapabilities() @@ -8178,23 +8589,22 @@ // 2. When a network connects, updateNetworkInfo propagates underlying network // capabilities before rematching networks. // Given that this scenario can't really happen, this is probably fine for now. - ce = callback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn); - final NetworkCapabilities vpnNc2 = ((CallbackEntry.CapabilitiesChanged) ce).getCaps(); + final NetworkCapabilities vpnNc2 = callback.expectCaps(mMockVpn); // The wifi network is brought up, NetworkCapabilities#mUnderlyingNetworks is updated to // it. underlyingNetwork.add(wifiNetwork); assertEquals(underlyingNetwork, vpnNc2.getUnderlyingNetworks()); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) .hasTransport(TRANSPORT_VPN)); assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) .hasTransport(TRANSPORT_WIFI)); // Disconnect the network, and expect to see the VPN capabilities change accordingly. - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - callback.expectCapabilitiesThat(mMockVpn, (nc) -> - nc.getTransportTypes().length == 1 && nc.hasTransport(TRANSPORT_VPN)); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); + callback.expectCaps(mMockVpn, c -> c.getTransportTypes().length == 1 + && c.hasTransport(TRANSPORT_VPN)); mMockVpn.disconnect(); mCm.unregisterNetworkCallback(callback); @@ -8214,15 +8624,14 @@ // Connect a VPN. mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */, - false /* isStrictMode */); + false /* privateDnsProbeSent */); callback.expectAvailableCallbacksUnvalidated(mMockVpn); // Connect cellular data. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(false /* validated */); - callback.expectCapabilitiesThat(mMockVpn, - nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) - && nc.hasTransport(TRANSPORT_CELLULAR)); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(false /* validated */); + callback.expectCaps(mMockVpn, c -> c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && c.hasTransport(TRANSPORT_CELLULAR)); callback.assertNoCallback(); assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) @@ -8234,11 +8643,10 @@ assertGetNetworkInfoOfGetActiveNetworkIsConnected(true); // Suspend the cellular network and expect the VPN to be suspended. - mCellNetworkAgent.suspend(); - callback.expectCapabilitiesThat(mMockVpn, - nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) - && nc.hasTransport(TRANSPORT_CELLULAR)); - callback.expect(CallbackEntry.SUSPENDED, mMockVpn); + mCellAgent.suspend(); + callback.expectCaps(mMockVpn, c -> !c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && c.hasTransport(TRANSPORT_CELLULAR)); + callback.expect(SUSPENDED, mMockVpn); callback.assertNoCallback(); assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) @@ -8251,12 +8659,11 @@ assertGetNetworkInfoOfGetActiveNetworkIsConnected(false); // Switch to another network. The VPN should no longer be suspended. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false /* validated */); - callback.expectCapabilitiesThat(mMockVpn, - nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) - && nc.hasTransport(TRANSPORT_WIFI)); - callback.expect(CallbackEntry.RESUMED, mMockVpn); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false /* validated */); + callback.expectCaps(mMockVpn, c -> c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && c.hasTransport(TRANSPORT_WIFI)); + callback.expect(RESUMED, mMockVpn); callback.assertNoCallback(); assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) @@ -8268,16 +8675,14 @@ assertGetNetworkInfoOfGetActiveNetworkIsConnected(true); // Unsuspend cellular and then switch back to it. The VPN remains not suspended. - mCellNetworkAgent.resume(); + mCellAgent.resume(); callback.assertNoCallback(); - mWiFiNetworkAgent.disconnect(); - callback.expectCapabilitiesThat(mMockVpn, - nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) - && nc.hasTransport(TRANSPORT_CELLULAR)); + mWiFiAgent.disconnect(); + callback.expectCaps(mMockVpn, c -> c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && c.hasTransport(TRANSPORT_CELLULAR)); // Spurious double callback? - callback.expectCapabilitiesThat(mMockVpn, - nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) - && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.expectCaps(mMockVpn, c -> c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && c.hasTransport(TRANSPORT_CELLULAR)); callback.assertNoCallback(); assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) @@ -8289,11 +8694,10 @@ assertGetNetworkInfoOfGetActiveNetworkIsConnected(true); // Suspend cellular and expect no connectivity. - mCellNetworkAgent.suspend(); - callback.expectCapabilitiesThat(mMockVpn, - nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) - && nc.hasTransport(TRANSPORT_CELLULAR)); - callback.expect(CallbackEntry.SUSPENDED, mMockVpn); + mCellAgent.suspend(); + callback.expectCaps(mMockVpn, c -> !c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && c.hasTransport(TRANSPORT_CELLULAR)); + callback.expect(SUSPENDED, mMockVpn); callback.assertNoCallback(); assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) @@ -8305,11 +8709,10 @@ assertGetNetworkInfoOfGetActiveNetworkIsConnected(false); // Resume cellular and expect that connectivity comes back. - mCellNetworkAgent.resume(); - callback.expectCapabilitiesThat(mMockVpn, - nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) - && nc.hasTransport(TRANSPORT_CELLULAR)); - callback.expect(CallbackEntry.RESUMED, mMockVpn); + mCellAgent.resume(); + callback.expectCaps(mMockVpn, c -> c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && c.hasTransport(TRANSPORT_CELLULAR)); + callback.expect(RESUMED, mMockVpn); callback.assertNoCallback(); assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) @@ -8348,14 +8751,14 @@ new Handler(ConnectivityThread.getInstanceLooper())); defaultCallback.assertNoCallback(); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false); - genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); vpnNetworkCallback.assertNoCallback(); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); @@ -8370,7 +8773,7 @@ NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig()) .isVpnValidationRequired(), mMockVpn.getAgent().getNetworkCapabilities())); - mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */); + mMockVpn.getAgent().setNetworkValid(false /* privateDnsProbeSent */); mMockVpn.connect(false); @@ -8381,16 +8784,15 @@ defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn); systemDefaultCallback.assertNoCallback(); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - assertEquals(mWiFiNetworkAgent.getNetwork(), - systemDefaultCallback.getLastAvailableNetwork()); + assertEquals(mWiFiAgent.getNetwork(), systemDefaultCallback.getLastAvailableNetwork()); ranges.clear(); mMockVpn.setUids(ranges); - genericNetworkCallback.expect(CallbackEntry.LOST, mMockVpn); + genericNetworkCallback.expect(LOST, mMockVpn); genericNotVpnNetworkCallback.assertNoCallback(); wifiNetworkCallback.assertNoCallback(); - vpnNetworkCallback.expect(CallbackEntry.LOST, mMockVpn); + vpnNetworkCallback.expect(LOST, mMockVpn); // TODO : The default network callback should actually get a LOST call here (also see the // comment below for AVAILABLE). This is because ConnectivityService does not look at UID @@ -8398,7 +8800,7 @@ // can't currently update their UIDs without disconnecting, so this does not matter too // much, but that is the reason the test here has to check for an update to the // capabilities instead of the expected LOST then AVAILABLE. - defaultCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn); + defaultCallback.expectCaps(mMockVpn); systemDefaultCallback.assertNoCallback(); ranges.add(new UidRange(uid, uid)); @@ -8410,25 +8812,25 @@ vpnNetworkCallback.expectAvailableCallbacksValidated(mMockVpn); // TODO : Here like above, AVAILABLE would be correct, but because this can't actually // happen outside of the test, ConnectivityService does not rematch callbacks. - defaultCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn); + defaultCallback.expectCaps(mMockVpn); systemDefaultCallback.assertNoCallback(); - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); - genericNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - genericNotVpnNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - wifiNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + genericNetworkCallback.expect(LOST, mWiFiAgent); + genericNotVpnNetworkCallback.expect(LOST, mWiFiAgent); + wifiNetworkCallback.expect(LOST, mWiFiAgent); vpnNetworkCallback.assertNoCallback(); defaultCallback.assertNoCallback(); - systemDefaultCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + systemDefaultCallback.expect(LOST, mWiFiAgent); mMockVpn.disconnect(); - genericNetworkCallback.expect(CallbackEntry.LOST, mMockVpn); + genericNetworkCallback.expect(LOST, mMockVpn); genericNotVpnNetworkCallback.assertNoCallback(); wifiNetworkCallback.assertNoCallback(); - vpnNetworkCallback.expect(CallbackEntry.LOST, mMockVpn); - defaultCallback.expect(CallbackEntry.LOST, mMockVpn); + vpnNetworkCallback.expect(LOST, mMockVpn); + defaultCallback.expect(LOST, mMockVpn); systemDefaultCallback.assertNoCallback(); assertEquals(null, mCm.getActiveNetwork()); @@ -8446,14 +8848,14 @@ final TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); - defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */, - false /* isStrictMode */); + false /* privateDnsProbeSent */); assertUidRangesUpdatedForMyUid(true); defaultCallback.assertNoCallback(); @@ -8472,22 +8874,22 @@ final TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); - defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); mMockVpn.establishForMyUid(true /* validated */, true /* hasInternet */, - false /* isStrictMode */); + false /* privateDnsProbeSent */); assertUidRangesUpdatedForMyUid(true); defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); mMockVpn.disconnect(); - defaultCallback.expect(CallbackEntry.LOST, mMockVpn); - defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); + defaultCallback.expect(LOST, mMockVpn); + defaultCallback.expectAvailableCallbacksValidated(mWiFiAgent); mCm.unregisterNetworkCallback(defaultCallback); } @@ -8498,14 +8900,14 @@ mCm.registerDefaultNetworkCallback(callback); // Bring up Ethernet. - mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); - mEthernetNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); + mEthernetAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); + mEthernetAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mEthernetAgent); callback.assertNoCallback(); // Bring up a VPN that has the INTERNET capability, initially unvalidated. mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */, - false /* isStrictMode */); + false /* privateDnsProbeSent */); assertUidRangesUpdatedForMyUid(true); // Even though the VPN is unvalidated, it becomes the default network for our app. @@ -8527,16 +8929,16 @@ mMockVpn.getAgent().getNetworkCapabilities())); // Pretend that the VPN network validates. - mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */); + mMockVpn.getAgent().setNetworkValid(false /* privateDnsProbeSent */); mMockVpn.getAgent().mNetworkMonitor.forceReevaluation(Process.myUid()); // Expect to see the validated capability, but no other changes, because the VPN is already // the default network for the app. - callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mMockVpn); + callback.expectCaps(mMockVpn, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); callback.assertNoCallback(); mMockVpn.disconnect(); - callback.expect(CallbackEntry.LOST, mMockVpn); - callback.expectAvailableCallbacksValidated(mEthernetNetworkAgent); + callback.expect(LOST, mMockVpn); + callback.expectAvailableCallbacksValidated(mEthernetAgent); } @Test @@ -8553,18 +8955,18 @@ // Connect cell. It will become the default network, and in the absence of setting // underlying networks explicitly it will become the sole underlying network for the vpn. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED); + mCellAgent.connect(true); mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */, - false /* isStrictMode */); + false /* privateDnsProbeSent */); assertUidRangesUpdatedForMyUid(true); vpnNetworkCallback.expectAvailableCallbacks(mMockVpn.getNetwork(), false /* suspended */, false /* validated */, false /* blocked */, TIMEOUT_MS); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn.getNetwork(), TIMEOUT_MS, - nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED)); + vpnNetworkCallback.expectCaps(mMockVpn.getNetwork(), TIMEOUT_MS, + c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); final NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork()); assertTrue(nc.hasTransport(TRANSPORT_VPN)); @@ -8602,7 +9004,7 @@ vpnNetworkCallback.assertNoCallback(); mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */, - false /* isStrictMode */); + false /* privateDnsProbeSent */); assertUidRangesUpdatedForMyUid(true); vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn); @@ -8620,130 +9022,136 @@ assertDefaultNetworkCapabilities(userId /* no networks */); // Connect cell and use it as an underlying network. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED); + mCellAgent.connect(true); + + mMockVpn.setUnderlyingNetworks(new Network[] { mCellAgent.getNetwork() }); + + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_CELLULAR) + && !c.hasTransport(TRANSPORT_WIFI) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED) + && c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertDefaultNetworkCapabilities(userId, mCellAgent); + + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED); + mWiFiAgent.connect(true); mMockVpn.setUnderlyingNetworks( - new Network[] { mCellNetworkAgent.getNetwork() }); + new Network[] { mCellAgent.getNetwork(), mWiFiAgent.getNetwork() }); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED) - && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - assertDefaultNetworkCapabilities(userId, mCellNetworkAgent); - - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED); - mWiFiNetworkAgent.connect(true); - - mMockVpn.setUnderlyingNetworks( - new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() }); - - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED) - && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_CELLULAR) + && c.hasTransport(TRANSPORT_WIFI) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED) + && c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertDefaultNetworkCapabilities(userId, mCellAgent, mWiFiAgent); // Don't disconnect, but note the VPN is not using wifi any more. - mMockVpn.setUnderlyingNetworks( - new Network[] { mCellNetworkAgent.getNetwork() }); + mMockVpn.setUnderlyingNetworks(new Network[] { mCellAgent.getNetwork() }); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED) - && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_CELLULAR) + && !c.hasTransport(TRANSPORT_WIFI) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED) + && c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); // The return value of getDefaultNetworkCapabilitiesForUser always includes the default // network (wifi) as well as the underlying networks (cell). - assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent); + assertDefaultNetworkCapabilities(userId, mCellAgent, mWiFiAgent); // Remove NOT_SUSPENDED from the only network and observe VPN is now suspended. - mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED) - && !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - vpnNetworkCallback.expect(CallbackEntry.SUSPENDED, mMockVpn); + mCellAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_CELLULAR) + && !c.hasTransport(TRANSPORT_WIFI) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED) + && !c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + vpnNetworkCallback.expect(SUSPENDED, mMockVpn); // Add NOT_SUSPENDED again and observe VPN is no longer suspended. - mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED) - && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - vpnNetworkCallback.expect(CallbackEntry.RESUMED, mMockVpn); + mCellAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_CELLULAR) + && !c.hasTransport(TRANSPORT_WIFI) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED) + && c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + vpnNetworkCallback.expect(RESUMED, mMockVpn); // Use Wifi but not cell. Note the VPN is now unmetered and not suspended. - mMockVpn.setUnderlyingNetworks( - new Network[] { mWiFiNetworkAgent.getNetwork() }); + mMockVpn.setUnderlyingNetworks(new Network[] { mWiFiAgent.getNetwork() }); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) - && caps.hasCapability(NET_CAPABILITY_NOT_METERED) - && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && !c.hasTransport(TRANSPORT_CELLULAR) + && c.hasTransport(TRANSPORT_WIFI) + && c.hasCapability(NET_CAPABILITY_NOT_METERED) + && c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertDefaultNetworkCapabilities(userId, mWiFiAgent); // Use both again. mMockVpn.setUnderlyingNetworks( - new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() }); + new Network[] { mCellAgent.getNetwork(), mWiFiAgent.getNetwork() }); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED) - && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_CELLULAR) + && c.hasTransport(TRANSPORT_WIFI) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED) + && c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertDefaultNetworkCapabilities(userId, mCellAgent, mWiFiAgent); // Cell is suspended again. As WiFi is not, this should not cause a callback. - mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED); + mCellAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED); vpnNetworkCallback.assertNoCallback(); // Stop using WiFi. The VPN is suspended again. - mMockVpn.setUnderlyingNetworks( - new Network[] { mCellNetworkAgent.getNetwork() }); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED) - && !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - vpnNetworkCallback.expect(CallbackEntry.SUSPENDED, mMockVpn); - assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent); + mMockVpn.setUnderlyingNetworks(new Network[] { mCellAgent.getNetwork() }); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_CELLULAR) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED) + && !c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + vpnNetworkCallback.expect(SUSPENDED, mMockVpn); + assertDefaultNetworkCapabilities(userId, mCellAgent, mWiFiAgent); // Use both again. mMockVpn.setUnderlyingNetworks( - new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() }); + new Network[] { mCellAgent.getNetwork(), mWiFiAgent.getNetwork() }); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED) - && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - vpnNetworkCallback.expect(CallbackEntry.RESUMED, mMockVpn); - assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_CELLULAR) + && c.hasTransport(TRANSPORT_WIFI) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED) + && c.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + vpnNetworkCallback.expect(RESUMED, mMockVpn); + assertDefaultNetworkCapabilities(userId, mCellAgent, mWiFiAgent); // Disconnect cell. Receive update without even removing the dead network from the // underlying networks – it's dead anyway. Not metered any more. - mCellNetworkAgent.disconnect(); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) - && caps.hasCapability(NET_CAPABILITY_NOT_METERED)); - assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent); + mCellAgent.disconnect(); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && !c.hasTransport(TRANSPORT_CELLULAR) + && c.hasTransport(TRANSPORT_WIFI) + && c.hasCapability(NET_CAPABILITY_NOT_METERED)); + assertDefaultNetworkCapabilities(userId, mWiFiAgent); // Disconnect wifi too. No underlying networks means this is now metered. - mWiFiNetworkAgent.disconnect(); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)); + mWiFiAgent.disconnect(); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && !c.hasTransport(TRANSPORT_CELLULAR) + && !c.hasTransport(TRANSPORT_WIFI) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED)); // When a network disconnects, the callbacks are fired before all state is updated, so for a // short time, synchronous calls will behave as if the network is still connected. Wait for // things to settle. @@ -8767,7 +9175,7 @@ vpnNetworkCallback.assertNoCallback(); mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */, - false /* isStrictMode */); + false /* privateDnsProbeSent */); assertUidRangesUpdatedForMyUid(true); vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn); @@ -8781,35 +9189,38 @@ assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE); // Connect to Cell; Cell is the default network. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_CELLULAR) + && !c.hasTransport(TRANSPORT_WIFI) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED)); // Connect to WiFi; WiFi is the new default. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.connect(true); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) - && caps.hasCapability(NET_CAPABILITY_NOT_METERED)); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && !c.hasTransport(TRANSPORT_CELLULAR) + && c.hasTransport(TRANSPORT_WIFI) + && c.hasCapability(NET_CAPABILITY_NOT_METERED)); // Disconnect Cell. The default network did not change, so there shouldn't be any changes in // the capabilities. - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); // Disconnect wifi too. Now we have no default network. - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); - vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, - (caps) -> caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)); + vpnNetworkCallback.expectCaps(mMockVpn, + c -> c.hasTransport(TRANSPORT_VPN) + && !c.hasTransport(TRANSPORT_CELLULAR) + && !c.hasTransport(TRANSPORT_WIFI) + && !c.hasCapability(NET_CAPABILITY_NOT_METERED)); mMockVpn.disconnect(); } @@ -8825,6 +9236,14 @@ final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerNetworkCallback(request, callback); + // File a VPN request to prevent VPN network being lingered. + final NetworkRequest vpnRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_VPN) + .removeCapability(NET_CAPABILITY_NOT_VPN) + .build(); + final TestNetworkCallback vpnCallback = new TestNetworkCallback(); + mCm.requestNetwork(vpnRequest, vpnCallback); + // Bring up a VPN mMockVpn.establishForMyUid(); assertUidRangesUpdatedForMyUid(true); @@ -8838,14 +9257,12 @@ assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE); // Set an underlying network and expect to see the VPN transports change. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - callback.expectCapabilitiesThat(mMockVpn, (caps) - -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_WIFI)); - callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps) - -> caps.hasCapability(NET_CAPABILITY_VALIDATED)); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + callback.expectCaps(mMockVpn, c -> c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_WIFI)); + callback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); doReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID)).when(mPackageManager) .getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER); @@ -8856,35 +9273,38 @@ // Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added // restricted user. final UidRange rRange = UidRange.createForUser(UserHandle.of(RESTRICTED_USER)); - final Range<Integer> restrictUidRange = new Range<Integer>(rRange.start, rRange.stop); - final Range<Integer> singleUidRange = new Range<Integer>(uid, uid); - callback.expectCapabilitiesThat(mMockVpn, (caps) - -> caps.getUids().size() == 2 - && caps.getUids().contains(singleUidRange) - && caps.getUids().contains(restrictUidRange) - && caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_WIFI)); + final Range<Integer> restrictUidRange = new Range<>(rRange.start, rRange.stop); + final Range<Integer> singleUidRange = new Range<>(uid, uid); + callback.expectCaps(mMockVpn, c -> + c.getUids().size() == 2 + && c.getUids().contains(singleUidRange) + && c.getUids().contains(restrictUidRange) + && c.hasTransport(TRANSPORT_VPN) + && c.hasTransport(TRANSPORT_WIFI)); // Change the VPN's capabilities somehow (specifically, disconnect wifi). - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - callback.expectCapabilitiesThat(mMockVpn, (caps) - -> caps.getUids().size() == 2 - && caps.getUids().contains(singleUidRange) - && caps.getUids().contains(restrictUidRange) - && caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_WIFI)); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); + callback.expectCaps(mMockVpn, c -> + c.getUids().size() == 2 + && c.getUids().contains(singleUidRange) + && c.getUids().contains(restrictUidRange) + && c.hasTransport(TRANSPORT_VPN) + && !c.hasTransport(TRANSPORT_WIFI)); // User removed and expect to lose the UID range for the restricted user. mMockVpn.onUserRemoved(RESTRICTED_USER); // Expect that the VPN gains the UID range for the restricted user, and that the capability // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved. - callback.expectCapabilitiesThat(mMockVpn, (caps) - -> caps.getUids().size() == 1 - && caps.getUids().contains(singleUidRange) - && caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_WIFI)); + callback.expectCaps(mMockVpn, c -> + c.getUids().size() == 1 + && c.getUids().contains(singleUidRange) + && c.hasTransport(TRANSPORT_VPN) + && !c.hasTransport(TRANSPORT_WIFI)); + + mCm.unregisterNetworkCallback(callback); + mCm.unregisterNetworkCallback(vpnCallback); } @Test @@ -8907,8 +9327,8 @@ final int uid = Process.myUid(); // Connect wifi and check that UIDs in the main and restricted profiles have network access. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true /* validated */); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true /* validated */); final int restrictedUid = UserHandle.getUid(RESTRICTED_USER, 42 /* appId */); assertNotNull(mCm.getActiveNetworkForUid(uid)); assertNotNull(mCm.getActiveNetworkForUid(restrictedUid)); @@ -8957,9 +9377,9 @@ public void testIsActiveNetworkMeteredOverWifi() throws Exception { // Returns true by default when no network is available. assertTrue(mCm.isActiveNetworkMetered()); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.connect(true); waitForIdle(); assertFalse(mCm.isActiveNetworkMetered()); @@ -8969,9 +9389,9 @@ public void testIsActiveNetworkMeteredOverCell() throws Exception { // Returns true by default when no network is available. assertTrue(mCm.isActiveNetworkMetered()); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.removeCapability(NET_CAPABILITY_NOT_METERED); + mCellAgent.connect(true); waitForIdle(); assertTrue(mCm.isActiveNetworkMetered()); @@ -8981,9 +9401,9 @@ public void testIsActiveNetworkMeteredOverVpnTrackingPlatformDefault() throws Exception { // Returns true by default when no network is available. assertTrue(mCm.isActiveNetworkMetered()); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.removeCapability(NET_CAPABILITY_NOT_METERED); + mCellAgent.connect(true); waitForIdle(); assertTrue(mCm.isActiveNetworkMetered()); @@ -8998,9 +9418,9 @@ assertTrue(mCm.isActiveNetworkMetered()); // Connect WiFi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.connect(true); waitForIdle(); // VPN should still be the active network. assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork()); @@ -9009,13 +9429,13 @@ assertFalse(mCm.isActiveNetworkMetered()); // Disconnecting Cell should not affect VPN's meteredness. - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); waitForIdle(); assertFalse(mCm.isActiveNetworkMetered()); // Disconnect WiFi; Now there is no platform default network. - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); waitForIdle(); // VPN without any underlying networks is treated as metered. @@ -9028,15 +9448,15 @@ public void testIsActiveNetworkMeteredOverVpnSpecifyingUnderlyingNetworks() throws Exception { // Returns true by default when no network is available. assertTrue(mCm.isActiveNetworkMetered()); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.removeCapability(NET_CAPABILITY_NOT_METERED); + mCellAgent.connect(true); waitForIdle(); assertTrue(mCm.isActiveNetworkMetered()); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.connect(true); waitForIdle(); assertFalse(mCm.isActiveNetworkMetered()); @@ -9047,16 +9467,14 @@ // Ensure VPN is now the active network. assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork()); // VPN is using Cell - mMockVpn.setUnderlyingNetworks( - new Network[] { mCellNetworkAgent.getNetwork() }); + mMockVpn.setUnderlyingNetworks(new Network[] { mCellAgent.getNetwork() }); waitForIdle(); // Expect VPN to be metered. assertTrue(mCm.isActiveNetworkMetered()); // VPN is now using WiFi - mMockVpn.setUnderlyingNetworks( - new Network[] { mWiFiNetworkAgent.getNetwork() }); + mMockVpn.setUnderlyingNetworks(new Network[] { mWiFiAgent.getNetwork() }); waitForIdle(); // Expect VPN to be unmetered @@ -9064,7 +9482,7 @@ // VPN is using Cell | WiFi. mMockVpn.setUnderlyingNetworks( - new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() }); + new Network[] { mCellAgent.getNetwork(), mWiFiAgent.getNetwork() }); waitForIdle(); // Expect VPN to be metered. @@ -9072,7 +9490,7 @@ // VPN is using WiFi | Cell. mMockVpn.setUnderlyingNetworks( - new Network[] { mWiFiNetworkAgent.getNetwork(), mCellNetworkAgent.getNetwork() }); + new Network[] { mWiFiAgent.getNetwork(), mCellAgent.getNetwork() }); waitForIdle(); // Order should not matter and VPN should still be metered. @@ -9092,9 +9510,9 @@ public void testIsActiveNetworkMeteredOverAlwaysMeteredVpn() throws Exception { // Returns true by default when no network is available. assertTrue(mCm.isActiveNetworkMetered()); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.connect(true); waitForIdle(); assertFalse(mCm.isActiveNetworkMetered()); @@ -9114,8 +9532,7 @@ // VPN explicitly declares WiFi as its underlying network. - mMockVpn.setUnderlyingNetworks( - new Network[] { mWiFiNetworkAgent.getNetwork() }); + mMockVpn.setUnderlyingNetworks(new Network[] { mWiFiAgent.getNetwork() }); waitForIdle(); // Doesn't really matter whether VPN declares its underlying networks explicitly. @@ -9123,7 +9540,7 @@ // With WiFi lost, VPN is basically without any underlying networks. And in that case it is // anyways suppose to be metered. - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); waitForIdle(); assertTrue(mCm.isActiveNetworkMetered()); @@ -9135,11 +9552,6 @@ public void expectAvailableThenValidatedCallbacks(HasNetwork n, int blockedStatus) { super.expectAvailableThenValidatedCallbacks(n.getNetwork(), blockedStatus, TIMEOUT_MS); } - public void expectBlockedStatusCallback(HasNetwork n, int blockedStatus) { - // This doesn't work: - // super.expectBlockedStatusCallback(blockedStatus, n.getNetwork()); - super.expectBlockedStatusCallback(blockedStatus, n.getNetwork(), TIMEOUT_MS); - } public void onBlockedStatusChanged(Network network, int blockedReasons) { getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons)); } @@ -9157,80 +9569,83 @@ mockUidNetworkingBlocked(); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - detailedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent, - BLOCKED_REASON_NONE); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + detailedCallback.expectAvailableThenValidatedCallbacks(mCellAgent, BLOCKED_REASON_NONE); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); - assertExtraInfoFromCmPresent(mCellNetworkAgent); + assertExtraInfoFromCmPresent(mCellAgent); setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER); - cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); - detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, - BLOCKED_REASON_BATTERY_SAVER); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked()); + detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent, + cb -> cb.getReason() == BLOCKED_REASON_BATTERY_SAVER); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); - assertExtraInfoFromCmBlocked(mCellNetworkAgent); + assertExtraInfoFromCmBlocked(mCellAgent); // If blocked state does not change but blocked reason does, the boolean callback is called. // TODO: investigate de-duplicating. setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED); - cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); - detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, - BLOCKED_METERED_REASON_USER_RESTRICTED); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked()); + detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent, + cb -> cb.getReason() == BLOCKED_METERED_REASON_USER_RESTRICTED); setBlockedReasonChanged(BLOCKED_REASON_NONE); - cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); - detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> !cb.getBlocked()); + detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent, + cb -> cb.getReason() == BLOCKED_REASON_NONE); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); - assertExtraInfoFromCmPresent(mCellNetworkAgent); + assertExtraInfoFromCmPresent(mCellAgent); setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); - cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); - detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, - BLOCKED_METERED_REASON_DATA_SAVER); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked()); + detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent, + cb -> cb.getReason() == BLOCKED_METERED_REASON_DATA_SAVER); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); - assertExtraInfoFromCmBlocked(mCellNetworkAgent); + assertExtraInfoFromCmBlocked(mCellAgent); // Restrict the network based on UID rule and NOT_METERED capability change. - mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent); - cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); - detailedCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent); - detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + mCellAgent.addCapability(NET_CAPABILITY_NOT_METERED); + cellNetworkCallback.expectCaps(mCellAgent, + c -> c.hasCapability(NET_CAPABILITY_NOT_METERED)); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> !cb.getBlocked()); + detailedCallback.expectCaps(mCellAgent, c -> c.hasCapability(NET_CAPABILITY_NOT_METERED)); + detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent, + cb -> cb.getReason() == BLOCKED_REASON_NONE); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); - assertExtraInfoFromCmPresent(mCellNetworkAgent); + assertExtraInfoFromCmPresent(mCellAgent); - mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); - cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, - mCellNetworkAgent); - cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); - detailedCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, - mCellNetworkAgent); - detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, - BLOCKED_METERED_REASON_DATA_SAVER); + mCellAgent.removeCapability(NET_CAPABILITY_NOT_METERED); + cellNetworkCallback.expectCaps(mCellAgent, + c -> !c.hasCapability(NET_CAPABILITY_NOT_METERED)); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked()); + detailedCallback.expectCaps(mCellAgent, + c -> !c.hasCapability(NET_CAPABILITY_NOT_METERED)); + detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent, + cb -> cb.getReason() == BLOCKED_METERED_REASON_DATA_SAVER); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); - assertExtraInfoFromCmBlocked(mCellNetworkAgent); + assertExtraInfoFromCmBlocked(mCellAgent); setBlockedReasonChanged(BLOCKED_REASON_NONE); - cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); - detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> !cb.getBlocked()); + detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent, + cb -> cb.getReason() == BLOCKED_REASON_NONE); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); - assertExtraInfoFromCmPresent(mCellNetworkAgent); + assertExtraInfoFromCmPresent(mCellAgent); setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.assertNoCallback(); @@ -9238,30 +9653,31 @@ // Restrict background data. Networking is not blocked because the network is unmetered. setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); - cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); - detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, - BLOCKED_METERED_REASON_DATA_SAVER); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked()); + detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent, + cb -> cb.getReason() == BLOCKED_METERED_REASON_DATA_SAVER); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); - assertExtraInfoFromCmBlocked(mCellNetworkAgent); + assertExtraInfoFromCmBlocked(mCellAgent); setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); cellNetworkCallback.assertNoCallback(); setBlockedReasonChanged(BLOCKED_REASON_NONE); - cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); - detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE); + cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> !cb.getBlocked()); + detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent, + cb -> cb.getReason() == BLOCKED_REASON_NONE); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); - assertExtraInfoFromCmPresent(mCellNetworkAgent); + assertExtraInfoFromCmPresent(mCellAgent); setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.assertNoCallback(); detailedCallback.assertNoCallback(); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); - assertExtraInfoFromCmPresent(mCellNetworkAgent); + assertExtraInfoFromCmPresent(mCellAgent); mCm.unregisterNetworkCallback(cellNetworkCallback); } @@ -9278,34 +9694,34 @@ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); defaultCallback.assertNoCallback(); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); - defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellAgent); + defaultCallback.expectCaps(mCellAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); // Allow to use the network after switching to NOT_METERED network. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.connect(true); - defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.connect(true); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); // Switch to METERED network. Restrict the use of the network. - mWiFiNetworkAgent.disconnect(); - defaultCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacksValidatedAndBlocked(mCellNetworkAgent); + mWiFiAgent.disconnect(); + defaultCallback.expect(LOST, mWiFiAgent); + defaultCallback.expectAvailableCallbacksValidatedAndBlocked(mCellAgent); // Network becomes NOT_METERED. - mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent); - defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); + mCellAgent.addCapability(NET_CAPABILITY_NOT_METERED); + defaultCallback.expectCaps(mCellAgent, c -> c.hasCapability(NET_CAPABILITY_NOT_METERED)); + defaultCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> !cb.getBlocked()); // Verify there's no Networkcallbacks invoked after data saver on/off. setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); setBlockedReasonChanged(BLOCKED_REASON_NONE); defaultCallback.assertNoCallback(); - mCellNetworkAgent.disconnect(); - defaultCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + defaultCallback.expect(LOST, mCellAgent); defaultCallback.assertNoCallback(); mCm.unregisterNetworkCallback(defaultCallback); @@ -9369,7 +9785,7 @@ // Expect exactly one blocked callback for each agent. for (int i = 0; i < agents.length; i++) { - final CallbackEntry e = callback.expect(CallbackEntry.BLOCKED_STATUS, TIMEOUT_MS, + final CallbackEntry e = callback.expect(BLOCKED_STATUS, TIMEOUT_MS, c -> c.getBlocked() == blocked); final Network network = e.getNetwork(); assertTrue("Received unexpected blocked callback for network " + network, @@ -9412,7 +9828,7 @@ final Set<Integer> excludedUids = new ArraySet<Integer>(); excludedUids.add(VPN_UID); - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { // On T onwards, the corresponding SDK sandbox UID should also be excluded excludedUids.add(toSdkSandboxUid(VPN_UID)); } @@ -9422,14 +9838,14 @@ expectNetworkRejectNonSecureVpn(inOrder, true, uidRangeParcels); // Connect a network when lockdown is active, expect to see it blocked. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(false /* validated */); - callback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent); - vpnUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - vpnUidDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - vpnDefaultCallbackAsUid.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false /* validated */); + callback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiAgent); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiAgent); + vpnUidCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + vpnUidDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + vpnDefaultCallbackAsUid.expectAvailableCallbacksUnvalidated(mWiFiAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); // Mobile is BLOCKED even though it's not actually connected. @@ -9438,14 +9854,14 @@ // Disable lockdown, expect to see the network unblocked. mMockVpn.setAlwaysOnPackage(null, false /* lockdown */, allowList); - callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent); - defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent); + callback.expect(BLOCKED_STATUS, mWiFiAgent, cb -> !cb.getBlocked()); + defaultCallback.expect(BLOCKED_STATUS, mWiFiAgent, cb -> !cb.getBlocked()); vpnUidCallback.assertNoCallback(); vpnUidDefaultCallback.assertNoCallback(); vpnDefaultCallbackAsUid.assertNoCallback(); expectNetworkRejectNonSecureVpn(inOrder, false, uidRangeParcels); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); @@ -9460,29 +9876,29 @@ vpnDefaultCallbackAsUid.assertNoCallback(); excludedUids.add(uid); - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { // On T onwards, the corresponding SDK sandbox UID should also be excluded excludedUids.add(toSdkSandboxUid(uid)); } final UidRangeParcel[] uidRangeParcelsAlsoExcludingUs = uidRangeParcelsExcludingUids( excludedUids.toArray(new Integer[0])); expectNetworkRejectNonSecureVpn(inOrder, true, uidRangeParcelsAlsoExcludingUs); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); // Connect a new network, expect it to be unblocked. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(false /* validated */); - callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(false /* validated */); + callback.expectAvailableCallbacksUnvalidated(mCellAgent); defaultCallback.assertNoCallback(); - vpnUidCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + vpnUidCallback.expectAvailableCallbacksUnvalidated(mCellAgent); vpnUidDefaultCallback.assertNoCallback(); vpnDefaultCallbackAsUid.assertNoCallback(); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); // Cellular is DISCONNECTED because it's not the default and there are no requests for it. assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); @@ -9497,12 +9913,12 @@ mMockVpn.setAlwaysOnPackage(ALWAYS_ON_PACKAGE, true /* lockdown */, allowList); waitForIdle(); expectNetworkRejectNonSecureVpn(inOrder, true, uidRangeParcels); - defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent); - assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent); + defaultCallback.expect(BLOCKED_STATUS, mWiFiAgent, cb -> cb.getBlocked()); + assertBlockedCallbackInAnyOrder(callback, true, mWiFiAgent, mCellAgent); vpnUidCallback.assertNoCallback(); vpnUidDefaultCallback.assertNoCallback(); vpnDefaultCallbackAsUid.assertNoCallback(); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); @@ -9510,13 +9926,13 @@ // Disable lockdown. Everything is unblocked. mMockVpn.setAlwaysOnPackage(null, false /* lockdown */, allowList); - defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent); - assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent); + defaultCallback.expect(BLOCKED_STATUS, mWiFiAgent, cb -> !cb.getBlocked()); + assertBlockedCallbackInAnyOrder(callback, false, mWiFiAgent, mCellAgent); vpnUidCallback.assertNoCallback(); vpnUidDefaultCallback.assertNoCallback(); vpnDefaultCallbackAsUid.assertNoCallback(); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); @@ -9530,8 +9946,8 @@ vpnUidCallback.assertNoCallback(); vpnUidDefaultCallback.assertNoCallback(); vpnDefaultCallbackAsUid.assertNoCallback(); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); @@ -9543,20 +9959,20 @@ vpnUidCallback.assertNoCallback(); vpnUidDefaultCallback.assertNoCallback(); vpnDefaultCallbackAsUid.assertNoCallback(); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); // Enable lockdown and connect a VPN. The VPN is not blocked. mMockVpn.setAlwaysOnPackage(ALWAYS_ON_PACKAGE, true /* lockdown */, allowList); - defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent); - assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent); + defaultCallback.expect(BLOCKED_STATUS, mWiFiAgent, cb -> cb.getBlocked()); + assertBlockedCallbackInAnyOrder(callback, true, mWiFiAgent, mCellAgent); vpnUidCallback.assertNoCallback(); vpnUidDefaultCallback.assertNoCallback(); vpnDefaultCallbackAsUid.assertNoCallback(); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); @@ -9569,15 +9985,15 @@ vpnUidDefaultCallback.assertNoCallback(); // VPN does not apply to VPN_UID vpnDefaultCallbackAsUid.assertNoCallback(); assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork()); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); mMockVpn.disconnect(); - defaultCallback.expect(CallbackEntry.LOST, mMockVpn); - defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent); + defaultCallback.expect(LOST, mMockVpn); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiAgent); vpnUidCallback.assertNoCallback(); vpnUidDefaultCallback.assertNoCallback(); vpnDefaultCallbackAsUid.assertNoCallback(); @@ -9596,8 +10012,8 @@ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED); // Connect Wi-Fi. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true /* validated */); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true /* validated */); // Connect a VPN that excludes its UID from its UID ranges. final LinkProperties lp = new LinkProperties(); @@ -9606,7 +10022,7 @@ final Set<UidRange> ranges = new ArraySet<>(); ranges.add(new UidRange(0, myUid - 1)); ranges.add(new UidRange(myUid + 1, UserHandle.PER_USER_RANGE - 1)); - mMockVpn.setUnderlyingNetworks(new Network[]{mWiFiNetworkAgent.getNetwork()}); + mMockVpn.setUnderlyingNetworks(new Network[] { mWiFiAgent.getNetwork() }); mMockVpn.establish(lp, myUid, ranges); // Wait for validation before registering callbacks. @@ -9628,8 +10044,8 @@ perUidCb.expectAvailableCallbacksValidated(mMockVpn); // getActiveNetwork is not affected by this bug. assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetworkForUid(myUid + 1)); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(myUid)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(myUid)); doAsUid(otherUid, () -> mCm.unregisterNetworkCallback(otherUidCb)); mCm.unregisterNetworkCallback(defaultCb); @@ -9712,11 +10128,11 @@ cellLp.setInterfaceName("rmnet0"); cellLp.addLinkAddress(new LinkAddress("2001:db8::1/64")); cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, "rmnet0")); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); - mCellNetworkAgent.connect(false /* validated */); - callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); - defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); - systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent.connect(false /* validated */); + callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellAgent); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellAgent); + systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellAgent); waitForIdle(); assertNull(mMockVpn.getAgent()); @@ -9725,37 +10141,36 @@ // TODO: consider fixing this. cellLp.addLinkAddress(new LinkAddress("192.0.2.2/25")); cellLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "rmnet0")); - mCellNetworkAgent.sendLinkProperties(cellLp); - callback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); - defaultCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); - systemDefaultCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, - mCellNetworkAgent); + mCellAgent.sendLinkProperties(cellLp); + callback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); + defaultCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); + systemDefaultCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); waitForIdle(); assertNull(mMockVpn.getAgent()); // Disconnect, then try again with a network that supports IPv4 at connection time. // Expect lockdown VPN to come up. ExpectedBroadcast b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED); - mCellNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mCellNetworkAgent); - defaultCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); - systemDefaultCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + callback.expect(LOST, mCellAgent); + defaultCallback.expect(LOST, mCellAgent); + systemDefaultCallback.expect(LOST, mCellAgent); b1.expectBroadcast(); // When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten // with the state of the VPN network. So expect a CONNECTING broadcast. b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTING); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); - mCellNetworkAgent.connect(false /* validated */); - callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); - defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); - systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent.connect(false /* validated */); + callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellAgent); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellAgent); + systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellAgent); b1.expectBroadcast(); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED); - assertExtraInfoFromCmBlocked(mCellNetworkAgent); + assertExtraInfoFromCmBlocked(mCellAgent); // TODO: it would be nice if we could simply rely on the production code here, and have // LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with @@ -9773,7 +10188,7 @@ mMockVpn.expectStartLegacyVpnRunner(); b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED); ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED); - establishLegacyLockdownVpn(mCellNetworkAgent.getNetwork()); + establishLegacyLockdownVpn(mCellAgent.getNetwork()); callback.expectAvailableThenValidatedCallbacks(mMockVpn); defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn); systemDefaultCallback.assertNoCallback(); @@ -9784,7 +10199,7 @@ assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); - assertExtraInfoFromCmPresent(mCellNetworkAgent); + assertExtraInfoFromCmPresent(mCellAgent); assertTrue(vpnNc.hasTransport(TRANSPORT_VPN)); assertTrue(vpnNc.hasTransport(TRANSPORT_CELLULAR)); assertFalse(vpnNc.hasTransport(TRANSPORT_WIFI)); @@ -9799,13 +10214,13 @@ final NetworkCapabilities wifiNc = new NetworkCapabilities(); wifiNc.addTransportType(TRANSPORT_WIFI); wifiNc.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc); b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED); // Wifi is CONNECTING because the VPN isn't up yet. b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTING); ExpectedBroadcast b3 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED); - mWiFiNetworkAgent.connect(false /* validated */); + mWiFiAgent.connect(false /* validated */); b1.expectBroadcast(); b2.expectBroadcast(); b3.expectBroadcast(); @@ -9816,23 +10231,23 @@ // connected, so the network is not considered blocked by the lockdown UID ranges? But the // fact that a VPN is connected should only result in the VPN itself being unblocked, not // any other network. Bug in isUidBlockedByVpn? - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - callback.expect(CallbackEntry.LOST, mMockVpn); - defaultCallback.expect(CallbackEntry.LOST, mMockVpn); - defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent); - systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + callback.expect(LOST, mMockVpn); + defaultCallback.expect(LOST, mMockVpn); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiAgent); + systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // While the VPN is reconnecting on the new network, everything is blocked. assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED); - assertExtraInfoFromCmBlocked(mWiFiNetworkAgent); + assertExtraInfoFromCmBlocked(mWiFiAgent); // The VPN comes up again on wifi. b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED); b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED); - establishLegacyLockdownVpn(mWiFiNetworkAgent.getNetwork()); + establishLegacyLockdownVpn(mWiFiAgent.getNetwork()); callback.expectAvailableThenValidatedCallbacks(mMockVpn); defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn); systemDefaultCallback.assertNoCallback(); @@ -9842,7 +10257,7 @@ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); - assertExtraInfoFromCmPresent(mWiFiNetworkAgent); + assertExtraInfoFromCmPresent(mWiFiAgent); vpnNc = mCm.getNetworkCapabilities(mMockVpn.getNetwork()); assertTrue(vpnNc.hasTransport(TRANSPORT_VPN)); assertTrue(vpnNc.hasTransport(TRANSPORT_WIFI)); @@ -9850,8 +10265,8 @@ assertTrue(vpnNc.hasCapability(NET_CAPABILITY_NOT_METERED)); // Disconnect cell. Nothing much happens since it's not the default network. - mCellNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + callback.expect(LOST, mCellAgent); defaultCallback.assertNoCallback(); systemDefaultCallback.assertNoCallback(); @@ -9859,20 +10274,21 @@ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); - assertExtraInfoFromCmPresent(mWiFiNetworkAgent); + assertExtraInfoFromCmPresent(mWiFiAgent); b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED); b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED); - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - systemDefaultCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); + systemDefaultCallback.expect(LOST, mWiFiAgent); b1.expectBroadcast(); - callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI)); + callback.expectCaps(mMockVpn, c -> !c.hasTransport(TRANSPORT_WIFI)); mMockVpn.expectStopVpnRunnerPrivileged(); - callback.expect(CallbackEntry.LOST, mMockVpn); + callback.expect(LOST, mMockVpn); b2.expectBroadcast(); VMSHandlerThread.quitSafely(); + VMSHandlerThread.join(); } @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2) @@ -9954,6 +10370,50 @@ } } + private void doTestSetFirewallChainEnabledCloseSocket(final int chain, + final boolean isAllowList) throws Exception { + reset(mDestroySocketsWrapper); + + mCm.setFirewallChainEnabled(chain, true /* enabled */); + final Set<Integer> uids = + new ArraySet<>(List.of(TEST_PACKAGE_UID, TEST_PACKAGE_UID2)); + if (isAllowList) { + final Set<Range<Integer>> range = new ArraySet<>( + List.of(new Range<>(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE))); + verify(mDestroySocketsWrapper).destroyLiveTcpSockets(range, uids); + } else { + verify(mDestroySocketsWrapper).destroyLiveTcpSocketsByOwnerUids(uids); + } + + mCm.setFirewallChainEnabled(chain, false /* enabled */); + verifyNoMoreInteractions(mDestroySocketsWrapper); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testSetFirewallChainEnabledCloseSocket() throws Exception { + doReturn(new ArraySet<>(Arrays.asList(TEST_PACKAGE_UID, TEST_PACKAGE_UID2))) + .when(mBpfNetMaps) + .getUidsWithDenyRuleOnDenyListChain(anyInt()); + doReturn(new ArraySet<>(Arrays.asList(TEST_PACKAGE_UID, TEST_PACKAGE_UID2))) + .when(mBpfNetMaps) + .getUidsWithAllowRuleOnAllowListChain(anyInt()); + + final boolean allowlist = true; + final boolean denylist = false; + + doReturn(true).when(mBpfNetMaps).isFirewallAllowList(anyInt()); + doTestSetFirewallChainEnabledCloseSocket(FIREWALL_CHAIN_DOZABLE, allowlist); + doTestSetFirewallChainEnabledCloseSocket(FIREWALL_CHAIN_POWERSAVE, allowlist); + doTestSetFirewallChainEnabledCloseSocket(FIREWALL_CHAIN_RESTRICTED, allowlist); + doTestSetFirewallChainEnabledCloseSocket(FIREWALL_CHAIN_LOW_POWER_STANDBY, allowlist); + + doReturn(false).when(mBpfNetMaps).isFirewallAllowList(anyInt()); + doTestSetFirewallChainEnabledCloseSocket(FIREWALL_CHAIN_STANDBY, denylist); + doTestSetFirewallChainEnabledCloseSocket(FIREWALL_CHAIN_OEM_DENY_1, denylist); + doTestSetFirewallChainEnabledCloseSocket(FIREWALL_CHAIN_OEM_DENY_2, denylist); + doTestSetFirewallChainEnabledCloseSocket(FIREWALL_CHAIN_OEM_DENY_3, denylist); + } + private void doTestReplaceFirewallChain(final int chain) { final int[] uids = new int[] {1001, 1002}; mCm.replaceFirewallChain(chain, uids); @@ -10016,32 +10476,32 @@ callbackWithoutCap); // Setup networks with testing capability and verify the default network changes. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.addCapability(testCap); - mCellNetworkAgent.connect(true); - callbackWithCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - callbackWithoutCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId)); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.addCapability(testCap); + mCellAgent.connect(true); + callbackWithCap.expectAvailableThenValidatedCallbacks(mCellAgent); + callbackWithoutCap.expectAvailableThenValidatedCallbacks(mCellAgent); + verify(mMockNetd).networkSetDefault(eq(mCellAgent.getNetwork().netId)); reset(mMockNetd); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(testCap); - mWiFiNetworkAgent.connect(true); - callbackWithCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - callbackWithoutCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); - verify(mMockNetd).networkSetDefault(eq(mWiFiNetworkAgent.getNetwork().netId)); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.addCapability(testCap); + mWiFiAgent.connect(true); + callbackWithCap.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + callbackWithoutCap.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); + verify(mMockNetd).networkSetDefault(eq(mWiFiAgent.getNetwork().netId)); reset(mMockNetd); // Remove the testing capability on wifi, verify the callback and default network // changes back to cellular. - mWiFiNetworkAgent.removeCapability(testCap); - callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent); - callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent); - verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId)); + mWiFiAgent.removeCapability(testCap); + callbackWithCap.expectAvailableCallbacksValidated(mCellAgent); + callbackWithoutCap.expectCaps(mWiFiAgent, c -> !c.hasCapability(testCap)); + verify(mMockNetd).networkSetDefault(eq(mCellAgent.getNetwork().netId)); reset(mMockNetd); - mCellNetworkAgent.removeCapability(testCap); - callbackWithCap.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.removeCapability(testCap); + callbackWithCap.expect(LOST, mCellAgent); callbackWithoutCap.assertNoCallback(); verify(mMockNetd).networkClearDefault(); @@ -10054,8 +10514,8 @@ public final void testBatteryStatsNetworkType() throws Exception { final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName("cell0"); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent.connect(true); waitForIdle(); final ArrayTrackRecord<ReportedInterfaces>.ReadHead readHead = mDeps.mReportedInterfaceHistory.newReadHead(); @@ -10065,24 +10525,24 @@ final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName("wifi0"); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + mWiFiAgent.connect(true); waitForIdle(); assertNotNull(readHead.poll(TIMEOUT_MS, ri -> ri.contentEquals(mServiceContext, wifiLp.getInterfaceName(), new int[] { TRANSPORT_WIFI }))); - mCellNetworkAgent.disconnect(); - mWiFiNetworkAgent.disconnect(); + mCellAgent.disconnect(); + mWiFiAgent.disconnect(); cellLp.setInterfaceName("wifi0"); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent.connect(true); waitForIdle(); assertNotNull(readHead.poll(TIMEOUT_MS, ri -> ri.contentEquals(mServiceContext, cellLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR }))); - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); } /** @@ -10121,11 +10581,22 @@ return event; } + private void verifyWakeupModifyInterface(String iface, boolean add) throws RemoteException { + if (add) { + verify(mMockNetd).wakeupAddInterface(eq(iface), anyString(), anyInt(), + anyInt()); + } else { + verify(mMockNetd).wakeupDelInterface(eq(iface), anyString(), anyInt(), + anyInt()); + } + } + private <T> T verifyWithOrder(@Nullable InOrder inOrder, @NonNull T t) { if (inOrder != null) { return inOrder.verify(t); } else { - return verify(t); + // times(1) for consistency with the above. InOrder#verify always implies times(1). + return verify(t, times(1)); } } @@ -10139,7 +10610,7 @@ private void verifyClatdStart(@Nullable InOrder inOrder, @NonNull String iface, int netId, @NonNull String nat64Prefix) throws Exception { - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { verifyWithOrder(inOrder, mClatCoordinator) .clatStart(eq(iface), eq(netId), eq(new IpPrefix(nat64Prefix))); } else { @@ -10149,7 +10620,7 @@ private void verifyNeverClatdStart(@Nullable InOrder inOrder, @NonNull String iface) throws Exception { - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { verifyNeverWithOrder(inOrder, mClatCoordinator).clatStart(eq(iface), anyInt(), any()); } else { verifyNeverWithOrder(inOrder, mMockNetd).clatdStart(eq(iface), anyString()); @@ -10158,7 +10629,7 @@ private void verifyClatdStop(@Nullable InOrder inOrder, @NonNull String iface) throws Exception { - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { verifyWithOrder(inOrder, mClatCoordinator).clatStop(); } else { verifyWithOrder(inOrder, mMockNetd).clatdStop(eq(iface)); @@ -10167,13 +10638,28 @@ private void verifyNeverClatdStop(@Nullable InOrder inOrder, @NonNull String iface) throws Exception { - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { verifyNeverWithOrder(inOrder, mClatCoordinator).clatStop(); } else { verifyNeverWithOrder(inOrder, mMockNetd).clatdStop(eq(iface)); } } + private void expectNativeNetworkCreated(int netId, int permission, String iface, + InOrder inOrder) throws Exception { + verifyWithOrder(inOrder, mMockNetd).networkCreate(nativeNetworkConfigPhysical(netId, + permission)); + verifyWithOrder(inOrder, mMockDnsResolver).createNetworkCache(eq(netId)); + if (iface != null) { + verifyWithOrder(inOrder, mMockNetd).networkAddInterface(netId, iface); + } + } + + private void expectNativeNetworkCreated(int netId, int permission, String iface) + throws Exception { + expectNativeNetworkCreated(netId, permission, iface, null /* inOrder */); + } + @Test public void testStackedLinkProperties() throws Exception { final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24"); @@ -10203,26 +10689,23 @@ cellLp.addLinkAddress(myIpv6); cellLp.addRoute(ipv6Default); cellLp.addRoute(ipv6Subnet); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); reset(mClatCoordinator); // Connect with ipv6 link properties. Expect prefix discovery to be started. - mCellNetworkAgent.connect(true); - int cellNetId = mCellNetworkAgent.getNetwork().netId; + mCellAgent.connect(true); + int cellNetId = mCellAgent.getNetwork().netId; waitForIdle(); - verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(cellNetId, - INetd.PERMISSION_NONE)); + expectNativeNetworkCreated(cellNetId, INetd.PERMISSION_NONE, MOBILE_IFNAME); assertRoutesAdded(cellNetId, ipv6Subnet, ipv6Default); - verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId)); - verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME); final ArrayTrackRecord<ReportedInterfaces>.ReadHead readHead = mDeps.mReportedInterfaceHistory.newReadHead(); assertNotNull(readHead.poll(TIMEOUT_MS, ri -> ri.contentEquals(mServiceContext, cellLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR }))); - networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + networkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId); // Switching default network updates TCP buffer sizes. @@ -10230,8 +10713,8 @@ // Add an IPv4 address. Expect prefix discovery to be stopped. Netd doesn't tell us that // the NAT64 prefix was removed because one was never discovered. cellLp.addLinkAddress(myIpv4); - mCellNetworkAgent.sendLinkProperties(cellLp); - networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + mCellAgent.sendLinkProperties(cellLp); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); assertRoutesAdded(cellNetId, ipv4Subnet); verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any()); @@ -10253,37 +10736,37 @@ // Remove IPv4 address. Expect prefix discovery to be started again. cellLp.removeLinkAddress(myIpv4); - mCellNetworkAgent.sendLinkProperties(cellLp); - networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + mCellAgent.sendLinkProperties(cellLp); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId); assertRoutesRemoved(cellNetId, ipv4Subnet); // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started. - Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent); - assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix()); + Nat464Xlat clat = getNat464Xlat(mCellAgent); + assertNull(mCm.getLinkProperties(mCellAgent.getNetwork()).getNat64Prefix()); mService.mResolverUnsolEventCallback.onNat64PrefixEvent( makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96)); LinkProperties lpBeforeClat = networkCallback.expect( - CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp(); + LINK_PROPERTIES_CHANGED, mCellAgent).getLp(); assertEquals(0, lpBeforeClat.getStackedLinks().size()); assertEquals(kNat64Prefix, lpBeforeClat.getNat64Prefix()); verifyClatdStart(null /* inOrder */, MOBILE_IFNAME, cellNetId, kNat64Prefix.toString()); // Clat iface comes up. Expect stacked link to be added. clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true); - networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); - List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork()) + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); + List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellAgent.getNetwork()) .getStackedLinks(); assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0)); assertRoutesAdded(cellNetId, stackedDefault); verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_MOBILE_IFNAME); // Change trivial linkproperties and see if stacked link is preserved. cellLp.addDnsServer(InetAddress.getByName("8.8.8.8")); - mCellNetworkAgent.sendLinkProperties(cellLp); - networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + mCellAgent.sendLinkProperties(cellLp); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); List<LinkProperties> stackedLpsAfterChange = - mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks(); + mCm.getLinkProperties(mCellAgent.getNetwork()).getStackedLinks(); assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST); assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0)); @@ -10306,19 +10789,19 @@ // Expect clatd to be stopped and started with the new prefix. mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent( cellNetId, PREFIX_OPERATION_ADDED, kOtherNat64PrefixString, 96)); - networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, - (lp) -> lp.getStackedLinks().size() == 0); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent, + cb -> cb.getLp().getStackedLinks().size() == 0); verifyClatdStop(null /* inOrder */, MOBILE_IFNAME); assertRoutesRemoved(cellNetId, stackedDefault); verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_MOBILE_IFNAME); verifyClatdStart(null /* inOrder */, MOBILE_IFNAME, cellNetId, kOtherNat64Prefix.toString()); - networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, - (lp) -> lp.getNat64Prefix().equals(kOtherNat64Prefix)); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent, + cb -> cb.getLp().getNat64Prefix().equals(kOtherNat64Prefix)); clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true); - networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, - (lp) -> lp.getStackedLinks().size() == 1); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent, + cb -> cb.getLp().getStackedLinks().size() == 1); assertRoutesAdded(cellNetId, stackedDefault); verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_MOBILE_IFNAME); reset(mMockNetd); @@ -10328,15 +10811,15 @@ // linkproperties are cleaned up. cellLp.addLinkAddress(myIpv4); cellLp.addRoute(ipv4Subnet); - mCellNetworkAgent.sendLinkProperties(cellLp); - networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + mCellAgent.sendLinkProperties(cellLp); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); assertRoutesAdded(cellNetId, ipv4Subnet); verifyClatdStop(null /* inOrder */, MOBILE_IFNAME); verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId); // As soon as stop is called, the linkproperties lose the stacked interface. - networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); - LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork()); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); + LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellAgent.getNetwork()); LinkProperties expected = new LinkProperties(cellLp); expected.setNat64Prefix(kOtherNat64Prefix); assertEquals(expected, actualLpAfterIpv4); @@ -10347,6 +10830,11 @@ clat.interfaceRemoved(CLAT_MOBILE_IFNAME); networkCallback.assertNoCallback(); verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_MOBILE_IFNAME); + + if (mDeps.isAtLeastU()) { + verifyWakeupModifyInterface(CLAT_MOBILE_IFNAME, false); + } + verifyNoMoreInteractions(mMockNetd); verifyNoMoreInteractions(mClatCoordinator); verifyNoMoreInteractions(mMockDnsResolver); @@ -10359,49 +10847,70 @@ // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone. mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent( cellNetId, PREFIX_OPERATION_REMOVED, kOtherNat64PrefixString, 96)); - networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, - (lp) -> lp.getNat64Prefix() == null); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent, + cb -> cb.getLp().getNat64Prefix() == null); // Remove IPv4 address and expect prefix discovery and clatd to be started again. cellLp.removeLinkAddress(myIpv4); cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME)); cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8")); - mCellNetworkAgent.sendLinkProperties(cellLp); - networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + mCellAgent.sendLinkProperties(cellLp); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); assertRoutesRemoved(cellNetId, ipv4Subnet); // Directly-connected routes auto-added. verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId); mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent( cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96)); - networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); verifyClatdStart(null /* inOrder */, MOBILE_IFNAME, cellNetId, kNat64Prefix.toString()); // Clat iface comes up. Expect stacked link to be added. clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true); - networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, - (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent, + cb -> cb.getLp().getStackedLinks().size() == 1 + && cb.getLp().getNat64Prefix() != null); assertRoutesAdded(cellNetId, stackedDefault); verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_MOBILE_IFNAME); + if (mDeps.isAtLeastU()) { + verifyWakeupModifyInterface(CLAT_MOBILE_IFNAME, true); + } + // NAT64 prefix is removed. Expect that clat is stopped. mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent( cellNetId, PREFIX_OPERATION_REMOVED, kNat64PrefixString, 96)); - networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, - (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent, + cb -> cb.getLp().getStackedLinks().size() == 0 + && cb.getLp().getNat64Prefix() == null); assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault); // Stop has no effect because clat is already stopped. verifyClatdStop(null /* inOrder */, MOBILE_IFNAME); - networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, - (lp) -> lp.getStackedLinks().size() == 0); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent, + cb -> cb.getLp().getStackedLinks().size() == 0); verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_MOBILE_IFNAME); verify(mMockNetd, times(1)).interfaceGetCfg(CLAT_MOBILE_IFNAME); + + if (mDeps.isAtLeastU()) { + verifyWakeupModifyInterface(CLAT_MOBILE_IFNAME, false); + } + // Clean up. - mCellNetworkAgent.disconnect(); - networkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + networkCallback.expect(LOST, mCellAgent); networkCallback.assertNoCallback(); verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(), eq(Integer.toString(TRANSPORT_CELLULAR))); verify(mMockNetd).networkDestroy(cellNetId); + if (mDeps.isAtLeastU()) { + verify(mMockNetd).setNetworkAllowlist(any()); + } else { + verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + if (mDeps.isAtLeastU()) { + verifyWakeupModifyInterface(MOBILE_IFNAME, false); + } + verifyNoMoreInteractions(mMockNetd); verifyNoMoreInteractions(mClatCoordinator); reset(mMockNetd); @@ -10413,44 +10922,65 @@ doReturn(getClatInterfaceConfigParcel(myIpv4)).when(mMockNetd) .interfaceGetCfg(CLAT_MOBILE_IFNAME); cellLp.setNat64Prefix(kNat64Prefix); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); - mCellNetworkAgent.connect(false /* validated */); - networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); - cellNetId = mCellNetworkAgent.getNetwork().netId; + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent.connect(false /* validated */); + networkCallback.expectAvailableCallbacksUnvalidated(mCellAgent); + cellNetId = mCellAgent.getNetwork().netId; verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(cellNetId, INetd.PERMISSION_NONE)); assertRoutesAdded(cellNetId, ipv6Subnet, ipv6Default); // Clatd is started and clat iface comes up. Expect stacked link to be added. verifyClatdStart(null /* inOrder */, MOBILE_IFNAME, cellNetId, kNat64Prefix.toString()); - clat = getNat464Xlat(mCellNetworkAgent); + clat = getNat464Xlat(mCellAgent); clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true /* up */); - networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, - (lp) -> lp.getStackedLinks().size() == 1 - && lp.getNat64Prefix().equals(kNat64Prefix)); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent, + cb -> cb.getLp().getStackedLinks().size() == 1 + && cb.getLp().getNat64Prefix().equals(kNat64Prefix)); verify(mMockNetd).networkAddInterface(cellNetId, CLAT_MOBILE_IFNAME); // assertRoutesAdded sees all calls since last mMockNetd reset, so expect IPv6 routes again. assertRoutesAdded(cellNetId, ipv6Subnet, ipv6Default, stackedDefault); + + if (mDeps.isAtLeastU()) { + verifyWakeupModifyInterface(MOBILE_IFNAME, true); + } + reset(mMockNetd); reset(mClatCoordinator); // Disconnect the network. clat is stopped and the network is destroyed. - mCellNetworkAgent.disconnect(); - networkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + networkCallback.expect(LOST, mCellAgent); networkCallback.assertNoCallback(); verifyClatdStop(null /* inOrder */, MOBILE_IFNAME); + + if (mDeps.isAtLeastU()) { + verifyWakeupModifyInterface(CLAT_MOBILE_IFNAME, false); + } + verify(mMockNetd).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(), eq(Integer.toString(TRANSPORT_CELLULAR))); verify(mMockNetd).networkDestroy(cellNetId); + if (mDeps.isAtLeastU()) { + verify(mMockNetd).setNetworkAllowlist(any()); + } else { + verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + if (mDeps.isAtLeastU()) { + verifyWakeupModifyInterface(MOBILE_IFNAME, false); + } + verifyNoMoreInteractions(mMockNetd); verifyNoMoreInteractions(mClatCoordinator); mCm.unregisterNetworkCallback(networkCallback); } - private void expectNat64PrefixChange(TestableNetworkCallback callback, + private void expectNat64PrefixChange(TestNetworkCallback callback, TestNetworkAgentWrapper agent, IpPrefix prefix) { - callback.expectLinkPropertiesThat(agent, x -> Objects.equals(x.getNat64Prefix(), prefix)); + callback.expect(LINK_PROPERTIES_CHANGED, agent, + x -> Objects.equals(x.getLp().getNat64Prefix(), prefix)); } @Test @@ -10480,11 +11010,11 @@ // prefix discovery is never started. LinkProperties lp = new LinkProperties(baseLp); lp.setNat64Prefix(pref64FromRa); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); - mWiFiNetworkAgent.connect(false); - final Network network = mWiFiNetworkAgent.getNetwork(); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); + mWiFiAgent.connect(false); + final Network network = mWiFiAgent.getNetwork(); int netId = network.getNetId(); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); verifyClatdStart(inOrder, iface, netId, pref64FromRa.toString()); inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString()); inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId); @@ -10493,8 +11023,8 @@ // If the RA prefix is withdrawn, clatd is stopped and prefix discovery is started. lp.setNat64Prefix(null); - mWiFiNetworkAgent.sendLinkProperties(lp); - expectNat64PrefixChange(callback, mWiFiNetworkAgent, null); + mWiFiAgent.sendLinkProperties(lp); + expectNat64PrefixChange(callback, mWiFiAgent, null); verifyClatdStop(inOrder, iface); inOrder.verify(mMockDnsResolver).setPrefix64(netId, ""); inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId); @@ -10502,8 +11032,8 @@ // If the RA prefix appears while DNS discovery is in progress, discovery is stopped and // clatd is started with the prefix from the RA. lp.setNat64Prefix(pref64FromRa); - mWiFiNetworkAgent.sendLinkProperties(lp); - expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa); + mWiFiAgent.sendLinkProperties(lp); + expectNat64PrefixChange(callback, mWiFiAgent, pref64FromRa); verifyClatdStart(inOrder, iface, netId, pref64FromRa.toString()); inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId); inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString()); @@ -10511,21 +11041,21 @@ // Withdraw the RA prefix so we can test the case where an RA prefix appears after DNS // discovery has succeeded. lp.setNat64Prefix(null); - mWiFiNetworkAgent.sendLinkProperties(lp); - expectNat64PrefixChange(callback, mWiFiNetworkAgent, null); + mWiFiAgent.sendLinkProperties(lp); + expectNat64PrefixChange(callback, mWiFiAgent, null); verifyClatdStop(inOrder, iface); inOrder.verify(mMockDnsResolver).setPrefix64(netId, ""); inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId); mService.mResolverUnsolEventCallback.onNat64PrefixEvent( makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96)); - expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns); + expectNat64PrefixChange(callback, mWiFiAgent, pref64FromDns); verifyClatdStart(inOrder, iface, netId, pref64FromDns.toString()); // If an RA advertises the same prefix that was discovered by DNS, nothing happens: prefix // discovery is not stopped, and there are no callbacks. lp.setNat64Prefix(pref64FromDns); - mWiFiNetworkAgent.sendLinkProperties(lp); + mWiFiAgent.sendLinkProperties(lp); callback.assertNoCallback(); verifyNeverClatdStop(inOrder, iface); verifyNeverClatdStart(inOrder, iface); @@ -10535,7 +11065,7 @@ // If the RA is later withdrawn, nothing happens again. lp.setNat64Prefix(null); - mWiFiNetworkAgent.sendLinkProperties(lp); + mWiFiAgent.sendLinkProperties(lp); callback.assertNoCallback(); verifyNeverClatdStop(inOrder, iface); verifyNeverClatdStart(inOrder, iface); @@ -10545,8 +11075,8 @@ // If the RA prefix changes, clatd is restarted and prefix discovery is stopped. lp.setNat64Prefix(pref64FromRa); - mWiFiNetworkAgent.sendLinkProperties(lp); - expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa); + mWiFiAgent.sendLinkProperties(lp); + expectNat64PrefixChange(callback, mWiFiAgent, pref64FromRa); verifyClatdStop(inOrder, iface); inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId); @@ -10560,8 +11090,8 @@ // If the RA prefix changes, clatd is restarted and prefix discovery is not started. lp.setNat64Prefix(newPref64FromRa); - mWiFiNetworkAgent.sendLinkProperties(lp); - expectNat64PrefixChange(callback, mWiFiNetworkAgent, newPref64FromRa); + mWiFiAgent.sendLinkProperties(lp); + expectNat64PrefixChange(callback, mWiFiAgent, newPref64FromRa); verifyClatdStop(inOrder, iface); inOrder.verify(mMockDnsResolver).setPrefix64(netId, ""); verifyClatdStart(inOrder, iface, netId, newPref64FromRa.toString()); @@ -10571,7 +11101,7 @@ // If the RA prefix changes to the same value, nothing happens. lp.setNat64Prefix(newPref64FromRa); - mWiFiNetworkAgent.sendLinkProperties(lp); + mWiFiAgent.sendLinkProperties(lp); callback.assertNoCallback(); assertEquals(newPref64FromRa, mCm.getLinkProperties(network).getNat64Prefix()); verifyNeverClatdStop(inOrder, iface); @@ -10585,19 +11115,19 @@ // If the same prefix is learned first by DNS and then by RA, and clat is later stopped, // (e.g., because the network disconnects) setPrefix64(netid, "") is never called. lp.setNat64Prefix(null); - mWiFiNetworkAgent.sendLinkProperties(lp); - expectNat64PrefixChange(callback, mWiFiNetworkAgent, null); + mWiFiAgent.sendLinkProperties(lp); + expectNat64PrefixChange(callback, mWiFiAgent, null); verifyClatdStop(inOrder, iface); inOrder.verify(mMockDnsResolver).setPrefix64(netId, ""); inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId); mService.mResolverUnsolEventCallback.onNat64PrefixEvent( makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96)); - expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns); + expectNat64PrefixChange(callback, mWiFiAgent, pref64FromDns); verifyClatdStart(inOrder, iface, netId, pref64FromDns.toString()); inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any()); lp.setNat64Prefix(pref64FromDns); - mWiFiNetworkAgent.sendLinkProperties(lp); + mWiFiAgent.sendLinkProperties(lp); callback.assertNoCallback(); verifyNeverClatdStop(inOrder, iface); verifyNeverClatdStart(inOrder, iface); @@ -10609,8 +11139,8 @@ // before CONNECTIVITY_ACTION is sent. Wait for CONNECTIVITY_ACTION before verifying that // clat has been stopped, or the test will be flaky. ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED); - mWiFiNetworkAgent.disconnect(); - callback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.disconnect(); + callback.expect(LOST, mWiFiAgent); b.expectBroadcast(); verifyClatdStop(inOrder, iface); @@ -10637,17 +11167,17 @@ cellLp.setInterfaceName(MOBILE_IFNAME); cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64")); cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, MOBILE_IFNAME)); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.sendLinkProperties(cellLp); - mCellNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - final int cellNetId = mCellNetworkAgent.getNetwork().netId; + mCellAgent.sendLinkProperties(cellLp); + mCellAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + final int cellNetId = mCellAgent.getNetwork().netId; waitForIdle(); verify(mMockDnsResolver, never()).startPrefix64Discovery(cellNetId); - Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent); + Nat464Xlat clat = getNat464Xlat(mCellAgent); assertTrue("Nat464Xlat was not IDLE", !clat.isStarted()); // This cannot happen because prefix discovery cannot succeed if it is never started. @@ -10667,25 +11197,25 @@ .build(); mCm.registerNetworkCallback(networkRequest, networkCallback); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); - mCellNetworkAgent.sendLinkProperties(cellLp); - mCellNetworkAgent.connect(true); - networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent.sendLinkProperties(cellLp); + mCellAgent.connect(true); + networkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(), eq(Integer.toString(TRANSPORT_CELLULAR))); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); - mWiFiNetworkAgent.sendLinkProperties(wifiLp); + mWiFiAgent.sendLinkProperties(wifiLp); // Network switch - mWiFiNetworkAgent.connect(true); - networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - networkCallback.expectLosing(mCellNetworkAgent); - networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + mWiFiAgent.connect(true); + networkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + networkCallback.expectLosing(mCellAgent); + networkCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(), eq(Integer.toString(TRANSPORT_WIFI))); verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(), @@ -10693,8 +11223,8 @@ // Disconnect wifi and switch back to cell reset(mMockNetd); - mWiFiNetworkAgent.disconnect(); - networkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); + mWiFiAgent.disconnect(); + networkCallback.expect(LOST, mWiFiAgent); assertNoCallbacks(networkCallback); verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(), eq(Integer.toString(TRANSPORT_WIFI))); @@ -10703,13 +11233,13 @@ // reconnect wifi reset(mMockNetd); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); wifiLp.setInterfaceName(WIFI_IFNAME); - mWiFiNetworkAgent.sendLinkProperties(wifiLp); - mWiFiNetworkAgent.connect(true); - networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - networkCallback.expectLosing(mCellNetworkAgent); - networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + mWiFiAgent.sendLinkProperties(wifiLp); + mWiFiAgent.connect(true); + networkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); + networkCallback.expectLosing(mCellAgent); + networkCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(), eq(Integer.toString(TRANSPORT_WIFI))); verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(), @@ -10717,21 +11247,20 @@ // Disconnect cell reset(mMockNetd); - mCellNetworkAgent.disconnect(); - networkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + networkCallback.expect(LOST, mCellAgent); // LOST callback is triggered earlier than removing idle timer. Broadcast should also be // sent as network being switched. Ensure rule removal for cell will not be triggered // unexpectedly before network being removed. waitForIdle(); verify(mMockNetd, times(0)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(), eq(Integer.toString(TRANSPORT_CELLULAR))); - verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId)); - verify(mMockDnsResolver, times(1)) - .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId)); + verify(mMockNetd, times(1)).networkDestroy(eq(mCellAgent.getNetwork().netId)); + verify(mMockDnsResolver, times(1)).destroyNetworkCache(eq(mCellAgent.getNetwork().netId)); // Disconnect wifi ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED); - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); b.expectBroadcast(); verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(), eq(Integer.toString(TRANSPORT_WIFI))); @@ -10758,21 +11287,21 @@ final TestNetworkCallback networkCallback = new TestNetworkCallback(); mCm.registerNetworkCallback(networkRequest, networkCallback); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); reset(mMockNetd); // Switching default network updates TCP buffer sizes. - mCellNetworkAgent.connect(false); - networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + mCellAgent.connect(false); + networkCallback.expectAvailableCallbacksUnvalidated(mCellAgent); verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES); // Change link Properties should have updated tcp buffer size. LinkProperties lp = new LinkProperties(); lp.setTcpBufferSizes(testTcpBufferSizes); - mCellNetworkAgent.sendLinkProperties(lp); - networkCallback.expect(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + mCellAgent.sendLinkProperties(lp); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent); verifyTcpBufferSizeChange(testTcpBufferSizes); // Clean up. - mCellNetworkAgent.disconnect(); - networkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + networkCallback.expect(LOST, mCellAgent); networkCallback.assertNoCallback(); mCm.unregisterNetworkCallback(networkCallback); } @@ -10780,8 +11309,8 @@ @Test public void testGetGlobalProxyForNetwork() throws Exception { final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - final Network wifiNetwork = mWiFiNetworkAgent.getNetwork(); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + final Network wifiNetwork = mWiFiAgent.getNetwork(); mProxyTracker.setGlobalProxy(testProxyInfo); assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork)); } @@ -10789,15 +11318,15 @@ @Test public void testGetProxyForActiveNetwork() throws Exception { final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); waitForIdle(); assertNull(mService.getProxyForNetwork(null)); final LinkProperties testLinkProperties = new LinkProperties(); testLinkProperties.setHttpProxy(testProxyInfo); - mWiFiNetworkAgent.sendLinkProperties(testLinkProperties); + mWiFiAgent.sendLinkProperties(testLinkProperties); waitForIdle(); assertEquals(testProxyInfo, mService.getProxyForNetwork(null)); @@ -10808,8 +11337,8 @@ final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); // Set up a WiFi network with no proxy - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); waitForIdle(); assertNull(mService.getProxyForNetwork(null)); @@ -10822,7 +11351,7 @@ // Test that the VPN network returns a proxy, and the WiFi does not. assertEquals(testProxyInfo, mService.getProxyForNetwork(mMockVpn.getNetwork())); assertEquals(testProxyInfo, mService.getProxyForNetwork(null)); - assertNull(mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork())); + assertNull(mService.getProxyForNetwork(mWiFiAgent.getNetwork())); // Test that the VPN network returns no proxy when it is set to null. testLinkProperties.setHttpProxy(null); @@ -10833,7 +11362,7 @@ // Set WiFi proxy and check that the vpn proxy is still null. testLinkProperties.setHttpProxy(testProxyInfo); - mWiFiNetworkAgent.sendLinkProperties(testLinkProperties); + mWiFiAgent.sendLinkProperties(testLinkProperties); waitForIdle(); assertNull(mService.getProxyForNetwork(null)); @@ -10841,8 +11370,8 @@ // correct proxy setting. mMockVpn.disconnect(); waitForIdle(); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); - assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork())); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiAgent.getNetwork())); assertEquals(testProxyInfo, mService.getProxyForNetwork(null)); } @@ -10863,7 +11392,6 @@ verify(mBpfNetMaps, times(2)).addUidInterfaceRules(eq("tun0"), uidCaptor.capture()); assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID); assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID); - assertTrue(mService.mPermissionMonitor.getVpnInterfaceUidRanges("tun0").equals(vpnRange)); mMockVpn.disconnect(); waitForIdle(); @@ -10871,7 +11399,6 @@ // Disconnected VPN should have interface rules removed verify(mBpfNetMaps).removeUidInterfaceRules(uidCaptor.capture()); assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID); - assertNull(mService.mPermissionMonitor.getVpnInterfaceUidRanges("tun0")); } private void checkInterfaceFilteringRuleWithNullInterface(final LinkProperties lp, @@ -10881,7 +11408,7 @@ mMockVpn.establish(lp, uid, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, uid); - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { // On T and above, VPN should have rules for null interface. Null Interface is a // wildcard and this accepts traffic from all the interfaces. // There are two expected invocations, one during the VPN initial @@ -10896,8 +11423,6 @@ assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID, VPN_UID); assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID, VPN_UID); } - assertEquals(mService.mPermissionMonitor.getVpnInterfaceUidRanges(null /* iface */), - vpnRange); mMockVpn.disconnect(); waitForIdle(); @@ -10909,7 +11434,6 @@ } else { assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID, VPN_UID); } - assertNull(mService.mPermissionMonitor.getVpnInterfaceUidRanges(null /* iface */)); } else { // Before T, rules are not configured for null interface. verify(mBpfNetMaps, never()).addUidInterfaceRules(any(), any()); @@ -11021,15 +11545,15 @@ @Test public void testLinkPropertiesWithWakeOnLanForActiveNetwork() throws Exception { - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_WOL_IFNAME); wifiLp.setWakeOnLanSupported(false); // Default network switch should update ifaces. - mWiFiNetworkAgent.connect(false); - mWiFiNetworkAgent.sendLinkProperties(wifiLp); + mWiFiAgent.connect(false); + mWiFiAgent.sendLinkProperties(wifiLp); waitForIdle(); // ConnectivityService should have changed the WakeOnLanSupported to true @@ -11421,20 +11945,19 @@ .addTransportType(TRANSPORT_WIFI).build(); mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), ncTemplate); - mWiFiNetworkAgent.connect(false); + mWiFiAgent.connect(false); - wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); // Send network capabilities update with TransportInfo to trigger capabilities changed // callback. - mWiFiNetworkAgent.setNetworkCapabilities( - ncTemplate.setTransportInfo(actualTransportInfo), true); + mWiFiAgent.setNetworkCapabilities(ncTemplate.setTransportInfo(actualTransportInfo), true); - wifiNetworkCallback.expectCapabilitiesThat(mWiFiNetworkAgent, - nc -> Objects.equals(expectedOwnerUid, nc.getOwnerUid()) - && Objects.equals(expectedTransportInfo, nc.getTransportInfo())); + wifiNetworkCallback.expectCaps(mWiFiAgent, + c -> Objects.equals(expectedOwnerUid, c.getOwnerUid()) + && Objects.equals(expectedTransportInfo, c.getTransportInfo())); } @Test @@ -11461,32 +11984,31 @@ .addTransportType(TRANSPORT_WIFI) .setTransportInfo(new TestTransportInfo()); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), - ncTemplate); - mWiFiNetworkAgent.connect(true /* validated; waits for callback */); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), ncTemplate); + mWiFiAgent.connect(true /* validated; waits for callback */); // NETWORK_SETTINGS redaction is controlled by the NETWORK_SETTINGS permission - assertTrue(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted); + assertTrue(getTestTransportInfo(mWiFiAgent).settingsRedacted); withPermission(NETWORK_SETTINGS, () -> { - assertFalse(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted); + assertFalse(getTestTransportInfo(mWiFiAgent).settingsRedacted); }); - assertTrue(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted); + assertTrue(getTestTransportInfo(mWiFiAgent).settingsRedacted); // LOCAL_MAC_ADDRESS redaction is controlled by the LOCAL_MAC_ADDRESS permission - assertTrue(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted); + assertTrue(getTestTransportInfo(mWiFiAgent).localMacAddressRedacted); withPermission(LOCAL_MAC_ADDRESS, () -> { - assertFalse(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted); + assertFalse(getTestTransportInfo(mWiFiAgent).localMacAddressRedacted); }); - assertTrue(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted); + assertTrue(getTestTransportInfo(mWiFiAgent).localMacAddressRedacted); // Synchronous getNetworkCapabilities calls never return unredacted location-sensitive // information. - assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted); + assertTrue(getTestTransportInfo(mWiFiAgent).locationRedacted); setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); - assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted); + assertTrue(getTestTransportInfo(mWiFiAgent).locationRedacted); denyAllLocationPrivilegedPermissions(); - assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted); + assertTrue(getTestTransportInfo(mWiFiAgent).locationRedacted); } private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) @@ -11875,7 +12397,7 @@ @Test public void testUnderlyingNetworksWillBeSetInNetworkAgentInfoConstructor() throws Exception { - assumeTrue(SdkLevel.isAtLeastT()); + assumeTrue(mDeps.isAtLeastT()); final Network network1 = new Network(100); final Network network2 = new Network(101); final List<Network> underlyingNetworks = new ArrayList<>(); @@ -11911,9 +12433,9 @@ mCm.registerDefaultNetworkCallback(callback); final LinkProperties linkProperties = new LinkProperties(); linkProperties.setInterfaceName(INTERFACE_NAME); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, linkProperties); - mCellNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, linkProperties); + mCellAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellAgent); callback.assertNoCallback(); final NetworkRequest request = new NetworkRequest.Builder().build(); @@ -11950,10 +12472,10 @@ final NetworkCapabilities ncTemplate = new NetworkCapabilities() .addTransportType(TRANSPORT_CELLULAR) .setTransportInfo(new TestTransportInfo()); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), ncTemplate); - mCellNetworkAgent.connect(true); - callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellAgent); callback.assertNoCallback(); // Make sure a report is sent and that the caps are suitably redacted. @@ -11979,7 +12501,7 @@ // Trigger notifyDataStallSuspected() on the INetworkMonitorCallbacks instance in the // cellular network agent - mCellNetworkAgent.notifyDataStallSuspected(); + mCellAgent.notifyDataStallSuspected(); // Verify onDataStallSuspected fired verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS)).onDataStallSuspected( @@ -11990,7 +12512,7 @@ public void testConnectivityDiagnosticsCallbackOnConnectivityReported() throws Exception { setUpConnectivityDiagnosticsCallback(); - final Network n = mCellNetworkAgent.getNetwork(); + final Network n = mCellAgent.getNetwork(); final boolean hasConnectivity = true; mService.reportNetworkConnectivity(n, hasConnectivity); @@ -12023,7 +12545,7 @@ // report known Connectivity from a different uid. Verify that network is not re-validated // and this callback is not notified. - final Network n = mCellNetworkAgent.getNetwork(); + final Network n = mCellAgent.getNetwork(); final boolean hasConnectivity = true; doAsUid(Process.myUid() + 1, () -> mService.reportNetworkConnectivity(n, hasConnectivity)); @@ -12075,11 +12597,11 @@ final NetworkRequest request = new NetworkRequest.Builder().build(); final TestNetworkCallback networkCallback = new TestNetworkCallback(); mCm.registerNetworkCallback(request, networkCallback); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); reset(mMockNetd); - mCellNetworkAgent.connect(false); - networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); - final int netId = mCellNetworkAgent.getNetwork().netId; + mCellAgent.connect(false); + networkCallback.expectAvailableCallbacksUnvalidated(mCellAgent); + final int netId = mCellAgent.getNetwork().netId; final String iface = "rmnet_data0"; final InetAddress gateway = InetAddress.getByName("fe80::5678"); @@ -12096,8 +12618,9 @@ lp.addRoute(direct); lp.addRoute(rio1); lp.addRoute(defaultRoute); - mCellNetworkAgent.sendLinkProperties(lp); - networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, x -> x.getRoutes().size() == 3); + mCellAgent.sendLinkProperties(lp); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent, + x -> x.getLp().getRoutes().size() == 3); assertRoutesAdded(netId, direct, rio1, defaultRoute); reset(mMockNetd); @@ -12111,9 +12634,9 @@ assertFalse(lp.getRoutes().contains(defaultRoute)); assertTrue(lp.getRoutes().contains(defaultWithMtu)); - mCellNetworkAgent.sendLinkProperties(lp); - networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, - x -> x.getRoutes().contains(rio2)); + mCellAgent.sendLinkProperties(lp); + networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent, + x -> x.getLp().getRoutes().contains(rio2)); assertRoutesRemoved(netId, rio1); assertRoutesAdded(netId, rio2); @@ -12200,12 +12723,11 @@ private void assertVpnUidRangesUpdated(boolean add, Set<UidRange> vpnRanges, int exemptUid) throws Exception { - InOrder inOrder = inOrder(mMockNetd); - ArgumentCaptor<int[]> exemptUidCaptor = ArgumentCaptor.forClass(int[].class); + InOrder inOrder = inOrder(mMockNetd, mDestroySocketsWrapper); + final Set<Integer> exemptUidSet = new ArraySet<>(List.of(exemptUid, Process.VPN_UID)); - inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)), - exemptUidCaptor.capture()); - assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid); + inOrder.verify(mDestroySocketsWrapper).destroyLiveTcpSockets( + UidRange.toIntRanges(vpnRanges), exemptUidSet); if (add) { inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel( @@ -12217,20 +12739,19 @@ toUidRangeStableParcels(vpnRanges), PREFERENCE_ORDER_VPN)); } - inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)), - exemptUidCaptor.capture()); - assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid); + inOrder.verify(mDestroySocketsWrapper).destroyLiveTcpSockets( + UidRange.toIntRanges(vpnRanges), exemptUidSet); } @Test public void testVpnUidRangesUpdate() throws Exception { // Set up a WiFi network without proxy. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); assertNull(mService.getProxyForNetwork(null)); assertNull(mCm.getDefaultProxy()); - final ExpectedBroadcast b1 = registerPacProxyBroadcast(); + final ExpectedBroadcast b1 = expectProxyChangeAction(); final LinkProperties lp = new LinkProperties(); lp.setInterfaceName("tun0"); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); @@ -12243,7 +12764,7 @@ b1.expectNoBroadcast(500); // Update to new range which is old range minus APP1, i.e. only APP2 - final ExpectedBroadcast b2 = registerPacProxyBroadcast(); + final ExpectedBroadcast b2 = expectProxyChangeAction(); final Set<UidRange> newRanges = new HashSet<>(asList( new UidRange(vpnRange.start, APP1_UID - 1), new UidRange(APP1_UID + 1, vpnRange.stop))); @@ -12257,20 +12778,20 @@ b2.expectNoBroadcast(500); final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); - final ExpectedBroadcast b3 = registerPacProxyBroadcast(); + final ExpectedBroadcast b3 = expectProxyChangeAction(); lp.setHttpProxy(testProxyInfo); mMockVpn.sendLinkProperties(lp); waitForIdle(); // Proxy is set, so send a proxy broadcast. b3.expectBroadcast(); - final ExpectedBroadcast b4 = registerPacProxyBroadcast(); + final ExpectedBroadcast b4 = expectProxyChangeAction(); mMockVpn.setUids(vpnRanges); waitForIdle(); // Uid has changed and proxy is already set, so send a proxy broadcast. b4.expectBroadcast(); - final ExpectedBroadcast b5 = registerPacProxyBroadcast(); + final ExpectedBroadcast b5 = expectProxyChangeAction(); // Proxy is removed, send a proxy broadcast. lp.setHttpProxy(null); mMockVpn.sendLinkProperties(lp); @@ -12278,11 +12799,11 @@ b5.expectBroadcast(); // Proxy is added in WiFi(default network), setDefaultProxy will be called. - final LinkProperties wifiLp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork()); + final LinkProperties wifiLp = mCm.getLinkProperties(mWiFiAgent.getNetwork()); assertNotNull(wifiLp); final ExpectedBroadcast b6 = expectProxyChangeAction(testProxyInfo); wifiLp.setHttpProxy(testProxyInfo); - mWiFiNetworkAgent.sendLinkProperties(wifiLp); + mWiFiAgent.sendLinkProperties(wifiLp); waitForIdle(); b6.expectBroadcast(); } @@ -12290,8 +12811,8 @@ @Test public void testProxyBroadcastWillBeSentWhenVpnHasProxyAndConnects() throws Exception { // Set up a WiFi network without proxy. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); assertNull(mService.getProxyForNetwork(null)); assertNull(mCm.getDefaultProxy()); @@ -12303,7 +12824,7 @@ lp.setHttpProxy(testProxyInfo); final UidRange vpnRange = PRIMARY_UIDRANGE; final Set<UidRange> vpnRanges = Collections.singleton(vpnRange); - final ExpectedBroadcast b1 = registerPacProxyBroadcast(); + final ExpectedBroadcast b1 = expectProxyChangeAction(); mMockVpn.setOwnerAndAdminUid(VPN_UID); mMockVpn.registerAgent(false, vpnRanges, lp); // In any case, the proxy broadcast won't be sent before VPN goes into CONNECTED state. @@ -12311,8 +12832,9 @@ // proxy broadcast will get null. b1.expectNoBroadcast(500); - final ExpectedBroadcast b2 = registerPacProxyBroadcast(); - mMockVpn.connect(true /* validated */, true /* hasInternet */, false /* isStrictMode */); + final ExpectedBroadcast b2 = expectProxyChangeAction(); + mMockVpn.connect(true /* validated */, true /* hasInternet */, + false /* privateDnsProbeSent */); waitForIdle(); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); // Vpn is connected with proxy, so the proxy broadcast will be sent to inform the apps to @@ -12324,31 +12846,31 @@ public void testProxyBroadcastWillBeSentWhenTheProxyOfNonDefaultNetworkHasChanged() throws Exception { // Set up a CELLULAR network without proxy. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); assertNull(mService.getProxyForNetwork(null)); assertNull(mCm.getDefaultProxy()); // CELLULAR network should be the default network. - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); // Set up a WiFi network without proxy. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); assertNull(mService.getProxyForNetwork(null)); assertNull(mCm.getDefaultProxy()); // WiFi network should be the default network. - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetwork()); // CELLULAR network is not the default network. - assertNotEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertNotEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); // CELLULAR network is not the system default network, but it might be a per-app default // network. The proxy broadcast should be sent once its proxy has changed. final LinkProperties cellularLp = new LinkProperties(); cellularLp.setInterfaceName(MOBILE_IFNAME); final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); - final ExpectedBroadcast b = registerPacProxyBroadcast(); + final ExpectedBroadcast b = expectProxyChangeAction(); cellularLp.setHttpProxy(testProxyInfo); - mCellNetworkAgent.sendLinkProperties(cellularLp); + mCellAgent.sendLinkProperties(cellularLp); b.expectBroadcast(); } @@ -12377,66 +12899,64 @@ .build(); mCm.registerNetworkCallback(allNetworksRequest, allNetworksCb); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true /* validated */); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true /* validated */); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - allNetworksCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + allNetworksCb.expectAvailableThenValidatedCallbacks(mCellAgent); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true /* validated */); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true /* validated */); - mDefaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + mDefaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); // While the default callback doesn't see the network before it's validated, the listen // sees the network come up and validate later - allNetworksCb.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - allNetworksCb.expectLosing(mCellNetworkAgent); - allNetworksCb.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - allNetworksCb.expect(CallbackEntry.LOST, mCellNetworkAgent, - TEST_LINGER_DELAY_MS * 2); + allNetworksCb.expectAvailableCallbacksUnvalidated(mWiFiAgent); + allNetworksCb.expectLosing(mCellAgent); + allNetworksCb.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED)); + allNetworksCb.expect(LOST, mCellAgent, TEST_LINGER_DELAY_MS * 2); // The cell network has disconnected (see LOST above) because it was outscored and // had no requests (see setAlwaysOnNetworks(false) above) - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); final NetworkScore score = new NetworkScore.Builder().setLegacyInt(30).build(); - mCellNetworkAgent.setScore(score); - mCellNetworkAgent.connect(false /* validated */); + mCellAgent.setScore(score); + mCellAgent.connect(false /* validated */); // The cell network gets torn down right away. - allNetworksCb.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); - allNetworksCb.expect(CallbackEntry.LOST, mCellNetworkAgent, - TEST_NASCENT_DELAY_MS * 2); + allNetworksCb.expectAvailableCallbacksUnvalidated(mCellAgent); + allNetworksCb.expect(LOST, mCellAgent, TEST_NASCENT_DELAY_MS * 2); allNetworksCb.assertNoCallback(); // Now create a cell network with KEEP_CONNECTED_FOR_HANDOVER and make sure it's // not disconnected immediately when outscored. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); final NetworkScore scoreKeepup = new NetworkScore.Builder().setLegacyInt(30) .setKeepConnectedReason(KEEP_CONNECTED_FOR_HANDOVER).build(); - mCellNetworkAgent.setScore(scoreKeepup); - mCellNetworkAgent.connect(true /* validated */); + mCellAgent.setScore(scoreKeepup); + mCellAgent.connect(true /* validated */); - allNetworksCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + allNetworksCb.expectAvailableThenValidatedCallbacks(mCellAgent); mDefaultNetworkCallback.assertNoCallback(); - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); - allNetworksCb.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - mDefaultNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + allNetworksCb.expect(LOST, mWiFiAgent); + mDefaultNetworkCallback.expect(LOST, mWiFiAgent); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); // Reconnect a WiFi network and make sure the cell network is still not torn down. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true /* validated */); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true /* validated */); - allNetworksCb.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - mDefaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + allNetworksCb.expectAvailableThenValidatedCallbacks(mWiFiAgent); + mDefaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); // Now remove the reason to keep connected and make sure the network lingers and is // torn down. - mCellNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(30).build()); - allNetworksCb.expectLosing(mCellNetworkAgent, TEST_NASCENT_DELAY_MS * 2); - allNetworksCb.expect(CallbackEntry.LOST, mCellNetworkAgent, TEST_LINGER_DELAY_MS * 2); + mCellAgent.setScore(new NetworkScore.Builder().setLegacyInt(30).build()); + allNetworksCb.expectLosing(mCellAgent, TEST_NASCENT_DELAY_MS * 2); + allNetworksCb.expect(LOST, mCellAgent, TEST_LINGER_DELAY_MS * 2); mDefaultNetworkCallback.assertNoCallback(); mCm.unregisterNetworkCallback(allNetworksCb); @@ -12454,21 +12974,21 @@ mFilter = mock(QosFilter.class); // Ensure the network is disconnected before anything else occurs - assertNull(mCellNetworkAgent); + assertNull(mCellAgent); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); verifyActiveNetwork(TRANSPORT_CELLULAR); waitForIdle(); - final Network network = mCellNetworkAgent.getNetwork(); + final Network network = mCellAgent.getNetwork(); final Pair<IQosCallback, IBinder> pair = createQosCallback(); mCallback = pair.first; doReturn(network).when(mFilter).getNetwork(); doReturn(QosCallbackException.EX_TYPE_FILTER_NONE).when(mFilter).validate(); - mAgentWrapper = mCellNetworkAgent; + mAgentWrapper = mCellAgent; } void registerQosCallback(@NonNull final QosFilter filter, @@ -13058,12 +13578,12 @@ // Corresponds to a metered cellular network. Will be used for the default network. case TRANSPORT_CELLULAR: if (!connectAgent) { - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); break; } - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.removeCapability(NET_CAPABILITY_NOT_METERED); + mCellAgent.connect(true); break; // Corresponds to a restricted ethernet network with OEM_PAID/OEM_PRIVATE. case TRANSPORT_ETHERNET: @@ -13076,12 +13596,12 @@ // Corresponds to unmetered Wi-Fi. case TRANSPORT_WIFI: if (!connectAgent) { - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); break; } - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.connect(true); break; default: throw new AssertionError("Unsupported transport type passed in."); @@ -13091,15 +13611,15 @@ } private void startOemManagedNetwork(final boolean isOemPaid) throws Exception { - mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); - mEthernetNetworkAgent.addCapability( + mEthernetAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); + mEthernetAgent.addCapability( isOemPaid ? NET_CAPABILITY_OEM_PAID : NET_CAPABILITY_OEM_PRIVATE); - mEthernetNetworkAgent.removeCapability(NET_CAPABILITY_NOT_RESTRICTED); - mEthernetNetworkAgent.connect(true); + mEthernetAgent.removeCapability(NET_CAPABILITY_NOT_RESTRICTED); + mEthernetAgent.connect(true); } private void stopOemManagedNetwork() { - mEthernetNetworkAgent.disconnect(); + mEthernetAgent.disconnect(); waitForIdle(); } @@ -13332,7 +13852,7 @@ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, null, - mEthernetNetworkAgent.getNetwork()); + mEthernetAgent.getNetwork()); // Verify that the active network is correct verifyActiveNetwork(TRANSPORT_ETHERNET); @@ -13353,16 +13873,16 @@ assertTrue(mCm.isActiveNetworkMetered()); // Connect to an unmetered restricted network that will only be available to the OEM pref. - mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); - mEthernetNetworkAgent.addCapability(NET_CAPABILITY_OEM_PAID); - mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mEthernetNetworkAgent.removeCapability(NET_CAPABILITY_NOT_RESTRICTED); - mEthernetNetworkAgent.connect(true); + mEthernetAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); + mEthernetAgent.addCapability(NET_CAPABILITY_OEM_PAID); + mEthernetAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mEthernetAgent.removeCapability(NET_CAPABILITY_NOT_RESTRICTED); + mEthernetAgent.connect(true); waitForIdle(); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, null, - mEthernetNetworkAgent.getNetwork()); + mEthernetAgent.getNetwork()); assertFalse(mCm.isActiveNetworkMetered()); // default NCs will be unregistered in tearDown @@ -13393,19 +13913,18 @@ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, null, - mEthernetNetworkAgent.getNetwork()); + mEthernetAgent.getNetwork()); // At this point with a restricted network used, the available callback should trigger. - defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); - assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), - mEthernetNetworkAgent.getNetwork()); + defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetAgent); + assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mEthernetAgent.getNetwork()); otherUidDefaultCallback.assertNoCallback(); // Now bring down the default network which should trigger a LOST callback. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); // At this point, with no network is available, the lost callback should trigger - defaultNetworkCallback.expect(CallbackEntry.LOST, mEthernetNetworkAgent); + defaultNetworkCallback.expect(LOST, mEthernetAgent); otherUidDefaultCallback.assertNoCallback(); // Confirm we can unregister without issues. @@ -13438,12 +13957,11 @@ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, null, - mEthernetNetworkAgent.getNetwork()); + mEthernetAgent.getNetwork()); // At this point with a restricted network used, the available callback should trigger - defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); - assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), - mEthernetNetworkAgent.getNetwork()); + defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetAgent); + assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mEthernetAgent.getNetwork()); otherUidDefaultCallback.assertNoCallback(); // Now bring down the default network which should trigger a LOST callback. @@ -13451,7 +13969,7 @@ otherUidDefaultCallback.assertNoCallback(); // At this point, with no network is available, the lost callback should trigger - defaultNetworkCallback.expect(CallbackEntry.LOST, mEthernetNetworkAgent); + defaultNetworkCallback.expect(LOST, mEthernetAgent); otherUidDefaultCallback.assertNoCallback(); // Confirm we can unregister without issues. @@ -13484,27 +14002,26 @@ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, null, - mEthernetNetworkAgent.getNetwork()); + mEthernetAgent.getNetwork()); // As this callback does not have access to the OEM_PAID network, it will not fire. defaultNetworkCallback.assertNoCallback(); assertDefaultNetworkCapabilities(userId /* no networks */); // The other UID does have access, and gets a callback. - otherUidDefaultCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); + otherUidDefaultCallback.expectAvailableThenValidatedCallbacks(mEthernetAgent); // Bring up unrestricted cellular. This should now satisfy the default network. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mCellAgent.getNetwork(), + mEthernetAgent.getNetwork()); // At this point with an unrestricted network used, the available callback should trigger // The other UID is unaffected and remains on the paid network. - defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), - mCellNetworkAgent.getNetwork()); - assertDefaultNetworkCapabilities(userId, mCellNetworkAgent); + defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCellAgent.getNetwork()); + assertDefaultNetworkCapabilities(userId, mCellAgent); otherUidDefaultCallback.assertNoCallback(); // Now bring down the per-app network. @@ -13513,13 +14030,13 @@ // Since the callback didn't use the per-app network, only the other UID gets a callback. // Because the preference specifies no fallback, it does not switch to cellular. defaultNetworkCallback.assertNoCallback(); - otherUidDefaultCallback.expect(CallbackEntry.LOST, mEthernetNetworkAgent); + otherUidDefaultCallback.expect(LOST, mEthernetAgent); // Now bring down the default network. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false); // As this callback was tracking the default, this should now trigger. - defaultNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + defaultNetworkCallback.expect(LOST, mCellAgent); otherUidDefaultCallback.assertNoCallback(); // Confirm we can unregister without issues. @@ -13672,22 +14189,22 @@ // Bring up metered cellular. This will satisfy the fallback network. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); verifySetOemNetworkPreferenceForPreference(uidRanges, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, OEM_PREF_ANY_NET_ID, 0 /* times */, false /* shouldDestroyNetwork */); // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); verifySetOemNetworkPreferenceForPreference(uidRanges, - mEthernetNetworkAgent.getNetwork().netId, 1 /* times */, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, + mEthernetAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, false /* shouldDestroyNetwork */); // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true); verifySetOemNetworkPreferenceForPreference(uidRanges, - mWiFiNetworkAgent.getNetwork().netId, 1 /* times */, - mEthernetNetworkAgent.getNetwork().netId, 1 /* times */, + mWiFiAgent.getNetwork().netId, 1 /* times */, + mEthernetAgent.getNetwork().netId, 1 /* times */, false /* shouldDestroyNetwork */); // Disconnecting OEM_PAID should have no effect as it is lower in priority then unmetered. @@ -13701,15 +14218,15 @@ // Disconnecting unmetered should put PANS on lowest priority fallback request. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false); verifySetOemNetworkPreferenceForPreference(uidRanges, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, - mWiFiNetworkAgent.getNetwork().netId, 0 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, + mWiFiAgent.getNetwork().netId, 0 /* times */, true /* shouldDestroyNetwork */); // Disconnecting the fallback network should result in no connectivity. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false); verifySetOemNetworkPreferenceForPreference(uidRanges, OEM_PREF_ANY_NET_ID, 0 /* times */, - mCellNetworkAgent.getNetwork().netId, 0 /* times */, + mCellAgent.getNetwork().netId, 0 /* times */, true /* shouldDestroyNetwork */); } @@ -13747,22 +14264,22 @@ // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); verifySetOemNetworkPreferenceForPreference(uidRanges, - mEthernetNetworkAgent.getNetwork().netId, 1 /* times */, + mEthernetAgent.getNetwork().netId, 1 /* times */, mService.mNoServiceNetwork.network.getNetId(), 1 /* times */, false /* shouldDestroyNetwork */); // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true); verifySetOemNetworkPreferenceForPreference(uidRanges, - mWiFiNetworkAgent.getNetwork().netId, 1 /* times */, - mEthernetNetworkAgent.getNetwork().netId, 1 /* times */, + mWiFiAgent.getNetwork().netId, 1 /* times */, + mEthernetAgent.getNetwork().netId, 1 /* times */, false /* shouldDestroyNetwork */); // Disconnecting unmetered should put PANS on OEM_PAID. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false); verifySetOemNetworkPreferenceForPreference(uidRanges, - mEthernetNetworkAgent.getNetwork().netId, 1 /* times */, - mWiFiNetworkAgent.getNetwork().netId, 0 /* times */, + mEthernetAgent.getNetwork().netId, 1 /* times */, + mWiFiAgent.getNetwork().netId, 0 /* times */, true /* shouldDestroyNetwork */); // Disconnecting OEM_PAID should result in no connectivity. @@ -13770,7 +14287,7 @@ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); verifySetOemNetworkPreferenceForPreference(uidRanges, mService.mNoServiceNetwork.network.getNetId(), 1 /* times */, - mEthernetNetworkAgent.getNetwork().netId, 0 /* times */, + mEthernetAgent.getNetwork().netId, 0 /* times */, true /* shouldDestroyNetwork */); } @@ -13814,7 +14331,7 @@ // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); verifySetOemNetworkPreferenceForPreference(uidRanges, - mEthernetNetworkAgent.getNetwork().netId, 1 /* times */, + mEthernetAgent.getNetwork().netId, 1 /* times */, mService.mNoServiceNetwork.network.getNetId(), 1 /* times */, false /* shouldDestroyNetwork */); @@ -13822,7 +14339,7 @@ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); verifySetOemNetworkPreferenceForPreference(uidRanges, mService.mNoServiceNetwork.network.getNetId(), 1 /* times */, - mEthernetNetworkAgent.getNetwork().netId, 0 /* times */, + mEthernetAgent.getNetwork().netId, 0 /* times */, true /* shouldDestroyNetwork */); } @@ -13866,7 +14383,7 @@ // Bring up ethernet with OEM_PRIVATE. This will satisfy NET_CAPABILITY_OEM_PRIVATE. startOemManagedNetwork(false); verifySetOemNetworkPreferenceForPreference(uidRanges, - mEthernetNetworkAgent.getNetwork().netId, 1 /* times */, + mEthernetAgent.getNetwork().netId, 1 /* times */, mService.mNoServiceNetwork.network.getNetId(), 1 /* times */, false /* shouldDestroyNetwork */); @@ -13874,7 +14391,7 @@ stopOemManagedNetwork(); verifySetOemNetworkPreferenceForPreference(uidRanges, mService.mNoServiceNetwork.network.getNetId(), 1 /* times */, - mEthernetNetworkAgent.getNetwork().netId, 0 /* times */, + mEthernetAgent.getNetwork().netId, 0 /* times */, true /* shouldDestroyNetwork */); } @@ -13907,7 +14424,7 @@ // Test that we correctly add the expected values for multiple users. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); verifySetOemNetworkPreferenceForPreference(uidRanges, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, OEM_PREF_ANY_NET_ID, 0 /* times */, false /* shouldDestroyNetwork */); @@ -13915,7 +14432,7 @@ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false); verifySetOemNetworkPreferenceForPreference(uidRanges, OEM_PREF_ANY_NET_ID, 0 /* times */, - mCellNetworkAgent.getNetwork().netId, 0 /* times */, + mCellAgent.getNetwork().netId, 0 /* times */, true /* shouldDestroyNetwork */); } @@ -13950,7 +14467,7 @@ // Test that we correctly add the expected values for multiple users. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, OEM_PREF_ANY_NET_ID, 0 /* times */, false /* shouldDestroyNetwork */); @@ -13963,8 +14480,8 @@ // Test that we correctly add values for all users and remove for the single user. verifySetOemNetworkPreferenceForPreference(uidRangesBothUsers, uidRangesSingleUser, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, false /* shouldDestroyNetwork */); // Send a broadcast indicating a user was removed. @@ -13975,8 +14492,8 @@ // Test that we correctly add values for the single user and remove for the all users. verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser, uidRangesBothUsers, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, false /* shouldDestroyNetwork */); } @@ -14006,7 +14523,7 @@ // Test that we correctly add the expected values for installed packages. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, OEM_PREF_ANY_NET_ID, 0 /* times */, false /* shouldDestroyNetwork */); @@ -14022,8 +14539,8 @@ // Test the single package is removed and the combined packages are added. verifySetOemNetworkPreferenceForPreference(uidRangesAllPackages, uidRangesSinglePackage, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, false /* shouldDestroyNetwork */); // Set the system to no longer recognize the package to be installed @@ -14036,8 +14553,8 @@ // Test the combined packages are removed and the single package is added. verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage, uidRangesAllPackages, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, false /* shouldDestroyNetwork */); // Set the system to change the installed package's uid @@ -14053,8 +14570,8 @@ // Test the original uid is removed and is replaced with the new uid. verifySetOemNetworkPreferenceForPreference(uidRangesReplacedPackage, uidRangesSinglePackage, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, - mCellNetworkAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, + mCellAgent.getNetwork().netId, 1 /* times */, false /* shouldDestroyNetwork */); } @@ -14079,32 +14596,32 @@ // Bring up metered cellular. This will satisfy the fallback network. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), - mCellNetworkAgent.getNetwork()); + mCellAgent.getNetwork(), + mCellAgent.getNetwork()); // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mCellAgent.getNetwork(), + mEthernetAgent.getNetwork()); // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mWiFiNetworkAgent.getNetwork(), - mWiFiNetworkAgent.getNetwork()); + mWiFiAgent.getNetwork(), + mWiFiAgent.getNetwork()); // Disconnecting unmetered Wi-Fi will put the pref on OEM_PAID and fallback on cellular. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mCellAgent.getNetwork(), + mEthernetAgent.getNetwork()); // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, null, - mEthernetNetworkAgent.getNetwork()); + mEthernetAgent.getNetwork()); // Disconnecting OEM_PAID will put both on null as it is the last network. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); @@ -14152,8 +14669,8 @@ oemPaidFactory.register(); oemPaidFactory.expectRequestAdd(); // Because nobody satisfies the request - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); // A network connected that satisfies the default internet request. For the OEM_PAID // preference, this is not as good as an OEM_PAID network, so even if the score of @@ -14188,7 +14705,7 @@ expectNoRequestChanged(internetFactory); internetFactory.assertRequestCountEquals(0); - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); // The network satisfying the default internet request has disconnected, so the // internetFactory sees the default request again. However there is a network with OEM_PAID // connected, so the 2nd OEM_PAID req is already satisfied, so the oemPaidFactory doesn't @@ -14199,8 +14716,8 @@ internetFactory.assertRequestCountEquals(1); // Cell connects again, still with score 50. Back to the previous state. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); expectNoRequestChanged(oemPaidFactory); oemPaidFactory.assertRequestCountEquals(1); internetFactory.expectRequestRemove(); @@ -14212,18 +14729,18 @@ wifiCallback); // Now WiFi connects and it's unmetered, but it's weaker than cell. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(30).setExiting(true) + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiAgent.setScore(new NetworkScore.Builder().setLegacyInt(30).setExiting(true) .build()); // Not the best Internet network, but unmetered - mWiFiNetworkAgent.connect(true); + mWiFiAgent.connect(true); // The OEM_PAID preference prefers an unmetered network to an OEM_PAID network, so // the oemPaidFactory can't beat wifi no matter how high its score. oemPaidFactory.expectRequestRemove(); expectNoRequestChanged(internetFactory); - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); // Now that the best internet network (cell, with its 50 score compared to 30 for WiFi // at this point), the default internet request is satisfied by a network worse than // the internetFactory announced, so it gets the request. However, there is still an @@ -14254,32 +14771,32 @@ // Bring up metered cellular. This will satisfy the fallback network but not the pref. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), + mCellAgent.getNetwork(), mService.mNoServiceNetwork.network()); // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mCellAgent.getNetwork(), + mEthernetAgent.getNetwork()); // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mWiFiNetworkAgent.getNetwork(), - mWiFiNetworkAgent.getNetwork()); + mWiFiAgent.getNetwork(), + mWiFiAgent.getNetwork()); // Disconnecting unmetered Wi-Fi will put the OEM pref on OEM_PAID and fallback on cellular. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mCellAgent.getNetwork(), + mEthernetAgent.getNetwork()); // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, null, - mEthernetNetworkAgent.getNetwork()); + mEthernetAgent.getNetwork()); // Disconnecting OEM_PAID puts the fallback on null and the pref on the disconnected net. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); @@ -14312,32 +14829,32 @@ // Bring up metered cellular. This will satisfy the fallback network. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), + mCellAgent.getNetwork(), mService.mNoServiceNetwork.network()); // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mCellAgent.getNetwork(), + mEthernetAgent.getNetwork()); // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mWiFiNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mWiFiAgent.getNetwork(), + mEthernetAgent.getNetwork()); // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mCellAgent.getNetwork(), + mEthernetAgent.getNetwork()); // Disconnecting OEM_PAID will keep the fallback on cellular and nothing for OEM_PAID. // OEM_PAID_ONLY not supporting a fallback now uses the disconnected network. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), + mCellAgent.getNetwork(), mService.mNoServiceNetwork.network()); // Disconnecting cellular will put the fallback on null and the pref on disconnected. @@ -14371,32 +14888,32 @@ // Bring up metered cellular. This will satisfy the fallback network. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), + mCellAgent.getNetwork(), mService.mNoServiceNetwork.network()); // Bring up ethernet with OEM_PRIVATE. This will satisfy NET_CAPABILITY_OEM_PRIVATE. startOemManagedNetwork(false); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mCellAgent.getNetwork(), + mEthernetAgent.getNetwork()); // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mWiFiNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mWiFiAgent.getNetwork(), + mEthernetAgent.getNetwork()); // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular. setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), - mEthernetNetworkAgent.getNetwork()); + mCellAgent.getNetwork(), + mEthernetAgent.getNetwork()); // Disconnecting OEM_PRIVATE will keep the fallback on cellular. // OEM_PRIVATE_ONLY not supporting a fallback now uses to the disconnected network. stopOemManagedNetwork(); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, - mCellNetworkAgent.getNetwork(), + mCellAgent.getNetwork(), mService.mNoServiceNetwork.network()); // Disconnecting cellular will put the fallback on null and pref on disconnected. @@ -14417,14 +14934,14 @@ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); - mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); - mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); - mSystemDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc -> - nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - mDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc -> - nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + mCellAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); + mSystemDefaultNetworkCallback.expectCaps(mCellAgent, + c -> c.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + mDefaultNetworkCallback.expectCaps(mCellAgent, + c -> c.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); // default callbacks will be unregistered in tearDown } @@ -14478,29 +14995,29 @@ final TestNetworkCallback cellCb = new TestNetworkCallback(); mCm.requestNetwork(new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(), cellCb); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp, cellNcTemplate); - mCellNetworkAgent.connect(true); - cellCb.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp, cellNcTemplate); + mCellAgent.connect(true); + cellCb.expectAvailableCallbacksUnvalidated(mCellAgent); List<NetworkStateSnapshot> snapshots = mCm.getAllNetworkStateSnapshots(); assertLength(1, snapshots); // Compose the expected cellular snapshot for verification. final NetworkCapabilities cellNc = - mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()); + mCm.getNetworkCapabilities(mCellAgent.getNetwork()); final NetworkStateSnapshot cellSnapshot = new NetworkStateSnapshot( - mCellNetworkAgent.getNetwork(), cellNc, cellLp, + mCellAgent.getNetwork(), cellNc, cellLp, null, ConnectivityManager.TYPE_MOBILE); assertEquals(cellSnapshot, snapshots.get(0)); // Connect wifi and verify the snapshots. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); waitForIdle(); // Compose the expected wifi snapshot for verification. final NetworkCapabilities wifiNc = - mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()); + mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()); final NetworkStateSnapshot wifiSnapshot = new NetworkStateSnapshot( - mWiFiNetworkAgent.getNetwork(), wifiNc, new LinkProperties(), null, + mWiFiAgent.getNetwork(), wifiNc, new LinkProperties(), null, ConnectivityManager.TYPE_WIFI); snapshots = mCm.getAllNetworkStateSnapshots(); @@ -14508,33 +15025,33 @@ assertContainsAll(snapshots, cellSnapshot, wifiSnapshot); // Set cellular as suspended, verify the snapshots will contain suspended networks. - mCellNetworkAgent.suspend(); + mCellAgent.suspend(); waitForIdle(); final NetworkCapabilities cellSuspendedNc = - mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()); + mCm.getNetworkCapabilities(mCellAgent.getNetwork()); assertFalse(cellSuspendedNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); final NetworkStateSnapshot cellSuspendedSnapshot = new NetworkStateSnapshot( - mCellNetworkAgent.getNetwork(), cellSuspendedNc, cellLp, + mCellAgent.getNetwork(), cellSuspendedNc, cellLp, null, ConnectivityManager.TYPE_MOBILE); snapshots = mCm.getAllNetworkStateSnapshots(); assertLength(2, snapshots); assertContainsAll(snapshots, cellSuspendedSnapshot, wifiSnapshot); // Disconnect wifi, verify the snapshots contain only cellular. - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); waitForIdle(); snapshots = mCm.getAllNetworkStateSnapshots(); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetwork()); assertLength(1, snapshots); assertEquals(cellSuspendedSnapshot, snapshots.get(0)); - mCellNetworkAgent.resume(); + mCellAgent.resume(); waitForIdle(); snapshots = mCm.getAllNetworkStateSnapshots(); assertLength(1, snapshots); assertEquals(cellSnapshot, snapshots.get(0)); - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); waitForIdle(); verifyNoNetwork(); mCm.unregisterNetworkCallback(cellCb); @@ -14605,35 +15122,35 @@ new NetworkRequest.Builder().addCapability(NET_CAPABILITY_TRUSTED).build(), bestMatchingCb, mCsHandlerThread.getThreadHandler()); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - bestMatchingCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + bestMatchingCb.expectAvailableThenValidatedCallbacks(mCellAgent); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mWiFiAgent); // Change something on cellular to trigger capabilities changed, since the callback // only cares about the best network, verify it received nothing from cellular. - mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); + mCellAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); bestMatchingCb.assertNoCallback(); // Make cellular the best network again, verify the callback now tracks cellular. - mWiFiNetworkAgent.adjustScore(-50); - bestMatchingCb.expectAvailableCallbacksValidated(mCellNetworkAgent); + mWiFiAgent.adjustScore(-50); + bestMatchingCb.expectAvailableCallbacksValidated(mCellAgent); // Make cellular temporary non-trusted, which will not satisfying the request. // Verify the callback switch from/to the other network accordingly. - mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED); - bestMatchingCb.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - mCellNetworkAgent.addCapability(NET_CAPABILITY_TRUSTED); - bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mCellNetworkAgent); + mCellAgent.removeCapability(NET_CAPABILITY_TRUSTED); + bestMatchingCb.expectAvailableCallbacksValidated(mWiFiAgent); + mCellAgent.addCapability(NET_CAPABILITY_TRUSTED); + bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mCellAgent); // Verify the callback doesn't care about wifi disconnect. - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); bestMatchingCb.assertNoCallback(); - mCellNetworkAgent.disconnect(); - bestMatchingCb.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + bestMatchingCb.expect(LOST, mCellAgent); } private UidRangeParcel[] uidRangeFor(final UserHandle handle) { @@ -14728,25 +15245,32 @@ UserHandle testHandle, TestNetworkCallback profileDefaultNetworkCallback, TestNetworkCallback disAllowProfileDefaultNetworkCallback) throws Exception { - final InOrder inOrder = inOrder(mMockNetd); + final InOrder inOrder = inOrder(mMockNetd, mMockDnsResolver); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); - mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - profileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + profileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); if (disAllowProfileDefaultNetworkCallback != null) { - disAllowProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks( - mCellNetworkAgent); + disAllowProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); } inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( - mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); + mCellAgent.getNetwork().netId, INetd.PERMISSION_NONE)); final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent(profileNetworkPreference.getPreferenceEnterpriseId()); + if (mService.shouldCreateNetworksImmediately()) { + expectNativeNetworkCreated(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM, + null /* iface */, inOrder); + } if (connectWorkProfileAgentAhead) { workAgent.connect(false); + if (!mService.shouldCreateNetworksImmediately()) { + expectNativeNetworkCreated(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM, + null /* iface */, inOrder); + } } final TestOnCompleteListener listener = new TestOnCompleteListener(); @@ -14768,7 +15292,7 @@ // system default is not handled specially, the rules are always active as long as // a preference is set. inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig( - mCellNetworkAgent.getNetwork().netId, + mCellAgent.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreference), PREFERENCE_ORDER_PROFILE)); } @@ -14778,7 +15302,7 @@ if (allowFallback && !connectWorkProfileAgentAhead) { assertNoCallbacks(profileDefaultNetworkCallback); } else if (!connectWorkProfileAgentAhead) { - profileDefaultNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + profileDefaultNetworkCallback.expect(LOST, mCellAgent); if (disAllowProfileDefaultNetworkCallback != null) { assertNoCallbacks(disAllowProfileDefaultNetworkCallback); } @@ -14786,6 +15310,11 @@ if (!connectWorkProfileAgentAhead) { workAgent.connect(false); + if (!mService.shouldCreateNetworksImmediately()) { + inOrder.verify(mMockNetd).networkCreate( + nativeNetworkConfigPhysical(workAgent.getNetwork().netId, + INetd.PERMISSION_SYSTEM)); + } } profileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent); @@ -14794,8 +15323,6 @@ } mSystemDefaultNetworkCallback.assertNoCallback(); mDefaultNetworkCallback.assertNoCallback(); - inOrder.verify(mMockNetd).networkCreate( - nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM)); inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig( workAgent.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreference), @@ -14803,29 +15330,28 @@ if (allowFallback && !connectWorkProfileAgentAhead) { inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig( - mCellNetworkAgent.getNetwork().netId, + mCellAgent.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreference), PREFERENCE_ORDER_PROFILE)); } // Make sure changes to the work agent send callbacks to the app in the work profile, but // not to the other apps. - workAgent.setNetworkValid(true /* isStrictMode */); + workAgent.setNetworkValid(true /* privateDnsProbeSent */); workAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); - profileDefaultNetworkCallback.expectCapabilitiesThat(workAgent, - nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED) - && nc.hasCapability(NET_CAPABILITY_ENTERPRISE) - && nc.hasEnterpriseId( - profileNetworkPreference.getPreferenceEnterpriseId()) - && nc.getEnterpriseIds().length == 1); + profileDefaultNetworkCallback.expectCaps(workAgent, + c -> c.hasCapability(NET_CAPABILITY_VALIDATED) + && c.hasCapability(NET_CAPABILITY_ENTERPRISE) + && c.hasEnterpriseId(profileNetworkPreference.getPreferenceEnterpriseId()) + && c.getEnterpriseIds().length == 1); if (disAllowProfileDefaultNetworkCallback != null) { assertNoCallbacks(disAllowProfileDefaultNetworkCallback); } assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback); workAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); - profileDefaultNetworkCallback.expectCapabilitiesThat(workAgent, nc -> - nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + profileDefaultNetworkCallback.expectCaps(workAgent, + c -> c.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); if (disAllowProfileDefaultNetworkCallback != null) { assertNoCallbacks(disAllowProfileDefaultNetworkCallback); } @@ -14833,49 +15359,47 @@ // Conversely, change a capability on the system-wide default network and make sure // that only the apps outside of the work profile receive the callbacks. - mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); - mSystemDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc -> - nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - mDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc -> - nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + mCellAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); + mSystemDefaultNetworkCallback.expectCaps(mCellAgent, + c -> c.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + mDefaultNetworkCallback.expectCaps(mCellAgent, + c -> c.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); if (disAllowProfileDefaultNetworkCallback != null) { - disAllowProfileDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc -> - nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + disAllowProfileDefaultNetworkCallback.expectCaps(mCellAgent, + c -> c.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); } profileDefaultNetworkCallback.assertNoCallback(); // Disconnect and reconnect the system-wide default network and make sure that the // apps on this network see the appropriate callbacks, and the app on the work profile // doesn't because it continues to use the enterprise network. - mCellNetworkAgent.disconnect(); - mSystemDefaultNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); - mDefaultNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + mSystemDefaultNetworkCallback.expect(LOST, mCellAgent); + mDefaultNetworkCallback.expect(LOST, mCellAgent); if (disAllowProfileDefaultNetworkCallback != null) { - disAllowProfileDefaultNetworkCallback.expect( - CallbackEntry.LOST, mCellNetworkAgent); + disAllowProfileDefaultNetworkCallback.expect(LOST, mCellAgent); } profileDefaultNetworkCallback.assertNoCallback(); - inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId); + inOrder.verify(mMockNetd).networkDestroy(mCellAgent.getNetwork().netId); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); if (disAllowProfileDefaultNetworkCallback != null) { - disAllowProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks( - mCellNetworkAgent); + disAllowProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); } profileDefaultNetworkCallback.assertNoCallback(); inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( - mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); + mCellAgent.getNetwork().netId, INetd.PERMISSION_NONE)); // When the agent disconnects, test that the app on the work profile falls back to the // default network. workAgent.disconnect(); - profileDefaultNetworkCallback.expect(CallbackEntry.LOST, workAgent); + profileDefaultNetworkCallback.expect(LOST, workAgent); if (allowFallback) { - profileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + profileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); if (disAllowProfileDefaultNetworkCallback != null) { assertNoCallbacks(disAllowProfileDefaultNetworkCallback); } @@ -14883,27 +15407,26 @@ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback); if (allowFallback) { inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig( - mCellNetworkAgent.getNetwork().netId, + mCellAgent.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreference), PREFERENCE_ORDER_PROFILE)); } inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId); - mCellNetworkAgent.disconnect(); - mSystemDefaultNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); - mDefaultNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + mSystemDefaultNetworkCallback.expect(LOST, mCellAgent); + mDefaultNetworkCallback.expect(LOST, mCellAgent); if (disAllowProfileDefaultNetworkCallback != null) { - disAllowProfileDefaultNetworkCallback.expect( - CallbackEntry.LOST, mCellNetworkAgent); + disAllowProfileDefaultNetworkCallback.expect(LOST, mCellAgent); } if (allowFallback) { - profileDefaultNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); + profileDefaultNetworkCallback.expect(LOST, mCellAgent); } // Waiting for the handler to be idle before checking for networkDestroy is necessary // here because ConnectivityService calls onLost before the network is fully torn down. waitForIdle(); - inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId); + inOrder.verify(mMockNetd).networkDestroy(mCellAgent.getNetwork().netId); // If the control comes here, callbacks seem to behave correctly in the presence of // a default network when the enterprise network goes up and down. Now, make sure they @@ -14923,14 +15446,13 @@ workAgent2.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreference), PREFERENCE_ORDER_PROFILE)); - workAgent2.setNetworkValid(true /* isStrictMode */); + workAgent2.setNetworkValid(true /* privateDnsProbeSent */); workAgent2.mNetworkMonitor.forceReevaluation(Process.myUid()); - profileDefaultNetworkCallback.expectCapabilitiesThat(workAgent2, - nc -> nc.hasCapability(NET_CAPABILITY_ENTERPRISE) - && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) - && nc.hasEnterpriseId( - profileNetworkPreference.getPreferenceEnterpriseId()) - && nc.getEnterpriseIds().length == 1); + profileDefaultNetworkCallback.expectCaps(workAgent2, + c -> c.hasCapability(NET_CAPABILITY_ENTERPRISE) + && !c.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) + && c.hasEnterpriseId(profileNetworkPreference.getPreferenceEnterpriseId()) + && c.getEnterpriseIds().length == 1); if (disAllowProfileDefaultNetworkCallback != null) { assertNoCallbacks(disAllowProfileDefaultNetworkCallback); } @@ -14940,7 +15462,7 @@ // When the agent disconnects, test that the app on the work profile fall back to the // default network. workAgent2.disconnect(); - profileDefaultNetworkCallback.expect(CallbackEntry.LOST, workAgent2); + profileDefaultNetworkCallback.expect(LOST, workAgent2); if (disAllowProfileDefaultNetworkCallback != null) { assertNoCallbacks(disAllowProfileDefaultNetworkCallback); } @@ -15286,23 +15808,23 @@ registerDefaultNetworkCallbackAsUid(appCb3, testWorkProfileAppUid3); // Connect both a regular cell agent and an enterprise network first. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); final TestNetworkAgentWrapper workAgent1 = makeEnterpriseNetworkAgent(NET_ENTERPRISE_ID_1); final TestNetworkAgentWrapper workAgent2 = makeEnterpriseNetworkAgent(NET_ENTERPRISE_ID_2); workAgent1.connect(true); workAgent2.connect(true); - mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); - appCb1.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - appCb2.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - appCb3.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + appCb1.expectAvailableThenValidatedCallbacks(mCellAgent); + appCb2.expectAvailableThenValidatedCallbacks(mCellAgent); + appCb3.expectAvailableThenValidatedCallbacks(mCellAgent); verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( - mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); + mCellAgent.getNetwork().netId, INetd.PERMISSION_NONE)); verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( workAgent1.getNetwork().netId, INetd.PERMISSION_SYSTEM)); verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( @@ -15369,8 +15891,8 @@ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback); appCb3.expectAvailableCallbacksValidated(workAgent1); - appCb2.expectAvailableCallbacksValidated(mCellNetworkAgent); - appCb1.expectAvailableCallbacksValidated(mCellNetworkAgent); + appCb2.expectAvailableCallbacksValidated(mCellAgent); + appCb1.expectAvailableCallbacksValidated(mCellAgent); // Set the preferences for testHandle to default. ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder = @@ -15387,9 +15909,9 @@ PREFERENCE_ORDER_PROFILE)); assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback, appCb1, appCb2); - appCb3.expectAvailableCallbacksValidated(mCellNetworkAgent); + appCb3.expectAvailableCallbacksValidated(mCellAgent); workAgent2.disconnect(); - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); mCm.unregisterNetworkCallback(appCb1); mCm.unregisterNetworkCallback(appCb2); @@ -15434,8 +15956,8 @@ registerDefaultNetworkCallbackAsUid(appCb5, testWorkProfileAppUid5); // Connect both a regular cell agent and an enterprise network first. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); final TestNetworkAgentWrapper workAgent1 = makeEnterpriseNetworkAgent(NET_ENTERPRISE_ID_1); final TestNetworkAgentWrapper workAgent2 = makeEnterpriseNetworkAgent(NET_ENTERPRISE_ID_2); @@ -15449,16 +15971,16 @@ workAgent4.connect(true); workAgent5.connect(true); - mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - appCb1.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - appCb2.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - appCb3.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - appCb4.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - appCb5.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + appCb1.expectAvailableThenValidatedCallbacks(mCellAgent); + appCb2.expectAvailableThenValidatedCallbacks(mCellAgent); + appCb3.expectAvailableThenValidatedCallbacks(mCellAgent); + appCb4.expectAvailableThenValidatedCallbacks(mCellAgent); + appCb5.expectAvailableThenValidatedCallbacks(mCellAgent); verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( - mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); + mCellAgent.getNetwork().netId, INetd.PERMISSION_NONE)); verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( workAgent1.getNetwork().netId, INetd.PERMISSION_SYSTEM)); verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( @@ -15550,36 +16072,36 @@ workAgent4.disconnect(); workAgent5.disconnect(); - appCb1.expect(CallbackEntry.LOST, workAgent1); - appCb2.expect(CallbackEntry.LOST, workAgent2); - appCb3.expect(CallbackEntry.LOST, workAgent3); - appCb4.expect(CallbackEntry.LOST, workAgent4); - appCb5.expect(CallbackEntry.LOST, workAgent5); + appCb1.expect(LOST, workAgent1); + appCb2.expect(LOST, workAgent2); + appCb3.expect(LOST, workAgent3); + appCb4.expect(LOST, workAgent4); + appCb5.expect(LOST, workAgent5); - appCb1.expectAvailableCallbacksValidated(mCellNetworkAgent); + appCb1.expectAvailableCallbacksValidated(mCellAgent); appCb2.assertNoCallback(); - appCb3.expectAvailableCallbacksValidated(mCellNetworkAgent); + appCb3.expectAvailableCallbacksValidated(mCellAgent); appCb4.assertNoCallback(); - appCb5.expectAvailableCallbacksValidated(mCellNetworkAgent); + appCb5.expectAvailableCallbacksValidated(mCellAgent); verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig( - mCellNetworkAgent.getNetwork().netId, + mCellAgent.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreferenceBuilder1.build()), PREFERENCE_ORDER_PROFILE)); verify(mMockNetd, never()).networkAddUidRangesParcel(new NativeUidRangeConfig( - mCellNetworkAgent.getNetwork().netId, + mCellAgent.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreferenceBuilder2.build()), PREFERENCE_ORDER_PROFILE)); verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig( - mCellNetworkAgent.getNetwork().netId, + mCellAgent.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreferenceBuilder3.build()), PREFERENCE_ORDER_PROFILE)); verify(mMockNetd, never()).networkAddUidRangesParcel(new NativeUidRangeConfig( - mCellNetworkAgent.getNetwork().netId, + mCellAgent.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreferenceBuilder4.build()), PREFERENCE_ORDER_PROFILE)); verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig( - mCellNetworkAgent.getNetwork().netId, + mCellAgent.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreferenceBuilder5.build()), PREFERENCE_ORDER_PROFILE)); @@ -15597,9 +16119,9 @@ listener.expectOnComplete(); assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback, appCb1, appCb3, appCb5); - appCb2.expectAvailableCallbacksValidated(mCellNetworkAgent); - appCb4.expectAvailableCallbacksValidated(mCellNetworkAgent); - mCellNetworkAgent.disconnect(); + appCb2.expectAvailableCallbacksValidated(mCellAgent); + appCb4.expectAvailableCallbacksValidated(mCellAgent); + mCellAgent.disconnect(); mCm.unregisterNetworkCallback(appCb1); mCm.unregisterNetworkCallback(appCb2); @@ -15619,8 +16141,8 @@ final UserHandle testHandle = setupEnterpriseNetwork(); // Connect both a regular cell agent and an enterprise network first. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent(); workAgent.connect(true); @@ -15630,27 +16152,27 @@ r -> r.run(), listener); listener.expectOnComplete(); inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( - mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); + mCellAgent.getNetwork().netId, INetd.PERMISSION_NONE)); inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig( workAgent.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE)); registerDefaultNetworkCallbacks(); - mSystemDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + mSystemDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent); mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_DEFAULT, r -> r.run(), listener); listener.expectOnComplete(); - mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback); inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig( workAgent.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE)); workAgent.disconnect(); - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); // Callbacks will be unregistered by tearDown() } @@ -15672,18 +16194,18 @@ registerDefaultNetworkCallbackAsUid(app4Cb, testWorkProfileAppUid4); // Connect both a regular cell agent and an enterprise network first. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent(); workAgent.connect(true); - mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - app4Cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + app4Cb.expectAvailableThenValidatedCallbacks(mCellAgent); inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( - mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); + mCellAgent.getNetwork().netId, INetd.PERMISSION_NONE)); inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM)); @@ -15714,12 +16236,12 @@ inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig( workAgent.getNetwork().netId, uidRangeFor(testHandle2), PREFERENCE_ORDER_PROFILE)); - mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback, app4Cb); workAgent.disconnect(); - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); mCm.unregisterNetworkCallback(app4Cb); // Other callbacks will be unregistered by tearDown() @@ -15730,17 +16252,17 @@ final InOrder inOrder = inOrder(mMockNetd); final UserHandle testHandle = setupEnterpriseNetwork(); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); final TestOnCompleteListener listener = new TestOnCompleteListener(); mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE, r -> r.run(), listener); listener.expectOnComplete(); inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( - mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); + mCellAgent.getNetwork().netId, INetd.PERMISSION_NONE)); inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig( - mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle), + mCellAgent.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE)); final Intent removedIntent = new Intent(ACTION_USER_REMOVED); @@ -15748,10 +16270,256 @@ processBroadcast(removedIntent); inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig( - mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle), + mCellAgent.getNetwork().netId, uidRangeFor(testHandle), PREFERENCE_ORDER_PROFILE)); } + @Test + public void testProfileNetworkPreferenceBlocking_addUser() throws Exception { + final InOrder inOrder = inOrder(mMockNetd); + doReturn(asList(PRIMARY_USER_HANDLE)).when(mUserManager).getUserHandles(anyBoolean()); + + // Only one network + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + + // Verify uid ranges 0~99999 are allowed + final ArraySet<UidRange> allowedRanges = new ArraySet<>(); + allowedRanges.add(PRIMARY_UIDRANGE); + final NativeUidRangeConfig config1User = new NativeUidRangeConfig( + mCellAgent.getNetwork().netId, + toUidRangeStableParcels(allowedRanges), + 0 /* subPriority */); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist(new NativeUidRangeConfig[]{config1User}); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + doReturn(asList(PRIMARY_USER_HANDLE, SECONDARY_USER_HANDLE)) + .when(mUserManager).getUserHandles(anyBoolean()); + final Intent addedIntent = new Intent(ACTION_USER_ADDED); + addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(SECONDARY_USER)); + processBroadcast(addedIntent); + + // Make sure the allow list has been updated. + allowedRanges.add(UidRange.createForUser(SECONDARY_USER_HANDLE)); + final NativeUidRangeConfig config2Users = new NativeUidRangeConfig( + mCellAgent.getNetwork().netId, + toUidRangeStableParcels(allowedRanges), + 0 /* subPriority */); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist(new NativeUidRangeConfig[]{config2Users}); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + } + + @Test + public void testProfileNetworkPreferenceBlocking_changePreference() throws Exception { + final InOrder inOrder = inOrder(mMockNetd); + final UserHandle testHandle = setupEnterpriseNetwork(); + doReturn(asList(PRIMARY_USER_HANDLE, testHandle)) + .when(mUserManager).getUserHandles(anyBoolean()); + + // Start with 1 default network and 1 enterprise network, both networks should + // not be restricted since the blocking preference is not set yet. + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + + // Verify uid ranges 0~99999, 200000~299999 are all allowed for cellular. + final UidRange profileUidRange = + UidRange.createForUser(UserHandle.of(TEST_WORK_PROFILE_USER_ID)); + ArraySet<UidRange> allowedAllUidRanges = new ArraySet<>(); + allowedAllUidRanges.add(PRIMARY_UIDRANGE); + allowedAllUidRanges.add(profileUidRange); + final UidRangeParcel[] allowAllUidRangesParcel = toUidRangeStableParcels( + allowedAllUidRanges); + final NativeUidRangeConfig cellAllAllowedConfig = new NativeUidRangeConfig( + mCellAgent.getNetwork().netId, + allowAllUidRangesParcel, + 0 /* subPriority */); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist( + new NativeUidRangeConfig[]{cellAllAllowedConfig}); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + // Verify the same uid ranges are also applied for enterprise network. + final TestNetworkAgentWrapper enterpriseAgent = makeEnterpriseNetworkAgent( + NET_ENTERPRISE_ID_1); + enterpriseAgent.connect(true); + final NativeUidRangeConfig enterpriseAllAllowedConfig = new NativeUidRangeConfig( + enterpriseAgent.getNetwork().netId, + allowAllUidRangesParcel, + 0 /* subPriority */); + // Network agents are stored in an ArraySet which does not guarantee the order and + // making the order of the list undeterministic. Thus, verify this in order insensitive way. + final ArgumentCaptor<NativeUidRangeConfig[]> configsCaptor = ArgumentCaptor.forClass( + NativeUidRangeConfig[].class); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture()); + assertContainsAll(List.of(configsCaptor.getValue()), + List.of(cellAllAllowedConfig, enterpriseAllAllowedConfig)); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + // Setup profile preference which only applies to test app uid on the managed profile. + ProfileNetworkPreference.Builder prefBuilder = new ProfileNetworkPreference.Builder(); + prefBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING) + .setIncludedUids(new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID)}) + .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1); + final TestOnCompleteListener listener = new TestOnCompleteListener(); + mCm.setProfileNetworkPreferences(testHandle, + List.of(prefBuilder.build()), + r -> r.run(), listener); + listener.expectOnComplete(); + + // Verify Netd is called for the preferences changed. + // Cell: 0~99999, 200000~TEST_APP_UID-1, TEST_APP_UID+1~299999 + // Enterprise: 0~99999, 200000~299999 + final ArraySet<UidRange> excludeAppRanges = new ArraySet<>(); + excludeAppRanges.add(PRIMARY_UIDRANGE); + excludeAppRanges.addAll(UidRangeUtils.removeRangeSetFromUidRange( + profileUidRange, + new ArraySet(new UidRange[]{ + (new UidRange(TEST_WORK_PROFILE_APP_UID, TEST_WORK_PROFILE_APP_UID))}) + )); + final UidRangeParcel[] excludeAppRangesParcel = toUidRangeStableParcels(excludeAppRanges); + final NativeUidRangeConfig cellExcludeAppConfig = new NativeUidRangeConfig( + mCellAgent.getNetwork().netId, + excludeAppRangesParcel, + 0 /* subPriority */); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture()); + assertContainsAll(List.of(configsCaptor.getValue()), + List.of(cellExcludeAppConfig, enterpriseAllAllowedConfig)); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + // Verify unset by giving all allowed set for all users when the preference got removed. + mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE, + r -> r.run(), listener); + listener.expectOnComplete(); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture()); + assertContainsAll(List.of(configsCaptor.getValue()), + List.of(cellAllAllowedConfig, enterpriseAllAllowedConfig)); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + // Verify issuing with cellular set only when a network with enterprise capability + // disconnects. + enterpriseAgent.disconnect(); + waitForIdle(); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist( + new NativeUidRangeConfig[]{cellAllAllowedConfig}); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + } + + @Test + public void testProfileNetworkPreferenceBlocking_networkChanges() throws Exception { + final InOrder inOrder = inOrder(mMockNetd); + final UserHandle testHandle = setupEnterpriseNetwork(); + doReturn(asList(PRIMARY_USER_HANDLE, testHandle)) + .when(mUserManager).getUserHandles(anyBoolean()); + + // Setup profile preference which only applies to test app uid on the managed profile. + ProfileNetworkPreference.Builder prefBuilder = new ProfileNetworkPreference.Builder(); + prefBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING) + .setIncludedUids(new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID)}) + .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1); + final TestOnCompleteListener listener = new TestOnCompleteListener(); + mCm.setProfileNetworkPreferences(testHandle, + List.of(prefBuilder.build()), + r -> r.run(), listener); + listener.expectOnComplete(); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist(new NativeUidRangeConfig[]{}); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + // Start with 1 default network, which should be restricted since the blocking + // preference is already set. + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + + // Verify cellular network applies to the allow list. + // Cell: 0~99999, 200000~TEST_APP_UID-1, TEST_APP_UID+1~299999 + // Enterprise: 0~99999, 200000~299999 + final ArraySet<UidRange> excludeAppRanges = new ArraySet<>(); + final UidRange profileUidRange = + UidRange.createForUser(UserHandle.of(TEST_WORK_PROFILE_USER_ID)); + excludeAppRanges.add(PRIMARY_UIDRANGE); + excludeAppRanges.addAll(UidRangeUtils.removeRangeSetFromUidRange( + profileUidRange, + new ArraySet(new UidRange[]{ + (new UidRange(TEST_WORK_PROFILE_APP_UID, TEST_WORK_PROFILE_APP_UID))}) + )); + final UidRangeParcel[] excludeAppRangesParcel = toUidRangeStableParcels(excludeAppRanges); + final NativeUidRangeConfig cellExcludeAppConfig = new NativeUidRangeConfig( + mCellAgent.getNetwork().netId, + excludeAppRangesParcel, + 0 /* subPriority */); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist( + new NativeUidRangeConfig[]{cellExcludeAppConfig}); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + // Verify enterprise network is not blocked for test app. + final TestNetworkAgentWrapper enterpriseAgent = makeEnterpriseNetworkAgent( + NET_ENTERPRISE_ID_1); + enterpriseAgent.connect(true); + ArraySet<UidRange> allowedAllUidRanges = new ArraySet<>(); + allowedAllUidRanges.add(PRIMARY_UIDRANGE); + allowedAllUidRanges.add(profileUidRange); + final UidRangeParcel[] allowAllUidRangesParcel = toUidRangeStableParcels( + allowedAllUidRanges); + final NativeUidRangeConfig enterpriseAllAllowedConfig = new NativeUidRangeConfig( + enterpriseAgent.getNetwork().netId, + allowAllUidRangesParcel, + 0 /* subPriority */); + // Network agents are stored in an ArraySet which does not guarantee the order and + // making the order of the list undeterministic. Thus, verify this in order insensitive way. + final ArgumentCaptor<NativeUidRangeConfig[]> configsCaptor = ArgumentCaptor.forClass( + NativeUidRangeConfig[].class); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture()); + assertContainsAll(List.of(configsCaptor.getValue()), + List.of(enterpriseAllAllowedConfig, cellExcludeAppConfig)); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + // Verify issuing with cellular set only when enterprise network disconnects. + enterpriseAgent.disconnect(); + waitForIdle(); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist( + new NativeUidRangeConfig[]{cellExcludeAppConfig}); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + + mCellAgent.disconnect(); + waitForIdle(); + if (mDeps.isAtLeastU()) { + inOrder.verify(mMockNetd).setNetworkAllowlist(new NativeUidRangeConfig[]{}); + } else { + inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any()); + } + } + /** * Make sure wrong preferences for per-profile default networking are rejected. */ @@ -15762,7 +16530,7 @@ ProfileNetworkPreference.Builder profileNetworkPreferenceBuilder = new ProfileNetworkPreference.Builder(); profileNetworkPreferenceBuilder.setPreference( - PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK + 1); + PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING + 1); profileNetworkPreferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1); assertThrows("Should not be able to set an illegal preference", IllegalArgumentException.class, @@ -15801,7 +16569,7 @@ profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE); profileNetworkPreferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1); final TestOnCompleteListener listener = new TestOnCompleteListener(); - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { mCm.setProfileNetworkPreferences(testHandle, List.of(profileNetworkPreferenceBuilder.build()), r -> r.run(), listener); @@ -15909,7 +16677,7 @@ agent.getNetwork().getNetId(), intToUidRangeStableParcels(uids), preferenceOrder); - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids200Parcel); } @@ -15917,8 +16685,8 @@ uids.add(400); nc.setAllowedUids(uids); agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */); - if (SdkLevel.isAtLeastT()) { - cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().equals(uids)); + if (mDeps.isAtLeastT()) { + cb.expectCaps(agent, c -> c.getAllowedUids().equals(uids)); } else { cb.assertNoCallback(); } @@ -15928,14 +16696,14 @@ agent.getNetwork().getNetId(), intToUidRangeStableParcels(uids), preferenceOrder); - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids300400Parcel); } nc.setAllowedUids(uids); agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */); - if (SdkLevel.isAtLeastT()) { - cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().equals(uids)); + if (mDeps.isAtLeastT()) { + cb.expectCaps(agent, c -> c.getAllowedUids().equals(uids)); inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids200Parcel); } else { cb.assertNoCallback(); @@ -15945,8 +16713,8 @@ uids.add(600); nc.setAllowedUids(uids); agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */); - if (SdkLevel.isAtLeastT()) { - cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().equals(uids)); + if (mDeps.isAtLeastT()) { + cb.expectCaps(agent, c -> c.getAllowedUids().equals(uids)); } else { cb.assertNoCallback(); } @@ -15954,7 +16722,7 @@ agent.getNetwork().getNetId(), intToUidRangeStableParcels(uids), preferenceOrder); - if (SdkLevel.isAtLeastT()) { + if (mDeps.isAtLeastT()) { inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids600Parcel); inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids300400Parcel); } @@ -15962,8 +16730,8 @@ uids.clear(); nc.setAllowedUids(uids); agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */); - if (SdkLevel.isAtLeastT()) { - cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().isEmpty()); + if (mDeps.isAtLeastT()) { + cb.expectCaps(agent, c -> c.getAllowedUids().isEmpty()); inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids600Parcel); } else { cb.assertNoCallback(); @@ -15997,7 +16765,7 @@ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) .removeCapability(NET_CAPABILITY_NOT_RESTRICTED); - mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET, + mEthernetAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET, new LinkProperties(), ncb.build()); final ArraySet<Integer> serviceUidSet = new ArraySet<>(); @@ -16009,22 +16777,21 @@ .addTransportType(TRANSPORT_ETHERNET) .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) .build(), cb); - mEthernetNetworkAgent.connect(true); - cb.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); + mEthernetAgent.connect(true); + cb.expectAvailableThenValidatedCallbacks(mEthernetAgent); // Cell gets to set the service UID as access UID ncb.setAllowedUids(serviceUidSet); - mEthernetNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); - if (SdkLevel.isAtLeastT() && hasAutomotiveFeature) { - cb.expectCapabilitiesThat(mEthernetNetworkAgent, - caps -> caps.getAllowedUids().equals(serviceUidSet)); + mEthernetAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); + if (mDeps.isAtLeastT() && hasAutomotiveFeature) { + cb.expectCaps(mEthernetAgent, c -> c.getAllowedUids().equals(serviceUidSet)); } else { // S and no automotive feature must ignore access UIDs. cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS); } - mEthernetNetworkAgent.disconnect(); - cb.expect(CallbackEntry.LOST, mEthernetNetworkAgent); + mEthernetAgent.disconnect(); + cb.expect(LOST, mEthernetAgent); mCm.unregisterNetworkCallback(cb); } @@ -16047,7 +16814,7 @@ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) .setNetworkSpecifier(new TelephonyNetworkSpecifier(1 /* subid */)); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), ncb.build()); final ArraySet<Integer> serviceUidSet = new ArraySet<>(); @@ -16065,13 +16832,12 @@ .addTransportType(TRANSPORT_CELLULAR) .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) .build(), cb); - mCellNetworkAgent.connect(true); - cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent.connect(true); + cb.expectAvailableThenValidatedCallbacks(mCellAgent); ncb.setAllowedUids(serviceUidSet); - mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); - if (SdkLevel.isAtLeastT()) { - cb.expectCapabilitiesThat(mCellNetworkAgent, - caps -> caps.getAllowedUids().equals(serviceUidSet)); + mCellAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); + if (mDeps.isAtLeastT()) { + cb.expectCaps(mCellAgent, c -> c.getAllowedUids().equals(serviceUidSet)); } else { // S must ignore access UIDs. cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS); @@ -16079,10 +16845,9 @@ // ...but not to some other UID. Rejection sets UIDs to the empty set ncb.setAllowedUids(nonServiceUidSet); - mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); - if (SdkLevel.isAtLeastT()) { - cb.expectCapabilitiesThat(mCellNetworkAgent, - caps -> caps.getAllowedUids().isEmpty()); + mCellAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); + if (mDeps.isAtLeastT()) { + cb.expectCaps(mCellAgent, c -> c.getAllowedUids().isEmpty()); } else { // S must ignore access UIDs. cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS); @@ -16090,11 +16855,11 @@ // ...and also not to multiple UIDs even including the service UID ncb.setAllowedUids(serviceUidSetPlus); - mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); + mCellAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS); - mCellNetworkAgent.disconnect(); - cb.expect(CallbackEntry.LOST, mCellNetworkAgent); + mCellAgent.disconnect(); + cb.expect(LOST, mCellAgent); mCm.unregisterNetworkCallback(cb); // Must be unset before touching the transports, because remove and add transport types @@ -16108,12 +16873,11 @@ .addTransportType(TRANSPORT_WIFI) .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) .build(), cb); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, - new LinkProperties(), ncb.build()); - mWiFiNetworkAgent.connect(true); - cb.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), ncb.build()); + mWiFiAgent.connect(true); + cb.expectAvailableThenValidatedCallbacks(mWiFiAgent); ncb.setAllowedUids(serviceUidSet); - mWiFiNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); + mWiFiAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS); mCm.unregisterNetworkCallback(cb); } @@ -16184,7 +16948,7 @@ final NetworkCallback[] callbacks = new NetworkCallback[remainingCount]; doAsUid(otherAppUid, () -> { for (int i = 0; i < remainingCount; ++i) { - callbacks[i] = new TestableNetworkCallback(); + callbacks[i] = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(callbacks[i]); } }); @@ -16300,12 +17064,12 @@ public void testMobileDataPreferredUidsChanged() throws Exception { final InOrder inorder = inOrder(mMockNetd); registerDefaultNetworkCallbacks(); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); - final int cellNetId = mCellNetworkAgent.getNetwork().netId; + final int cellNetId = mCellAgent.getNetwork().netId; inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical( cellNetId, INetd.PERMISSION_NONE)); @@ -16358,13 +17122,13 @@ cellNetworkCallback.assertNoCallback(); registerDefaultNetworkCallbacks(); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent); + mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); - final int wifiNetId = mWiFiNetworkAgent.getNetwork().netId; + final int wifiNetId = mWiFiAgent.getNetwork().netId; inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical( wifiNetId, INetd.PERMISSION_NONE)); @@ -16385,14 +17149,14 @@ // Cellular network connected. mTestPackageDefaultNetworkCallback should receive // callback with cellular network and net id and uid ranges should be updated to netd. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); mDefaultNetworkCallback.assertNoCallback(); - mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); - final int cellNetId = mCellNetworkAgent.getNetwork().netId; + final int cellNetId = mCellAgent.getNetwork().netId; final NativeUidRangeConfig cellConfig = new NativeUidRangeConfig(cellNetId, uidRanges, PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED); inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical( @@ -16402,26 +17166,26 @@ // Cellular network disconnected. mTestPackageDefaultNetworkCallback should receive // callback with wifi network from fallback request. - mCellNetworkAgent.disconnect(); + mCellAgent.disconnect(); mDefaultNetworkCallback.assertNoCallback(); - cellNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); - mTestPackageDefaultNetworkCallback.expect(CallbackEntry.LOST, mCellNetworkAgent); - mTestPackageDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + cellNetworkCallback.expect(LOST, mCellAgent); + mTestPackageDefaultNetworkCallback.expect(LOST, mCellAgent); + mTestPackageDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(wifiConfig); inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any()); inorder.verify(mMockNetd).networkDestroy(cellNetId); // Cellular network comes back. mTestPackageDefaultNetworkCallback should receive // callback with cellular network. - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); mDefaultNetworkCallback.assertNoCallback(); - mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); - final int cellNetId2 = mCellNetworkAgent.getNetwork().netId; + final int cellNetId2 = mCellAgent.getNetwork().netId; final NativeUidRangeConfig cellConfig2 = new NativeUidRangeConfig(cellNetId2, uidRanges, PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED); inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical( @@ -16431,11 +17195,11 @@ // Wifi network disconnected. mTestPackageDefaultNetworkCallback should not receive // any callback. - mWiFiNetworkAgent.disconnect(); - mDefaultNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + mWiFiAgent.disconnect(); + mDefaultNetworkCallback.expect(LOST, mWiFiAgent); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); mTestPackageDefaultNetworkCallback.assertNoCallback(); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); waitForIdle(); inorder.verify(mMockNetd, never()).networkAddUidRangesParcel(any()); inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any()); @@ -16467,15 +17231,15 @@ cellFactory.expectRequestAdds(2); cellFactory.assertRequestCountEquals(2); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); // The cellFactory however is outscored, and should lose default internet request. // But it should still see mobile data preferred request. cellFactory.expectRequestRemove(); cellFactory.assertRequestCountEquals(1); - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); // The network satisfying the default internet request has disconnected, so the // cellFactory sees the default internet requests again. cellFactory.expectRequestAdd(); @@ -16483,6 +17247,7 @@ } finally { cellFactory.terminate(); handlerThread.quitSafely(); + handlerThread.join(); } } @@ -16517,7 +17282,7 @@ final UserHandle testHandle = setupEnterpriseNetwork(); setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); - final int cellNetId = mCellNetworkAgent.getNetwork().netId; + final int cellNetId = mCellAgent.getNetwork().netId; inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical( cellNetId, INetd.PERMISSION_NONE)); @@ -16590,28 +17355,28 @@ // Register callbacks and have wifi network as default network. registerDefaultNetworkCallbacks(); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(true); + mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent); + mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent); + mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID)); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); // Set MOBILE_DATA_PREFERRED_UIDS setting with TEST_WORK_PROFILE_APP_UID and // TEST_PACKAGE_UID. Both mProfileDefaultNetworkCallback and // mTestPackageDefaultNetworkCallback should receive callback with cell network. setAndUpdateMobileDataPreferredUids(Set.of(TEST_WORK_PROFILE_APP_UID, TEST_PACKAGE_UID)); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); mDefaultNetworkCallback.assertNoCallback(); - mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - assertEquals(mCellNetworkAgent.getNetwork(), + mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellAgent); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID)); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); // Set user profile network preference with test profile. mProfileDefaultNetworkCallback // should receive callback with higher priority network preference (enterprise network). @@ -16626,7 +17391,7 @@ assertNoCallbacks(mDefaultNetworkCallback, mTestPackageDefaultNetworkCallback); mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent); assertEquals(workAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID)); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); // Set oem network preference with TEST_PACKAGE_UID. mTestPackageDefaultNetworkCallback // should receive callback with higher priority network preference (current default network) @@ -16637,8 +17402,8 @@ final UidRangeParcel[] uidRanges1 = toUidRangeStableParcels(uidRangesForUids(uids1)); setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges1, TEST_PACKAGE_NAME); assertNoCallbacks(mDefaultNetworkCallback, mProfileDefaultNetworkCallback); - mTestPackageDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + mTestPackageDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); assertEquals(workAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID)); // Set oem network preference with TEST_WORK_PROFILE_APP_UID. Both @@ -16650,11 +17415,11 @@ setupSetOemNetworkPreferenceForPreferenceTest( networkPref, uidRanges2, "com.android.test", testHandle); mDefaultNetworkCallback.assertNoCallback(); - mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - mTestPackageDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); - assertEquals(mWiFiNetworkAgent.getNetwork(), + mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiAgent); + mTestPackageDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); + assertEquals(mWiFiAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID)); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); // Remove oem network preference, mProfileDefaultNetworkCallback should receive callback // with current highest priority network preference (enterprise network) and the others @@ -16666,23 +17431,23 @@ assertNoCallbacks(mDefaultNetworkCallback, mTestPackageDefaultNetworkCallback); mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent); assertEquals(workAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID)); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); // Remove user profile network preference. mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_DEFAULT, r -> r.run(), listener); listener.expectOnComplete(); assertNoCallbacks(mDefaultNetworkCallback, mTestPackageDefaultNetworkCallback); - mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); - assertEquals(mCellNetworkAgent.getNetwork(), + mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_WORK_PROFILE_APP_UID)); - assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); + assertEquals(mCellAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID)); // Disconnect wifi - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); assertNoCallbacks(mProfileDefaultNetworkCallback, mTestPackageDefaultNetworkCallback); - mDefaultNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent); - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + mDefaultNetworkCallback.expect(LOST, mWiFiAgent); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); } @Test @@ -16696,13 +17461,13 @@ public void testUpdateRateLimit_EnableDisable() throws Exception { final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + mWiFiAgent.connect(true); final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); - mCellNetworkAgent.connect(false); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent.connect(false); waitForIdle(); @@ -16735,8 +17500,8 @@ public void testUpdateRateLimit_WhenNewNetworkIsAdded() throws Exception { final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + mWiFiAgent.connect(true); waitForIdle(); @@ -16751,8 +17516,8 @@ final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); - mCellNetworkAgent.connect(false); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent.connect(false); assertNotNull(readHead.poll(TIMEOUT_MS, it -> it.first == cellLp.getInterfaceName() && it.second == rateLimitInBytesPerSec)); } @@ -16762,8 +17527,8 @@ final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); - mWiFiNetworkAgent.connectWithoutInternet(); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + mWiFiAgent.connectWithoutInternet(); waitForIdle(); @@ -16787,8 +17552,8 @@ // - ensure network interface is not rate limited final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + mWiFiAgent.connect(true); waitForIdle(); final ArrayTrackRecord<Pair<String, Long>>.ReadHead readHeadWifi = @@ -16800,14 +17565,14 @@ it -> it.first == wifiLp.getInterfaceName() && it.second == rateLimitInBytesPerSec)); - mWiFiNetworkAgent.disconnect(); + mWiFiAgent.disconnect(); assertNotNull(readHeadWifi.poll(TIMEOUT_MS, it -> it.first == wifiLp.getInterfaceName() && it.second == -1)); setIngressRateLimit(-1); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + mWiFiAgent.connect(true); assertNull(readHeadWifi.poll(TIMEOUT_MS, it -> it.first == wifiLp.getInterfaceName())); } @@ -16815,8 +17580,8 @@ public void testUpdateRateLimit_UpdateExistingRateLimit() throws Exception { final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + mWiFiAgent.connect(true); waitForIdle(); final ArrayTrackRecord<Pair<String, Long>>.ReadHead readHeadWifi = @@ -16845,8 +17610,8 @@ public void testUpdateRateLimit_DoesNothingBeforeT() throws Exception { final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + mWiFiAgent.connect(true); waitForIdle(); final ArrayTrackRecord<Pair<String, Long>>.ReadHead readHead = @@ -16885,8 +17650,8 @@ 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); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellAgent.connect(true); NetworkCapabilities wifiNc1 = new NetworkCapabilities() .addCapability(NET_CAPABILITY_INTERNET) .addCapability(NET_CAPABILITY_NOT_VPN) @@ -16899,105 +17664,100 @@ .setTransportInfo(new WifiInfo.Builder().setBssid(bssid2).build()); final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc1); - mWiFiNetworkAgent.connect(true); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc1); + mWiFiAgent.connect(true); // The default network will be switching to Wi-Fi Network. final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback(); final NetworkRequest wifiRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_WIFI).build(); mCm.requestNetwork(wifiRequest, wifiNetworkCallback); - wifiNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); + wifiNetworkCallback.expectAvailableCallbacksValidated(mWiFiAgent); registerDefaultNetworkCallbacks(); - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiAgent); // There is a bug in the current code where ignoring validation after roam will not // correctly change the default network if the result if the validation is partial or // captive portal. TODO : fix the bug and reinstate this code. if (false) { // Wi-Fi roaming from wifiNc1 to wifiNc2 but the network is now behind a captive portal. - mWiFiNetworkAgent.setNetworkCapabilities(wifiNc2, true /* sendToConnectivityService */); + mWiFiAgent.setNetworkCapabilities(wifiNc2, true /* sendToConnectivityService */); // The only thing changed in this CAPS is the BSSID, which can't be tested for in this // test because it's redacted. - wifiNetworkCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, - mWiFiNetworkAgent); - mDefaultNetworkCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, - mWiFiNetworkAgent); - mWiFiNetworkAgent.setNetworkPortal(TEST_REDIRECT_URL, false /* isStrictMode */); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false); + wifiNetworkCallback.expectCaps(mWiFiAgent); + mDefaultNetworkCallback.expectCaps(mWiFiAgent); + mWiFiAgent.setNetworkPortal(TEST_REDIRECT_URL, false /* privateDnsProbeSent */); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), false); // Wi-Fi is now detected to have a portal : cell should become the default network. - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); - wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, - mWiFiNetworkAgent); - wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, - mWiFiNetworkAgent); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); + wifiNetworkCallback.expectCaps(mWiFiAgent, + c -> !c.hasCapability(NET_CAPABILITY_VALIDATED)); + wifiNetworkCallback.expectCaps(mWiFiAgent, + c -> c.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)); // Wi-Fi becomes valid again. The default network goes back to Wi-Fi. - mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_CAPTIVE_PORTAL, - mWiFiNetworkAgent); + mWiFiAgent.setNetworkValid(false /* privateDnsProbeSent */); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiAgent); + wifiNetworkCallback.expectCaps(mWiFiAgent, + c -> !c.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)); // Wi-Fi roaming from wifiNc2 to wifiNc1, and the network now has partial connectivity. - mWiFiNetworkAgent.setNetworkCapabilities(wifiNc1, true); - wifiNetworkCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, - mWiFiNetworkAgent); - mDefaultNetworkCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, - mWiFiNetworkAgent); - mWiFiNetworkAgent.setNetworkPartial(); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false); + mWiFiAgent.setNetworkCapabilities(wifiNc1, true); + wifiNetworkCallback.expectCaps(mWiFiAgent); + mDefaultNetworkCallback.expectCaps(mWiFiAgent); + mWiFiAgent.setNetworkPartial(); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), false); // Wi-Fi now only offers partial connectivity, so in the absence of accepting partial // connectivity explicitly for this network, it loses default status to cell. - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); - wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, - mWiFiNetworkAgent); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); + wifiNetworkCallback.expectCaps(mWiFiAgent, + c -> c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)); // Wi-Fi becomes valid again. The default network goes back to Wi-Fi. - mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_PARTIAL_CONNECTIVITY, - mWiFiNetworkAgent); + mWiFiAgent.setNetworkValid(false /* privateDnsProbeSent */); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), true); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiAgent); + wifiNetworkCallback.expectCaps(mWiFiAgent, + c -> !c.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)); } 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. // If they are ignored, this will not cause a switch until later. - mWiFiNetworkAgent.setNetworkCapabilities(wifiNc2, true); - mDefaultNetworkCallback.expect(CallbackEntry.NETWORK_CAPS_UPDATED, - mWiFiNetworkAgent); - mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false); + mWiFiAgent.setNetworkCapabilities(wifiNc2, true); + mDefaultNetworkCallback.expectCaps(mWiFiAgent); + mWiFiAgent.setNetworkInvalid(false /* invalidBecauseOfPrivateDns */); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), false); if (enabled) { // Network validation failed, but the result will be ignored. - assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability( + assertTrue(mCm.getNetworkCapabilities(mWiFiAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); - mWiFiNetworkAgent.setNetworkValid(false); + mWiFiAgent.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); + mWiFiAgent.setNetworkCapabilities(wifiNc1, true); + mWiFiAgent.setNetworkInvalid(false); waitForValidationBlock.block(150); - mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false); - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + mCm.reportNetworkConnectivity(mWiFiAgent.getNetwork(), false); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); } else { - mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellAgent); } // 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); + mCellAgent.disconnect(); + mDefaultNetworkCallback.expect(LOST, mCellAgent); + mDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiAgent); } @@ -17008,14 +17768,14 @@ @Test public void testIgnoreValidationAfterRoamEnabled() throws Exception { - final boolean enabled = !SdkLevel.isAtLeastT(); + final boolean enabled = !mDeps.isAtLeastT(); doTestIgnoreValidationAfterRoam(5_000, enabled); } @Test public void testShouldIgnoreValidationFailureAfterRoam() { // Always disabled on T+. - assumeFalse(SdkLevel.isAtLeastT()); + assumeFalse(mDeps.isAtLeastT()); NetworkAgentInfo nai = fakeWifiNai(new NetworkCapabilities()); @@ -17073,18 +17833,93 @@ }); } + private void verifyMtuSetOnWifiInterface(int mtu) throws Exception { + verify(mMockNetd, times(1)).interfaceSetMtu(WIFI_IFNAME, mtu); + } + + private void verifyMtuNeverSetOnWifiInterface() throws Exception { + verify(mMockNetd, never()).interfaceSetMtu(eq(WIFI_IFNAME), anyInt()); + } + + private void verifyMtuSetOnWifiInterfaceOnlyUpToT(int mtu) throws Exception { + if (!mService.shouldCreateNetworksImmediately()) { + verify(mMockNetd, times(1)).interfaceSetMtu(WIFI_IFNAME, mtu); + } else { + verify(mMockNetd, never()).interfaceSetMtu(eq(WIFI_IFNAME), anyInt()); + } + } + + private void verifyMtuSetOnWifiInterfaceOnlyStartingFromU(int mtu) throws Exception { + if (mService.shouldCreateNetworksImmediately()) { + verify(mMockNetd, times(1)).interfaceSetMtu(WIFI_IFNAME, mtu); + } else { + verify(mMockNetd, never()).interfaceSetMtu(eq(WIFI_IFNAME), anyInt()); + } + } + @Test - public void testSendLinkPropertiesSetInterfaceMtu() throws Exception { + public void testSendLinkPropertiesSetInterfaceMtuBeforeConnect() throws Exception { + final int mtu = 1281; + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(WIFI_IFNAME); + lp.setMtu(mtu); + + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.sendLinkProperties(lp); + waitForIdle(); + verifyMtuSetOnWifiInterface(mtu); + reset(mMockNetd); + + mWiFiAgent.connect(false /* validated */); + // Before U, the MTU is always (re-)applied when the network connects. + verifyMtuSetOnWifiInterfaceOnlyUpToT(mtu); + } + + @Test + public void testSendLinkPropertiesUpdateInterfaceMtuBeforeConnect() throws Exception { final int mtu = 1327; LinkProperties lp = new LinkProperties(); lp.setInterfaceName(WIFI_IFNAME); lp.setMtu(mtu); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - mWiFiNetworkAgent.sendLinkProperties(lp); - + // Registering an agent with an MTU only sets the MTU on U+. + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); waitForIdle(); - verify(mMockNetd).interfaceSetMtu(eq(WIFI_IFNAME), eq(mtu)); + verifyMtuSetOnWifiInterfaceOnlyStartingFromU(mtu); + reset(mMockNetd); + + // Future updates with the same MTU don't set the MTU even on T when it's not set initially. + mWiFiAgent.sendLinkProperties(lp); + waitForIdle(); + verifyMtuNeverSetOnWifiInterface(); + + // Updating with a different MTU does work. + lp.setMtu(mtu + 1); + mWiFiAgent.sendLinkProperties(lp); + waitForIdle(); + verifyMtuSetOnWifiInterface(mtu + 1); + reset(mMockNetd); + + mWiFiAgent.connect(false /* validated */); + // Before U, the MTU is always (re-)applied when the network connects. + verifyMtuSetOnWifiInterfaceOnlyUpToT(mtu + 1); + } + + @Test + public void testSendLinkPropertiesUpdateInterfaceMtuAfterConnect() throws Exception { + final int mtu = 1327; + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(WIFI_IFNAME); + lp.setMtu(mtu); + + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiAgent.connect(false /* validated */); + verifyMtuNeverSetOnWifiInterface(); + + mWiFiAgent.sendLinkProperties(lp); + waitForIdle(); + // The MTU is always (re-)applied when the network connects. + verifyMtuSetOnWifiInterface(mtu); } @Test @@ -17094,15 +17929,16 @@ lp.setInterfaceName(WIFI_IFNAME); lp.setMtu(mtu); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); + mWiFiAgent.connect(false /* validated */); + verifyMtuSetOnWifiInterface(mtu); + reset(mMockNetd); LinkProperties lp2 = new LinkProperties(lp); lp2.setMtu(mtu2); - - mWiFiNetworkAgent.sendLinkProperties(lp2); - + mWiFiAgent.sendLinkProperties(lp2); waitForIdle(); - verify(mMockNetd).interfaceSetMtu(eq(WIFI_IFNAME), eq(mtu2)); + verifyMtuSetOnWifiInterface(mtu2); } @Test @@ -17112,11 +17948,14 @@ lp.setInterfaceName(WIFI_IFNAME); lp.setMtu(mtu); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); - mWiFiNetworkAgent.sendLinkProperties(new LinkProperties(lp)); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); + mWiFiAgent.connect(false /* validated */); + verifyMtuSetOnWifiInterface(mtu); + reset(mMockNetd); + mWiFiAgent.sendLinkProperties(new LinkProperties(lp)); waitForIdle(); - verify(mMockNetd, never()).interfaceSetMtu(eq(WIFI_IFNAME), anyInt()); + verifyMtuNeverSetOnWifiInterface(); } @Test @@ -17126,16 +17965,16 @@ lp.setInterfaceName(WIFI_IFNAME); lp.setMtu(mtu); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); + mWiFiAgent.connect(false /* validated */); + verifyMtuSetOnWifiInterface(mtu); + reset(mMockNetd); - LinkProperties lp2 = new LinkProperties(); - assertNull(lp2.getInterfaceName()); - lp2.setMtu(mtu); - - mWiFiNetworkAgent.sendLinkProperties(new LinkProperties(lp2)); - + LinkProperties lp2 = new LinkProperties(lp); + lp2.setInterfaceName(null); + mWiFiAgent.sendLinkProperties(new LinkProperties(lp2)); waitForIdle(); - verify(mMockNetd, never()).interfaceSetMtu(any(), anyInt()); + verifyMtuNeverSetOnWifiInterface(); } @Test @@ -17145,17 +17984,132 @@ lp.setInterfaceName(WIFI_IFNAME); lp.setMtu(mtu); - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); + mWiFiAgent.connect(false /* validated */); + verifyMtuSetOnWifiInterface(mtu); + reset(mMockNetd); final String ifaceName2 = WIFI_IFNAME + "_2"; - LinkProperties lp2 = new LinkProperties(); + LinkProperties lp2 = new LinkProperties(lp); lp2.setInterfaceName(ifaceName2); - lp2.setMtu(mtu); - mWiFiNetworkAgent.sendLinkProperties(new LinkProperties(lp2)); + mWiFiAgent.sendLinkProperties(new LinkProperties(lp2)); + waitForIdle(); + verify(mMockNetd, times(1)).interfaceSetMtu(eq(ifaceName2), eq(mtu)); + verifyMtuNeverSetOnWifiInterface(); + } + + @Test + public void testCreateDeliveryGroupKeyForConnectivityAction() throws Exception { + final NetworkInfo info = new NetworkInfo(0 /* type */, 2 /* subtype */, + "MOBILE" /* typeName */, "LTE" /* subtypeName */); + assertEquals("0;2;null", createDeliveryGroupKeyForConnectivityAction(info)); + + info.setExtraInfo("test_info"); + assertEquals("0;2;test_info", createDeliveryGroupKeyForConnectivityAction(info)); + } + + @Test + public void testNetdWakeupAddInterfaceForWifiTransport() throws Exception { + final LinkProperties wifiLp = new LinkProperties(); + wifiLp.setInterfaceName(WIFI_IFNAME); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + mWiFiAgent.connect(false /* validated */); + + final String expectedPrefix = makeNflogPrefix(WIFI_IFNAME, + mWiFiAgent.getNetwork().getNetworkHandle()); + verify(mMockNetd).wakeupAddInterface(WIFI_IFNAME, expectedPrefix, PACKET_WAKEUP_MARK, + PACKET_WAKEUP_MASK); + } + + @Test + public void testNetdWakeupAddInterfaceForCellularTransport() throws Exception { + final LinkProperties cellLp = new LinkProperties(); + cellLp.setInterfaceName(MOBILE_IFNAME); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellAgent.connect(false /* validated */); + + if (mDeps.isAtLeastU()) { + final String expectedPrefix = makeNflogPrefix(MOBILE_IFNAME, + mCellAgent.getNetwork().getNetworkHandle()); + verify(mMockNetd).wakeupAddInterface(MOBILE_IFNAME, expectedPrefix, PACKET_WAKEUP_MARK, + PACKET_WAKEUP_MASK); + } else { + verify(mMockNetd, never()).wakeupAddInterface(eq(MOBILE_IFNAME), anyString(), anyInt(), + anyInt()); + } + } + + @Test + public void testNetdWakeupAddInterfaceForEthernetTransport() throws Exception { + final String ethernetIface = "eth42"; + + final LinkProperties ethLp = new LinkProperties(); + ethLp.setInterfaceName(ethernetIface); + mEthernetAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET, ethLp); + mEthernetAgent.connect(false /* validated */); + + verify(mMockNetd, never()).wakeupAddInterface(eq(ethernetIface), anyString(), anyInt(), + anyInt()); + } + + private static final int TEST_FROZEN_UID = 1000; + private static final int TEST_UNFROZEN_UID = 2000; + + /** + * Send a UidFrozenStateChanged message to ConnectivityService. Verify that only the frozen UID + * gets passed to socketDestroy(). + */ + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testFrozenUidSocketDestroy() throws Exception { + ArgumentCaptor<UidFrozenStateChangedCallback> callbackArg = + ArgumentCaptor.forClass(UidFrozenStateChangedCallback.class); + + verify(mActivityManager).registerUidFrozenStateChangedCallback(any(), + callbackArg.capture()); + + final int[] uids = {TEST_FROZEN_UID, TEST_UNFROZEN_UID}; + final int[] frozenStates = {UID_FROZEN_STATE_FROZEN, UID_FROZEN_STATE_UNFROZEN}; + + callbackArg.getValue().onUidFrozenStateChanged(uids, frozenStates); waitForIdle(); - // TODO(b/246398088): the MTU should be set on the new interface. - verify(mMockNetd, never()).interfaceSetMtu(eq(ifaceName2), eq(mtu)); + + final Set<Integer> exemptUids = new ArraySet(); + final UidRange frozenUidRange = new UidRange(TEST_FROZEN_UID, TEST_FROZEN_UID); + final Set<UidRange> ranges = Collections.singleton(frozenUidRange); + + verify(mDestroySocketsWrapper).destroyLiveTcpSockets(eq(UidRange.toIntRanges(ranges)), + eq(exemptUids)); + } + + @Test + public void testDisconnectSuspendedNetworkStopClatd() throws Exception { + final TestNetworkCallback networkCallback = new TestNetworkCallback(); + final NetworkRequest networkRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_DUN) + .build(); + mCm.requestNetwork(networkRequest, networkCallback); + + final IpPrefix nat64Prefix = new IpPrefix(InetAddress.getByName("64:ff9b::"), 96); + NetworkCapabilities nc = new NetworkCapabilities().addCapability(NET_CAPABILITY_DUN); + final LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(MOBILE_IFNAME); + lp.addLinkAddress(new LinkAddress("2001:db8:1::1/64")); + lp.setNat64Prefix(nat64Prefix); + mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, lp, nc); + mCellAgent.connect(true /* validated */, false /* hasInternet */, + false /* privateDnsProbeSent */); + + verifyClatdStart(null /* inOrder */, MOBILE_IFNAME, mCellAgent.getNetwork().netId, + nat64Prefix.toString()); + + mCellAgent.suspend(); + mCm.unregisterNetworkCallback(networkCallback); + mCellAgent.expectDisconnected(); + waitForIdle(); + + verifyClatdStop(null /* inOrder */, MOBILE_IFNAME); } }
diff --git a/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java index 624071a..1618a62 100644 --- a/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java +++ b/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -23,6 +23,7 @@ import static android.net.IpSecManager.DIRECTION_FWD; import static android.net.IpSecManager.DIRECTION_IN; import static android.net.IpSecManager.DIRECTION_OUT; +import static android.net.IpSecManager.FEATURE_IPSEC_TUNNEL_MIGRATION; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; @@ -30,11 +31,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -49,6 +55,7 @@ import android.net.IpSecAlgorithm; import android.net.IpSecConfig; import android.net.IpSecManager; +import android.net.IpSecMigrateInfoParcel; import android.net.IpSecSpiResponse; import android.net.IpSecTransform; import android.net.IpSecTransformResponse; @@ -130,6 +137,9 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F }; + private static final String NEW_SRC_ADDRESS = "2001:db8:2::1"; + private static final String NEW_DST_ADDRESS = "2001:db8:2::2"; + AppOpsManager mMockAppOps = mock(AppOpsManager.class); ConnectivityManager mMockConnectivityMgr = mock(ConnectivityManager.class); @@ -369,8 +379,8 @@ .ipSecAddSecurityAssociation( eq(mUid), eq(config.getMode()), - eq(config.getSourceAddress()), - eq(config.getDestinationAddress()), + eq(mSourceAddr), + eq(mDestinationAddr), eq((config.getNetwork() != null) ? config.getNetwork().netId : 0), eq(TEST_SPI), eq(0), @@ -910,9 +920,60 @@ } } + @Test + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testApplyAndMigrateTunnelModeTransformOutbound() throws Exception { + verifyApplyAndMigrateTunnelModeTransformCommon(false, DIRECTION_OUT); + } + + @Test + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testApplyAndMigrateTunnelModeTransformOutboundReleasedSpi() throws Exception { + verifyApplyAndMigrateTunnelModeTransformCommon(true, DIRECTION_OUT); + } + + @Test + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testApplyAndMigrateTunnelModeTransformInbound() throws Exception { + verifyApplyAndMigrateTunnelModeTransformCommon(false, DIRECTION_IN); + } + + @Test + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testApplyAndMigrateTunnelModeTransformInboundReleasedSpi() throws Exception { + verifyApplyAndMigrateTunnelModeTransformCommon(true, DIRECTION_IN); + } + + @Test + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testApplyAndMigrateTunnelModeTransformForward() throws Exception { + verifyApplyAndMigrateTunnelModeTransformCommon(false, DIRECTION_FWD); + } + + @Test + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testApplyAndMigrateTunnelModeTransformForwardReleasedSpi() throws Exception { + verifyApplyAndMigrateTunnelModeTransformCommon(true, DIRECTION_FWD); + } + public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply, int direction) throws Exception { - IpSecConfig ipSecConfig = new IpSecConfig(); + verifyApplyTunnelModeTransformCommon( + new IpSecConfig(), closeSpiBeforeApply, false /* isMigrating */, direction); + } + + public void verifyApplyAndMigrateTunnelModeTransformCommon( + boolean closeSpiBeforeApply, int direction) throws Exception { + verifyApplyTunnelModeTransformCommon( + new IpSecConfig(), closeSpiBeforeApply, true /* isMigrating */, direction); + } + + public int verifyApplyTunnelModeTransformCommon( + IpSecConfig ipSecConfig, + boolean closeSpiBeforeApply, + boolean isMigrating, + int direction) + throws Exception { ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL); addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); addAuthAndCryptToIpSecConfig(ipSecConfig); @@ -928,6 +989,12 @@ int transformResourceId = createTransformResp.resourceId; int tunnelResourceId = createTunnelResp.resourceId; + + if (isMigrating) { + mIpSecService.migrateTransform( + transformResourceId, NEW_SRC_ADDRESS, NEW_DST_ADDRESS, BLESSED_PACKAGE); + } + mIpSecService.applyTunnelModeTransform( tunnelResourceId, direction, transformResourceId, BLESSED_PACKAGE); @@ -947,8 +1014,16 @@ ipSecConfig.setXfrmInterfaceId(tunnelResourceId); verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp); - } + if (isMigrating) { + verify(mMockNetd, times(ADDRESS_FAMILIES.length)) + .ipSecMigrate(any(IpSecMigrateInfoParcel.class)); + } else { + verify(mMockNetd, never()).ipSecMigrate(any()); + } + + return tunnelResourceId; + } @Test public void testApplyTunnelModeTransformWithClosedSpi() throws Exception { @@ -1023,7 +1098,7 @@ } @Test - public void testFeatureFlagVerification() throws Exception { + public void testFeatureFlagIpSecTunnelsVerification() throws Exception { when(mMockPkgMgr.hasSystemFeature(eq(PackageManager.FEATURE_IPSEC_TUNNELS))) .thenReturn(false); @@ -1035,4 +1110,17 @@ } catch (UnsupportedOperationException expected) { } } + + @Test + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testFeatureFlagIpSecTunnelMigrationVerification() throws Exception { + when(mMockPkgMgr.hasSystemFeature(eq(FEATURE_IPSEC_TUNNEL_MIGRATION))).thenReturn(false); + + try { + mIpSecService.migrateTransform( + 1 /* transformId */, NEW_SRC_ADDRESS, NEW_DST_ADDRESS, BLESSED_PACKAGE); + fail("Expected UnsupportedOperationException for disabled feature"); + } catch (UnsupportedOperationException expected) { + } + } }
diff --git a/tests/unit/java/com/android/server/IpSecServiceTest.java b/tests/unit/java/com/android/server/IpSecServiceTest.java index 6955620..4b6857c 100644 --- a/tests/unit/java/com/android/server/IpSecServiceTest.java +++ b/tests/unit/java/com/android/server/IpSecServiceTest.java
@@ -82,7 +82,7 @@ private static final int MAX_NUM_ENCAP_SOCKETS = 100; private static final int MAX_NUM_SPIS = 100; private static final int TEST_UDP_ENCAP_INVALID_PORT = 100; - private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000; + private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 200000; private static final InetAddress INADDR_ANY;
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java index 5808beb..1997215 100644 --- a/tests/unit/java/com/android/server/NsdServiceTest.java +++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -16,16 +16,28 @@ package com.android.server; +import static android.net.InetAddresses.parseNumericAddress; +import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_PLATFORM_MDNS_BACKEND; +import static android.net.connectivity.ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER; +import static android.net.nsd.NsdManager.FAILURE_BAD_PARAMETERS; import static android.net.nsd.NsdManager.FAILURE_INTERNAL_ERROR; +import static android.net.nsd.NsdManager.FAILURE_OPERATION_NOT_RUNNING; + +import static com.android.server.NsdService.parseTypeAndSubtype; +import static com.android.testutils.ContextUtils.mockService; import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.doReturn; @@ -36,13 +48,14 @@ import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.compat.testing.PlatformCompatChangeRule; import android.content.ContentResolver; import android.content.Context; import android.net.INetd; -import android.net.InetAddresses; +import android.net.Network; import android.net.mdns.aidl.DiscoveryInfo; import android.net.mdns.aidl.GetAddressInfo; import android.net.mdns.aidl.IMDnsEventListener; @@ -63,10 +76,19 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; +import android.util.Pair; import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; +import com.android.server.NsdService.Dependencies; +import com.android.server.connectivity.mdns.MdnsAdvertiser; +import com.android.server.connectivity.mdns.MdnsDiscoveryManager; +import com.android.server.connectivity.mdns.MdnsSearchOptions; +import com.android.server.connectivity.mdns.MdnsServiceBrowserListener; +import com.android.server.connectivity.mdns.MdnsServiceInfo; +import com.android.server.connectivity.mdns.MdnsSocketProvider; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; import com.android.testutils.HandlerUtils; @@ -82,7 +104,12 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Collections; import java.util.LinkedList; +import java.util.List; +import java.util.Objects; import java.util.Queue; // TODOs: @@ -96,11 +123,13 @@ private static final long CLEANUP_DELAY_MS = 500; private static final long TIMEOUT_MS = 500; private static final String SERVICE_NAME = "a_name"; - private static final String SERVICE_TYPE = "a_type"; + private static final String SERVICE_TYPE = "_test._tcp"; private static final String SERVICE_FULL_NAME = SERVICE_NAME + "." + SERVICE_TYPE; private static final String DOMAIN_NAME = "mytestdevice.local"; private static final int PORT = 2201; private static final int IFACE_IDX_ANY = 0; + private static final String IPV4_ADDRESS = "192.0.2.0"; + private static final String IPV6_ADDRESS = "2001:db8::"; // Records INsdManagerCallback created when NsdService#connect is called. // Only accessed on the test thread, since NsdService#connect is called by the NsdManager @@ -112,6 +141,10 @@ @Mock Context mContext; @Mock ContentResolver mResolver; @Mock MDnsManager mMockMDnsM; + @Mock Dependencies mDeps; + @Mock MdnsDiscoveryManager mDiscoveryManager; + @Mock MdnsAdvertiser mAdvertiser; + @Mock MdnsSocketProvider mSocketProvider; HandlerThread mThread; TestHandler mHandler; NsdService mService; @@ -133,9 +166,7 @@ mThread.start(); mHandler = new TestHandler(mThread.getLooper()); when(mContext.getContentResolver()).thenReturn(mResolver); - doReturn(MDnsManager.MDNS_SERVICE).when(mContext) - .getSystemServiceName(MDnsManager.class); - doReturn(mMockMDnsM).when(mContext).getSystemService(MDnsManager.MDNS_SERVICE); + mockService(mContext, MDnsManager.class, MDnsManager.MDNS_SERVICE, mMockMDnsM); if (mContext.getSystemService(MDnsManager.class) == null) { // Test is using mockito-extended doCallRealMethod().when(mContext).getSystemService(MDnsManager.class); @@ -146,7 +177,11 @@ doReturn(true).when(mMockMDnsM).discover(anyInt(), anyString(), anyInt()); doReturn(true).when(mMockMDnsM).resolve( anyInt(), anyString(), anyString(), anyString(), anyInt()); - + doReturn(false).when(mDeps).isMdnsDiscoveryManagerEnabled(any(Context.class)); + doReturn(mDiscoveryManager).when(mDeps) + .makeMdnsDiscoveryManager(any(), any(), any()); + doReturn(mSocketProvider).when(mDeps).makeMdnsSocketProvider(any(), any(), any()); + doReturn(mAdvertiser).when(mDeps).makeMdnsAdvertiser(any(), any(), any(), any()); mService = makeService(); } @@ -159,7 +194,9 @@ } @Test - @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @DisableCompatChanges({ + RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER, + ENABLE_PLATFORM_MDNS_BACKEND}) public void testPreSClients() throws Exception { // Pre S client connected, the daemon should be started. connectClient(mService); @@ -186,7 +223,8 @@ } @Test - @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @EnableCompatChanges(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) public void testNoDaemonStartedWhenClientsConnect() throws Exception { // Creating an NsdManager will not cause daemon startup. connectClient(mService); @@ -220,7 +258,8 @@ } @Test - @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @EnableCompatChanges(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) public void testClientRequestsAreGCedAtDisconnection() throws Exception { final NsdManager client = connectClient(mService); final INsdManagerCallback cb1 = getCallback(); @@ -263,7 +302,8 @@ } @Test - @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @EnableCompatChanges(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER) + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) public void testCleanupDelayNoRequestActive() throws Exception { final NsdManager client = connectClient(mService); @@ -299,6 +339,7 @@ } @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) public void testDiscoverOnTetheringDownstream() throws Exception { final NsdManager client = connectClient(mService); final int interfaceIdx = 123; @@ -382,13 +423,44 @@ final NsdServiceInfo resolvedService = resInfoCaptor.getValue(); assertEquals(SERVICE_NAME, resolvedService.getServiceName()); assertEquals("." + SERVICE_TYPE, resolvedService.getServiceType()); - assertEquals(InetAddresses.parseNumericAddress(serviceAddress), resolvedService.getHost()); + assertEquals(parseNumericAddress(serviceAddress), resolvedService.getHost()); assertEquals(servicePort, resolvedService.getPort()); assertNull(resolvedService.getNetwork()); assertEquals(interfaceIdx, resolvedService.getInterfaceIndex()); } @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) + public void testDiscoverOnBlackholeNetwork() throws Exception { + final NsdManager client = connectClient(mService); + final DiscoveryListener discListener = mock(DiscoveryListener.class); + client.discoverServices(SERVICE_TYPE, PROTOCOL, discListener); + waitForIdle(); + + final IMDnsEventListener eventListener = getEventListener(); + final ArgumentCaptor<Integer> discIdCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mMockMDnsM).discover(discIdCaptor.capture(), eq(SERVICE_TYPE), + eq(0) /* interfaceIdx */); + // NsdManager uses a separate HandlerThread to dispatch callbacks (on ServiceHandler), so + // this needs to use a timeout + verify(discListener, timeout(TIMEOUT_MS)).onDiscoveryStarted(SERVICE_TYPE); + + final DiscoveryInfo discoveryInfo = new DiscoveryInfo( + discIdCaptor.getValue(), + IMDnsEventListener.SERVICE_FOUND, + SERVICE_NAME, + SERVICE_TYPE, + DOMAIN_NAME, + 123 /* interfaceIdx */, + INetd.DUMMY_NET_ID); // netId of the blackhole network + eventListener.onServiceDiscoveryStatus(discoveryInfo); + waitForIdle(); + + verify(discListener, never()).onServiceFound(any()); + } + + @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) public void testServiceRegistrationSuccessfulAndFailed() throws Exception { final NsdManager client = connectClient(mService); final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE); @@ -435,6 +507,7 @@ } @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) public void testServiceDiscoveryFailed() throws Exception { final NsdManager client = connectClient(mService); final DiscoveryListener discListener = mock(DiscoveryListener.class); @@ -461,6 +534,7 @@ } @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) public void testServiceResolutionFailed() throws Exception { final NsdManager client = connectClient(mService); final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE); @@ -491,6 +565,7 @@ } @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) public void testGettingAddressFailed() throws Exception { final NsdManager client = connectClient(mService); final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE); @@ -537,6 +612,7 @@ } @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) public void testNoCrashWhenProcessResolutionAfterBinderDied() throws Exception { final NsdManager client = connectClient(mService); final INsdManagerCallback cb = getCallback(); @@ -555,14 +631,720 @@ anyInt()/* interfaceIdx */); } + @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) + public void testStopServiceResolution() { + final NsdManager client = connectClient(mService); + final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE); + final ResolveListener resolveListener = mock(ResolveListener.class); + client.resolveService(request, resolveListener); + waitForIdle(); + + final ArgumentCaptor<Integer> resolvIdCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mMockMDnsM).resolve(resolvIdCaptor.capture(), eq(SERVICE_NAME), eq(SERVICE_TYPE), + eq("local.") /* domain */, eq(IFACE_IDX_ANY)); + + final int resolveId = resolvIdCaptor.getValue(); + client.stopServiceResolution(resolveListener); + waitForIdle(); + + verify(mMockMDnsM).stopOperation(resolveId); + verify(resolveListener, timeout(TIMEOUT_MS)).onResolutionStopped(argThat(ns -> + request.getServiceName().equals(ns.getServiceName()) + && request.getServiceType().equals(ns.getServiceType()))); + } + + @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) + public void testStopResolutionFailed() { + final NsdManager client = connectClient(mService); + final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE); + final ResolveListener resolveListener = mock(ResolveListener.class); + client.resolveService(request, resolveListener); + waitForIdle(); + + final ArgumentCaptor<Integer> resolvIdCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mMockMDnsM).resolve(resolvIdCaptor.capture(), eq(SERVICE_NAME), eq(SERVICE_TYPE), + eq("local.") /* domain */, eq(IFACE_IDX_ANY)); + + final int resolveId = resolvIdCaptor.getValue(); + doReturn(false).when(mMockMDnsM).stopOperation(anyInt()); + client.stopServiceResolution(resolveListener); + waitForIdle(); + + verify(mMockMDnsM).stopOperation(resolveId); + verify(resolveListener, timeout(TIMEOUT_MS)).onStopResolutionFailed(argThat(ns -> + request.getServiceName().equals(ns.getServiceName()) + && request.getServiceType().equals(ns.getServiceType())), + eq(FAILURE_OPERATION_NOT_RUNNING)); + } + + @Test @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) + public void testStopResolutionDuringGettingAddress() throws RemoteException { + final NsdManager client = connectClient(mService); + final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE); + final ResolveListener resolveListener = mock(ResolveListener.class); + client.resolveService(request, resolveListener); + waitForIdle(); + + final IMDnsEventListener eventListener = getEventListener(); + final ArgumentCaptor<Integer> resolvIdCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mMockMDnsM).resolve(resolvIdCaptor.capture(), eq(SERVICE_NAME), eq(SERVICE_TYPE), + eq("local.") /* domain */, eq(IFACE_IDX_ANY)); + + // Resolve service successfully. + final ResolutionInfo resolutionInfo = new ResolutionInfo( + resolvIdCaptor.getValue(), + IMDnsEventListener.SERVICE_RESOLVED, + null /* serviceName */, + null /* serviceType */, + null /* domain */, + SERVICE_FULL_NAME, + DOMAIN_NAME, + PORT, + new byte[0] /* txtRecord */, + IFACE_IDX_ANY); + doReturn(true).when(mMockMDnsM).getServiceAddress(anyInt(), any(), anyInt()); + eventListener.onServiceResolutionStatus(resolutionInfo); + waitForIdle(); + + final ArgumentCaptor<Integer> getAddrIdCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mMockMDnsM).getServiceAddress(getAddrIdCaptor.capture(), eq(DOMAIN_NAME), + eq(IFACE_IDX_ANY)); + + final int getAddrId = getAddrIdCaptor.getValue(); + client.stopServiceResolution(resolveListener); + waitForIdle(); + + verify(mMockMDnsM).stopOperation(getAddrId); + verify(resolveListener, timeout(TIMEOUT_MS)).onResolutionStopped(argThat(ns -> + request.getServiceName().equals(ns.getServiceName()) + && request.getServiceType().equals(ns.getServiceType()))); + } + + private void verifyUpdatedServiceInfo(NsdServiceInfo info, String serviceName, + String serviceType, List<InetAddress> address, int port, int interfaceIndex, + Network network) { + assertEquals(serviceName, info.getServiceName()); + assertEquals(serviceType, info.getServiceType()); + assertEquals(address, info.getHostAddresses()); + assertEquals(port, info.getPort()); + assertEquals(network, info.getNetwork()); + assertEquals(interfaceIndex, info.getInterfaceIndex()); + } + + @Test + public void testRegisterAndUnregisterServiceInfoCallback() { + final NsdManager client = connectClient(mService); + final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE); + final NsdManager.ServiceInfoCallback serviceInfoCallback = mock( + NsdManager.ServiceInfoCallback.class); + final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local"; + final Network network = new Network(999); + request.setNetwork(network); + client.registerServiceInfoCallback(request, Runnable::run, serviceInfoCallback); + waitForIdle(); + // Verify the registration callback start. + final ArgumentCaptor<MdnsServiceBrowserListener> listenerCaptor = + ArgumentCaptor.forClass(MdnsServiceBrowserListener.class); + verify(mSocketProvider).startMonitoringSockets(); + verify(mDiscoveryManager).registerListener(eq(serviceTypeWithLocalDomain), + listenerCaptor.capture(), argThat(options -> network.equals(options.getNetwork()))); + + final MdnsServiceBrowserListener listener = listenerCaptor.getValue(); + final MdnsServiceInfo mdnsServiceInfo = new MdnsServiceInfo( + SERVICE_NAME, + serviceTypeWithLocalDomain.split("\\."), + List.of(), /* subtypes */ + new String[]{"android", "local"}, /* hostName */ + PORT, + List.of(IPV4_ADDRESS), + List.of(IPV6_ADDRESS), + List.of() /* textStrings */, + List.of() /* textEntries */, + 1234, + network); + + // Verify onServiceFound callback + listener.onServiceFound(mdnsServiceInfo); + final ArgumentCaptor<NsdServiceInfo> updateInfoCaptor = + ArgumentCaptor.forClass(NsdServiceInfo.class); + verify(serviceInfoCallback, timeout(TIMEOUT_MS).times(1)) + .onServiceUpdated(updateInfoCaptor.capture()); + verifyUpdatedServiceInfo(updateInfoCaptor.getAllValues().get(0) /* info */, SERVICE_NAME, + SERVICE_TYPE, + List.of(parseNumericAddress(IPV4_ADDRESS), parseNumericAddress(IPV6_ADDRESS)), + PORT, IFACE_IDX_ANY, new Network(999)); + + // Service addresses changed. + final String v4Address = "192.0.2.1"; + final String v6Address = "2001:db8::1"; + final MdnsServiceInfo updatedServiceInfo = new MdnsServiceInfo( + SERVICE_NAME, + serviceTypeWithLocalDomain.split("\\."), + List.of(), /* subtypes */ + new String[]{"android", "local"}, /* hostName */ + PORT, + List.of(v4Address), + List.of(v6Address), + List.of() /* textStrings */, + List.of() /* textEntries */, + 1234, + network); + + // Verify onServiceUpdated callback. + listener.onServiceUpdated(updatedServiceInfo); + verify(serviceInfoCallback, timeout(TIMEOUT_MS).times(2)) + .onServiceUpdated(updateInfoCaptor.capture()); + verifyUpdatedServiceInfo(updateInfoCaptor.getAllValues().get(2) /* info */, SERVICE_NAME, + SERVICE_TYPE, + List.of(parseNumericAddress(v4Address), parseNumericAddress(v6Address)), + PORT, IFACE_IDX_ANY, new Network(999)); + + // Verify service callback unregistration. + client.unregisterServiceInfoCallback(serviceInfoCallback); + waitForIdle(); + verify(serviceInfoCallback, timeout(TIMEOUT_MS)).onServiceInfoCallbackUnregistered(); + } + + @Test + public void testRegisterServiceCallbackFailed() { + final NsdManager client = connectClient(mService); + final String invalidServiceType = "a_service"; + final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, invalidServiceType); + final NsdManager.ServiceInfoCallback serviceInfoCallback = mock( + NsdManager.ServiceInfoCallback.class); + client.registerServiceInfoCallback(request, Runnable::run, serviceInfoCallback); + waitForIdle(); + + // Fail to register service callback. + verify(serviceInfoCallback, timeout(TIMEOUT_MS)) + .onServiceInfoCallbackRegistrationFailed(eq(FAILURE_BAD_PARAMETERS)); + } + + @Test + public void testUnregisterNotRegisteredCallback() { + final NsdManager client = connectClient(mService); + final NsdManager.ServiceInfoCallback serviceInfoCallback = mock( + NsdManager.ServiceInfoCallback.class); + + assertThrows(IllegalArgumentException.class, () -> + client.unregisterServiceInfoCallback(serviceInfoCallback)); + } + + private void setMdnsDiscoveryManagerEnabled() { + doReturn(true).when(mDeps).isMdnsDiscoveryManagerEnabled(any(Context.class)); + } + + private void setMdnsAdvertiserEnabled() { + doReturn(true).when(mDeps).isMdnsAdvertiserEnabled(any(Context.class)); + } + + @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) + public void testMdnsDiscoveryManagerFeature() { + // Create NsdService w/o feature enabled. + final NsdManager client = connectClient(mService); + final DiscoveryListener discListenerWithoutFeature = mock(DiscoveryListener.class); + client.discoverServices(SERVICE_TYPE, PROTOCOL, discListenerWithoutFeature); + waitForIdle(); + + final ArgumentCaptor<Integer> legacyIdCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mMockMDnsM).discover(legacyIdCaptor.capture(), any(), anyInt()); + verifyNoMoreInteractions(mDiscoveryManager); + + setMdnsDiscoveryManagerEnabled(); + final DiscoveryListener discListenerWithFeature = mock(DiscoveryListener.class); + client.discoverServices(SERVICE_TYPE, PROTOCOL, discListenerWithFeature); + waitForIdle(); + + final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local"; + final ArgumentCaptor<MdnsServiceBrowserListener> listenerCaptor = + ArgumentCaptor.forClass(MdnsServiceBrowserListener.class); + verify(mDiscoveryManager).registerListener(eq(serviceTypeWithLocalDomain), + listenerCaptor.capture(), any()); + + client.stopServiceDiscovery(discListenerWithoutFeature); + waitForIdle(); + verify(mMockMDnsM).stopOperation(legacyIdCaptor.getValue()); + + client.stopServiceDiscovery(discListenerWithFeature); + waitForIdle(); + verify(mDiscoveryManager).unregisterListener(serviceTypeWithLocalDomain, + listenerCaptor.getValue()); + } + + @Test + public void testDiscoveryWithMdnsDiscoveryManager() { + setMdnsDiscoveryManagerEnabled(); + + final NsdManager client = connectClient(mService); + final DiscoveryListener discListener = mock(DiscoveryListener.class); + final Network network = new Network(999); + final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local"; + // Verify the discovery start / stop. + final ArgumentCaptor<MdnsServiceBrowserListener> listenerCaptor = + ArgumentCaptor.forClass(MdnsServiceBrowserListener.class); + client.discoverServices(SERVICE_TYPE, PROTOCOL, network, r -> r.run(), discListener); + waitForIdle(); + verify(mSocketProvider).startMonitoringSockets(); + verify(mDiscoveryManager).registerListener(eq(serviceTypeWithLocalDomain), + listenerCaptor.capture(), argThat(options -> network.equals(options.getNetwork()))); + verify(discListener, timeout(TIMEOUT_MS)).onDiscoveryStarted(SERVICE_TYPE); + + final MdnsServiceBrowserListener listener = listenerCaptor.getValue(); + final MdnsServiceInfo foundInfo = new MdnsServiceInfo( + SERVICE_NAME, /* serviceInstanceName */ + serviceTypeWithLocalDomain.split("\\."), /* serviceType */ + List.of(), /* subtypes */ + new String[] {"android", "local"}, /* hostName */ + 12345, /* port */ + List.of(IPV4_ADDRESS), + List.of(IPV6_ADDRESS), + List.of(), /* textStrings */ + List.of(), /* textEntries */ + 1234, /* interfaceIndex */ + network); + + // Verify onServiceNameDiscovered callback + listener.onServiceNameDiscovered(foundInfo); + verify(discListener, timeout(TIMEOUT_MS)).onServiceFound(argThat(info -> + info.getServiceName().equals(SERVICE_NAME) + // Service type in discovery callbacks has a dot at the end + && info.getServiceType().equals(SERVICE_TYPE + ".") + && info.getNetwork().equals(network))); + + final MdnsServiceInfo removedInfo = new MdnsServiceInfo( + SERVICE_NAME, /* serviceInstanceName */ + serviceTypeWithLocalDomain.split("\\."), /* serviceType */ + null, /* subtypes */ + null, /* hostName */ + 0, /* port */ + List.of(), /* ipv4Address */ + List.of(), /* ipv6Address */ + null, /* textStrings */ + null, /* textEntries */ + 1234, /* interfaceIndex */ + network); + // Verify onServiceNameRemoved callback + listener.onServiceNameRemoved(removedInfo); + verify(discListener, timeout(TIMEOUT_MS)).onServiceLost(argThat(info -> + info.getServiceName().equals(SERVICE_NAME) + // Service type in discovery callbacks has a dot at the end + && info.getServiceType().equals(SERVICE_TYPE + ".") + && info.getNetwork().equals(network))); + + client.stopServiceDiscovery(discListener); + waitForIdle(); + verify(mDiscoveryManager).unregisterListener(eq(serviceTypeWithLocalDomain), any()); + verify(discListener, timeout(TIMEOUT_MS)).onDiscoveryStopped(SERVICE_TYPE); + verify(mSocketProvider, timeout(CLEANUP_DELAY_MS + TIMEOUT_MS)).requestStopWhenInactive(); + } + + @Test + public void testDiscoveryWithMdnsDiscoveryManager_FailedWithInvalidServiceType() { + setMdnsDiscoveryManagerEnabled(); + + final NsdManager client = connectClient(mService); + final DiscoveryListener discListener = mock(DiscoveryListener.class); + final Network network = new Network(999); + final String invalidServiceType = "a_service"; + client.discoverServices( + invalidServiceType, PROTOCOL, network, r -> r.run(), discListener); + waitForIdle(); + verify(discListener, timeout(TIMEOUT_MS)) + .onStartDiscoveryFailed(invalidServiceType, FAILURE_INTERNAL_ERROR); + + final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local"; + client.discoverServices( + serviceTypeWithLocalDomain, PROTOCOL, network, r -> r.run(), discListener); + waitForIdle(); + verify(discListener, timeout(TIMEOUT_MS)) + .onStartDiscoveryFailed(serviceTypeWithLocalDomain, FAILURE_INTERNAL_ERROR); + + final String serviceTypeWithoutTcpOrUdpEnding = "_test._com"; + client.discoverServices( + serviceTypeWithoutTcpOrUdpEnding, PROTOCOL, network, r -> r.run(), discListener); + waitForIdle(); + verify(discListener, timeout(TIMEOUT_MS)) + .onStartDiscoveryFailed(serviceTypeWithoutTcpOrUdpEnding, FAILURE_INTERNAL_ERROR); + } + + @Test + @EnableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) + public void testDiscoveryWithMdnsDiscoveryManager_UsesSubtypes() { + final String typeWithSubtype = SERVICE_TYPE + ",_subtype"; + final NsdManager client = connectClient(mService); + final NsdServiceInfo regInfo = new NsdServiceInfo("Instance", typeWithSubtype); + final Network network = new Network(999); + regInfo.setHostAddresses(List.of(parseNumericAddress("192.0.2.123"))); + regInfo.setPort(12345); + regInfo.setNetwork(network); + + final RegistrationListener regListener = mock(RegistrationListener.class); + client.registerService(regInfo, NsdManager.PROTOCOL_DNS_SD, Runnable::run, regListener); + waitForIdle(); + verify(mAdvertiser).addService(anyInt(), argThat(s -> + "Instance".equals(s.getServiceName()) + && SERVICE_TYPE.equals(s.getServiceType())), eq("_subtype")); + + final DiscoveryListener discListener = mock(DiscoveryListener.class); + client.discoverServices(typeWithSubtype, PROTOCOL, network, Runnable::run, discListener); + waitForIdle(); + final ArgumentCaptor<MdnsSearchOptions> optionsCaptor = + ArgumentCaptor.forClass(MdnsSearchOptions.class); + verify(mDiscoveryManager).registerListener(eq(SERVICE_TYPE + ".local"), any(), + optionsCaptor.capture()); + assertEquals(Collections.singletonList("subtype"), optionsCaptor.getValue().getSubtypes()); + } + + @Test + public void testResolutionWithMdnsDiscoveryManager() throws UnknownHostException { + setMdnsDiscoveryManagerEnabled(); + + final NsdManager client = connectClient(mService); + final ResolveListener resolveListener = mock(ResolveListener.class); + final Network network = new Network(999); + final String serviceType = "_nsd._service._tcp"; + final String constructedServiceType = "_service._tcp.local"; + final ArgumentCaptor<MdnsServiceBrowserListener> listenerCaptor = + ArgumentCaptor.forClass(MdnsServiceBrowserListener.class); + final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, serviceType); + request.setNetwork(network); + client.resolveService(request, resolveListener); + waitForIdle(); + verify(mSocketProvider).startMonitoringSockets(); + final ArgumentCaptor<MdnsSearchOptions> optionsCaptor = + ArgumentCaptor.forClass(MdnsSearchOptions.class); + verify(mDiscoveryManager).registerListener(eq(constructedServiceType), + listenerCaptor.capture(), + optionsCaptor.capture()); + assertEquals(network, optionsCaptor.getValue().getNetwork()); + // Subtypes are not used for resolution, only for discovery + assertEquals(Collections.emptyList(), optionsCaptor.getValue().getSubtypes()); + + final MdnsServiceBrowserListener listener = listenerCaptor.getValue(); + final MdnsServiceInfo mdnsServiceInfo = new MdnsServiceInfo( + SERVICE_NAME, + constructedServiceType.split("\\."), + List.of(), /* subtypes */ + new String[]{"android", "local"}, /* hostName */ + PORT, + List.of(IPV4_ADDRESS), + List.of("2001:db8::1", "2001:db8::2"), + List.of() /* textStrings */, + List.of(MdnsServiceInfo.TextEntry.fromBytes(new byte[]{ + 'k', 'e', 'y', '=', (byte) 0xFF, (byte) 0xFE})) /* textEntries */, + 1234, + network); + + // Verify onServiceFound callback + listener.onServiceFound(mdnsServiceInfo); + final ArgumentCaptor<NsdServiceInfo> infoCaptor = + ArgumentCaptor.forClass(NsdServiceInfo.class); + verify(resolveListener, timeout(TIMEOUT_MS)).onServiceResolved(infoCaptor.capture()); + final NsdServiceInfo info = infoCaptor.getValue(); + assertEquals(SERVICE_NAME, info.getServiceName()); + assertEquals("._service._tcp", info.getServiceType()); + assertEquals(PORT, info.getPort()); + assertTrue(info.getAttributes().containsKey("key")); + assertEquals(1, info.getAttributes().size()); + assertArrayEquals(new byte[]{(byte) 0xFF, (byte) 0xFE}, info.getAttributes().get("key")); + assertEquals(parseNumericAddress(IPV4_ADDRESS), info.getHost()); + assertEquals(3, info.getHostAddresses().size()); + assertTrue(info.getHostAddresses().stream().anyMatch( + address -> address.equals(parseNumericAddress("2001:db8::1")))); + assertTrue(info.getHostAddresses().stream().anyMatch( + address -> address.equals(parseNumericAddress("2001:db8::2")))); + assertEquals(network, info.getNetwork()); + + // Verify the listener has been unregistered. + verify(mDiscoveryManager, timeout(TIMEOUT_MS)) + .unregisterListener(eq(constructedServiceType), any()); + verify(mSocketProvider, timeout(CLEANUP_DELAY_MS + TIMEOUT_MS)).requestStopWhenInactive(); + } + + @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) + public void testMdnsAdvertiserFeatureFlagging() { + // Create NsdService w/o feature enabled. + final NsdManager client = connectClient(mService); + final NsdServiceInfo regInfo = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE); + regInfo.setHost(parseNumericAddress("192.0.2.123")); + regInfo.setPort(12345); + final RegistrationListener regListenerWithoutFeature = mock(RegistrationListener.class); + client.registerService(regInfo, PROTOCOL, regListenerWithoutFeature); + waitForIdle(); + + final ArgumentCaptor<Integer> legacyIdCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mMockMDnsM).registerService(legacyIdCaptor.capture(), any(), any(), anyInt(), + any(), anyInt()); + verifyNoMoreInteractions(mAdvertiser); + + setMdnsAdvertiserEnabled(); + final RegistrationListener regListenerWithFeature = mock(RegistrationListener.class); + client.registerService(regInfo, PROTOCOL, regListenerWithFeature); + waitForIdle(); + + final ArgumentCaptor<Integer> serviceIdCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mAdvertiser).addService(serviceIdCaptor.capture(), + argThat(info -> matches(info, regInfo)), eq(null) /* subtype */); + + client.unregisterService(regListenerWithoutFeature); + waitForIdle(); + verify(mMockMDnsM).stopOperation(legacyIdCaptor.getValue()); + verify(mAdvertiser, never()).removeService(anyInt()); + + client.unregisterService(regListenerWithFeature); + waitForIdle(); + verify(mAdvertiser).removeService(serviceIdCaptor.getValue()); + } + + @Test + @DisableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) + public void testTypeSpecificFeatureFlagging() { + doReturn("_type1._tcp:flag1,_type2._tcp:flag2").when(mDeps).getTypeAllowlistFlags(); + doReturn(true).when(mDeps).isFeatureEnabled(any(), + eq("mdns_discovery_manager_allowlist_flag1_version")); + doReturn(true).when(mDeps).isFeatureEnabled(any(), + eq("mdns_advertiser_allowlist_flag2_version")); + + final NsdManager client = connectClient(mService); + final NsdServiceInfo service1 = new NsdServiceInfo(SERVICE_NAME, "_type1._tcp"); + service1.setHostAddresses(List.of(parseNumericAddress("2001:db8::123"))); + service1.setPort(1234); + final NsdServiceInfo service2 = new NsdServiceInfo(SERVICE_NAME, "_type2._tcp"); + service2.setHostAddresses(List.of(parseNumericAddress("2001:db8::123"))); + service2.setPort(1234); + + client.discoverServices(service1.getServiceType(), + NsdManager.PROTOCOL_DNS_SD, mock(DiscoveryListener.class)); + client.discoverServices(service2.getServiceType(), + NsdManager.PROTOCOL_DNS_SD, mock(DiscoveryListener.class)); + waitForIdle(); + + // The DiscoveryManager is enabled for _type1 but not _type2 + verify(mDiscoveryManager).registerListener(eq("_type1._tcp.local"), any(), any()); + verify(mDiscoveryManager, never()).registerListener( + eq("_type2._tcp.local"), any(), any()); + + client.resolveService(service1, mock(ResolveListener.class)); + client.resolveService(service2, mock(ResolveListener.class)); + waitForIdle(); + + // Same behavior for resolve + verify(mDiscoveryManager, times(2)).registerListener( + eq("_type1._tcp.local"), any(), any()); + verify(mDiscoveryManager, never()).registerListener( + eq("_type2._tcp.local"), any(), any()); + + client.registerService(service1, NsdManager.PROTOCOL_DNS_SD, + mock(RegistrationListener.class)); + client.registerService(service2, NsdManager.PROTOCOL_DNS_SD, + mock(RegistrationListener.class)); + waitForIdle(); + + // The advertiser is enabled for _type2 but not _type1 + verify(mAdvertiser, never()).addService( + anyInt(), argThat(info -> matches(info, service1)), eq(null) /* subtype */); + verify(mAdvertiser).addService( + anyInt(), argThat(info -> matches(info, service2)), eq(null) /* subtype */); + } + + @Test + public void testAdvertiseWithMdnsAdvertiser() { + setMdnsAdvertiserEnabled(); + + final NsdManager client = connectClient(mService); + final RegistrationListener regListener = mock(RegistrationListener.class); + // final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local"; + final ArgumentCaptor<MdnsAdvertiser.AdvertiserCallback> cbCaptor = + ArgumentCaptor.forClass(MdnsAdvertiser.AdvertiserCallback.class); + verify(mDeps).makeMdnsAdvertiser(any(), any(), cbCaptor.capture(), any()); + + final NsdServiceInfo regInfo = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE); + regInfo.setHost(parseNumericAddress("192.0.2.123")); + regInfo.setPort(12345); + regInfo.setAttribute("testattr", "testvalue"); + regInfo.setNetwork(new Network(999)); + + client.registerService(regInfo, NsdManager.PROTOCOL_DNS_SD, Runnable::run, regListener); + waitForIdle(); + verify(mSocketProvider).startMonitoringSockets(); + final ArgumentCaptor<Integer> idCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mAdvertiser).addService(idCaptor.capture(), argThat(info -> + matches(info, regInfo)), eq(null) /* subtype */); + + // Verify onServiceRegistered callback + final MdnsAdvertiser.AdvertiserCallback cb = cbCaptor.getValue(); + cb.onRegisterServiceSucceeded(idCaptor.getValue(), regInfo); + + verify(regListener, timeout(TIMEOUT_MS)).onServiceRegistered(argThat(info -> matches(info, + new NsdServiceInfo(regInfo.getServiceName(), null)))); + + client.unregisterService(regListener); + waitForIdle(); + verify(mAdvertiser).removeService(idCaptor.getValue()); + verify(regListener, timeout(TIMEOUT_MS)).onServiceUnregistered( + argThat(info -> matches(info, regInfo))); + verify(mSocketProvider, timeout(TIMEOUT_MS)).requestStopWhenInactive(); + } + + @Test + public void testAdvertiseWithMdnsAdvertiser_FailedWithInvalidServiceType() { + setMdnsAdvertiserEnabled(); + + final NsdManager client = connectClient(mService); + final RegistrationListener regListener = mock(RegistrationListener.class); + // final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local"; + final ArgumentCaptor<MdnsAdvertiser.AdvertiserCallback> cbCaptor = + ArgumentCaptor.forClass(MdnsAdvertiser.AdvertiserCallback.class); + verify(mDeps).makeMdnsAdvertiser(any(), any(), cbCaptor.capture(), any()); + + final NsdServiceInfo regInfo = new NsdServiceInfo(SERVICE_NAME, "invalid_type"); + regInfo.setHost(parseNumericAddress("192.0.2.123")); + regInfo.setPort(12345); + regInfo.setAttribute("testattr", "testvalue"); + regInfo.setNetwork(new Network(999)); + + client.registerService(regInfo, NsdManager.PROTOCOL_DNS_SD, Runnable::run, regListener); + waitForIdle(); + verify(mAdvertiser, never()).addService(anyInt(), any(), any()); + + verify(regListener, timeout(TIMEOUT_MS)).onRegistrationFailed( + argThat(info -> matches(info, regInfo)), eq(FAILURE_INTERNAL_ERROR)); + } + + @Test + public void testAdvertiseWithMdnsAdvertiser_LongServiceName() { + setMdnsAdvertiserEnabled(); + + final NsdManager client = connectClient(mService); + final RegistrationListener regListener = mock(RegistrationListener.class); + // final String serviceTypeWithLocalDomain = SERVICE_TYPE + ".local"; + final ArgumentCaptor<MdnsAdvertiser.AdvertiserCallback> cbCaptor = + ArgumentCaptor.forClass(MdnsAdvertiser.AdvertiserCallback.class); + verify(mDeps).makeMdnsAdvertiser(any(), any(), cbCaptor.capture(), any()); + + final NsdServiceInfo regInfo = new NsdServiceInfo("a".repeat(70), SERVICE_TYPE); + regInfo.setHost(parseNumericAddress("192.0.2.123")); + regInfo.setPort(12345); + regInfo.setAttribute("testattr", "testvalue"); + regInfo.setNetwork(new Network(999)); + + client.registerService(regInfo, NsdManager.PROTOCOL_DNS_SD, Runnable::run, regListener); + waitForIdle(); + final ArgumentCaptor<Integer> idCaptor = ArgumentCaptor.forClass(Integer.class); + // Service name is truncated to 63 characters + verify(mAdvertiser).addService(idCaptor.capture(), + argThat(info -> info.getServiceName().equals("a".repeat(63))), + eq(null) /* subtype */); + + // Verify onServiceRegistered callback + final MdnsAdvertiser.AdvertiserCallback cb = cbCaptor.getValue(); + cb.onRegisterServiceSucceeded(idCaptor.getValue(), regInfo); + + verify(regListener, timeout(TIMEOUT_MS)).onServiceRegistered( + argThat(info -> matches(info, new NsdServiceInfo(regInfo.getServiceName(), null)))); + } + + @Test + public void testStopServiceResolutionWithMdnsDiscoveryManager() { + setMdnsDiscoveryManagerEnabled(); + + final NsdManager client = connectClient(mService); + final ResolveListener resolveListener = mock(ResolveListener.class); + final Network network = new Network(999); + final String serviceType = "_nsd._service._tcp"; + final String constructedServiceType = "_service._tcp.local"; + final ArgumentCaptor<MdnsServiceBrowserListener> listenerCaptor = + ArgumentCaptor.forClass(MdnsServiceBrowserListener.class); + final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, serviceType); + request.setNetwork(network); + client.resolveService(request, resolveListener); + waitForIdle(); + verify(mSocketProvider).startMonitoringSockets(); + final ArgumentCaptor<MdnsSearchOptions> optionsCaptor = + ArgumentCaptor.forClass(MdnsSearchOptions.class); + verify(mDiscoveryManager).registerListener(eq(constructedServiceType), + listenerCaptor.capture(), + optionsCaptor.capture()); + assertEquals(network, optionsCaptor.getValue().getNetwork()); + // Subtypes are not used for resolution, only for discovery + assertEquals(Collections.emptyList(), optionsCaptor.getValue().getSubtypes()); + + client.stopServiceResolution(resolveListener); + waitForIdle(); + + // Verify the listener has been unregistered. + verify(mDiscoveryManager, timeout(TIMEOUT_MS)) + .unregisterListener(eq(constructedServiceType), eq(listenerCaptor.getValue())); + verify(resolveListener, timeout(TIMEOUT_MS)).onResolutionStopped(argThat(ns -> + request.getServiceName().equals(ns.getServiceName()) + && request.getServiceType().equals(ns.getServiceType()))); + verify(mSocketProvider, timeout(CLEANUP_DELAY_MS + TIMEOUT_MS)).requestStopWhenInactive(); + } + + @Test + public void testParseTypeAndSubtype() { + final String serviceType1 = "test._tcp"; + final String serviceType2 = "_test._quic"; + final String serviceType3 = "_test._quic,_test1,_test2"; + final String serviceType4 = "_123._udp."; + final String serviceType5 = "_TEST._999._tcp."; + final String serviceType6 = "_998._tcp.,_TEST"; + final String serviceType7 = "_997._tcp,_TEST"; + + assertNull(parseTypeAndSubtype(serviceType1)); + assertNull(parseTypeAndSubtype(serviceType2)); + assertNull(parseTypeAndSubtype(serviceType3)); + assertEquals(new Pair<>("_123._udp", null), parseTypeAndSubtype(serviceType4)); + assertEquals(new Pair<>("_999._tcp", "_TEST"), parseTypeAndSubtype(serviceType5)); + assertEquals(new Pair<>("_998._tcp", "_TEST"), parseTypeAndSubtype(serviceType6)); + assertEquals(new Pair<>("_997._tcp", "_TEST"), parseTypeAndSubtype(serviceType7)); + } + + @Test + @EnableCompatChanges(ENABLE_PLATFORM_MDNS_BACKEND) + public void testEnablePlatformMdnsBackend() { + final NsdManager client = connectClient(mService); + final NsdServiceInfo regInfo = new NsdServiceInfo("a".repeat(70), SERVICE_TYPE); + final Network network = new Network(999); + regInfo.setHostAddresses(List.of(parseNumericAddress("192.0.2.123"))); + regInfo.setPort(12345); + regInfo.setAttribute("testattr", "testvalue"); + regInfo.setNetwork(network); + + // Verify the registration uses MdnsAdvertiser + final RegistrationListener regListener = mock(RegistrationListener.class); + client.registerService(regInfo, NsdManager.PROTOCOL_DNS_SD, Runnable::run, regListener); + waitForIdle(); + verify(mSocketProvider).startMonitoringSockets(); + verify(mAdvertiser).addService(anyInt(), any(), any()); + + // Verify the discovery uses MdnsDiscoveryManager + final DiscoveryListener discListener = mock(DiscoveryListener.class); + client.discoverServices(SERVICE_TYPE, PROTOCOL, network, r -> r.run(), discListener); + waitForIdle(); + verify(mDiscoveryManager).registerListener(anyString(), any(), any()); + + // Verify the discovery uses MdnsDiscoveryManager + final ResolveListener resolveListener = mock(ResolveListener.class); + client.resolveService(regInfo, r -> r.run(), resolveListener); + waitForIdle(); + verify(mDiscoveryManager, times(2)).registerListener(anyString(), any(), any()); + } + private void waitForIdle() { HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS); } NsdService makeService() { - final NsdService service = new NsdService(mContext, mHandler, CLEANUP_DELAY_MS) { + final NsdService service = new NsdService(mContext, mHandler, CLEANUP_DELAY_MS, mDeps) { @Override - public INsdServiceConnector connect(INsdManagerCallback baseCb) { + public INsdServiceConnector connect(INsdManagerCallback baseCb, + boolean runNewMdnsBackend) { // Wrap the callback in a transparent mock, to mock asBinder returning a // LinkToDeathRecorder. This will allow recording the binder death recipient // registered on the callback. Use a transparent mock and not a spy as the actual @@ -571,7 +1353,7 @@ AdditionalAnswers.delegatesTo(baseCb)); doReturn(new LinkToDeathRecorder()).when(cb).asBinder(); mCreatedCallbacks.add(cb); - return super.connect(cb); + return super.connect(cb, runNewMdnsBackend); } }; return service; @@ -599,6 +1381,19 @@ verify(mMockMDnsM, timeout(cleanupDelayMs + TIMEOUT_MS)).stopDaemon(); } + /** + * Return true if two service info are the same. + * + * Useful for argument matchers as {@link NsdServiceInfo} does not implement equals. + */ + private boolean matches(NsdServiceInfo a, NsdServiceInfo b) { + return Objects.equals(a.getServiceName(), b.getServiceName()) + && Objects.equals(a.getServiceType(), b.getServiceType()) + && Objects.equals(a.getHost(), b.getHost()) + && Objects.equals(a.getNetwork(), b.getNetwork()) + && Objects.equals(a.getAttributes(), b.getAttributes()); + } + public static class TestHandler extends Handler { public Message lastMessage;
diff --git a/tests/unit/java/com/android/server/VpnManagerServiceTest.java b/tests/unit/java/com/android/server/VpnManagerServiceTest.java index c8a93a6..deb56ef 100644 --- a/tests/unit/java/com/android/server/VpnManagerServiceTest.java +++ b/tests/unit/java/com/android/server/VpnManagerServiceTest.java
@@ -131,6 +131,11 @@ Vpn vpn, VpnProfile profile) { return mLockdownVpnTracker; } + + @Override + public @UserIdInt int getMainUserId() { + return UserHandle.USER_SYSTEM; + } } @Before
diff --git a/tests/unit/java/com/android/server/connectivity/ApplicationSelfCertifiedNetworkCapabilitiesTest.kt b/tests/unit/java/com/android/server/connectivity/ApplicationSelfCertifiedNetworkCapabilitiesTest.kt new file mode 100644 index 0000000..f2d7aaa --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/ApplicationSelfCertifiedNetworkCapabilitiesTest.kt
@@ -0,0 +1,96 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity + +import android.net.NetworkCapabilities +import android.os.Build +import androidx.test.InstrumentationRegistry +import androidx.test.filters.SmallTest +import com.android.frameworks.tests.net.R +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import com.google.common.truth.Truth.assertThat +import kotlin.test.assertFailsWith +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(DevSdkIgnoreRunner::class) +@SmallTest +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) +class ApplicationSelfCertifiedNetworkCapabilitiesTest { + private val mResource = InstrumentationRegistry.getContext().getResources() + private val bandwidthCapability = NetworkCapabilities.Builder().apply { + addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + }.build() + private val latencyCapability = NetworkCapabilities.Builder().apply { + addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) + }.build() + private val emptyCapability = NetworkCapabilities.Builder().build() + private val bothCapabilities = NetworkCapabilities.Builder().apply { + addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) + addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) + }.build() + + @Test + fun parseXmlWithWrongTag_shouldIgnoreWrongTag() { + val parser = mResource.getXml( + R.xml.self_certified_capabilities_wrong_tag + ) + val selfDeclaredCaps = ApplicationSelfCertifiedNetworkCapabilities.createFromXml(parser) + selfDeclaredCaps.enforceSelfCertifiedNetworkCapabilitiesDeclared(latencyCapability) + selfDeclaredCaps.enforceSelfCertifiedNetworkCapabilitiesDeclared(bandwidthCapability) + } + + @Test + fun parseXmlWithWrongDeclaration_shouldThrowException() { + val parser = mResource.getXml( + R.xml.self_certified_capabilities_wrong_declaration + ) + val exception = assertFailsWith<InvalidTagException> { + ApplicationSelfCertifiedNetworkCapabilities.createFromXml(parser) + } + assertThat(exception.message).contains("network-capabilities-declaration1") + } + + @Test + fun checkIfSelfCertifiedNetworkCapabilitiesDeclared_shouldThrowExceptionWhenNoDeclaration() { + val parser = mResource.getXml(R.xml.self_certified_capabilities_other) + val selfDeclaredCaps = ApplicationSelfCertifiedNetworkCapabilities.createFromXml(parser) + val exception1 = assertFailsWith<SecurityException> { + selfDeclaredCaps.enforceSelfCertifiedNetworkCapabilitiesDeclared(latencyCapability) + } + assertThat(exception1.message).contains( + ApplicationSelfCertifiedNetworkCapabilities.PRIORITIZE_LATENCY + ) + val exception2 = assertFailsWith<SecurityException> { + selfDeclaredCaps.enforceSelfCertifiedNetworkCapabilitiesDeclared(bandwidthCapability) + } + assertThat(exception2.message).contains( + ApplicationSelfCertifiedNetworkCapabilities.PRIORITIZE_BANDWIDTH + ) + } + + @Test + fun checkIfSelfCertifiedNetworkCapabilitiesDeclared_shouldPassIfDeclarationExist() { + val parser = mResource.getXml(R.xml.self_certified_capabilities_both) + val selfDeclaredCaps = ApplicationSelfCertifiedNetworkCapabilities.createFromXml(parser) + selfDeclaredCaps.enforceSelfCertifiedNetworkCapabilitiesDeclared(latencyCapability) + selfDeclaredCaps.enforceSelfCertifiedNetworkCapabilitiesDeclared(bandwidthCapability) + selfDeclaredCaps.enforceSelfCertifiedNetworkCapabilitiesDeclared(bothCapabilities) + selfDeclaredCaps.enforceSelfCertifiedNetworkCapabilitiesDeclared(emptyCapability) + } +}
diff --git a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java new file mode 100644 index 0000000..9e0435d --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
@@ -0,0 +1,394 @@ +/* + * 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; + +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.longThat; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.app.AlarmManager; +import android.content.Context; +import android.content.res.Resources; +import android.net.INetd; +import android.net.ISocketKeepaliveCallback; +import android.net.KeepalivePacketData; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.MarkMaskParcel; +import android.net.NattKeepalivePacketData; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.os.Binder; +import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.connectivity.resources.R; +import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; +import com.android.testutils.HandlerUtils; + +import libcore.util.HexEncoding; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.FileDescriptor; +import java.net.InetAddress; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(DevSdkIgnoreRunner.class) +@SmallTest +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) +public class AutomaticOnOffKeepaliveTrackerTest { + private static final String TAG = AutomaticOnOffKeepaliveTrackerTest.class.getSimpleName(); + private static final int TEST_NETID = 0xA85; + private static final int TEST_NETID_FWMARK = 0x0A85; + private static final int OTHER_NETID = 0x1A85; + private static final int NETID_MASK = 0xffff; + private static final int TIMEOUT_MS = 30_000; + private static final int MOCK_RESOURCE_ID = 5; + private static final int TEST_KEEPALIVE_INTERVAL_SEC = 10; + private AutomaticOnOffKeepaliveTracker mAOOKeepaliveTracker; + private HandlerThread mHandlerThread; + + @Mock INetd mNetd; + @Mock AutomaticOnOffKeepaliveTracker.Dependencies mDependencies; + @Mock Context mCtx; + @Mock AlarmManager mAlarmManager; + TestKeepaliveTracker mKeepaliveTracker; + AOOTestHandler mTestHandler; + + // Hexadecimal representation of a SOCK_DIAG response with tcp info. + private static final String SOCK_DIAG_TCP_INET_HEX = + // struct nlmsghdr. + "14010000" + // length = 276 + "1400" + // type = SOCK_DIAG_BY_FAMILY + "0301" + // flags = NLM_F_REQUEST | NLM_F_DUMP + "00000000" + // seqno + "00000000" + // pid (0 == kernel) + // struct inet_diag_req_v2 + "02" + // family = AF_INET + "06" + // state + "00" + // timer + "00" + // retrans + // inet_diag_sockid + "DEA5" + // idiag_sport = 42462 + "71B9" + // idiag_dport = 47473 + "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 + "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 + "00000000" + // idiag_if + "34ED000076270000" + // idiag_cookie = 43387759684916 + "00000000" + // idiag_expires + "00000000" + // idiag_rqueue + "00000000" + // idiag_wqueue + "00000000" + // idiag_uid + "00000000" + // idiag_inode + // rtattr + "0500" + // len = 5 + "0800" + // type = 8 + "00000000" + // data + "0800" + // len = 8 + "0F00" + // type = 15(INET_DIAG_MARK) + "850A0C00" + // data, socket mark=789125 + "AC00" + // len = 172 + "0200" + // type = 2(INET_DIAG_INFO) + // tcp_info + "01" + // state = TCP_ESTABLISHED + "00" + // ca_state = TCP_CA_OPEN + "05" + // retransmits = 5 + "00" + // probes = 0 + "00" + // backoff = 0 + "07" + // option = TCPI_OPT_WSCALE|TCPI_OPT_SACK|TCPI_OPT_TIMESTAMPS + "88" + // wscale = 8 + "00" + // delivery_rate_app_limited = 0 + "4A911B00" + // rto = 1806666 + "00000000" + // ato = 0 + "2E050000" + // sndMss = 1326 + "18020000" + // rcvMss = 536 + "00000000" + // unsacked = 0 + "00000000" + // acked = 0 + "00000000" + // lost = 0 + "00000000" + // retrans = 0 + "00000000" + // fackets = 0 + "BB000000" + // lastDataSent = 187 + "00000000" + // lastAckSent = 0 + "BB000000" + // lastDataRecv = 187 + "BB000000" + // lastDataAckRecv = 187 + "DC050000" + // pmtu = 1500 + "30560100" + // rcvSsthresh = 87600 + "3E2C0900" + // rttt = 601150 + "1F960400" + // rttvar = 300575 + "78050000" + // sndSsthresh = 1400 + "0A000000" + // sndCwnd = 10 + "A8050000" + // advmss = 1448 + "03000000" + // reordering = 3 + "00000000" + // rcvrtt = 0 + "30560100" + // rcvspace = 87600 + "00000000" + // totalRetrans = 0 + "53AC000000000000" + // pacingRate = 44115 + "FFFFFFFFFFFFFFFF" + // maxPacingRate = 18446744073709551615 + "0100000000000000" + // bytesAcked = 1 + "0000000000000000" + // bytesReceived = 0 + "0A000000" + // SegsOut = 10 + "00000000" + // SegsIn = 0 + "00000000" + // NotSentBytes = 0 + "3E2C0900" + // minRtt = 601150 + "00000000" + // DataSegsIn = 0 + "00000000" + // DataSegsOut = 0 + "0000000000000000"; // deliverRate = 0 + private static final String SOCK_DIAG_NO_TCP_INET_HEX = + // struct nlmsghdr + "14000000" // length = 20 + + "0300" // type = NLMSG_DONE + + "0301" // flags = NLM_F_REQUEST | NLM_F_DUMP + + "00000000" // seqno + + "00000000" // pid (0 == kernel) + // struct inet_diag_req_v2 + + "02" // family = AF_INET + + "06" // state + + "00" // timer + + "00"; // retrans + private static final byte[] SOCK_DIAG_NO_TCP_INET_BYTES = + HexEncoding.decode(SOCK_DIAG_NO_TCP_INET_HEX.toCharArray(), false); + private static final String TEST_RESPONSE_HEX = + SOCK_DIAG_TCP_INET_HEX + SOCK_DIAG_NO_TCP_INET_HEX; + private static final byte[] TEST_RESPONSE_BYTES = + HexEncoding.decode(TEST_RESPONSE_HEX.toCharArray(), false); + + private class TestKeepaliveTracker extends KeepaliveTracker { + private KeepaliveInfo mKi; + + TestKeepaliveTracker(@NonNull final Context context, @NonNull final Handler handler) { + super(context, handler); + } + + public void setReturnedKeepaliveInfo(@NonNull final KeepaliveInfo ki) { + mKi = ki; + } + + @NonNull + @Override + public KeepaliveInfo makeNattKeepaliveInfo(@Nullable final NetworkAgentInfo nai, + @Nullable final FileDescriptor fd, final int intervalSeconds, + @NonNull final ISocketKeepaliveCallback cb, @NonNull final String srcAddrString, + final int srcPort, + @NonNull final String dstAddrString, final int dstPort) { + if (null == mKi) { + throw new IllegalStateException("Must call setReturnedKeepaliveInfo"); + } + return mKi; + } + } + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + + doReturn(PERMISSION_GRANTED).when(mCtx).checkPermission(any() /* permission */, + anyInt() /* pid */, anyInt() /* uid */); + ConnectivityResources.setResourcesContextForTest(mCtx); + final Resources mockResources = mock(Resources.class); + doReturn(new String[] { "0,3", "3,3" }).when(mockResources) + .getStringArray(R.array.config_networkSupportedKeepaliveCount); + doReturn(mockResources).when(mCtx).getResources(); + doReturn(mNetd).when(mDependencies).getNetd(); + doReturn(mAlarmManager).when(mDependencies).getAlarmManager(any()); + doReturn(makeMarkMaskParcel(NETID_MASK, TEST_NETID_FWMARK)).when(mNetd) + .getFwmarkForNetwork(TEST_NETID); + + doNothing().when(mDependencies).sendRequest(any(), any()); + + mHandlerThread = new HandlerThread("KeepaliveTrackerTest"); + mHandlerThread.start(); + mTestHandler = new AOOTestHandler(mHandlerThread.getLooper()); + mKeepaliveTracker = new TestKeepaliveTracker(mCtx, mTestHandler); + doReturn(mKeepaliveTracker).when(mDependencies).newKeepaliveTracker(mCtx, mTestHandler); + doReturn(true).when(mDependencies).isFeatureEnabled(any(), anyBoolean()); + mAOOKeepaliveTracker = + new AutomaticOnOffKeepaliveTracker(mCtx, mTestHandler, mDependencies); + } + + private final class AOOTestHandler extends Handler { + public AutomaticOnOffKeepaliveTracker.AutomaticOnOffKeepalive mLastAutoKi = null; + + AOOTestHandler(@NonNull final Looper looper) { + super(looper); + } + + @Override + public void handleMessage(@NonNull final Message msg) { + switch (msg.what) { + case AutomaticOnOffKeepaliveTracker.CMD_REQUEST_START_KEEPALIVE: + Log.d(TAG, "Test handler received CMD_REQUEST_START_KEEPALIVE : " + msg); + mAOOKeepaliveTracker.handleStartKeepalive(msg); + break; + case AutomaticOnOffKeepaliveTracker.CMD_MONITOR_AUTOMATIC_KEEPALIVE: + Log.d(TAG, "Test handler received CMD_MONITOR_AUTOMATIC_KEEPALIVE : " + msg); + mLastAutoKi = mAOOKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj); + break; + } + } + } + + @Test + public void testIsAnyTcpSocketConnected_runOnNonHandlerThread() throws Exception { + setupResponseWithSocketExisting(); + assertThrows(IllegalStateException.class, + () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID)); + } + + @Test + public void testIsAnyTcpSocketConnected_withTargetNetId() throws Exception { + setupResponseWithSocketExisting(); + mTestHandler.post( + () -> assertTrue(mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID))); + } + + @Test + public void testIsAnyTcpSocketConnected_withIncorrectNetId() throws Exception { + setupResponseWithSocketExisting(); + mTestHandler.post( + () -> assertFalse(mAOOKeepaliveTracker.isAnyTcpSocketConnected(OTHER_NETID))); + } + + @Test + public void testIsAnyTcpSocketConnected_noSocketExists() throws Exception { + setupResponseWithoutSocketExisting(); + mTestHandler.post( + () -> assertFalse(mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID))); + } + + @Test + public void testAlarm() throws Exception { + final InetAddress srcAddress = InetAddress.getByAddress( + new byte[] { (byte) 192, 0, 0, (byte) 129 }); + final int srcPort = 12345; + final InetAddress dstAddress = InetAddress.getByAddress(new byte[] { 8, 8, 8, 8}); + final int dstPort = 12345; + + final NetworkAgentInfo nai = mock(NetworkAgentInfo.class); + nai.networkCapabilities = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR).build(); + nai.networkInfo = new NetworkInfo(TYPE_MOBILE, 0 /* subtype */, "LTE", "LTE"); + nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "test reason", + "test extra info"); + nai.linkProperties = new LinkProperties(); + nai.linkProperties.addLinkAddress(new LinkAddress(srcAddress, 24)); + + final Socket socket = new Socket(); + socket.bind(null); + final FileDescriptor fd = socket.getFileDescriptor$(); + final IBinder binder = new Binder(); + final ISocketKeepaliveCallback cb = mock(ISocketKeepaliveCallback.class); + doReturn(binder).when(cb).asBinder(); + final Network underpinnedNetwork = mock(Network.class); + + final KeepalivePacketData kpd = new NattKeepalivePacketData(srcAddress, srcPort, + dstAddress, dstPort, new byte[] {1}); + final KeepaliveInfo ki = mKeepaliveTracker.new KeepaliveInfo(cb, nai, kpd, + TEST_KEEPALIVE_INTERVAL_SEC, KeepaliveInfo.TYPE_NATT, fd); + mKeepaliveTracker.setReturnedKeepaliveInfo(ki); + + // Mock elapsed real time to verify the alarm timer. + final long time = SystemClock.elapsedRealtime(); + doReturn(time).when(mDependencies).getElapsedRealtime(); + + mAOOKeepaliveTracker.startNattKeepalive(nai, fd, 10 /* intervalSeconds */, cb, + srcAddress.toString(), srcPort, dstAddress.toString(), dstPort, + true /* automaticOnOffKeepalives */, underpinnedNetwork); + HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS); + + final ArgumentCaptor<AlarmManager.OnAlarmListener> listenerCaptor = + ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class); + // The alarm timer should be smaller than the keepalive delay. Verify the alarm trigger time + // is higher than base time but smaller than the keepalive delay. + verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME), + longThat(t -> t > time + 1000L && t < time + TEST_KEEPALIVE_INTERVAL_SEC * 1000L), + any() /* tag */, listenerCaptor.capture(), eq(mTestHandler)); + final AlarmManager.OnAlarmListener listener = listenerCaptor.getValue(); + + // For realism, the listener should be posted on the handler + mTestHandler.post(() -> listener.onAlarm()); + // Wait for the listener to be called. The listener enqueues a message to the handler. + HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS); + // Wait for the message posted by the listener to be processed. + HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS); + + assertNotNull(mTestHandler.mLastAutoKi); + assertEquals(cb, mTestHandler.mLastAutoKi.getCallback()); + assertEquals(underpinnedNetwork, mTestHandler.mLastAutoKi.getUnderpinnedNetwork()); + socket.close(); + } + + private void setupResponseWithSocketExisting() throws Exception { + final ByteBuffer tcpBufferV6 = getByteBuffer(TEST_RESPONSE_BYTES); + final ByteBuffer tcpBufferV4 = getByteBuffer(TEST_RESPONSE_BYTES); + doReturn(tcpBufferV6, tcpBufferV4).when(mDependencies).recvSockDiagResponse(any()); + } + + private void setupResponseWithoutSocketExisting() throws Exception { + final ByteBuffer tcpBufferV6 = getByteBuffer(SOCK_DIAG_NO_TCP_INET_BYTES); + final ByteBuffer tcpBufferV4 = getByteBuffer(SOCK_DIAG_NO_TCP_INET_BYTES); + doReturn(tcpBufferV6, tcpBufferV4).when(mDependencies).recvSockDiagResponse(any()); + } + + private MarkMaskParcel makeMarkMaskParcel(final int mask, final int mark) { + final MarkMaskParcel parcel = new MarkMaskParcel(); + parcel.mask = mask; + parcel.mark = mark; + return parcel; + } + + private ByteBuffer getByteBuffer(final byte[] bytes) { + final ByteBuffer buffer = ByteBuffer.wrap(bytes); + buffer.order(ByteOrder.nativeOrder()); + return buffer; + } +}
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java index b651c33..4158663 100644 --- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java +++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -313,8 +313,7 @@ * Stop clatd. */ @Override - public void stopClatd(@NonNull String iface, @NonNull String pfx96, @NonNull String v4, - @NonNull String v6, int pid) throws IOException { + public void stopClatd(int pid) throws IOException { if (pid == -1) { fail("unsupported arg: " + pid); } @@ -479,8 +478,7 @@ eq((short) PRIO_CLAT), eq((short) ETH_P_IP)); inOrder.verify(mEgressMap).deleteEntry(eq(EGRESS_KEY)); inOrder.verify(mIngressMap).deleteEntry(eq(INGRESS_KEY)); - inOrder.verify(mDeps).stopClatd(eq(BASE_IFACE), eq(NAT64_PREFIX_STRING), - eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(CLATD_PID)); + inOrder.verify(mDeps).stopClatd(eq(CLATD_PID)); inOrder.verify(mCookieTagMap).deleteEntry(eq(COOKIE_TAG_KEY)); assertNull(coordinator.getClatdTrackerForTesting()); inOrder.verifyNoMoreInteractions();
diff --git a/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java index 719314a..5881a8e 100644 --- a/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java +++ b/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -80,6 +80,7 @@ private static final byte[] MAC_ADDR = {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b}; + private static final long NET_HANDLE = new Network(4291).getNetworkHandle(); @Mock Context mCtx; @Mock IIpConnectivityMetrics mMockService; @@ -607,7 +608,7 @@ void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp, String dstIp, int sport, int dport, long now) throws Exception { - String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface; + String prefix = NET_HANDLE + ":" + iface; mNetdListener.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now); }
diff --git a/tests/unit/java/com/android/server/connectivity/KeepaliveStatsTrackerTest.java b/tests/unit/java/com/android/server/connectivity/KeepaliveStatsTrackerTest.java new file mode 100644 index 0000000..d262255 --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/KeepaliveStatsTrackerTest.java
@@ -0,0 +1,504 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; + +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import com.android.metrics.DailykeepaliveInfoReported; +import com.android.metrics.DurationForNumOfKeepalive; +import com.android.metrics.DurationPerNumOfKeepalive; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(DevSdkIgnoreRunner.class) +@SmallTest +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) +public class KeepaliveStatsTrackerTest { + private static final int TEST_UID = 1234; + + private KeepaliveStatsTracker mKeepaliveStatsTracker; + @Mock KeepaliveStatsTracker.Dependencies mDependencies; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + setUptimeMillis(0); + mKeepaliveStatsTracker = new KeepaliveStatsTracker(mDependencies); + } + + private void setUptimeMillis(long time) { + doReturn(time).when(mDependencies).getUptimeMillis(); + } + + /** + * Asserts that a DurationPerNumOfKeepalive contains expected values + * + * @param expectRegisteredDurations integer array where the index is the number of concurrent + * keepalives and the value is the expected duration of time that the tracker is in a state + * with the given number of keepalives registered. + * @param expectActiveDurations integer array where the index is the number of concurrent + * keepalives and the value is the expected duration of time that the tracker is in a state + * with the given number of keepalives active. + * @param resultDurationsPerNumOfKeepalive the DurationPerNumOfKeepalive message to assert. + */ + private void assertDurationMetrics( + int[] expectRegisteredDurations, + int[] expectActiveDurations, + DurationPerNumOfKeepalive resultDurationsPerNumOfKeepalive) { + final int maxNumOfKeepalive = expectRegisteredDurations.length; + assertEquals(maxNumOfKeepalive, expectActiveDurations.length); + assertEquals( + maxNumOfKeepalive, + resultDurationsPerNumOfKeepalive.getDurationForNumOfKeepaliveCount()); + for (int numOfKeepalive = 0; numOfKeepalive < maxNumOfKeepalive; numOfKeepalive++) { + final DurationForNumOfKeepalive resultDurations = + resultDurationsPerNumOfKeepalive.getDurationForNumOfKeepalive(numOfKeepalive); + + assertEquals(numOfKeepalive, resultDurations.getNumOfKeepalive()); + assertEquals( + expectRegisteredDurations[numOfKeepalive], + resultDurations.getKeepaliveRegisteredDurationsMsec()); + assertEquals( + expectActiveDurations[numOfKeepalive], + resultDurations.getKeepaliveActiveDurationsMsec()); + } + } + + private void assertDailyKeepaliveInfoReported( + DailykeepaliveInfoReported dailyKeepaliveInfoReported, + int[] expectRegisteredDurations, + int[] expectActiveDurations) { + // TODO(b/273451360) Assert these values when they are filled. + assertFalse(dailyKeepaliveInfoReported.hasKeepaliveLifetimePerCarrier()); + assertFalse(dailyKeepaliveInfoReported.hasKeepaliveRequests()); + assertFalse(dailyKeepaliveInfoReported.hasAutomaticKeepaliveRequests()); + assertFalse(dailyKeepaliveInfoReported.hasDistinctUserCount()); + assertTrue(dailyKeepaliveInfoReported.getUidList().isEmpty()); + + final DurationPerNumOfKeepalive resultDurations = + dailyKeepaliveInfoReported.getDurationPerNumOfKeepalive(); + assertDurationMetrics(expectRegisteredDurations, expectActiveDurations, resultDurations); + } + + @Test + public void testNoKeepalive() { + final int writeTime = 5000; + + setUptimeMillis(writeTime); + final DailykeepaliveInfoReported dailyKeepaliveInfoReported = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + + // Expect that the durations are all in numOfKeepalive = 0. + final int[] expectRegisteredDurations = new int[] {writeTime}; + final int[] expectActiveDurations = new int[] {writeTime}; + + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported, + expectRegisteredDurations, + expectActiveDurations); + } + + /* + * Diagram of test (not to scale): + * Key: S - Start/Stop, P - Pause, R - Resume, W - Write + * + * Keepalive S W + * Timeline |------------------------------| + */ + @Test + public void testOneKeepalive_startOnly() { + final int startTime = 1000; + final int writeTime = 5000; + + setUptimeMillis(startTime); + mKeepaliveStatsTracker.onStartKeepalive(); + + setUptimeMillis(writeTime); + final DailykeepaliveInfoReported dailyKeepaliveInfoReported = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + + // The keepalive is never stopped, expect the duration for numberOfKeepalive of 1 to range + // from startTime to writeTime. + final int[] expectRegisteredDurations = new int[] {startTime, writeTime - startTime}; + final int[] expectActiveDurations = new int[] {startTime, writeTime - startTime}; + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported, + expectRegisteredDurations, + expectActiveDurations); + } + + /* + * Diagram of test (not to scale): + * Key: S - Start/Stop, P - Pause, R - Resume, W - Write + * + * Keepalive S P W + * Timeline |------------------------------| + */ + @Test + public void testOneKeepalive_paused() { + final int startTime = 1000; + final int pauseTime = 2030; + final int writeTime = 5000; + + setUptimeMillis(startTime); + mKeepaliveStatsTracker.onStartKeepalive(); + + setUptimeMillis(pauseTime); + mKeepaliveStatsTracker.onPauseKeepalive(); + + setUptimeMillis(writeTime); + final DailykeepaliveInfoReported dailyKeepaliveInfoReported = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + + // The keepalive is paused but not stopped, expect the registered duration for + // numberOfKeepalive of 1 to still range from startTime to writeTime while the active + // duration stops at pauseTime. + final int[] expectRegisteredDurations = new int[] {startTime, writeTime - startTime}; + final int[] expectActiveDurations = + new int[] {startTime + (writeTime - pauseTime), pauseTime - startTime}; + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported, + expectRegisteredDurations, + expectActiveDurations); + } + + /* + * Diagram of test (not to scale): + * Key: S - Start/Stop, P - Pause, R - Resume, W - Write + * + * Keepalive S P R W + * Timeline |------------------------------| + */ + @Test + public void testOneKeepalive_resumed() { + final int startTime = 1000; + final int pauseTime = 2030; + final int resumeTime = 3450; + final int writeTime = 5000; + + setUptimeMillis(startTime); + mKeepaliveStatsTracker.onStartKeepalive(); + + setUptimeMillis(pauseTime); + mKeepaliveStatsTracker.onPauseKeepalive(); + + setUptimeMillis(resumeTime); + mKeepaliveStatsTracker.onResumeKeepalive(); + + setUptimeMillis(writeTime); + final DailykeepaliveInfoReported dailyKeepaliveInfoReported = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + + // The keepalive is paused and resumed but not stopped, expect the registered duration for + // numberOfKeepalive of 1 to still range from startTime to writeTime while the active + // duration stops at pauseTime but resumes at resumeTime and stops at writeTime. + final int[] expectRegisteredDurations = new int[] {startTime, writeTime - startTime}; + final int[] expectActiveDurations = + new int[] { + startTime + (resumeTime - pauseTime), + (pauseTime - startTime) + (writeTime - resumeTime) + }; + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported, + expectRegisteredDurations, + expectActiveDurations); + } + + /* + * Diagram of test (not to scale): + * Key: S - Start/Stop, P - Pause, R - Resume, W - Write + * + * Keepalive S P R S W + * Timeline |------------------------------| + */ + @Test + public void testOneKeepalive_stopped() { + final int startTime = 1000; + final int pauseTime = 2930; + final int resumeTime = 3452; + final int stopTime = 4157; + final int writeTime = 5000; + + setUptimeMillis(startTime); + mKeepaliveStatsTracker.onStartKeepalive(); + + setUptimeMillis(pauseTime); + mKeepaliveStatsTracker.onPauseKeepalive(); + + setUptimeMillis(resumeTime); + mKeepaliveStatsTracker.onResumeKeepalive(); + + setUptimeMillis(stopTime); + mKeepaliveStatsTracker.onStopKeepalive(/* wasActive= */ true); + + setUptimeMillis(writeTime); + final DailykeepaliveInfoReported dailyKeepaliveInfoReported = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + + // The keepalive is now stopped, expect the registered duration for numberOfKeepalive of 1 + // to now range from startTime to stopTime while the active duration stops at pauseTime but + // resumes at resumeTime and stops again at stopTime. + final int[] expectRegisteredDurations = + new int[] {startTime + (writeTime - stopTime), stopTime - startTime}; + final int[] expectActiveDurations = + new int[] { + startTime + (resumeTime - pauseTime) + (writeTime - stopTime), + (pauseTime - startTime) + (stopTime - resumeTime) + }; + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported, + expectRegisteredDurations, + expectActiveDurations); + } + + /* + * Diagram of test (not to scale): + * Key: S - Start/Stop, P - Pause, R - Resume, W - Write + * + * Keepalive S P S W + * Timeline |------------------------------| + */ + @Test + public void testOneKeepalive_pausedStopped() { + final int startTime = 1000; + final int pauseTime = 2930; + final int stopTime = 4157; + final int writeTime = 5000; + + setUptimeMillis(startTime); + mKeepaliveStatsTracker.onStartKeepalive(); + + setUptimeMillis(pauseTime); + mKeepaliveStatsTracker.onPauseKeepalive(); + + setUptimeMillis(stopTime); + mKeepaliveStatsTracker.onStopKeepalive(/* wasActive= */ false); + + setUptimeMillis(writeTime); + final DailykeepaliveInfoReported dailyKeepaliveInfoReported = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + + // The keepalive is stopped while paused, expect the registered duration for + // numberOfKeepalive of 1 to range from startTime to stopTime while the active duration + // simply stops at pauseTime. + final int[] expectRegisteredDurations = + new int[] {startTime + (writeTime - stopTime), stopTime - startTime}; + final int[] expectActiveDurations = + new int[] {startTime + (writeTime - pauseTime), (pauseTime - startTime)}; + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported, + expectRegisteredDurations, + expectActiveDurations); + } + + /* + * Diagram of test (not to scale): + * Key: S - Start/Stop, P - Pause, R - Resume, W - Write + * + * Keepalive S P R P R P R S W + * Timeline |------------------------------| + */ + @Test + public void testOneKeepalive_multiplePauses() { + final int startTime = 1000; + // Alternating timestamps of pause and resume + final int[] pauseResumeTimes = new int[] {1200, 1400, 1700, 2000, 2400, 2800}; + final int stopTime = 4000; + final int writeTime = 5000; + + setUptimeMillis(startTime); + mKeepaliveStatsTracker.onStartKeepalive(); + + for (int i = 0; i < pauseResumeTimes.length; i++) { + setUptimeMillis(pauseResumeTimes[i]); + if (i % 2 == 0) { + mKeepaliveStatsTracker.onPauseKeepalive(); + } else { + mKeepaliveStatsTracker.onResumeKeepalive(); + } + } + + setUptimeMillis(stopTime); + mKeepaliveStatsTracker.onStopKeepalive(/* wasActive= */ true); + + setUptimeMillis(writeTime); + final DailykeepaliveInfoReported dailyKeepaliveInfoReported = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + + final int[] expectRegisteredDurations = + new int[] {startTime + (writeTime - stopTime), stopTime - startTime}; + final int[] expectActiveDurations = + new int[] { + startTime + /* sum of (Resume - Pause) */ (900) + (writeTime - stopTime), + (pauseResumeTimes[0] - startTime) + + /* sum of (Pause - Resume) */ (700) + + (stopTime - pauseResumeTimes[5]) + }; + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported, + expectRegisteredDurations, + expectActiveDurations); + } + + /* + * Diagram of test (not to scale): + * Key: S - Start/Stop, P - Pause, R - Resume, W - Write + * + * Keepalive1 S1 P1 R1 S1 W + * Keepalive2 S2 P2 R2 W + * Timeline |------------------------------| + */ + @Test + public void testTwoKeepalives() { + // The suffix 1/2 indicates which keepalive it is referring to. + final int startTime1 = 1000; + final int pauseTime1 = 1500; + final int startTime2 = 2000; + final int resumeTime1 = 2500; + final int pauseTime2 = 3000; + final int resumeTime2 = 3500; + final int stopTime1 = 4157; + final int writeTime = 5000; + + setUptimeMillis(startTime1); + mKeepaliveStatsTracker.onStartKeepalive(); + + setUptimeMillis(pauseTime1); + mKeepaliveStatsTracker.onPauseKeepalive(); + + setUptimeMillis(startTime2); + mKeepaliveStatsTracker.onStartKeepalive(); + + setUptimeMillis(resumeTime1); + mKeepaliveStatsTracker.onResumeKeepalive(); + + setUptimeMillis(pauseTime2); + mKeepaliveStatsTracker.onPauseKeepalive(); + + setUptimeMillis(resumeTime2); + mKeepaliveStatsTracker.onResumeKeepalive(); + + setUptimeMillis(stopTime1); + mKeepaliveStatsTracker.onStopKeepalive(/* wasActive= */ true); + + setUptimeMillis(writeTime); + final DailykeepaliveInfoReported dailyKeepaliveInfoReported = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + + // With two keepalives, the number of concurrent keepalives can vary from 0-2 depending on + // both keepalive states. + final int[] expectRegisteredDurations = + new int[] { + startTime1, + // 1 registered keepalive before keepalive2 starts and after keepalive1 stops. + (startTime2 - startTime1) + (writeTime - stopTime1), + // 2 registered keepalives between keepalive2 start and keepalive1 stop. + stopTime1 - startTime2 + }; + + final int[] expectActiveDurations = + new int[] { + // 0 active keepalives when keepalive1 is paused before keepalive2 starts. + startTime1 + (startTime2 - pauseTime1), + // 1 active keepalive before keepalive1 is paused. + (pauseTime1 - startTime1) + // before keepalive1 is resumed and after keepalive2 starts. + + (resumeTime1 - startTime2) + // during keepalive2 is paused since keepalive1 has been resumed. + + (resumeTime2 - pauseTime2) + // after keepalive1 stops since keepalive2 has been resumed. + + (writeTime - stopTime1), + // 2 active keepalives before keepalive2 is paused and before keepalive1 stops. + (pauseTime2 - resumeTime1) + (stopTime1 - resumeTime2) + }; + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported, + expectRegisteredDurations, + expectActiveDurations); + } + + /* + * Diagram of test (not to scale): + * Key: S - Start/Stop, P - Pause, R - Resume, W - Write + * + * Keepalive S W(reset+W) S W + * Timeline |------------------------------| + */ + @Test + public void testResetMetrics() { + final int startTime = 1000; + final int writeTime = 5000; + final int stopTime = 7000; + final int writeTime2 = 10000; + + setUptimeMillis(startTime); + mKeepaliveStatsTracker.onStartKeepalive(); + + setUptimeMillis(writeTime); + final DailykeepaliveInfoReported dailyKeepaliveInfoReported = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + + // Same expect as testOneKeepalive_startOnly + final int[] expectRegisteredDurations = new int[] {startTime, writeTime - startTime}; + final int[] expectActiveDurations = new int[] {startTime, writeTime - startTime}; + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported, + expectRegisteredDurations, + expectActiveDurations); + + // Reset metrics + mKeepaliveStatsTracker.resetMetrics(); + + final DailykeepaliveInfoReported dailyKeepaliveInfoReported2 = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + // Expect the stored durations to be 0 but still contain the number of keepalive = 1. + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported2, + /* expectRegisteredDurations= */ new int[] {0, 0}, + /* expectActiveDurations= */ new int[] {0, 0}); + + // Expect that the keepalive is still registered after resetting so it can be stopped. + setUptimeMillis(stopTime); + mKeepaliveStatsTracker.onStopKeepalive(/* wasActive= */ true); + + setUptimeMillis(writeTime2); + final DailykeepaliveInfoReported dailyKeepaliveInfoReported3 = + mKeepaliveStatsTracker.buildKeepaliveMetrics(); + + final int[] expectRegisteredDurations2 = + new int[] {writeTime2 - stopTime, stopTime - writeTime}; + final int[] expectActiveDurations2 = + new int[] {writeTime2 - stopTime, stopTime - writeTime}; + assertDailyKeepaliveInfoReported( + dailyKeepaliveInfoReported3, + expectRegisteredDurations2, + expectActiveDurations2); + } +}
diff --git a/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java index 0d371fa..e6c0c83 100644 --- a/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -34,7 +34,6 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.ConnectivityManager; -import android.net.ConnectivityResources; import android.net.IDnsResolver; import android.net.INetd; import android.net.LinkProperties;
diff --git a/tests/unit/java/com/android/server/connectivity/MultinetworkPolicyTrackerTest.kt b/tests/unit/java/com/android/server/connectivity/MultinetworkPolicyTrackerTest.kt index b52e8a8..f19ba4f 100644 --- a/tests/unit/java/com/android/server/connectivity/MultinetworkPolicyTrackerTest.kt +++ b/tests/unit/java/com/android/server/connectivity/MultinetworkPolicyTrackerTest.kt
@@ -21,10 +21,8 @@ import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY -import android.net.ConnectivityResources import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI import android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE -import com.android.server.connectivity.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener import android.os.Build import android.os.Handler import android.os.test.TestLooper @@ -37,6 +35,7 @@ import com.android.connectivity.resources.R import com.android.internal.util.test.FakeSettingsProvider import com.android.modules.utils.build.SdkLevel +import com.android.server.connectivity.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRunner import org.junit.After
diff --git a/tests/unit/java/com/android/server/connectivity/MultinetworkPolicyTrackerTestDependencies.kt b/tests/unit/java/com/android/server/connectivity/MultinetworkPolicyTrackerTestDependencies.kt index 744c020..4c82c76 100644 --- a/tests/unit/java/com/android/server/connectivity/MultinetworkPolicyTrackerTestDependencies.kt +++ b/tests/unit/java/com/android/server/connectivity/MultinetworkPolicyTrackerTestDependencies.kt
@@ -1,7 +1,6 @@ package com.android.server.connectivity import android.content.res.Resources -import android.net.ConnectivityResources import android.provider.DeviceConfig import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY import android.provider.DeviceConfig.OnPropertiesChangedListener
diff --git a/tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java index 7d6c3ae..d667662 100644 --- a/tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java +++ b/tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -41,6 +42,8 @@ import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; +import libcore.util.EmptyArray; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -60,6 +63,9 @@ private static final String EXAMPLE_IPV4 = "192.0.2.1"; private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1"; + private static final Network TEST_WIFI_NETWORK = new Network(5391); + private static final Network TEST_CELL_NETWORK = new Network(5832); + private static final byte[] MAC_ADDR = {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b}; @@ -76,6 +82,8 @@ public void setUp() { mCm = mock(ConnectivityManager.class); mService = new NetdEventListenerService(mCm); + doReturn(CAPABILITIES_WIFI).when(mCm).getNetworkCapabilities(TEST_WIFI_NETWORK); + doReturn(CAPABILITIES_CELL).when(mCm).getNetworkCapabilities(TEST_CELL_NETWORK); } @Test @@ -109,19 +117,25 @@ wakeupEvent(iface, uids[5], v4, tcp, mac, srcIp, dstIp, sport, dport, now); wakeupEvent(iface, uids[6], v6, udp, mac, srcIp6, dstIp6, sport, dport, now); wakeupEvent(iface, uids[7], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now); - wakeupEvent(iface, uids[8], v6, udp, mac, srcIp6, dstIp6, sport, dport, now); + wakeupEvent("rmnet0", uids[8], v6, udp, EmptyArray.BYTE, srcIp6, dstIp6, sport, dport, now, + TEST_CELL_NETWORK); String[] events2 = remove(listNetdEvent(), baseline); - int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line + int expectedLength2 = uids.length + 2; // +2 for the WakeupStats headers assertEquals(expectedLength2, events2.length); + assertStringContains(events2[0], "WakeupStats"); - assertStringContains(events2[0], "wlan0"); - assertStringContains(events2[0], "0x800"); + assertStringContains(events2[0], "rmnet0"); assertStringContains(events2[0], "0x86dd"); + + assertStringContains(events2[1], "WakeupStats"); + assertStringContains(events2[1], "wlan0"); + assertStringContains(events2[1], "0x800"); + assertStringContains(events2[1], "0x86dd"); for (int i = 0; i < uids.length; i++) { - String got = events2[i+1]; + String got = events2[i + 2]; assertStringContains(got, "WakeupEvent"); - assertStringContains(got, "wlan0"); + assertStringContains(got, ((i == 8) ? "rmnet0" : "wlan0")); assertStringContains(got, "uid: " + uids[i]); } @@ -132,11 +146,13 @@ } String[] events3 = remove(listNetdEvent(), baseline); - int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line + int expectedLength3 = BUFFER_LENGTH + 2; // +2 for the WakeupStats headers assertEquals(expectedLength3, events3.length); - assertStringContains(events2[0], "WakeupStats"); - assertStringContains(events2[0], "wlan0"); - for (int i = 1; i < expectedLength3; i++) { + assertStringContains(events3[0], "WakeupStats"); + assertStringContains(events3[0], "rmnet0"); + assertStringContains(events3[1], "WakeupStats"); + assertStringContains(events3[1], "wlan0"); + for (int i = 2; i < expectedLength3; i++) { String got = events3[i]; assertStringContains(got, "WakeupEvent"); assertStringContains(got, "wlan0"); @@ -171,19 +187,24 @@ final int icmp6 = 58; wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now); - wakeupEvent("rmnet0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, now); + wakeupEvent("rmnet0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, now, + TEST_CELL_NETWORK); wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, now); - wakeupEvent("rmnet0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now); + wakeupEvent("rmnet0", 10008, v4, tcp, EmptyArray.BYTE, srcIp, dstIp, sport, dport, now, + TEST_CELL_NETWORK); wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now); wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now); - wakeupEvent("rmnet0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now); + wakeupEvent("rmnet0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now, + TEST_CELL_NETWORK); wakeupEvent("wlan0", 10004, v4, udp, mac, srcIp, dstIp, sport, dport, now); wakeupEvent("wlan0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now); wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now); wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now); - wakeupEvent("rmnet0", 10052, v4, tcp, mac, srcIp, dstIp, sport, dport, now); + wakeupEvent("rmnet0", 10052, v4, tcp, mac, srcIp, dstIp, sport, dport, now, + TEST_CELL_NETWORK); wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now); - wakeupEvent("rmnet0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now); + wakeupEvent("rmnet0", 1000, v6, tcp, null, srcIp6, dstIp6, sport, dport, now, + TEST_CELL_NETWORK); wakeupEvent("wlan0", 1010, v4, udp, mac, srcIp, dstIp, sport, dport, now); String got = flushStatistics(); @@ -212,7 +233,7 @@ " >", " l2_broadcast_count: 0", " l2_multicast_count: 0", - " l2_unicast_count: 5", + " l2_unicast_count: 3", " no_uid_wakeups: 0", " non_application_wakeups: 0", " root_wakeups: 0", @@ -497,8 +518,13 @@ } void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp, - String dstIp, int sport, int dport, long now) throws Exception { - String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface; + String dstIp, int sport, int dport, long now) { + wakeupEvent(iface, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now, TEST_WIFI_NETWORK); + } + + void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp, + String dstIp, int sport, int dport, long now, Network network) { + String prefix = network.getNetworkHandle() + ":" + iface; mService.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now); }
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java index 9a5298d..a27a0bf 100644 --- a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java +++ b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -51,13 +51,14 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.net.ConnectivityResources; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.os.Build; import android.os.Bundle; +import android.os.PowerManager; import android.os.UserHandle; import android.telephony.TelephonyManager; +import android.testing.PollingCheck; import android.util.DisplayMetrics; import android.widget.TextView; @@ -391,7 +392,15 @@ final Instrumentation instr = InstrumentationRegistry.getInstrumentation(); final UiDevice uiDevice = UiDevice.getInstance(instr); - UiDevice.getInstance(instr).pressHome(); + final Context ctx = instr.getContext(); + final PowerManager pm = ctx.getSystemService(PowerManager.class); + + // Wake up the device (it has no effect if the device is already awake). + uiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); + uiDevice.executeShellCommand("wm dismiss-keyguard"); + PollingCheck.check("Wait for the screen to be turned on failed, timeout=" + TEST_TIMEOUT_MS, + TEST_TIMEOUT_MS, () -> pm.isInteractive()); + uiDevice.pressHome(); // UiDevice.getLauncherPackageName() requires the test manifest to have a <queries> tag for // the launcher intent. @@ -404,7 +413,6 @@ // Non-"no internet" notifications are not affected verify(mNotificationManager).notify(eq(TEST_NOTIF_TAG), eq(NETWORK_SWITCH.eventId), any()); - final Context ctx = instr.getContext(); final String testAction = "com.android.connectivity.coverage.TEST_DIALOG"; final Intent intent = new Intent(testAction) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
diff --git a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java index 8076edb..cf02e3a 100644 --- a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -46,7 +46,6 @@ 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.AdditionalMatchers.aryEq; import static org.mockito.ArgumentMatchers.any; @@ -844,7 +843,6 @@ // When VPN is disconnected, expect rules to be torn down mPermissionMonitor.onVpnUidRangesRemoved(ifName, vpnRange2, VPN_UID); verify(mBpfNetMaps).removeUidInterfaceRules(aryEq(new int[] {MOCK_UID12})); - assertNull(mPermissionMonitor.getVpnInterfaceUidRanges(ifName)); } @Test @@ -915,7 +913,6 @@ verify(mBpfNetMaps, times(2)).updateUidLockdownRule(anyInt(), eq(true) /* add */); verify(mBpfNetMaps).updateUidLockdownRule(MOCK_UID11, true /* add */); verify(mBpfNetMaps).updateUidLockdownRule(VPN_UID, true /* add */); - assertEquals(mPermissionMonitor.getVpnLockdownUidRanges(), Set.of(lockdownRange)); reset(mBpfNetMaps); @@ -924,7 +921,6 @@ verify(mBpfNetMaps, times(2)).updateUidLockdownRule(anyInt(), eq(false) /* add */); verify(mBpfNetMaps).updateUidLockdownRule(MOCK_UID11, false /* add */); verify(mBpfNetMaps).updateUidLockdownRule(VPN_UID, false /* add */); - assertTrue(mPermissionMonitor.getVpnLockdownUidRanges().isEmpty()); } @Test @@ -944,7 +940,6 @@ mPermissionMonitor.updateVpnLockdownUidRanges(true /* add */, lockdownRange); verify(mBpfNetMaps).updateUidLockdownRule(anyInt(), eq(true) /* add */); verify(mBpfNetMaps).updateUidLockdownRule(MOCK_UID11, true /* add */); - assertEquals(mPermissionMonitor.getVpnLockdownUidRanges(), Set.of(lockdownRange)); reset(mBpfNetMaps); @@ -952,7 +947,6 @@ // already has the rule mPermissionMonitor.updateVpnLockdownUidRanges(true /* add */, lockdownRange); verify(mBpfNetMaps, never()).updateUidLockdownRule(anyInt(), anyBoolean()); - assertEquals(mPermissionMonitor.getVpnLockdownUidRanges(), Set.of(lockdownRange)); reset(mBpfNetMaps); @@ -960,7 +954,6 @@ // the range 2 times. mPermissionMonitor.updateVpnLockdownUidRanges(false /* add */, lockdownRange); verify(mBpfNetMaps, never()).updateUidLockdownRule(anyInt(), anyBoolean()); - assertEquals(mPermissionMonitor.getVpnLockdownUidRanges(), Set.of(lockdownRange)); reset(mBpfNetMaps); @@ -969,7 +962,6 @@ mPermissionMonitor.updateVpnLockdownUidRanges(false /* add */, lockdownRange); verify(mBpfNetMaps).updateUidLockdownRule(anyInt(), eq(false) /* add */); verify(mBpfNetMaps).updateUidLockdownRule(MOCK_UID11, false /* add */); - assertTrue(mPermissionMonitor.getVpnLockdownUidRanges().isEmpty()); } @Test @@ -990,7 +982,6 @@ mPermissionMonitor.updateVpnLockdownUidRanges(true /* add */, lockdownRangeDuplicates); verify(mBpfNetMaps).updateUidLockdownRule(anyInt(), eq(true) /* add */); verify(mBpfNetMaps).updateUidLockdownRule(MOCK_UID11, true /* add */); - assertEquals(mPermissionMonitor.getVpnLockdownUidRanges(), Set.of(lockdownRange)); reset(mBpfNetMaps); @@ -998,7 +989,6 @@ // ranges we added contains duplicated uid ranges. mPermissionMonitor.updateVpnLockdownUidRanges(false /* add */, lockdownRange); verify(mBpfNetMaps, never()).updateUidLockdownRule(anyInt(), anyBoolean()); - assertEquals(mPermissionMonitor.getVpnLockdownUidRanges(), Set.of(lockdownRange)); reset(mBpfNetMaps); @@ -1006,7 +996,6 @@ mPermissionMonitor.updateVpnLockdownUidRanges(false /* add */, lockdownRange); verify(mBpfNetMaps).updateUidLockdownRule(anyInt(), eq(false) /* add */); verify(mBpfNetMaps).updateUidLockdownRule(MOCK_UID11, false /* add */); - assertTrue(mPermissionMonitor.getVpnLockdownUidRanges().isEmpty()); } @Test
diff --git a/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java b/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java index b8c552e..ad4785d 100644 --- a/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java +++ b/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java
@@ -402,4 +402,27 @@ expected.add(uids20_24); assertEquals(expected, UidRangeUtils.convertArrayToUidRange(input)); } + + @Test + public void testSortRangesByStartUid() throws Exception { + final UidRange uid1 = new UidRange(100, 110); + final UidRange uid2 = new UidRange(120, 130); + final UidRange[] unsortedRanges = new UidRange[] {uid2, uid1}; + final UidRange[] sortedRanges = UidRangeUtils.sortRangesByStartUid(unsortedRanges); + assertEquals(uid1, sortedRanges[0]); + assertEquals(uid2, sortedRanges[1]); + } + + @Test + public void testSortedRangesContainOverlap() throws Exception { + final UidRange uid1 = new UidRange(100, 110); + final UidRange uid2 = new UidRange(109, 120); + final UidRange uid3 = new UidRange(120, 130); + final UidRange[] overlapRanges1 = new UidRange[] {uid1, uid2}; + final UidRange[] overlapRanges2 = new UidRange[] {uid2, uid3}; + final UidRange[] notOverlapRanges = new UidRange[] {uid1, uid3}; + assertTrue(UidRangeUtils.sortedRangesContainOverlap(overlapRanges1)); + assertTrue(UidRangeUtils.sortedRangesContainOverlap(overlapRanges2)); + assertFalse(UidRangeUtils.sortedRangesContainOverlap(notOverlapRanges)); + } }
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java index 677e7b6..2d2819c 100644 --- a/tests/unit/java/com/android/server/connectivity/VpnTest.java +++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -25,15 +25,38 @@ import static android.net.ConnectivityManager.NetworkCallback; import static android.net.INetd.IF_STATE_DOWN; import static android.net.INetd.IF_STATE_UP; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.net.VpnManager.TYPE_VPN_PLATFORM; +import static android.net.cts.util.IkeSessionTestUtils.CHILD_PARAMS; +import static android.net.cts.util.IkeSessionTestUtils.TEST_IDENTITY; +import static android.net.cts.util.IkeSessionTestUtils.TEST_KEEPALIVE_TIMEOUT_UNSET; +import static android.net.cts.util.IkeSessionTestUtils.getTestIkeSessionParams; import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_MOBIKE; -import static android.os.Build.VERSION_CODES.S_V2; +import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO; +import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_NONE; +import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_UDP; +import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO; +import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV4; +import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV6; import static android.os.UserHandle.PER_USER_RANGE; +import static android.telephony.CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL; +import static android.telephony.CarrierConfigManager.KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT; +import static android.telephony.CarrierConfigManager.KEY_PREFERRED_IKE_PROTOCOL_INT; import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU; +import static com.android.server.connectivity.Vpn.AUTOMATIC_KEEPALIVE_DELAY_SECONDS; +import static com.android.server.connectivity.Vpn.DEFAULT_LONG_LIVED_TCP_CONNS_EXPENSIVE_TIMEOUT_SEC; +import static com.android.server.connectivity.Vpn.DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT; +import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_AUTO; +import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_IPV4_UDP; +import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_IPV6_ESP; +import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_IPV6_UDP; import static com.android.testutils.Cleanup.testAndCleanup; -import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertArrayEquals; @@ -50,6 +73,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.longThat; import static org.mockito.Mockito.after; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; @@ -99,6 +123,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo.DetailedState; import android.net.RouteInfo; +import android.net.TelephonyNetworkSpecifier; import android.net.UidRangeParcel; import android.net.VpnManager; import android.net.VpnProfileState; @@ -106,15 +131,20 @@ import android.net.VpnTransportInfo; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; +import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; import android.net.ipsec.ike.IkeSessionConnectionInfo; +import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeNetworkLostException; import android.net.ipsec.ike.exceptions.IkeNonProtocolException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.net.ipsec.ike.exceptions.IkeTimeoutException; +import android.net.vcn.VcnTransportInfo; +import android.net.wifi.WifiInfo; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.ConditionVariable; @@ -128,11 +158,16 @@ import android.os.test.TestLooper; import android.provider.Settings; import android.security.Credentials; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Pair; import android.util.Range; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.R; @@ -140,14 +175,13 @@ import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.internal.util.HexDump; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.DeviceIdleInternal; import com.android.server.IpSecService; import com.android.server.VpnTestBase; import com.android.server.vcn.util.PersistableBundleUtils; import com.android.testutils.DevSdkIgnoreRule; -import com.android.testutils.DevSdkIgnoreRunner; -import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -164,6 +198,7 @@ import java.io.FileDescriptor; import java.io.FileWriter; import java.io.IOException; +import java.io.StringWriter; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -181,7 +216,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Tests for {@link Vpn}. @@ -189,9 +225,8 @@ * Build, install and run with: * runtest frameworks-net -c com.android.server.connectivity.VpnTest */ -@RunWith(DevSdkIgnoreRunner.class) +@RunWith(AndroidJUnit4.class) @SmallTest -@IgnoreUpTo(S_V2) public class VpnTest extends VpnTestBase { private static final String TAG = "VpnTest"; @@ -248,10 +283,14 @@ private static final String TEST_IFACE_NAME = "TEST_IFACE"; private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345; private static final long TEST_TIMEOUT_MS = 500L; + private static final long TIMEOUT_CROSSTHREAD_MS = 20_000L; private static final String PRIMARY_USER_APP_EXCLUDE_KEY = "VPNAPPEXCLUDED_27_com.testvpn.vpn"; static final String PKGS_BYTES = getPackageByteString(List.of(PKGS)); private static final Range<Integer> PRIMARY_USER_RANGE = uidRangeForUser(PRIMARY_USER.id); + private static final int TEST_KEEPALIVE_TIMER = 800; + private static final int TEST_SUB_ID = 1234; + private static final String TEST_MCCMNC = "12345"; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private UserManager mUserManager; @@ -266,17 +305,57 @@ @Mock private Vpn.VpnNetworkAgentWrapper mMockNetworkAgent; @Mock private ConnectivityManager mConnectivityManager; @Mock private ConnectivityDiagnosticsManager mCdm; + @Mock private TelephonyManager mTelephonyManager; + @Mock private TelephonyManager mTmPerSub; + @Mock private CarrierConfigManager mConfigManager; + @Mock private SubscriptionManager mSubscriptionManager; @Mock private IpSecService mIpSecService; @Mock private VpnProfileStore mVpnProfileStore; - @Mock private ScheduledThreadPoolExecutor mExecutor; - @Mock private ScheduledFuture mScheduledFuture; + private final TestExecutor mExecutor; @Mock DeviceIdleInternal mDeviceIdleInternal; private final VpnProfile mVpnProfile; private IpSecManager mIpSecManager; - private TestDeps mTestDeps; + public static class TestExecutor extends ScheduledThreadPoolExecutor { + public static final long REAL_DELAY = -1; + + // For the purposes of the test, run all scheduled tasks after 10ms to save + // execution time, unless overridden by the specific test. Set to REAL_DELAY + // to actually wait for the delay specified by the real call to schedule(). + public long delayMs = 10; + // If this is true, execute() will call the runnable inline. This is useful because + // super.execute() calls schedule(), which messes with checks that scheduled() is + // called a given number of times. + public boolean executeDirect = false; + + public TestExecutor() { + super(1); + } + + @Override + public void execute(final Runnable command) { + // See |executeDirect| for why this is necessary. + if (executeDirect) { + command.run(); + } else { + super.execute(command); + } + } + + @Override + public ScheduledFuture<?> schedule(final Runnable command, final long delay, + TimeUnit unit) { + if (0 == delay || delayMs == REAL_DELAY) { + // super.execute() calls schedule() with 0, so use the real delay if it's 0. + return super.schedule(command, delay, unit); + } else { + return super.schedule(command, delayMs, TimeUnit.MILLISECONDS); + } + } + } + public VpnTest() throws Exception { // Build an actual VPN profile that is capable of being converted to and from an // Ikev2VpnProfile @@ -284,6 +363,7 @@ new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY); builder.setAuthPsk(TEST_VPN_PSK); builder.setBypassable(true /* isBypassable */); + mExecutor = spy(new TestExecutor()); mVpnProfile = builder.build().toVpnProfile(); } @@ -310,6 +390,11 @@ mockService(IpSecManager.class, Context.IPSEC_SERVICE, mIpSecManager); mockService(ConnectivityDiagnosticsManager.class, Context.CONNECTIVITY_DIAGNOSTICS_SERVICE, mCdm); + mockService(TelephonyManager.class, Context.TELEPHONY_SERVICE, mTelephonyManager); + mockService(CarrierConfigManager.class, Context.CARRIER_CONFIG_SERVICE, mConfigManager); + mockService(SubscriptionManager.class, Context.TELEPHONY_SUBSCRIPTION_SERVICE, + mSubscriptionManager); + doReturn(mTmPerSub).when(mTelephonyManager).createForSubscriptionId(anyInt()); when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent)) .thenReturn(Resources.getSystem().getString( R.string.config_customVpnAlwaysOnDisconnectedDialogComponent)); @@ -344,7 +429,6 @@ // Set up mIkev2SessionCreator and mExecutor resetIkev2SessionCreator(mIkeSessionWrapper); - resetExecutor(mScheduledFuture); } private void resetIkev2SessionCreator(Vpn.IkeSessionWrapper ikeSession) { @@ -353,23 +437,6 @@ .thenReturn(ikeSession); } - private void resetExecutor(ScheduledFuture scheduledFuture) { - doAnswer( - (invocation) -> { - ((Runnable) invocation.getArgument(0)).run(); - return null; - }) - .when(mExecutor) - .execute(any()); - when(mExecutor.schedule( - any(Runnable.class), anyLong(), any())).thenReturn(mScheduledFuture); - } - - @After - public void tearDown() throws Exception { - doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(any()); - } - private <T> void mockService(Class<T> clazz, String name, T service) { doReturn(service).when(mContext).getSystemService(name); doReturn(name).when(mContext).getSystemServiceName(clazz); @@ -480,9 +547,9 @@ } private void verifyPowerSaveTempWhitelistApp(String packageName) { - verify(mDeviceIdleInternal).addPowerSaveTempWhitelistApp(anyInt(), eq(packageName), - anyLong(), anyInt(), eq(false), eq(PowerWhitelistManager.REASON_VPN), - eq("VpnManager event")); + verify(mDeviceIdleInternal, timeout(TEST_TIMEOUT_MS)).addPowerSaveTempWhitelistApp( + anyInt(), eq(packageName), anyLong(), anyInt(), eq(false), + eq(PowerWhitelistManager.REASON_VPN), eq("VpnManager event")); } @Test @@ -721,7 +788,8 @@ @Test public void testPrepare_throwSecurityExceptionWhenGivenPackageDoesNotBelongToTheCaller() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(); + mTestDeps.mIgnoreCallingUidChecks = false; + final Vpn vpn = createVpn(); assertThrows(SecurityException.class, () -> vpn.prepare("com.not.vpn.owner", null, VpnManager.TYPE_VPN_SERVICE)); assertThrows(SecurityException.class, @@ -733,7 +801,7 @@ @Test public void testPrepare_bothOldPackageAndNewPackageAreNull() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(); + final Vpn vpn = createVpn(); assertTrue(vpn.prepare(null, null, VpnManager.TYPE_VPN_SERVICE)); } @@ -816,17 +884,14 @@ assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG)); } - private Vpn createVpnAndSetupUidChecks(String... grantedOps) throws Exception { - return createVpnAndSetupUidChecks(PRIMARY_USER, grantedOps); + private Vpn createVpn(String... grantedOps) throws Exception { + return createVpn(PRIMARY_USER, grantedOps); } - private Vpn createVpnAndSetupUidChecks(UserInfo user, String... grantedOps) throws Exception { + private Vpn createVpn(UserInfo user, String... grantedOps) throws Exception { final Vpn vpn = createVpn(user.id); setMockedUsers(user); - when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt())) - .thenReturn(Process.myUid()); - for (final String opStr : grantedOps) { when(mAppOps.noteOpNoThrow(opStr, Process.myUid(), TEST_VPN_PKG, null /* attributionTag */, null /* message */)) @@ -855,7 +920,7 @@ public void testProvisionVpnProfileNoIpsecTunnels() throws Exception { when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)) .thenReturn(false); - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); try { checkProvisionVpnProfile( @@ -866,7 +931,7 @@ } private Vpn prepareVpnForVerifyAppExclusionList() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); when(mVpnProfileStore.get(PRIMARY_USER_APP_EXCLUDE_KEY)) @@ -982,7 +1047,7 @@ @Test public void testProvisionVpnProfilePreconsented() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); checkProvisionVpnProfile( vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); @@ -990,7 +1055,7 @@ @Test public void testProvisionVpnProfileNotPreconsented() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(); + final Vpn vpn = createVpn(); // Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller // had neither. @@ -1000,14 +1065,14 @@ @Test public void testProvisionVpnProfileVpnServicePreconsented() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_VPN); checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_VPN); } @Test public void testProvisionVpnProfileTooLarge() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); final VpnProfile bigProfile = new VpnProfile(""); bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]); @@ -1022,7 +1087,7 @@ @Test public void testProvisionVpnProfileRestrictedUser() throws Exception { final Vpn vpn = - createVpnAndSetupUidChecks( + createVpn( RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); try { @@ -1034,7 +1099,7 @@ @Test public void testDeleteVpnProfile() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(); + final Vpn vpn = createVpn(); vpn.deleteVpnProfile(TEST_VPN_PKG); @@ -1045,7 +1110,7 @@ @Test public void testDeleteVpnProfileRestrictedUser() throws Exception { final Vpn vpn = - createVpnAndSetupUidChecks( + createVpn( RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); try { @@ -1057,7 +1122,7 @@ @Test public void testGetVpnProfilePrivileged() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(); + final Vpn vpn = createVpn(); when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(new VpnProfile("").encode()); @@ -1076,7 +1141,7 @@ eq(null) /* message */); verify(mAppOps).startOp( eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER), - eq(Process.myUid()), + eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())), eq(packageName), eq(null) /* attributionTag */, eq(null) /* message */); @@ -1086,14 +1151,14 @@ // Add a small delay to double confirm that finishOp is only called once. verify(mAppOps, after(100)).finishOp( eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER), - eq(Process.myUid()), + eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())), eq(packageName), eq(null) /* attributionTag */); } @Test public void testStartVpnProfile() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); @@ -1106,7 +1171,7 @@ @Test public void testStartVpnProfileVpnServicePreconsented() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_VPN); when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); @@ -1120,7 +1185,7 @@ @Test public void testStartVpnProfileNotConsented() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(); + final Vpn vpn = createVpn(); try { vpn.startVpnProfile(TEST_VPN_PKG); @@ -1145,7 +1210,7 @@ @Test public void testStartVpnProfileMissingProfile() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null); @@ -1167,9 +1232,7 @@ @Test public void testStartVpnProfileRestrictedUser() throws Exception { - final Vpn vpn = - createVpnAndSetupUidChecks( - RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); try { vpn.startVpnProfile(TEST_VPN_PKG); @@ -1180,9 +1243,7 @@ @Test public void testStopVpnProfileRestrictedUser() throws Exception { - final Vpn vpn = - createVpnAndSetupUidChecks( - RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); try { vpn.stopVpnProfile(TEST_VPN_PKG); @@ -1193,7 +1254,7 @@ @Test public void testStartOpAndFinishOpWillBeCalledWhenPlatformVpnIsOnAndOff() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); vpn.startVpnProfile(TEST_VPN_PKG); @@ -1201,14 +1262,14 @@ // Add a small delay to make sure that startOp is only called once. verify(mAppOps, after(100).times(1)).startOp( eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER), - eq(Process.myUid()), + eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())), eq(TEST_VPN_PKG), eq(null) /* attributionTag */, eq(null) /* message */); // Check that the startOp is not called with OPSTR_ESTABLISH_VPN_SERVICE. verify(mAppOps, never()).startOp( eq(AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE), - eq(Process.myUid()), + eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())), eq(TEST_VPN_PKG), eq(null) /* attributionTag */, eq(null) /* message */); @@ -1218,7 +1279,9 @@ @Test public void testStartOpWithSeamlessHandover() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN); + // Create with SYSTEM_USER so that establish() will match the user ID when checking + // against Binder.getCallerUid + final Vpn vpn = createVpn(SYSTEM_USER, AppOpsManager.OPSTR_ACTIVATE_VPN); assertTrue(vpn.prepare(TEST_VPN_PKG, null, VpnManager.TYPE_VPN_SERVICE)); final VpnConfig config = new VpnConfig(); config.user = "VpnTest"; @@ -1249,12 +1312,12 @@ } private void verifyVpnManagerEvent(String sessionKey, String category, int errorClass, - int errorCode, String[] packageName, VpnProfileState... profileState) { + int errorCode, String[] packageName, @NonNull VpnProfileState... profileState) { final Context userContext = mContext.createContextAsUser(UserHandle.of(PRIMARY_USER.id), 0 /* flags */); final ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); - final int verifyTimes = (profileState == null) ? 1 : profileState.length; + final int verifyTimes = profileState.length; verify(userContext, times(verifyTimes)).startService(intentArgumentCaptor.capture()); for (int i = 0; i < verifyTimes; i++) { @@ -1285,10 +1348,8 @@ VpnManager.EXTRA_UNDERLYING_LINK_PROPERTIES)); } - if (profileState != null) { - assertEquals(profileState[i], intent.getParcelableExtra( - VpnManager.EXTRA_VPN_PROFILE_STATE, VpnProfileState.class)); - } + assertEquals(profileState[i], intent.getParcelableExtra( + VpnManager.EXTRA_VPN_PROFILE_STATE, VpnProfileState.class)); } reset(userContext); } @@ -1297,7 +1358,11 @@ // CATEGORY_EVENT_DEACTIVATED_BY_USER is not an error event, so both of errorClass and // errorCode won't be set. verifyVpnManagerEvent(sessionKey, VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER, - -1 /* errorClass */, -1 /* errorCode */, packageName, null /* profileState */); + -1 /* errorClass */, -1 /* errorCode */, packageName, + // VPN NetworkAgnet does not switch to CONNECTED in the test, and the state is not + // important here. Verify that the state as it is, i.e. CONNECTING state. + new VpnProfileState(VpnProfileState.STATE_CONNECTING, + sessionKey, false /* alwaysOn */, false /* lockdown */)); } private void verifyAlwaysOnStateChanged(String[] packageName, VpnProfileState... profileState) { @@ -1314,7 +1379,7 @@ // this is checked with CONTROL_VPN so simulate holding CONTROL_VPN in order to pass the // security checks. doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN); - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); @@ -1406,7 +1471,7 @@ @Test public void testReconnectVpnManagerVpnWithAlwaysOnEnabled() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); vpn.startVpnProfile(TEST_VPN_PKG); @@ -1430,51 +1495,83 @@ } @Test + public void testLockdown_enableDisableWhileConnected() throws Exception { + final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn( + createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */)); + + final InOrder order = inOrder(mTestDeps); + order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS)) + .newNetworkAgent(any(), any(), any(), any(), any(), any(), + argThat(config -> config.allowBypass), any(), any()); + + // Make VPN lockdown. + assertTrue(vpnSnapShot.vpn.setAlwaysOnPackage(TEST_VPN_PKG, true /* lockdown */, + null /* lockdownAllowlist */)); + + order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS)) + .newNetworkAgent(any(), any(), any(), any(), any(), any(), + argThat(config -> !config.allowBypass), any(), any()); + + // Disable lockdown. + assertTrue(vpnSnapShot.vpn.setAlwaysOnPackage(TEST_VPN_PKG, false /* lockdown */, + null /* lockdownAllowlist */)); + + order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS)) + .newNetworkAgent(any(), any(), any(), any(), any(), any(), + argThat(config -> config.allowBypass), any(), any()); + } + + @Test public void testSetPackageAuthorizationVpnService() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(); + final Vpn vpn = createVpn(); assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE)); verify(mAppOps) .setMode( eq(AppOpsManager.OPSTR_ACTIVATE_VPN), - eq(Process.myUid()), + eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())), eq(TEST_VPN_PKG), eq(AppOpsManager.MODE_ALLOWED)); } @Test public void testSetPackageAuthorizationPlatformVpn() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(); + final Vpn vpn = createVpn(); assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, TYPE_VPN_PLATFORM)); verify(mAppOps) .setMode( eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), - eq(Process.myUid()), + eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())), eq(TEST_VPN_PKG), eq(AppOpsManager.MODE_ALLOWED)); } @Test public void testSetPackageAuthorizationRevokeAuthorization() throws Exception { - final Vpn vpn = createVpnAndSetupUidChecks(); + final Vpn vpn = createVpn(); assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE)); verify(mAppOps) .setMode( eq(AppOpsManager.OPSTR_ACTIVATE_VPN), - eq(Process.myUid()), + eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())), eq(TEST_VPN_PKG), eq(AppOpsManager.MODE_IGNORED)); verify(mAppOps) .setMode( eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), - eq(Process.myUid()), + eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())), eq(TEST_VPN_PKG), eq(AppOpsManager.MODE_IGNORED)); } private NetworkCallback triggerOnAvailableAndGetCallback() throws Exception { + return triggerOnAvailableAndGetCallback(new NetworkCapabilities.Builder().build()); + } + + private NetworkCallback triggerOnAvailableAndGetCallback( + @NonNull final NetworkCapabilities caps) throws Exception { final ArgumentCaptor<NetworkCallback> networkCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class); verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)) @@ -1491,7 +1588,7 @@ // if NetworkCapabilities and LinkProperties of underlying network will be sent/cleared or // not. // See verifyVpnManagerEvent(). - cb.onCapabilitiesChanged(TEST_NETWORK, new NetworkCapabilities()); + cb.onCapabilitiesChanged(TEST_NETWORK, caps); cb.onLinkPropertiesChanged(TEST_NETWORK, new LinkProperties()); return cb; } @@ -1507,7 +1604,7 @@ final ArgumentCaptor<IkeSessionCallback> captor = ArgumentCaptor.forClass(IkeSessionCallback.class); - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); @@ -1530,10 +1627,7 @@ // same process with the real case. if (errorCode == VpnManager.ERROR_CODE_NETWORK_LOST) { cb.onLost(TEST_NETWORK); - final ArgumentCaptor<Runnable> runnableCaptor = - ArgumentCaptor.forClass(Runnable.class); - verify(mExecutor).schedule(runnableCaptor.capture(), anyLong(), any()); - runnableCaptor.getValue().run(); + verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any()); } else { final IkeSessionCallback ikeCb = captor.getValue(); ikeCb.onClosedWithException(exception); @@ -1542,7 +1636,10 @@ verifyPowerSaveTempWhitelistApp(TEST_VPN_PKG); reset(mDeviceIdleInternal); verifyVpnManagerEvent(sessionKey, category, errorType, errorCode, - new String[] {TEST_VPN_PKG}, null /* profileState */); + // VPN NetworkAgnet does not switch to CONNECTED in the test, and the state is not + // important here. Verify that the state as it is, i.e. CONNECTING state. + new String[] {TEST_VPN_PKG}, new VpnProfileState(VpnProfileState.STATE_CONNECTING, + sessionKey, false /* alwaysOn */, false /* lockdown */)); if (errorType == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) { verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)) .unregisterNetworkCallback(eq(cb)); @@ -1558,25 +1655,23 @@ } private IkeSessionCallback verifyRetryAndGetNewIkeCb(int retryIndex) { - final ArgumentCaptor<Runnable> runnableCaptor = - ArgumentCaptor.forClass(Runnable.class); final ArgumentCaptor<IkeSessionCallback> ikeCbCaptor = ArgumentCaptor.forClass(IkeSessionCallback.class); // Verify retry is scheduled - final long expectedDelay = mTestDeps.getNextRetryDelaySeconds(retryIndex); - verify(mExecutor).schedule(runnableCaptor.capture(), eq(expectedDelay), any()); + final long expectedDelayMs = mTestDeps.getNextRetryDelayMs(retryIndex); + final ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class); + verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), delayCaptor.capture(), + eq(TimeUnit.MILLISECONDS)); + final List<Long> delays = delayCaptor.getAllValues(); + assertEquals(expectedDelayMs, (long) delays.get(delays.size() - 1)); - // Mock the event of firing the retry task - runnableCaptor.getValue().run(); - - verify(mIkev2SessionCreator) + verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS + expectedDelayMs)) .createIkeSession(any(), any(), any(), any(), ikeCbCaptor.capture(), any()); // Forget the mIkev2SessionCreator#createIkeSession call and mExecutor#schedule call // for the next retry verification resetIkev2SessionCreator(mIkeSessionWrapper); - resetExecutor(mScheduledFuture); return ikeCbCaptor.getValue(); } @@ -1812,6 +1907,21 @@ private PlatformVpnSnapshot verifySetupPlatformVpn( IkeSessionConfiguration ikeConfig, boolean mtuSupportsIpv6) throws Exception { + return verifySetupPlatformVpn(mVpnProfile, ikeConfig, mtuSupportsIpv6); + } + + private PlatformVpnSnapshot verifySetupPlatformVpn(VpnProfile vpnProfile, + IkeSessionConfiguration ikeConfig, boolean mtuSupportsIpv6) throws Exception { + return verifySetupPlatformVpn(vpnProfile, ikeConfig, + new NetworkCapabilities.Builder().build() /* underlying network caps */, + mtuSupportsIpv6, false /* areLongLivedTcpConnectionsExpensive */); + } + + private PlatformVpnSnapshot verifySetupPlatformVpn(VpnProfile vpnProfile, + IkeSessionConfiguration ikeConfig, + @NonNull final NetworkCapabilities underlyingNetworkCaps, + boolean mtuSupportsIpv6, + boolean areLongLivedTcpConnectionsExpensive) throws Exception { if (!mtuSupportsIpv6) { doReturn(IPV6_MIN_MTU - 1).when(mTestDeps).calculateVpnMtu(any(), anyInt(), anyInt(), anyBoolean()); @@ -1820,13 +1930,16 @@ doReturn(mMockNetworkAgent).when(mTestDeps) .newNetworkAgent( any(), any(), anyString(), any(), any(), any(), any(), any(), any()); + doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork(); - final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) - .thenReturn(mVpnProfile.encode()); + .thenReturn(vpnProfile.encode()); vpn.startVpnProfile(TEST_VPN_PKG); - final NetworkCallback nwCb = triggerOnAvailableAndGetCallback(); + final NetworkCallback nwCb = triggerOnAvailableAndGetCallback(underlyingNetworkCaps); + verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any()); + reset(mExecutor); // Mock the setup procedure by firing callbacks final Pair<IkeSessionCallback, ChildSessionCallback> cbPair = @@ -1850,7 +1963,7 @@ verify(mTestDeps).newNetworkAgent( any(), any(), anyString(), ncCaptor.capture(), lpCaptor.capture(), any(), nacCaptor.capture(), any(), any()); - + verify(mIkeSessionWrapper).setUnderpinnedNetwork(TEST_NETWORK); // Check LinkProperties final LinkProperties lp = lpCaptor.getValue(); final List<RouteInfo> expectedRoutes = @@ -1893,8 +2006,10 @@ // Check if allowBypass is set or not. assertTrue(nacCaptor.getValue().isBypassableVpn()); - assertTrue(((VpnTransportInfo) ncCaptor.getValue().getTransportInfo()).getBypassable()); - + final VpnTransportInfo info = (VpnTransportInfo) ncCaptor.getValue().getTransportInfo(); + assertTrue(info.isBypassable()); + assertEquals(areLongLivedTcpConnectionsExpensive, + info.areLongLivedTcpConnectionsExpensive()); return new PlatformVpnSnapshot(vpn, nwCb, ikeCb, childCb); } @@ -1906,6 +2021,441 @@ } @Test + public void testMigrateIkeSession_FromIkeTunnConnParams_AutoTimerNoTimer() throws Exception { + doTestMigrateIkeSession_FromIkeTunnConnParams( + false /* isAutomaticIpVersionSelectionEnabled */, + true /* isAutomaticNattKeepaliveTimerEnabled */, + TEST_KEEPALIVE_TIMEOUT_UNSET /* keepaliveInProfile */, + ESP_IP_VERSION_AUTO /* ipVersionInProfile */, + ESP_ENCAP_TYPE_AUTO /* encapTypeInProfile */); + } + + @Test + public void testMigrateIkeSession_FromIkeTunnConnParams_AutoTimerTimerSet() throws Exception { + doTestMigrateIkeSession_FromIkeTunnConnParams( + false /* isAutomaticIpVersionSelectionEnabled */, + true /* isAutomaticNattKeepaliveTimerEnabled */, + TEST_KEEPALIVE_TIMER /* keepaliveInProfile */, + ESP_IP_VERSION_AUTO /* ipVersionInProfile */, + ESP_ENCAP_TYPE_AUTO /* encapTypeInProfile */); + } + + @Test + public void testMigrateIkeSession_FromIkeTunnConnParams_AutoIp() throws Exception { + doTestMigrateIkeSession_FromIkeTunnConnParams( + true /* isAutomaticIpVersionSelectionEnabled */, + false /* isAutomaticNattKeepaliveTimerEnabled */, + TEST_KEEPALIVE_TIMEOUT_UNSET /* keepaliveInProfile */, + ESP_IP_VERSION_AUTO /* ipVersionInProfile */, + ESP_ENCAP_TYPE_AUTO /* encapTypeInProfile */); + } + + @Test + public void testMigrateIkeSession_FromIkeTunnConnParams_AssignedIpProtocol() throws Exception { + doTestMigrateIkeSession_FromIkeTunnConnParams( + false /* isAutomaticIpVersionSelectionEnabled */, + false /* isAutomaticNattKeepaliveTimerEnabled */, + TEST_KEEPALIVE_TIMEOUT_UNSET /* keepaliveInProfile */, + ESP_IP_VERSION_IPV4 /* ipVersionInProfile */, + ESP_ENCAP_TYPE_UDP /* encapTypeInProfile */); + } + + @Test + public void testMigrateIkeSession_FromNotIkeTunnConnParams_AutoTimer() throws Exception { + doTestMigrateIkeSession_FromNotIkeTunnConnParams( + false /* isAutomaticIpVersionSelectionEnabled */, + true /* isAutomaticNattKeepaliveTimerEnabled */); + } + + @Test + public void testMigrateIkeSession_FromNotIkeTunnConnParams_AutoIp() throws Exception { + doTestMigrateIkeSession_FromNotIkeTunnConnParams( + true /* isAutomaticIpVersionSelectionEnabled */, + false /* isAutomaticNattKeepaliveTimerEnabled */); + } + + private void doTestMigrateIkeSession_FromNotIkeTunnConnParams( + boolean isAutomaticIpVersionSelectionEnabled, + boolean isAutomaticNattKeepaliveTimerEnabled) throws Exception { + final Ikev2VpnProfile ikeProfile = + new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY) + .setAuthPsk(TEST_VPN_PSK) + .setBypassable(true /* isBypassable */) + .setAutomaticNattKeepaliveTimerEnabled(isAutomaticNattKeepaliveTimerEnabled) + .setAutomaticIpVersionSelectionEnabled(isAutomaticIpVersionSelectionEnabled) + .build(); + + final int expectedKeepalive = isAutomaticNattKeepaliveTimerEnabled + ? AUTOMATIC_KEEPALIVE_DELAY_SECONDS + : DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT; + doTestMigrateIkeSession(ikeProfile.toVpnProfile(), + expectedKeepalive, + ESP_IP_VERSION_AUTO /* expectedIpVersion */, + ESP_ENCAP_TYPE_AUTO /* expectedEncapType */, + new NetworkCapabilities.Builder().build()); + } + + private Ikev2VpnProfile makeIkeV2VpnProfile( + boolean isAutomaticIpVersionSelectionEnabled, + boolean isAutomaticNattKeepaliveTimerEnabled, + int keepaliveInProfile, + int ipVersionInProfile, + int encapTypeInProfile) { + // TODO: Update helper function in IkeSessionTestUtils to support building IkeSessionParams + // with IP version and encap type when mainline-prod branch support these two APIs. + final IkeSessionParams params = getTestIkeSessionParams(true /* testIpv6 */, + new IkeFqdnIdentification(TEST_IDENTITY), keepaliveInProfile); + final IkeSessionParams ikeSessionParams = new IkeSessionParams.Builder(params) + .setIpVersion(ipVersionInProfile) + .setEncapType(encapTypeInProfile) + .build(); + + final IkeTunnelConnectionParams tunnelParams = + new IkeTunnelConnectionParams(ikeSessionParams, CHILD_PARAMS); + return new Ikev2VpnProfile.Builder(tunnelParams) + .setBypassable(true) + .setAutomaticNattKeepaliveTimerEnabled(isAutomaticNattKeepaliveTimerEnabled) + .setAutomaticIpVersionSelectionEnabled(isAutomaticIpVersionSelectionEnabled) + .build(); + } + + private void doTestMigrateIkeSession_FromIkeTunnConnParams( + boolean isAutomaticIpVersionSelectionEnabled, + boolean isAutomaticNattKeepaliveTimerEnabled, + int keepaliveInProfile, + int ipVersionInProfile, + int encapTypeInProfile) throws Exception { + doTestMigrateIkeSession_FromIkeTunnConnParams(isAutomaticIpVersionSelectionEnabled, + isAutomaticNattKeepaliveTimerEnabled, keepaliveInProfile, ipVersionInProfile, + encapTypeInProfile, new NetworkCapabilities.Builder().build()); + } + + private void doTestMigrateIkeSession_FromIkeTunnConnParams( + boolean isAutomaticIpVersionSelectionEnabled, + boolean isAutomaticNattKeepaliveTimerEnabled, + int keepaliveInProfile, + int ipVersionInProfile, + int encapTypeInProfile, + @NonNull final NetworkCapabilities nc) throws Exception { + final Ikev2VpnProfile ikeProfile = makeIkeV2VpnProfile( + isAutomaticIpVersionSelectionEnabled, + isAutomaticNattKeepaliveTimerEnabled, + keepaliveInProfile, + ipVersionInProfile, + encapTypeInProfile); + + final IkeSessionParams ikeSessionParams = + ikeProfile.getIkeTunnelConnectionParams().getIkeSessionParams(); + final int expectedKeepalive = isAutomaticNattKeepaliveTimerEnabled + ? AUTOMATIC_KEEPALIVE_DELAY_SECONDS + : ikeSessionParams.getNattKeepAliveDelaySeconds(); + final int expectedIpVersion = isAutomaticIpVersionSelectionEnabled + ? ESP_IP_VERSION_AUTO + : ikeSessionParams.getIpVersion(); + final int expectedEncapType = isAutomaticIpVersionSelectionEnabled + ? ESP_ENCAP_TYPE_AUTO + : ikeSessionParams.getEncapType(); + doTestMigrateIkeSession(ikeProfile.toVpnProfile(), expectedKeepalive, + expectedIpVersion, expectedEncapType, nc); + } + + @Test + public void doTestMigrateIkeSession_Vcn() throws Exception { + final int expectedKeepalive = 2097; // Any unlikely number will do + final NetworkCapabilities vcnNc = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .setTransportInfo(new VcnTransportInfo(TEST_SUB_ID, expectedKeepalive)) + .build(); + final Ikev2VpnProfile ikev2VpnProfile = makeIkeV2VpnProfile( + true /* isAutomaticIpVersionSelectionEnabled */, + true /* isAutomaticNattKeepaliveTimerEnabled */, + 234 /* keepaliveInProfile */, // Should be ignored, any value will do + ESP_IP_VERSION_IPV4, // Should be ignored + ESP_ENCAP_TYPE_UDP // Should be ignored + ); + doTestMigrateIkeSession( + ikev2VpnProfile.toVpnProfile(), + expectedKeepalive, + ESP_IP_VERSION_AUTO /* expectedIpVersion */, + ESP_ENCAP_TYPE_AUTO /* expectedEncapType */, + vcnNc); + } + + private void doTestMigrateIkeSession( + @NonNull final VpnProfile profile, + final int expectedKeepalive, + final int expectedIpVersion, + final int expectedEncapType, + @NonNull final NetworkCapabilities caps) throws Exception { + final PlatformVpnSnapshot vpnSnapShot = + verifySetupPlatformVpn(profile, + createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */), + caps /* underlying network capabilities */, + false /* mtuSupportsIpv6 */, + expectedKeepalive < DEFAULT_LONG_LIVED_TCP_CONNS_EXPENSIVE_TIMEOUT_SEC); + // Simulate a new network coming up + vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2); + verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt()); + + vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2, caps); + // Verify MOBIKE is triggered + verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(TEST_NETWORK_2, + expectedIpVersion, expectedEncapType, expectedKeepalive); + + vpnSnapShot.vpn.mVpnRunner.exitVpnRunner(); + } + + @Test + public void testLinkPropertiesUpdateTriggerReevaluation() throws Exception { + final boolean hasV6 = true; + + mockCarrierConfig(TEST_SUB_ID, TelephonyManager.SIM_STATE_LOADED, TEST_KEEPALIVE_TIMER, + PREFERRED_IKE_PROTOCOL_IPV6_ESP); + final IkeSessionParams params = getTestIkeSessionParams(hasV6, + new IkeFqdnIdentification(TEST_IDENTITY), TEST_KEEPALIVE_TIMER); + final IkeTunnelConnectionParams tunnelParams = + new IkeTunnelConnectionParams(params, CHILD_PARAMS); + final Ikev2VpnProfile ikeProfile = new Ikev2VpnProfile.Builder(tunnelParams) + .setBypassable(true) + .setAutomaticNattKeepaliveTimerEnabled(false) + .setAutomaticIpVersionSelectionEnabled(true) + .build(); + final PlatformVpnSnapshot vpnSnapShot = + verifySetupPlatformVpn(ikeProfile.toVpnProfile(), + createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */), + new NetworkCapabilities.Builder().build() /* underlying network caps */, + hasV6 /* mtuSupportsIpv6 */, + false /* areLongLivedTcpConnectionsExpensive */); + reset(mExecutor); + + // Simulate a new network coming up + final LinkProperties lp = new LinkProperties(); + lp.addLinkAddress(new LinkAddress("192.0.2.2/32")); + + // Have the executor use the real delay to make sure schedule() was called only + // once for all calls. Also, arrange for execute() not to call schedule() to avoid + // messing with the checks for schedule(). + mExecutor.delayMs = TestExecutor.REAL_DELAY; + mExecutor.executeDirect = true; + vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2); + vpnSnapShot.nwCb.onCapabilitiesChanged( + TEST_NETWORK_2, new NetworkCapabilities.Builder().build()); + vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp)); + verify(mExecutor).schedule(any(Runnable.class), longThat(it -> it > 0), any()); + reset(mExecutor); + + final InOrder order = inOrder(mIkeSessionWrapper); + + // Verify the network is started + order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2, + ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER); + + // Send the same properties, check that no migration is scheduled + vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp)); + verify(mExecutor, never()).schedule(any(Runnable.class), anyLong(), any()); + + // Add v6 address, verify MOBIKE is triggered + lp.addLinkAddress(new LinkAddress("2001:db8::1/64")); + vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp)); + order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2, + ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER); + + // Add another v4 address, verify MOBIKE is triggered + final LinkProperties stacked = new LinkProperties(); + stacked.setInterfaceName("v4-" + lp.getInterfaceName()); + stacked.addLinkAddress(new LinkAddress("192.168.0.1/32")); + lp.addStackedLink(stacked); + vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp)); + order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2, + ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER); + + vpnSnapShot.vpn.mVpnRunner.exitVpnRunner(); + } + + private void mockCarrierConfig(int subId, int simStatus, int keepaliveTimer, int ikeProtocol) { + final SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class); + doReturn(subId).when(subscriptionInfo).getSubscriptionId(); + doReturn(List.of(subscriptionInfo)).when(mSubscriptionManager) + .getActiveSubscriptionInfoList(); + + doReturn(simStatus).when(mTmPerSub).getSimApplicationState(); + doReturn(TEST_MCCMNC).when(mTmPerSub).getSimOperator(subId); + + final PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putInt(KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT, keepaliveTimer); + persistableBundle.putInt(KEY_PREFERRED_IKE_PROTOCOL_INT, ikeProtocol); + // For CarrierConfigManager.isConfigForIdentifiedCarrier check + persistableBundle.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, true); + doReturn(persistableBundle).when(mConfigManager).getConfigForSubId(subId); + } + + private CarrierConfigManager.CarrierConfigChangeListener getCarrierConfigListener() { + final ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); + + verify(mConfigManager).registerCarrierConfigChangeListener(any(), listenerCaptor.capture()); + + return listenerCaptor.getValue(); + } + + @Test + public void testNattKeepaliveTimerFromCarrierConfig_noSubId() throws Exception { + doTestReadCarrierConfig(new NetworkCapabilities(), + TelephonyManager.SIM_STATE_LOADED, + PREFERRED_IKE_PROTOCOL_IPV4_UDP, + AUTOMATIC_KEEPALIVE_DELAY_SECONDS /* expectedKeepaliveTimer */, + ESP_IP_VERSION_AUTO /* expectedIpVersion */, + ESP_ENCAP_TYPE_AUTO /* expectedEncapType */, + false /* expectedReadFromCarrierConfig*/, + true /* areLongLivedTcpConnectionsExpensive */); + } + + @Test + public void testNattKeepaliveTimerFromCarrierConfig_simAbsent() throws Exception { + doTestReadCarrierConfig(new NetworkCapabilities.Builder().build(), + TelephonyManager.SIM_STATE_ABSENT, + PREFERRED_IKE_PROTOCOL_IPV4_UDP, + AUTOMATIC_KEEPALIVE_DELAY_SECONDS /* expectedKeepaliveTimer */, + ESP_IP_VERSION_AUTO /* expectedIpVersion */, + ESP_ENCAP_TYPE_AUTO /* expectedEncapType */, + false /* expectedReadFromCarrierConfig*/, + true /* areLongLivedTcpConnectionsExpensive */); + } + + @Test + public void testNattKeepaliveTimerFromCarrierConfig() throws Exception { + doTestReadCarrierConfig(createTestCellNc(), + TelephonyManager.SIM_STATE_LOADED, + PREFERRED_IKE_PROTOCOL_AUTO, + TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */, + ESP_IP_VERSION_AUTO /* expectedIpVersion */, + ESP_ENCAP_TYPE_AUTO /* expectedEncapType */, + true /* expectedReadFromCarrierConfig*/, + false /* areLongLivedTcpConnectionsExpensive */); + } + + @Test + public void testNattKeepaliveTimerFromCarrierConfig_NotCell() throws Exception { + final NetworkCapabilities nc = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_WIFI) + .setTransportInfo(new WifiInfo.Builder().build()) + .build(); + doTestReadCarrierConfig(nc, + TelephonyManager.SIM_STATE_LOADED, + PREFERRED_IKE_PROTOCOL_IPV4_UDP, + AUTOMATIC_KEEPALIVE_DELAY_SECONDS /* expectedKeepaliveTimer */, + ESP_IP_VERSION_AUTO /* expectedIpVersion */, + ESP_ENCAP_TYPE_AUTO /* expectedEncapType */, + false /* expectedReadFromCarrierConfig*/, + true /* areLongLivedTcpConnectionsExpensive */); + } + + @Test + public void testPreferredIpProtocolFromCarrierConfig_v4UDP() throws Exception { + doTestReadCarrierConfig(createTestCellNc(), + TelephonyManager.SIM_STATE_LOADED, + PREFERRED_IKE_PROTOCOL_IPV4_UDP, + TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */, + ESP_IP_VERSION_IPV4 /* expectedIpVersion */, + ESP_ENCAP_TYPE_UDP /* expectedEncapType */, + true /* expectedReadFromCarrierConfig*/, + false /* areLongLivedTcpConnectionsExpensive */); + } + + @Test + public void testPreferredIpProtocolFromCarrierConfig_v6ESP() throws Exception { + doTestReadCarrierConfig(createTestCellNc(), + TelephonyManager.SIM_STATE_LOADED, + PREFERRED_IKE_PROTOCOL_IPV6_ESP, + TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */, + ESP_IP_VERSION_IPV6 /* expectedIpVersion */, + ESP_ENCAP_TYPE_NONE /* expectedEncapType */, + true /* expectedReadFromCarrierConfig*/, + false /* areLongLivedTcpConnectionsExpensive */); + } + + @Test + public void testPreferredIpProtocolFromCarrierConfig_v6UDP() throws Exception { + doTestReadCarrierConfig(createTestCellNc(), + TelephonyManager.SIM_STATE_LOADED, + PREFERRED_IKE_PROTOCOL_IPV6_UDP, + TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */, + ESP_IP_VERSION_IPV6 /* expectedIpVersion */, + ESP_ENCAP_TYPE_UDP /* expectedEncapType */, + true /* expectedReadFromCarrierConfig*/, + false /* areLongLivedTcpConnectionsExpensive */); + } + + private NetworkCapabilities createTestCellNc() { + return new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(TEST_SUB_ID) + .build()) + .build(); + } + + private void doTestReadCarrierConfig(NetworkCapabilities nc, int simState, int preferredIpProto, + int expectedKeepaliveTimer, int expectedIpVersion, int expectedEncapType, + boolean expectedReadFromCarrierConfig, + boolean areLongLivedTcpConnectionsExpensive) + throws Exception { + final Ikev2VpnProfile ikeProfile = + new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY) + .setAuthPsk(TEST_VPN_PSK) + .setBypassable(true /* isBypassable */) + .setAutomaticNattKeepaliveTimerEnabled(true) + .setAutomaticIpVersionSelectionEnabled(true) + .build(); + + final PlatformVpnSnapshot vpnSnapShot = + verifySetupPlatformVpn(ikeProfile.toVpnProfile(), + createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */), + new NetworkCapabilities.Builder().build() /* underlying network caps */, + false /* mtuSupportsIpv6 */, + true /* areLongLivedTcpConnectionsExpensive */); + + final CarrierConfigManager.CarrierConfigChangeListener listener = + getCarrierConfigListener(); + + // Simulate a new network coming up + vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2); + // Migration will not be started until receiving network capabilities change. + verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt()); + + reset(mIkeSessionWrapper); + mockCarrierConfig(TEST_SUB_ID, simState, TEST_KEEPALIVE_TIMER, preferredIpProto); + vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2, nc); + verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(TEST_NETWORK_2, + expectedIpVersion, expectedEncapType, expectedKeepaliveTimer); + if (expectedReadFromCarrierConfig) { + final ArgumentCaptor<NetworkCapabilities> ncCaptor = + ArgumentCaptor.forClass(NetworkCapabilities.class); + verify(mMockNetworkAgent).doSendNetworkCapabilities(ncCaptor.capture()); + + final VpnTransportInfo info = + (VpnTransportInfo) ncCaptor.getValue().getTransportInfo(); + assertEquals(areLongLivedTcpConnectionsExpensive, + info.areLongLivedTcpConnectionsExpensive()); + } else { + verify(mMockNetworkAgent, never()).doSendNetworkCapabilities(any()); + } + + reset(mExecutor); + reset(mIkeSessionWrapper); + reset(mMockNetworkAgent); + + // Trigger carrier config change + listener.onCarrierConfigChanged(1 /* logicalSlotIndex */, TEST_SUB_ID, + -1 /* carrierId */, -1 /* specificCarrierId */); + verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2, + expectedIpVersion, expectedEncapType, expectedKeepaliveTimer); + // Expect no NetworkCapabilities change. + // Call to doSendNetworkCapabilities() will not be triggered. + verify(mMockNetworkAgent, never()).doSendNetworkCapabilities(any()); + } + + @Test public void testStartPlatformVpn_mtuDoesNotSupportIpv6() throws Exception { final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn( @@ -1925,14 +2475,19 @@ // Mock network loss and verify a cleanup task is scheduled vpnSnapShot.nwCb.onLost(TEST_NETWORK); - verify(mExecutor).schedule(any(Runnable.class), anyLong(), any()); + verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any()); // Mock new network comes up and the cleanup task is cancelled vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2); - verify(mScheduledFuture).cancel(anyBoolean()); + verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt()); + vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2, + new NetworkCapabilities.Builder().build()); // Verify MOBIKE is triggered - verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2); + verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(eq(TEST_NETWORK_2), + eq(ESP_IP_VERSION_AUTO) /* ipVersion */, + eq(ESP_ENCAP_TYPE_AUTO) /* encapType */, + eq(DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT) /* keepaliveDelay */); // Mock the MOBIKE procedure vpnSnapShot.ikeCb.onIkeSessionConnectionInfoChanged(createIkeConnectInfo_2()); @@ -2022,9 +2577,13 @@ // Mock network switch vpnSnapShot.nwCb.onLost(TEST_NETWORK); vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2); + // The old IKE Session will not be killed until receiving network capabilities change. + verify(mIkeSessionWrapper, never()).kill(); + vpnSnapShot.nwCb.onCapabilitiesChanged( + TEST_NETWORK_2, new NetworkCapabilities.Builder().build()); // Verify the old IKE Session is killed - verify(mIkeSessionWrapper).kill(); + verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).kill(); // Capture callbacks of the new IKE Session final Pair<IkeSessionCallback, ChildSessionCallback> cbPair = @@ -2052,23 +2611,95 @@ vpnSnapShot.vpn.mVpnRunner.exitVpnRunner(); } + private String getDump(@NonNull final Vpn vpn) { + final StringWriter sw = new StringWriter(); + final IndentingPrintWriter writer = new IndentingPrintWriter(sw, ""); + vpn.dump(writer); + writer.flush(); + return sw.toString(); + } + + private int countMatches(@NonNull final Pattern regexp, @NonNull final String string) { + final Matcher m = regexp.matcher(string); + int i = 0; + while (m.find()) ++i; + return i; + } + + @Test + public void testNCEventChanges() throws Exception { + final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_RESTRICTED) + .setLinkDownstreamBandwidthKbps(1000) + .setLinkUpstreamBandwidthKbps(500); + + final Ikev2VpnProfile ikeProfile = + new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY) + .setAuthPsk(TEST_VPN_PSK) + .setBypassable(true /* isBypassable */) + .setAutomaticNattKeepaliveTimerEnabled(true) + .setAutomaticIpVersionSelectionEnabled(true) + .build(); + + final PlatformVpnSnapshot vpnSnapShot = + verifySetupPlatformVpn(ikeProfile.toVpnProfile(), + createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */), + ncBuilder.build(), false /* mtuSupportsIpv6 */, + true /* areLongLivedTcpConnectionsExpensive */); + + // Calls to onCapabilitiesChanged will be thrown to the executor for execution ; by + // default this will incur a 10ms delay before it's executed, messing with the timing + // of the log and having the checks for counts in equals() below flake. + mExecutor.executeDirect = true; + + // First nc changed triggered by verifySetupPlatformVpn + final Pattern pattern = Pattern.compile("Cap changed from", Pattern.MULTILINE); + final String stage1 = getDump(vpnSnapShot.vpn); + assertEquals(1, countMatches(pattern, stage1)); + + vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build()); + final String stage2 = getDump(vpnSnapShot.vpn); + // Was the same caps, there should still be only 1 match + assertEquals(1, countMatches(pattern, stage2)); + + ncBuilder.setLinkDownstreamBandwidthKbps(1200) + .setLinkUpstreamBandwidthKbps(300); + vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build()); + final String stage3 = getDump(vpnSnapShot.vpn); + // Was not an important change, should not be logged, still only 1 match + assertEquals(1, countMatches(pattern, stage3)); + + ncBuilder.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); + vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build()); + final String stage4 = getDump(vpnSnapShot.vpn); + // Change to caps is important, should cause a new match + assertEquals(2, countMatches(pattern, stage4)); + + ncBuilder.removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); + ncBuilder.setLinkDownstreamBandwidthKbps(600); + vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build()); + final String stage5 = getDump(vpnSnapShot.vpn); + // Change to caps is important, should cause a new match even with the unimportant change + assertEquals(3, countMatches(pattern, stage5)); + } + // TODO : beef up event logs tests + private void verifyHandlingNetworkLoss(PlatformVpnSnapshot vpnSnapShot) throws Exception { // Forget the #sendLinkProperties during first setup. reset(mMockNetworkAgent); - final ArgumentCaptor<Runnable> runnableCaptor = - ArgumentCaptor.forClass(Runnable.class); - // Mock network loss vpnSnapShot.nwCb.onLost(TEST_NETWORK); // Mock the grace period expires - verify(mExecutor).schedule(runnableCaptor.capture(), anyLong(), any()); - runnableCaptor.getValue().run(); + verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any()); final ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class); - verify(mMockNetworkAgent).doSendLinkProperties(lpCaptor.capture()); + verify(mMockNetworkAgent, timeout(TEST_TIMEOUT_MS)) + .doSendLinkProperties(lpCaptor.capture()); final LinkProperties lp = lpCaptor.getValue(); assertNull(lp.getInterfaceName()); @@ -2112,7 +2743,8 @@ private void verifyMobikeTriggered(List<Network> expected) { final ArgumentCaptor<Network> networkCaptor = ArgumentCaptor.forClass(Network.class); - verify(mIkeSessionWrapper).setNetwork(networkCaptor.capture()); + verify(mIkeSessionWrapper).setNetwork(networkCaptor.capture(), + anyInt() /* ipVersion */, anyInt() /* encapType */, anyInt() /* keepaliveDelay */); assertEquals(expected, Collections.singletonList(networkCaptor.getValue())); } @@ -2128,7 +2760,8 @@ connectivityDiagCallback.onDataStallSuspected(report); // Should not trigger MOBIKE if MOBIKE is not enabled - verify(mIkeSessionWrapper, never()).setNetwork(any()); + verify(mIkeSessionWrapper, never()).setNetwork(any() /* network */, + anyInt() /* ipVersion */, anyInt() /* encapType */, anyInt() /* keepaliveDelay */); } @Test @@ -2148,7 +2781,8 @@ // Expect to skip other data stall event if MOBIKE was started. reset(mIkeSessionWrapper); connectivityDiagCallback.onDataStallSuspected(report); - verify(mIkeSessionWrapper, never()).setNetwork(any()); + verify(mIkeSessionWrapper, never()).setNetwork(any() /* network */, + anyInt() /* ipVersion */, anyInt() /* encapType */, anyInt() /* keepaliveDelay */); reset(mIkev2SessionCreator); @@ -2163,9 +2797,7 @@ // 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(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any()); verify(mIkev2SessionCreator, never()).createIkeSession( any(), any(), any(), any(), any(), any()); } @@ -2191,17 +2823,16 @@ 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()); + verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), 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()); + verify(mExecutor, never()).schedule(any(Runnable.class), anyLong(), any()); - runnableCaptor.getValue().run(); - verify(mIkev2SessionCreator).createIkeSession(any(), any(), any(), any(), any(), any()); + verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS)) + .createIkeSession(any(), any(), any(), any(), any(), any()); } @Test @@ -2473,15 +3104,23 @@ } @Override - public long getNextRetryDelaySeconds(int retryCount) { + public long getNextRetryDelayMs(int retryCount) { // Simply return retryCount as the delay seconds for retrying. - return retryCount; + return retryCount * 1000; } @Override public ScheduledThreadPoolExecutor newScheduledThreadPoolExecutor() { return mExecutor; } + + public boolean mIgnoreCallingUidChecks = true; + @Override + public void verifyCallingUidAndPackage(Context context, String packageName, int userId) { + if (!mIgnoreCallingUidChecks) { + super.verifyCallingUidAndPackage(context, packageName, userId); + } + } } /** @@ -2544,30 +3183,4 @@ } catch (Exception e) { } } - - private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) { - doAnswer(invocation -> { - final Network network = (Network) invocation.getArguments()[0]; - return networks.get(network); - }).when(mConnectivityManager).getNetworkCapabilities(any()); - } - - // Need multiple copies of this, but Java's Stream objects can't be reused or - // duplicated. - private Stream<String> publicIpV4Routes() { - return Stream.of( - "0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4", - "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6", - "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9", - "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11", - "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14", - "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7", - "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4"); - } - - private Stream<String> publicIpV6Routes() { - return Stream.of( - "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6", - "fe00::/8", "2605:ef80:e:af1d::/64"); - } }
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt new file mode 100644 index 0000000..d9acc61 --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
@@ -0,0 +1,327 @@ +/* + * 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 android.net.InetAddresses.parseNumericAddress +import android.net.LinkAddress +import android.net.Network +import android.net.nsd.NsdServiceInfo +import android.os.Build +import android.os.Handler +import android.os.HandlerThread +import com.android.net.module.util.SharedLog +import com.android.server.connectivity.mdns.MdnsAdvertiser.AdvertiserCallback +import com.android.server.connectivity.mdns.MdnsSocketProvider.SocketCallback +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.DevSdkIgnoreRunner +import com.android.testutils.waitForIdle +import java.net.NetworkInterface +import java.util.Objects +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito.any +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.argThat +import org.mockito.Mockito.atLeastOnce +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify + +private const val SERVICE_ID_1 = 1 +private const val SERVICE_ID_2 = 2 +private const val LONG_SERVICE_ID_1 = 3 +private const val LONG_SERVICE_ID_2 = 4 +private const val CASE_INSENSITIVE_TEST_SERVICE_ID = 5 +private const val TIMEOUT_MS = 10_000L +private val TEST_ADDR = parseNumericAddress("2001:db8::123") +private val TEST_LINKADDR = LinkAddress(TEST_ADDR, 64 /* prefixLength */) +private val TEST_NETWORK_1 = mock(Network::class.java) +private val TEST_NETWORK_2 = mock(Network::class.java) +private val TEST_HOSTNAME = arrayOf("Android_test", "local") +private const val TEST_SUBTYPE = "_subtype" + +private val SERVICE_1 = NsdServiceInfo("TestServiceName", "_advertisertest._tcp").apply { + port = 12345 + hostAddresses = listOf(TEST_ADDR) + network = TEST_NETWORK_1 +} + +private val LONG_SERVICE_1 = + NsdServiceInfo("a".repeat(48) + "TestServiceName", "_longadvertisertest._tcp").apply { + port = 12345 + hostAddresses = listOf(TEST_ADDR) + network = TEST_NETWORK_1 + } + +private val ALL_NETWORKS_SERVICE = NsdServiceInfo("TestServiceName", "_advertisertest._tcp").apply { + port = 12345 + hostAddresses = listOf(TEST_ADDR) + network = null +} + +private val ALL_NETWORKS_SERVICE_2 = + NsdServiceInfo("TESTSERVICENAME", "_ADVERTISERTEST._tcp").apply { + port = 12345 + hostAddresses = listOf(TEST_ADDR) + network = null + } + +private val LONG_ALL_NETWORKS_SERVICE = + NsdServiceInfo("a".repeat(48) + "TestServiceName", "_longadvertisertest._tcp").apply { + port = 12345 + hostAddresses = listOf(TEST_ADDR) + network = null + } + +@RunWith(DevSdkIgnoreRunner::class) +@IgnoreUpTo(Build.VERSION_CODES.S_V2) +class MdnsAdvertiserTest { + private val thread = HandlerThread(MdnsAdvertiserTest::class.simpleName) + private val handler by lazy { Handler(thread.looper) } + private val socketProvider = mock(MdnsSocketProvider::class.java) + private val cb = mock(AdvertiserCallback::class.java) + private val sharedlog = mock(SharedLog::class.java) + + private val mockSocket1 = mock(MdnsInterfaceSocket::class.java) + private val mockSocket2 = mock(MdnsInterfaceSocket::class.java) + private val mockInterfaceAdvertiser1 = mock(MdnsInterfaceAdvertiser::class.java) + private val mockInterfaceAdvertiser2 = mock(MdnsInterfaceAdvertiser::class.java) + private val mockDeps = mock(MdnsAdvertiser.Dependencies::class.java) + + @Before + fun setUp() { + thread.start() + doReturn(TEST_HOSTNAME).`when`(mockDeps).generateHostname() + doReturn(mockInterfaceAdvertiser1).`when`(mockDeps).makeAdvertiser(eq(mockSocket1), + any(), any(), any(), any(), eq(TEST_HOSTNAME), any() + ) + doReturn(mockInterfaceAdvertiser2).`when`(mockDeps).makeAdvertiser(eq(mockSocket2), + any(), any(), any(), any(), eq(TEST_HOSTNAME), any() + ) + doReturn(true).`when`(mockInterfaceAdvertiser1).isProbing(anyInt()) + doReturn(true).`when`(mockInterfaceAdvertiser2).isProbing(anyInt()) + doReturn(createEmptyNetworkInterface()).`when`(mockSocket1).getInterface() + doReturn(createEmptyNetworkInterface()).`when`(mockSocket2).getInterface() + } + + @After + fun tearDown() { + thread.quitSafely() + thread.join() + } + + private fun createEmptyNetworkInterface(): NetworkInterface { + val constructor = NetworkInterface::class.java.getDeclaredConstructor() + constructor.isAccessible = true + return constructor.newInstance() + } + + @Test + fun testAddService_OneNetwork() { + val advertiser = MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog) + postSync { advertiser.addService(SERVICE_ID_1, SERVICE_1, null /* subtype */) } + + val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java) + verify(socketProvider).requestSocket(eq(TEST_NETWORK_1), socketCbCaptor.capture()) + + val socketCb = socketCbCaptor.value + postSync { socketCb.onSocketCreated(TEST_NETWORK_1, mockSocket1, listOf(TEST_LINKADDR)) } + + val intAdvCbCaptor = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java) + verify(mockDeps).makeAdvertiser( + eq(mockSocket1), + eq(listOf(TEST_LINKADDR)), + eq(thread.looper), + any(), + intAdvCbCaptor.capture(), + eq(TEST_HOSTNAME), + any() + ) + + doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1) + postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded( + mockInterfaceAdvertiser1, SERVICE_ID_1) } + verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), argThat { it.matches(SERVICE_1) }) + + postSync { socketCb.onInterfaceDestroyed(TEST_NETWORK_1, mockSocket1) } + verify(mockInterfaceAdvertiser1).destroyNow() + } + + @Test + fun testAddService_AllNetworks() { + val advertiser = MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog) + postSync { advertiser.addService(SERVICE_ID_1, ALL_NETWORKS_SERVICE, TEST_SUBTYPE) } + + val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java) + verify(socketProvider).requestSocket(eq(ALL_NETWORKS_SERVICE.network), + socketCbCaptor.capture()) + + val socketCb = socketCbCaptor.value + postSync { socketCb.onSocketCreated(TEST_NETWORK_1, mockSocket1, listOf(TEST_LINKADDR)) } + postSync { socketCb.onSocketCreated(TEST_NETWORK_2, mockSocket2, listOf(TEST_LINKADDR)) } + + val intAdvCbCaptor1 = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java) + val intAdvCbCaptor2 = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java) + verify(mockDeps).makeAdvertiser(eq(mockSocket1), eq(listOf(TEST_LINKADDR)), + eq(thread.looper), any(), intAdvCbCaptor1.capture(), eq(TEST_HOSTNAME), any() + ) + verify(mockDeps).makeAdvertiser(eq(mockSocket2), eq(listOf(TEST_LINKADDR)), + eq(thread.looper), any(), intAdvCbCaptor2.capture(), eq(TEST_HOSTNAME), any() + ) + verify(mockInterfaceAdvertiser1).addService( + anyInt(), eq(ALL_NETWORKS_SERVICE), eq(TEST_SUBTYPE)) + verify(mockInterfaceAdvertiser2).addService( + anyInt(), eq(ALL_NETWORKS_SERVICE), eq(TEST_SUBTYPE)) + + doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1) + postSync { intAdvCbCaptor1.value.onRegisterServiceSucceeded( + mockInterfaceAdvertiser1, SERVICE_ID_1) } + + // Need both advertisers to finish probing and call onRegisterServiceSucceeded + verify(cb, never()).onRegisterServiceSucceeded(anyInt(), any()) + doReturn(false).`when`(mockInterfaceAdvertiser2).isProbing(SERVICE_ID_1) + postSync { intAdvCbCaptor2.value.onRegisterServiceSucceeded( + mockInterfaceAdvertiser2, SERVICE_ID_1) } + verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), + argThat { it.matches(ALL_NETWORKS_SERVICE) }) + + // Unregister the service + postSync { advertiser.removeService(SERVICE_ID_1) } + verify(mockInterfaceAdvertiser1).removeService(SERVICE_ID_1) + verify(mockInterfaceAdvertiser2).removeService(SERVICE_ID_1) + + // Interface advertisers call onDestroyed after sending exit announcements + postSync { intAdvCbCaptor1.value.onDestroyed(mockSocket1) } + verify(socketProvider, never()).unrequestSocket(any()) + postSync { intAdvCbCaptor2.value.onDestroyed(mockSocket2) } + verify(socketProvider).unrequestSocket(socketCb) + } + + @Test + fun testAddService_Conflicts() { + val advertiser = MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog) + postSync { advertiser.addService(SERVICE_ID_1, SERVICE_1, null /* subtype */) } + + val oneNetSocketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java) + verify(socketProvider).requestSocket(eq(TEST_NETWORK_1), oneNetSocketCbCaptor.capture()) + val oneNetSocketCb = oneNetSocketCbCaptor.value + + // Register a service with the same name on all networks (name conflict) + postSync { advertiser.addService(SERVICE_ID_2, ALL_NETWORKS_SERVICE, null /* subtype */) } + val allNetSocketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java) + verify(socketProvider).requestSocket(eq(null), allNetSocketCbCaptor.capture()) + val allNetSocketCb = allNetSocketCbCaptor.value + + postSync { advertiser.addService(LONG_SERVICE_ID_1, LONG_SERVICE_1, null /* subtype */) } + postSync { advertiser.addService(LONG_SERVICE_ID_2, LONG_ALL_NETWORKS_SERVICE, + null /* subtype */) } + + postSync { advertiser.addService(CASE_INSENSITIVE_TEST_SERVICE_ID, ALL_NETWORKS_SERVICE_2, + null /* subtype */) } + + // Callbacks for matching network and all networks both get the socket + postSync { + oneNetSocketCb.onSocketCreated(TEST_NETWORK_1, mockSocket1, listOf(TEST_LINKADDR)) + allNetSocketCb.onSocketCreated(TEST_NETWORK_1, mockSocket1, listOf(TEST_LINKADDR)) + } + + val expectedRenamed = NsdServiceInfo( + "${ALL_NETWORKS_SERVICE.serviceName} (2)", ALL_NETWORKS_SERVICE.serviceType).apply { + port = ALL_NETWORKS_SERVICE.port + hostAddresses = ALL_NETWORKS_SERVICE.hostAddresses + network = ALL_NETWORKS_SERVICE.network + } + + val expectedLongRenamed = NsdServiceInfo( + "${LONG_ALL_NETWORKS_SERVICE.serviceName.dropLast(4)} (2)", + LONG_ALL_NETWORKS_SERVICE.serviceType).apply { + port = LONG_ALL_NETWORKS_SERVICE.port + hostAddresses = LONG_ALL_NETWORKS_SERVICE.hostAddresses + network = LONG_ALL_NETWORKS_SERVICE.network + } + + val expectedCaseInsensitiveRenamed = NsdServiceInfo( + "${ALL_NETWORKS_SERVICE_2.serviceName} (3)", ALL_NETWORKS_SERVICE_2.serviceType + ).apply { + port = ALL_NETWORKS_SERVICE_2.port + hostAddresses = ALL_NETWORKS_SERVICE_2.hostAddresses + network = ALL_NETWORKS_SERVICE_2.network + } + + val intAdvCbCaptor = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java) + verify(mockDeps).makeAdvertiser(eq(mockSocket1), eq(listOf(TEST_LINKADDR)), + eq(thread.looper), any(), intAdvCbCaptor.capture(), eq(TEST_HOSTNAME), any() + ) + verify(mockInterfaceAdvertiser1).addService(eq(SERVICE_ID_1), + argThat { it.matches(SERVICE_1) }, eq(null)) + verify(mockInterfaceAdvertiser1).addService(eq(SERVICE_ID_2), + argThat { it.matches(expectedRenamed) }, eq(null)) + verify(mockInterfaceAdvertiser1).addService(eq(LONG_SERVICE_ID_1), + argThat { it.matches(LONG_SERVICE_1) }, eq(null)) + verify(mockInterfaceAdvertiser1).addService(eq(LONG_SERVICE_ID_2), + argThat { it.matches(expectedLongRenamed) }, eq(null)) + verify(mockInterfaceAdvertiser1).addService(eq(CASE_INSENSITIVE_TEST_SERVICE_ID), + argThat { it.matches(expectedCaseInsensitiveRenamed) }, eq(null)) + + doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1) + postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded( + mockInterfaceAdvertiser1, SERVICE_ID_1) } + verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), argThat { it.matches(SERVICE_1) }) + + doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_2) + postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded( + mockInterfaceAdvertiser1, SERVICE_ID_2) } + verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_2), + argThat { it.matches(expectedRenamed) }) + + postSync { oneNetSocketCb.onInterfaceDestroyed(TEST_NETWORK_1, mockSocket1) } + postSync { allNetSocketCb.onInterfaceDestroyed(TEST_NETWORK_1, mockSocket1) } + + // destroyNow can be called multiple times + verify(mockInterfaceAdvertiser1, atLeastOnce()).destroyNow() + } + + @Test + fun testRemoveService_whenAllServiceRemoved_thenUpdateHostName() { + val advertiser = MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog) + verify(mockDeps, times(1)).generateHostname() + postSync { advertiser.addService(SERVICE_ID_1, SERVICE_1, null /* subtype */) } + postSync { advertiser.removeService(SERVICE_ID_1) } + verify(mockDeps, times(2)).generateHostname() + } + + private fun postSync(r: () -> Unit) { + handler.post(r) + handler.waitForIdle(TIMEOUT_MS) + } +} + +// NsdServiceInfo does not implement equals; this is useful to use in argument matchers +private fun NsdServiceInfo.matches(other: NsdServiceInfo): Boolean { + return Objects.equals(serviceName, other.serviceName) && + Objects.equals(serviceType, other.serviceType) && + Objects.equals(attributes, other.attributes) && + Objects.equals(hostAddresses, other.hostAddresses) && + port == other.port && + Objects.equals(network, other.network) +}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt new file mode 100644 index 0000000..7c6cb3e --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt
@@ -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 android.net.InetAddresses.parseNumericAddress +import android.os.Build +import android.os.HandlerThread +import android.os.SystemClock +import com.android.internal.util.HexDump +import com.android.server.connectivity.mdns.MdnsAnnouncer.AnnouncementInfo +import com.android.server.connectivity.mdns.MdnsAnnouncer.BaseAnnouncementInfo +import com.android.server.connectivity.mdns.MdnsRecordRepository.getReverseDnsAddress +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.DevSdkIgnoreRunner +import java.net.DatagramPacket +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mockito.any +import org.mockito.Mockito.atLeast +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import org.mockito.Mockito.timeout +import org.mockito.Mockito.verify + +private const val FIRST_ANNOUNCES_DELAY = 100L +private const val FIRST_ANNOUNCES_COUNT = 2 +private const val NEXT_ANNOUNCES_DELAY = 1L +private const val TEST_TIMEOUT_MS = 1000L + +@RunWith(DevSdkIgnoreRunner::class) +@IgnoreUpTo(Build.VERSION_CODES.S_V2) +class MdnsAnnouncerTest { + + private val thread = HandlerThread(MdnsAnnouncerTest::class.simpleName) + private val socket = mock(MdnsInterfaceSocket::class.java) + private val buffer = ByteArray(1500) + + @Before + fun setUp() { + doReturn(true).`when`(socket).hasJoinedIpv6() + thread.start() + } + + @After + fun tearDown() { + thread.quitSafely() + thread.join() + } + + private class TestAnnouncementInfo( + announcedRecords: List<MdnsRecord>, + additionalRecords: List<MdnsRecord> + ) : AnnouncementInfo(1 /* serviceId */, announcedRecords, additionalRecords) { + override fun getDelayMs(nextIndex: Int) = + if (nextIndex < FIRST_ANNOUNCES_COUNT) { + FIRST_ANNOUNCES_DELAY + } else { + NEXT_ANNOUNCES_DELAY + } + } + + @Test + fun testAnnounce() { + val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer) + @Suppress("UNCHECKED_CAST") + val cb = mock(MdnsPacketRepeater.PacketRepeaterCallback::class.java) + as MdnsPacketRepeater.PacketRepeaterCallback<BaseAnnouncementInfo> + val announcer = MdnsAnnouncer("testiface", thread.looper, replySender, cb) + /* + The expected packet replicates records announced when registering a service, as observed in + the legacy mDNS implementation (some ordering differs to be more readable). + Obtained with scapy 2.5.0 RC3 (2.4.5 does not compress TLDs like .arpa properly) with: + scapy.raw(scapy.dns_compress(scapy.DNS(rd=0, qr=1, aa=1, + qd = None, + an = + scapy.DNSRR(type='PTR', rrname='123.2.0.192.in-addr.arpa.', rdata='Android.local', + rclass=0x8001, ttl=120) / + scapy.DNSRR(type='PTR', + rrname='3.2.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa', + rdata='Android.local', rclass=0x8001, ttl=120) / + scapy.DNSRR(type='PTR', + rrname='6.5.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa', + rdata='Android.local', rclass=0x8001, ttl=120) / + scapy.DNSRR(type='PTR', rrname='_testtype._tcp.local', + rdata='testservice._testtype._tcp.local', rclass='IN', ttl=4500) / + scapy.DNSRRSRV(rrname='testservice._testtype._tcp.local', rclass=0x8001, port=31234, + target='Android.local', ttl=120) / + scapy.DNSRR(type='TXT', rrname='testservice._testtype._tcp.local', rclass=0x8001, rdata='', + ttl=4500) / + scapy.DNSRR(type='A', rrname='Android.local', rclass=0x8001, rdata='192.0.2.123', ttl=120) / + scapy.DNSRR(type='AAAA', rrname='Android.local', rclass=0x8001, rdata='2001:db8::123', + ttl=120) / + scapy.DNSRR(type='AAAA', rrname='Android.local', rclass=0x8001, rdata='2001:db8::456', + ttl=120), + ar = + scapy.DNSRRNSEC(rrname='123.2.0.192.in-addr.arpa.', rclass=0x8001, ttl=120, + nextname='123.2.0.192.in-addr.arpa.', typebitmaps=[12]) / + scapy.DNSRRNSEC( + rrname='3.2.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa', + rclass=0x8001, ttl=120, + nextname='3.2.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa', + typebitmaps=[12]) / + scapy.DNSRRNSEC( + rrname='6.5.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa', + rclass=0x8001, ttl=120, + nextname='6.5.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa', + typebitmaps=[12]) / + scapy.DNSRRNSEC( + rrname='testservice._testtype._tcp.local', rclass=0x8001, ttl=4500, + nextname='testservice._testtype._tcp.local', typebitmaps=[16, 33]) / + scapy.DNSRRNSEC( + rrname='Android.local', rclass=0x8001, ttl=120, nextname='Android.local', + typebitmaps=[1, 28])) + )).hex().upper() + */ + val expected = "00008400000000090000000503313233013201300331393207696E2D61646472046172706" + + "100000C800100000078000F07416E64726F6964056C6F63616C00013301320131013001300130013" + + "00130013001300130013001300130013001300130013001300130013001300130013001380142014" + + "40130013101300130013203697036C020000C8001000000780002C030013601350134C045000C800" + + "1000000780002C030095F7465737474797065045F746370C038000C000100001194000E0B7465737" + + "473657276696365C0A5C0C000218001000000780008000000007A02C030C0C000108001000011940" + + "000C03000018001000000780004C000027BC030001C800100000078001020010DB80000000000000" + + "00000000123C030001C800100000078001020010DB8000000000000000000000456C00C002F80010" + + "00000780006C00C00020008C03F002F8001000000780006C03F00020008C091002F8001000000780" + + "006C09100020008C0C0002F8001000011940009C0C000050000800040C030002F800100000078000" + + "8C030000440000008" + + val hostname = arrayOf("Android", "local") + val serviceType = arrayOf("_testtype", "_tcp", "local") + val serviceName = arrayOf("testservice", "_testtype", "_tcp", "local") + val v4Addr = parseNumericAddress("192.0.2.123") + val v6Addr1 = parseNumericAddress("2001:DB8::123") + val v6Addr2 = parseNumericAddress("2001:DB8::456") + val v4AddrRev = getReverseDnsAddress(v4Addr) + val v6Addr1Rev = getReverseDnsAddress(v6Addr1) + val v6Addr2Rev = getReverseDnsAddress(v6Addr2) + + val announcedRecords = listOf( + // Reverse address records + MdnsPointerRecord(v4AddrRev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + hostname), + MdnsPointerRecord(v6Addr1Rev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + hostname), + MdnsPointerRecord(v6Addr2Rev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + hostname), + // Service registration records (RFC6763) + MdnsPointerRecord( + serviceType, + 0L /* receiptTimeMillis */, + // Not a unique name owned by the announcer, so cacheFlush=false + false /* cacheFlush */, + 4500000L /* ttlMillis */, + serviceName), + MdnsServiceRecord( + serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + 0 /* servicePriority */, + 0 /* serviceWeight */, + 31234 /* servicePort */, + hostname), + MdnsTextRecord( + serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 4500000L /* ttlMillis */, + emptyList() /* entries */), + // Address records for the hostname + MdnsInetAddressRecord(hostname, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + v4Addr), + MdnsInetAddressRecord(hostname, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + v6Addr1), + MdnsInetAddressRecord(hostname, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + v6Addr2)) + // Negative responses (RFC6762 6.1) + val additionalRecords = listOf( + MdnsNsecRecord(v4AddrRev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + v4AddrRev, + intArrayOf(MdnsRecord.TYPE_PTR)), + MdnsNsecRecord(v6Addr1Rev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + v6Addr1Rev, + intArrayOf(MdnsRecord.TYPE_PTR)), + MdnsNsecRecord(v6Addr2Rev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + v6Addr2Rev, + intArrayOf(MdnsRecord.TYPE_PTR)), + MdnsNsecRecord(serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 4500000L /* ttlMillis */, + serviceName, + intArrayOf(MdnsRecord.TYPE_TXT, MdnsRecord.TYPE_SRV)), + MdnsNsecRecord(hostname, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + hostname, + intArrayOf(MdnsRecord.TYPE_A, MdnsRecord.TYPE_AAAA))) + val request = TestAnnouncementInfo(announcedRecords, additionalRecords) + + val timeStart = SystemClock.elapsedRealtime() + val startDelay = 50L + val sendId = 1 + announcer.startSending(sendId, request, startDelay) + + val captor = ArgumentCaptor.forClass(DatagramPacket::class.java) + repeat(FIRST_ANNOUNCES_COUNT) { i -> + verify(cb, timeout(TEST_TIMEOUT_MS)).onSent(i, request) + verify(socket, atLeast(i + 1)).send(any()) + val now = SystemClock.elapsedRealtime() + assertTrue(now > timeStart + startDelay + i * FIRST_ANNOUNCES_DELAY) + // Loops can be much slower than the expected timing (>100ms delay), use + // TEST_TIMEOUT_MS as tolerance. + assertTrue(now < timeStart + startDelay + (i + 1) * FIRST_ANNOUNCES_DELAY + + TEST_TIMEOUT_MS) + } + + // Subsequent announces should happen quickly (NEXT_ANNOUNCES_DELAY) + verify(socket, timeout(TEST_TIMEOUT_MS).times(MdnsAnnouncer.ANNOUNCEMENT_COUNT)) + .send(captor.capture()) + verify(cb, timeout(TEST_TIMEOUT_MS)).onFinished(request) + + captor.allValues.forEach { + assertEquals(expected, HexDump.toHexString(it.data)) + } + } +}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java index 3e3c3bf..aeaca06 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
@@ -18,118 +18,296 @@ import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2; -import static org.mockito.Mockito.mock; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Network; +import android.os.Handler; +import android.os.HandlerThread; import android.text.TextUtils; +import android.util.Pair; +import com.android.net.module.util.SharedLog; +import com.android.server.connectivity.mdns.MdnsSocketClientBase.SocketCreationCallback; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; +import com.android.testutils.HandlerUtils; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.List; /** Tests for {@link MdnsDiscoveryManager}. */ @RunWith(DevSdkIgnoreRunner.class) @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) public class MdnsDiscoveryManagerTests { - + private static final long DEFAULT_TIMEOUT = 2000L; private static final String SERVICE_TYPE_1 = "_googlecast._tcp.local"; private static final String SERVICE_TYPE_2 = "_test._tcp.local"; + private static final Network NETWORK_1 = Mockito.mock(Network.class); + private static final Network NETWORK_2 = Mockito.mock(Network.class); + private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_1_NULL_NETWORK = + Pair.create(SERVICE_TYPE_1, null); + private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_1_NETWORK_1 = + Pair.create(SERVICE_TYPE_1, NETWORK_1); + private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_2_NULL_NETWORK = + Pair.create(SERVICE_TYPE_2, null); + private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_2_NETWORK_1 = + Pair.create(SERVICE_TYPE_2, NETWORK_1); + private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_2_NETWORK_2 = + Pair.create(SERVICE_TYPE_2, NETWORK_2); @Mock private ExecutorProvider executorProvider; - @Mock private MdnsSocketClient socketClient; - @Mock private MdnsServiceTypeClient mockServiceTypeClientOne; - @Mock private MdnsServiceTypeClient mockServiceTypeClientTwo; + @Mock private MdnsSocketClientBase socketClient; + @Mock private MdnsServiceTypeClient mockServiceTypeClientType1NullNetwork; + @Mock private MdnsServiceTypeClient mockServiceTypeClientType1Network1; + @Mock private MdnsServiceTypeClient mockServiceTypeClientType2NullNetwork; + @Mock private MdnsServiceTypeClient mockServiceTypeClientType2Network1; + @Mock private MdnsServiceTypeClient mockServiceTypeClientType2Network2; @Mock MdnsServiceBrowserListener mockListenerOne; @Mock MdnsServiceBrowserListener mockListenerTwo; + @Mock SharedLog sharedLog; private MdnsDiscoveryManager discoveryManager; + private HandlerThread thread; + private Handler handler; @Before public void setUp() { MockitoAnnotations.initMocks(this); - when(mockServiceTypeClientOne.getServiceTypeLabels()) - .thenReturn(TextUtils.split(SERVICE_TYPE_1, "\\.")); - when(mockServiceTypeClientTwo.getServiceTypeLabels()) - .thenReturn(TextUtils.split(SERVICE_TYPE_2, "\\.")); - - discoveryManager = new MdnsDiscoveryManager(executorProvider, socketClient) { + thread = new HandlerThread("MdnsDiscoveryManagerTests"); + thread.start(); + handler = new Handler(thread.getLooper()); + doReturn(thread.getLooper()).when(socketClient).getLooper(); + discoveryManager = new MdnsDiscoveryManager(executorProvider, socketClient, + sharedLog) { @Override - MdnsServiceTypeClient createServiceTypeClient(@NonNull String serviceType) { - if (serviceType.equals(SERVICE_TYPE_1)) { - return mockServiceTypeClientOne; - } else if (serviceType.equals(SERVICE_TYPE_2)) { - return mockServiceTypeClientTwo; + MdnsServiceTypeClient createServiceTypeClient(@NonNull String serviceType, + @Nullable Network network) { + final Pair<String, Network> perNetworkServiceType = + Pair.create(serviceType, network); + if (perNetworkServiceType.equals(PER_NETWORK_SERVICE_TYPE_1_NULL_NETWORK)) { + return mockServiceTypeClientType1NullNetwork; + } else if (perNetworkServiceType.equals( + PER_NETWORK_SERVICE_TYPE_1_NETWORK_1)) { + return mockServiceTypeClientType1Network1; + } else if (perNetworkServiceType.equals( + PER_NETWORK_SERVICE_TYPE_2_NULL_NETWORK)) { + return mockServiceTypeClientType2NullNetwork; + } else if (perNetworkServiceType.equals( + PER_NETWORK_SERVICE_TYPE_2_NETWORK_1)) { + return mockServiceTypeClientType2Network1; + } else if (perNetworkServiceType.equals( + PER_NETWORK_SERVICE_TYPE_2_NETWORK_2)) { + return mockServiceTypeClientType2Network2; } return null; } }; } + @After + public void tearDown() { + if (thread != null) { + thread.quitSafely(); + } + } + + private void runOnHandler(Runnable r) { + handler.post(r); + HandlerUtils.waitForIdle(handler, DEFAULT_TIMEOUT); + } + + private SocketCreationCallback expectSocketCreationCallback(String serviceType, + MdnsServiceBrowserListener listener, MdnsSearchOptions options) throws IOException { + final ArgumentCaptor<SocketCreationCallback> callbackCaptor = + ArgumentCaptor.forClass(SocketCreationCallback.class); + runOnHandler(() -> discoveryManager.registerListener(serviceType, listener, options)); + verify(socketClient).startDiscovery(); + verify(socketClient).notifyNetworkRequested( + eq(listener), eq(options.getNetwork()), callbackCaptor.capture()); + return callbackCaptor.getValue(); + } + @Test public void registerListener_unregisterListener() throws IOException { - discoveryManager.registerListener( - SERVICE_TYPE_1, mockListenerOne, MdnsSearchOptions.getDefaultOptions()); - verify(socketClient).startDiscovery(); - verify(mockServiceTypeClientOne) - .startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); + final MdnsSearchOptions options = + MdnsSearchOptions.newBuilder().setNetwork(null /* network */).build(); + final SocketCreationCallback callback = expectSocketCreationCallback( + SERVICE_TYPE_1, mockListenerOne, options); + runOnHandler(() -> callback.onSocketCreated(null /* network */)); + verify(mockServiceTypeClientType1NullNetwork).startSendAndReceive(mockListenerOne, options); - when(mockServiceTypeClientOne.stopSendAndReceive(mockListenerOne)).thenReturn(true); - discoveryManager.unregisterListener(SERVICE_TYPE_1, mockListenerOne); - verify(mockServiceTypeClientOne).stopSendAndReceive(mockListenerOne); + when(mockServiceTypeClientType1NullNetwork.stopSendAndReceive(mockListenerOne)) + .thenReturn(true); + runOnHandler(() -> discoveryManager.unregisterListener(SERVICE_TYPE_1, mockListenerOne)); + verify(mockServiceTypeClientType1NullNetwork).stopSendAndReceive(mockListenerOne); verify(socketClient).stopDiscovery(); } @Test public void registerMultipleListeners() throws IOException { - discoveryManager.registerListener( - SERVICE_TYPE_1, mockListenerOne, MdnsSearchOptions.getDefaultOptions()); - verify(socketClient).startDiscovery(); - verify(mockServiceTypeClientOne) - .startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); + final MdnsSearchOptions options = + MdnsSearchOptions.newBuilder().setNetwork(null /* network */).build(); + final SocketCreationCallback callback = expectSocketCreationCallback( + SERVICE_TYPE_1, mockListenerOne, options); + runOnHandler(() -> callback.onSocketCreated(null /* network */)); + verify(mockServiceTypeClientType1NullNetwork).startSendAndReceive(mockListenerOne, options); + runOnHandler(() -> callback.onSocketCreated(NETWORK_1)); + verify(mockServiceTypeClientType1Network1).startSendAndReceive(mockListenerOne, options); - discoveryManager.registerListener( - SERVICE_TYPE_2, mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); - verify(mockServiceTypeClientTwo) - .startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); + final SocketCreationCallback callback2 = expectSocketCreationCallback( + SERVICE_TYPE_2, mockListenerTwo, options); + runOnHandler(() -> callback2.onSocketCreated(null /* network */)); + verify(mockServiceTypeClientType2NullNetwork).startSendAndReceive(mockListenerTwo, options); + runOnHandler(() -> callback2.onSocketCreated(NETWORK_2)); + verify(mockServiceTypeClientType2Network2).startSendAndReceive(mockListenerTwo, options); } @Test - public void onResponseReceived() { - discoveryManager.registerListener( - SERVICE_TYPE_1, mockListenerOne, MdnsSearchOptions.getDefaultOptions()); - discoveryManager.registerListener( - SERVICE_TYPE_2, mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); + public void onResponseReceived() throws IOException { + final MdnsSearchOptions options1 = + MdnsSearchOptions.newBuilder().setNetwork(null /* network */).build(); + final SocketCreationCallback callback = expectSocketCreationCallback( + SERVICE_TYPE_1, mockListenerOne, options1); + runOnHandler(() -> callback.onSocketCreated(null /* network */)); + verify(mockServiceTypeClientType1NullNetwork).startSendAndReceive( + mockListenerOne, options1); + runOnHandler(() -> callback.onSocketCreated(NETWORK_1)); + verify(mockServiceTypeClientType1Network1).startSendAndReceive(mockListenerOne, options1); - MdnsResponse responseForServiceTypeOne = createMockResponse(SERVICE_TYPE_1); - discoveryManager.onResponseReceived(responseForServiceTypeOne); - verify(mockServiceTypeClientOne).processResponse(responseForServiceTypeOne); + final MdnsSearchOptions options2 = + MdnsSearchOptions.newBuilder().setNetwork(NETWORK_2).build(); + final SocketCreationCallback callback2 = expectSocketCreationCallback( + SERVICE_TYPE_2, mockListenerTwo, options2); + runOnHandler(() -> callback2.onSocketCreated(NETWORK_2)); + verify(mockServiceTypeClientType2Network2).startSendAndReceive(mockListenerTwo, options2); - MdnsResponse responseForServiceTypeTwo = createMockResponse(SERVICE_TYPE_2); - discoveryManager.onResponseReceived(responseForServiceTypeTwo); - verify(mockServiceTypeClientTwo).processResponse(responseForServiceTypeTwo); + final MdnsPacket responseForServiceTypeOne = createMdnsPacket(SERVICE_TYPE_1); + final int ifIndex = 1; + runOnHandler(() -> discoveryManager.onResponseReceived( + responseForServiceTypeOne, ifIndex, null /* network */)); + // Packets for network null are only processed by the ServiceTypeClient for network null + verify(mockServiceTypeClientType1NullNetwork).processResponse(responseForServiceTypeOne, + ifIndex, null /* network */); + verify(mockServiceTypeClientType1Network1, never()).processResponse(any(), anyInt(), any()); + verify(mockServiceTypeClientType2Network2, never()).processResponse(any(), anyInt(), any()); - MdnsResponse responseForSubtype = createMockResponse("subtype._sub._googlecast._tcp.local"); - discoveryManager.onResponseReceived(responseForSubtype); - verify(mockServiceTypeClientOne).processResponse(responseForSubtype); + final MdnsPacket responseForServiceTypeTwo = createMdnsPacket(SERVICE_TYPE_2); + runOnHandler(() -> discoveryManager.onResponseReceived( + responseForServiceTypeTwo, ifIndex, NETWORK_1)); + verify(mockServiceTypeClientType1NullNetwork, never()).processResponse(any(), anyInt(), + eq(NETWORK_1)); + verify(mockServiceTypeClientType1Network1).processResponse(responseForServiceTypeTwo, + ifIndex, NETWORK_1); + verify(mockServiceTypeClientType2Network2, never()).processResponse(any(), anyInt(), + eq(NETWORK_1)); + + final MdnsPacket responseForSubtype = + createMdnsPacket("subtype._sub._googlecast._tcp.local"); + runOnHandler(() -> discoveryManager.onResponseReceived( + responseForSubtype, ifIndex, NETWORK_2)); + verify(mockServiceTypeClientType1NullNetwork, never()).processResponse( + any(), anyInt(), eq(NETWORK_2)); + verify(mockServiceTypeClientType1Network1, never()).processResponse( + any(), anyInt(), eq(NETWORK_2)); + verify(mockServiceTypeClientType2Network2).processResponse( + responseForSubtype, ifIndex, NETWORK_2); } - private MdnsResponse createMockResponse(String serviceType) { - MdnsPointerRecord mockPointerRecord = mock(MdnsPointerRecord.class); - MdnsResponse mockResponse = mock(MdnsResponse.class); - when(mockResponse.getPointerRecords()) - .thenReturn(Collections.singletonList(mockPointerRecord)); - when(mockPointerRecord.getName()).thenReturn(TextUtils.split(serviceType, "\\.")); - return mockResponse; + @Test + public void testSocketCreatedAndDestroyed() throws IOException { + // Create a ServiceTypeClient for SERVICE_TYPE_1 and NETWORK_1 + final MdnsSearchOptions network1Options = + MdnsSearchOptions.newBuilder().setNetwork(NETWORK_1).build(); + final SocketCreationCallback callback = expectSocketCreationCallback( + SERVICE_TYPE_1, mockListenerOne, network1Options); + runOnHandler(() -> callback.onSocketCreated(NETWORK_1)); + verify(mockServiceTypeClientType1Network1).startSendAndReceive( + mockListenerOne, network1Options); + + // Create a ServiceTypeClient for SERVICE_TYPE_2 and NETWORK_1 + final SocketCreationCallback callback2 = expectSocketCreationCallback( + SERVICE_TYPE_2, mockListenerTwo, network1Options); + runOnHandler(() -> callback2.onSocketCreated(NETWORK_1)); + verify(mockServiceTypeClientType2Network1).startSendAndReceive( + mockListenerTwo, network1Options); + + // Receive a response, it should be processed on both clients. + final MdnsPacket response = createMdnsPacket(SERVICE_TYPE_1); + final int ifIndex = 1; + runOnHandler(() -> discoveryManager.onResponseReceived( + response, ifIndex, NETWORK_1)); + verify(mockServiceTypeClientType1Network1).processResponse(response, ifIndex, NETWORK_1); + verify(mockServiceTypeClientType2Network1).processResponse(response, ifIndex, NETWORK_1); + + // The first callback receives a notification that the network has been destroyed, + // mockServiceTypeClientOne1 should send service removed notifications and remove from the + // list of clients. + runOnHandler(() -> callback.onAllSocketsDestroyed(NETWORK_1)); + verify(mockServiceTypeClientType1Network1).notifySocketDestroyed(); + + // Receive a response again, it should be processed only on + // mockServiceTypeClientType2Network1. Because the mockServiceTypeClientType1Network1 is + // removed from the list of clients, it is no longer able to process responses. + runOnHandler(() -> discoveryManager.onResponseReceived( + response, ifIndex, NETWORK_1)); + // Still times(1) as a response was received once previously + verify(mockServiceTypeClientType1Network1, times(1)) + .processResponse(response, ifIndex, NETWORK_1); + verify(mockServiceTypeClientType2Network1, times(2)) + .processResponse(response, ifIndex, NETWORK_1); + + // The client for NETWORK_1 receives the callback that the NETWORK_2 has been destroyed, + // mockServiceTypeClientTwo2 shouldn't send any notifications. + runOnHandler(() -> callback2.onAllSocketsDestroyed(NETWORK_2)); + verify(mockServiceTypeClientType2Network1, never()).notifySocketDestroyed(); + + // Receive a response again, mockServiceTypeClientType2Network1 is still in the list of + // clients, it's still able to process responses. + runOnHandler(() -> discoveryManager.onResponseReceived( + response, ifIndex, NETWORK_1)); + verify(mockServiceTypeClientType1Network1, times(1)) + .processResponse(response, ifIndex, NETWORK_1); + verify(mockServiceTypeClientType2Network1, times(3)) + .processResponse(response, ifIndex, NETWORK_1); + } + + private MdnsPacket createMdnsPacket(String serviceType) { + final String[] type = TextUtils.split(serviceType, "\\."); + final ArrayList<String> name = new ArrayList<>(type.length + 1); + name.add("TestName"); + name.addAll(Arrays.asList(type)); + return new MdnsPacket(0 /* flags */, + Collections.emptyList() /* questions */, + List.of(new MdnsPointerRecord( + type, + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 120000 /* ttlMillis */, + name.toArray(new String[0]) + )) /* answers */, + Collections.emptyList() /* authorityRecords */, + Collections.emptyList() /* additionalRecords */); } } \ No newline at end of file
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt new file mode 100644 index 0000000..dd458b8 --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
@@ -0,0 +1,291 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns + +import android.net.InetAddresses.parseNumericAddress +import android.net.LinkAddress +import android.net.nsd.NsdServiceInfo +import android.os.Build +import android.os.HandlerThread +import com.android.net.module.util.HexDump +import com.android.net.module.util.SharedLog +import com.android.server.connectivity.mdns.MdnsAnnouncer.AnnouncementInfo +import com.android.server.connectivity.mdns.MdnsAnnouncer.BaseAnnouncementInfo +import com.android.server.connectivity.mdns.MdnsAnnouncer.ExitAnnouncementInfo +import com.android.server.connectivity.mdns.MdnsInterfaceAdvertiser.EXIT_ANNOUNCEMENT_DELAY_MS +import com.android.server.connectivity.mdns.MdnsPacketRepeater.PacketRepeaterCallback +import com.android.server.connectivity.mdns.MdnsProber.ProbingInfo +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.DevSdkIgnoreRunner +import com.android.testutils.waitForIdle +import java.net.InetSocketAddress +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mockito.any +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.anyString +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.eq +import org.mockito.Mockito.mock +import org.mockito.Mockito.times +import org.mockito.Mockito.verify + +private const val LOG_TAG = "testlogtag" +private const val TIMEOUT_MS = 10_000L + +private val TEST_ADDRS = listOf(LinkAddress(parseNumericAddress("2001:db8::123"), 64)) +private val TEST_BUFFER = ByteArray(1300) +private val TEST_HOSTNAME = arrayOf("Android_test", "local") + +private const val TEST_SERVICE_ID_1 = 42 +private val TEST_SERVICE_1 = NsdServiceInfo().apply { + serviceType = "_testservice._tcp" + serviceName = "MyTestService" + port = 12345 +} + +@RunWith(DevSdkIgnoreRunner::class) +@IgnoreUpTo(Build.VERSION_CODES.S_V2) +class MdnsInterfaceAdvertiserTest { + private val socket = mock(MdnsInterfaceSocket::class.java) + private val thread = HandlerThread(MdnsInterfaceAdvertiserTest::class.simpleName) + private val cb = mock(MdnsInterfaceAdvertiser.Callback::class.java) + private val deps = mock(MdnsInterfaceAdvertiser.Dependencies::class.java) + private val repository = mock(MdnsRecordRepository::class.java) + private val replySender = mock(MdnsReplySender::class.java) + private val announcer = mock(MdnsAnnouncer::class.java) + private val prober = mock(MdnsProber::class.java) + private val sharedlog = SharedLog("MdnsInterfaceAdvertiserTest") + @Suppress("UNCHECKED_CAST") + private val probeCbCaptor = ArgumentCaptor.forClass(PacketRepeaterCallback::class.java) + as ArgumentCaptor<PacketRepeaterCallback<ProbingInfo>> + @Suppress("UNCHECKED_CAST") + private val announceCbCaptor = ArgumentCaptor.forClass(PacketRepeaterCallback::class.java) + as ArgumentCaptor<PacketRepeaterCallback<BaseAnnouncementInfo>> + private val packetHandlerCaptor = ArgumentCaptor.forClass( + MulticastPacketReader.PacketHandler::class.java) + + private val probeCb get() = probeCbCaptor.value + private val announceCb get() = announceCbCaptor.value + private val packetHandler get() = packetHandlerCaptor.value + + private val advertiser by lazy { + MdnsInterfaceAdvertiser( + socket, + TEST_ADDRS, + thread.looper, + TEST_BUFFER, + cb, + deps, + TEST_HOSTNAME, + sharedlog + ) + } + + @Before + fun setUp() { + doReturn(repository).`when`(deps).makeRecordRepository(any(), + eq(TEST_HOSTNAME) + ) + doReturn(replySender).`when`(deps).makeReplySender(anyString(), any(), any(), any()) + doReturn(announcer).`when`(deps).makeMdnsAnnouncer(anyString(), any(), any(), any()) + doReturn(prober).`when`(deps).makeMdnsProber(anyString(), any(), any(), any()) + + val knownServices = mutableSetOf<Int>() + doAnswer { inv -> + knownServices.add(inv.getArgument(0)) + + -1 + }.`when`(repository).addService(anyInt(), any(), any()) + doAnswer { inv -> + knownServices.remove(inv.getArgument(0)) + null + }.`when`(repository).removeService(anyInt()) + doAnswer { + knownServices.toIntArray().also { knownServices.clear() } + }.`when`(repository).clearServices() + doAnswer { inv -> + knownServices.contains(inv.getArgument(0)) + }.`when`(repository).hasActiveService(anyInt()) + thread.start() + advertiser.start() + + verify(socket).addPacketHandler(packetHandlerCaptor.capture()) + verify(deps).makeMdnsProber(any(), any(), any(), probeCbCaptor.capture()) + verify(deps).makeMdnsAnnouncer(any(), any(), any(), announceCbCaptor.capture()) + } + + @After + fun tearDown() { + thread.quitSafely() + thread.join() + } + + @Test + fun testAddRemoveService() { + val testAnnouncementInfo = addServiceAndFinishProbing(TEST_SERVICE_ID_1, TEST_SERVICE_1) + + verify(announcer).startSending(TEST_SERVICE_ID_1, testAnnouncementInfo, + 0L /* initialDelayMs */) + + thread.waitForIdle(TIMEOUT_MS) + verify(cb).onRegisterServiceSucceeded(advertiser, TEST_SERVICE_ID_1) + + // Remove the service: expect exit announcements + val testExitInfo = mock(ExitAnnouncementInfo::class.java) + doReturn(testExitInfo).`when`(repository).exitService(TEST_SERVICE_ID_1) + advertiser.removeService(TEST_SERVICE_ID_1) + + verify(prober).stop(TEST_SERVICE_ID_1) + verify(announcer).stop(TEST_SERVICE_ID_1) + verify(announcer).startSending(TEST_SERVICE_ID_1, testExitInfo, EXIT_ANNOUNCEMENT_DELAY_MS) + + // Exit announcements finish: the advertiser has no left service and destroys itself + announceCb.onFinished(testExitInfo) + thread.waitForIdle(TIMEOUT_MS) + verify(cb).onDestroyed(socket) + } + + @Test + fun testDoubleRemove() { + addServiceAndFinishProbing(TEST_SERVICE_ID_1, TEST_SERVICE_1) + + val testExitInfo = mock(ExitAnnouncementInfo::class.java) + doReturn(testExitInfo).`when`(repository).exitService(TEST_SERVICE_ID_1) + advertiser.removeService(TEST_SERVICE_ID_1) + + verify(prober).stop(TEST_SERVICE_ID_1) + verify(announcer).stop(TEST_SERVICE_ID_1) + verify(announcer).startSending(TEST_SERVICE_ID_1, testExitInfo, EXIT_ANNOUNCEMENT_DELAY_MS) + + doReturn(false).`when`(repository).hasActiveService(TEST_SERVICE_ID_1) + advertiser.removeService(TEST_SERVICE_ID_1) + // Prober, announcer were still stopped only one time + verify(prober, times(1)).stop(TEST_SERVICE_ID_1) + verify(announcer, times(1)).stop(TEST_SERVICE_ID_1) + } + + @Test + fun testReplyToQuery() { + addServiceAndFinishProbing(TEST_SERVICE_ID_1, TEST_SERVICE_1) + + val mockReply = mock(MdnsRecordRepository.ReplyInfo::class.java) + doReturn(mockReply).`when`(repository).getReply(any(), any()) + + // Query obtained with: + // scapy.raw(scapy.DNS( + // qd = scapy.DNSQR(qtype='PTR', qname='_testservice._tcp.local')) + // ).hex().upper() + val query = HexDump.hexStringToByteArray( + "0000010000010000000000000C5F7465737473657276696365045F746370056C6F63616C00000C0001" + ) + val src = InetSocketAddress(parseNumericAddress("2001:db8::456"), MdnsConstants.MDNS_PORT) + packetHandler.handlePacket(query, query.size, src) + + val packetCaptor = ArgumentCaptor.forClass(MdnsPacket::class.java) + verify(repository).getReply(packetCaptor.capture(), eq(src)) + + packetCaptor.value.let { + assertEquals(1, it.questions.size) + assertEquals(0, it.answers.size) + assertEquals(0, it.authorityRecords.size) + assertEquals(0, it.additionalRecords.size) + + assertTrue(it.questions[0] is MdnsPointerRecord) + assertContentEquals(arrayOf("_testservice", "_tcp", "local"), it.questions[0].name) + } + + verify(replySender).queueReply(mockReply) + } + + @Test + fun testConflict() { + addServiceAndFinishProbing(TEST_SERVICE_ID_1, TEST_SERVICE_1) + doReturn(setOf(TEST_SERVICE_ID_1)).`when`(repository).getConflictingServices(any()) + + // Reply obtained with: + // scapy.raw(scapy.DNS( + // qd = None, + // an = scapy.DNSRR(type='TXT', rrname='_testservice._tcp.local')) + // ).hex().upper() + val query = HexDump.hexStringToByteArray("0000010000000001000000000C5F7465737473657276696" + + "365045F746370056C6F63616C0000100001000000000000") + val src = InetSocketAddress(parseNumericAddress("2001:db8::456"), MdnsConstants.MDNS_PORT) + packetHandler.handlePacket(query, query.size, src) + + val packetCaptor = ArgumentCaptor.forClass(MdnsPacket::class.java) + verify(repository).getConflictingServices(packetCaptor.capture()) + + packetCaptor.value.let { + assertEquals(0, it.questions.size) + assertEquals(1, it.answers.size) + assertEquals(0, it.authorityRecords.size) + assertEquals(0, it.additionalRecords.size) + + assertTrue(it.answers[0] is MdnsTextRecord) + assertContentEquals(arrayOf("_testservice", "_tcp", "local"), it.answers[0].name) + } + + thread.waitForIdle(TIMEOUT_MS) + verify(cb).onServiceConflict(advertiser, TEST_SERVICE_ID_1) + } + + @Test + fun testRestartProbingForConflict() { + val mockProbingInfo = mock(ProbingInfo::class.java) + doReturn(mockProbingInfo).`when`(repository).setServiceProbing(TEST_SERVICE_ID_1) + + advertiser.restartProbingForConflict(TEST_SERVICE_ID_1) + + verify(prober).restartForConflict(mockProbingInfo) + } + + @Test + fun testRenameServiceForConflict() { + val mockProbingInfo = mock(ProbingInfo::class.java) + doReturn(mockProbingInfo).`when`(repository).renameServiceForConflict( + TEST_SERVICE_ID_1, TEST_SERVICE_1) + + advertiser.renameServiceForConflict(TEST_SERVICE_ID_1, TEST_SERVICE_1) + + verify(prober).restartForConflict(mockProbingInfo) + } + + private fun addServiceAndFinishProbing(serviceId: Int, serviceInfo: NsdServiceInfo): + AnnouncementInfo { + val testProbingInfo = mock(ProbingInfo::class.java) + doReturn(serviceId).`when`(testProbingInfo).serviceId + doReturn(testProbingInfo).`when`(repository).setServiceProbing(serviceId) + + advertiser.addService(serviceId, serviceInfo, null /* subtype */) + verify(repository).addService(serviceId, serviceInfo, null /* subtype */) + verify(prober).startProbing(testProbingInfo) + + // Simulate probing success: continues to announcing + val testAnnouncementInfo = mock(AnnouncementInfo::class.java) + doReturn(testAnnouncementInfo).`when`(repository).onProbingSucceeded(testProbingInfo) + probeCb.onFinished(testProbingInfo) + return testAnnouncementInfo + } +}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java new file mode 100644 index 0000000..87ba5d7 --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java
@@ -0,0 +1,320 @@ +/* + * 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.server.connectivity.mdns.MdnsSocketProvider.SocketCallback; +import static com.android.server.connectivity.mdns.MulticastPacketReader.PacketHandler; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.net.InetAddresses; +import android.net.Network; +import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; + +import com.android.net.module.util.HexDump; +import com.android.server.connectivity.mdns.MdnsSocketClientBase.SocketCreationCallback; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; +import com.android.testutils.HandlerUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.net.DatagramPacket; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.List; + +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) +public class MdnsMultinetworkSocketClientTest { + private static final byte[] BUFFER = new byte[10]; + private static final long DEFAULT_TIMEOUT = 2000L; + @Mock private Network mNetwork; + @Mock private MdnsSocketProvider mProvider; + @Mock private MdnsInterfaceSocket mSocket; + @Mock private MdnsServiceBrowserListener mListener; + @Mock private MdnsSocketClientBase.Callback mCallback; + @Mock private SocketCreationCallback mSocketCreationCallback; + private MdnsMultinetworkSocketClient mSocketClient; + private Handler mHandler; + + @Before + public void setUp() throws SocketException { + MockitoAnnotations.initMocks(this); + final HandlerThread thread = new HandlerThread("MdnsMultinetworkSocketClientTest"); + thread.start(); + mHandler = new Handler(thread.getLooper()); + mSocketClient = new MdnsMultinetworkSocketClient(thread.getLooper(), mProvider); + mHandler.post(() -> mSocketClient.setCallback(mCallback)); + } + + private SocketCallback expectSocketCallback() { + return expectSocketCallback(mListener, mNetwork); + } + + private SocketCallback expectSocketCallback(MdnsServiceBrowserListener listener, + Network requestedNetwork) { + final ArgumentCaptor<SocketCallback> callbackCaptor = + ArgumentCaptor.forClass(SocketCallback.class); + mHandler.post(() -> mSocketClient.notifyNetworkRequested( + listener, requestedNetwork, mSocketCreationCallback)); + verify(mProvider, timeout(DEFAULT_TIMEOUT)) + .requestSocket(eq(requestedNetwork), callbackCaptor.capture()); + return callbackCaptor.getValue(); + } + + private NetworkInterface createEmptyNetworkInterface() { + try { + Constructor<NetworkInterface> constructor = + NetworkInterface.class.getDeclaredConstructor(); + constructor.setAccessible(true); + return constructor.newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Test + public void testSendPacket() throws IOException { + final SocketCallback callback = expectSocketCallback(); + final DatagramPacket ipv4Packet = new DatagramPacket(BUFFER, 0 /* offset */, BUFFER.length, + InetAddresses.parseNumericAddress("192.0.2.1"), 0 /* port */); + final DatagramPacket ipv6Packet = new DatagramPacket(BUFFER, 0 /* offset */, BUFFER.length, + InetAddresses.parseNumericAddress("2001:db8::"), 0 /* port */); + + final MdnsInterfaceSocket tetherIfaceSock1 = mock(MdnsInterfaceSocket.class); + final MdnsInterfaceSocket tetherIfaceSock2 = mock(MdnsInterfaceSocket.class); + for (MdnsInterfaceSocket socket : List.of(mSocket, tetherIfaceSock1, tetherIfaceSock2)) { + doReturn(true).when(socket).hasJoinedIpv4(); + doReturn(true).when(socket).hasJoinedIpv6(); + doReturn(createEmptyNetworkInterface()).when(socket).getInterface(); + } + + // Notify socket created + callback.onSocketCreated(mNetwork, mSocket, List.of()); + verify(mSocketCreationCallback).onSocketCreated(mNetwork); + callback.onSocketCreated(null, tetherIfaceSock1, List.of()); + verify(mSocketCreationCallback).onSocketCreated(null); + callback.onSocketCreated(null, tetherIfaceSock2, List.of()); + verify(mSocketCreationCallback, times(2)).onSocketCreated(null); + + // Send packet to IPv4 with target network and verify sending has been called. + mSocketClient.sendMulticastPacket(ipv4Packet, mNetwork); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mSocket).send(ipv4Packet); + verify(tetherIfaceSock1, never()).send(any()); + verify(tetherIfaceSock2, never()).send(any()); + + // Send packet to IPv6 without target network and verify sending has been called. + mSocketClient.sendMulticastPacket(ipv6Packet, null); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mSocket, never()).send(ipv6Packet); + verify(tetherIfaceSock1).send(ipv6Packet); + verify(tetherIfaceSock2).send(ipv6Packet); + } + + @Test + public void testReceivePacket() { + final SocketCallback callback = expectSocketCallback(); + final byte[] data = HexDump.hexStringToByteArray( + // scapy.raw(scapy.dns_compress( + // scapy.DNS(rd=0, qr=1, aa=1, qd = None, + // an = + // scapy.DNSRR(type='PTR', rrname='_testtype._tcp.local', + // rdata='testservice._testtype._tcp.local', rclass='IN', ttl=4500) / + // scapy.DNSRRSRV(rrname='testservice._testtype._tcp.local', rclass=0x8001, + // port=31234, target='Android.local', ttl=120)) + // )).hex().upper() + "000084000000000200000000095F7465737474797065045F746370056C6F63616C00000C0001000011" + + "94000E0B7465737473657276696365C00CC02C00218001000000780010000000007A0207" + + "416E64726F6964C01B"); + + doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface(); + // Notify socket created + callback.onSocketCreated(mNetwork, mSocket, List.of()); + verify(mSocketCreationCallback).onSocketCreated(mNetwork); + + final ArgumentCaptor<PacketHandler> handlerCaptor = + ArgumentCaptor.forClass(PacketHandler.class); + verify(mSocket).addPacketHandler(handlerCaptor.capture()); + + // Send the data and verify the received records. + final PacketHandler handler = handlerCaptor.getValue(); + handler.handlePacket(data, data.length, null /* src */); + final ArgumentCaptor<MdnsPacket> responseCaptor = + ArgumentCaptor.forClass(MdnsPacket.class); + verify(mCallback).onResponseReceived(responseCaptor.capture(), anyInt(), any()); + final MdnsPacket response = responseCaptor.getValue(); + assertEquals(0, response.questions.size()); + assertEquals(0, response.additionalRecords.size()); + assertEquals(0, response.authorityRecords.size()); + + final String[] serviceName = "testservice._testtype._tcp.local".split("\\."); + assertEquals(List.of( + new MdnsPointerRecord("_testtype._tcp.local".split("\\."), + 0L /* receiptTimeMillis */, false /* cacheFlush */, 4500000 /* ttlMillis */, + serviceName), + new MdnsServiceRecord(serviceName, 0L /* receiptTimeMillis */, + false /* cacheFlush */, 4500000 /* ttlMillis */, 0 /* servicePriority */, + 0 /* serviceWeight */, 31234 /* servicePort */, + new String[] { "Android", "local" } /* serviceHost */) + ), response.answers); + } + + @Test + public void testSocketRemovedAfterNetworkUnrequested() throws IOException { + // Request sockets on all networks + final SocketCallback callback = expectSocketCallback(mListener, null); + final DatagramPacket ipv4Packet = new DatagramPacket(BUFFER, 0 /* offset */, BUFFER.length, + InetAddresses.parseNumericAddress("192.0.2.1"), 0 /* port */); + + // Notify 3 socket created, including 2 tethered interfaces (null network) + final MdnsInterfaceSocket socket2 = mock(MdnsInterfaceSocket.class); + final MdnsInterfaceSocket socket3 = mock(MdnsInterfaceSocket.class); + doReturn(true).when(mSocket).hasJoinedIpv4(); + doReturn(true).when(mSocket).hasJoinedIpv6(); + doReturn(true).when(socket2).hasJoinedIpv4(); + doReturn(true).when(socket2).hasJoinedIpv6(); + doReturn(true).when(socket3).hasJoinedIpv4(); + doReturn(true).when(socket3).hasJoinedIpv6(); + doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface(); + doReturn(createEmptyNetworkInterface()).when(socket2).getInterface(); + doReturn(createEmptyNetworkInterface()).when(socket3).getInterface(); + + callback.onSocketCreated(mNetwork, mSocket, List.of()); + callback.onSocketCreated(null, socket2, List.of()); + callback.onSocketCreated(null, socket3, List.of()); + verify(mSocketCreationCallback).onSocketCreated(mNetwork); + verify(mSocketCreationCallback, times(2)).onSocketCreated(null); + + // Send IPv4 packet on the non-null Network and verify sending has been called. + mSocketClient.sendMulticastPacket(ipv4Packet, mNetwork); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mSocket).send(ipv4Packet); + verify(socket2, never()).send(any()); + verify(socket3, never()).send(any()); + + // Request another socket with null network, get the same interfaces + final SocketCreationCallback socketCreationCb2 = mock(SocketCreationCallback.class); + final MdnsServiceBrowserListener listener2 = mock(MdnsServiceBrowserListener.class); + + // requestSocket is called a second time + final ArgumentCaptor<SocketCallback> callback2Captor = + ArgumentCaptor.forClass(SocketCallback.class); + mHandler.post(() -> mSocketClient.notifyNetworkRequested( + listener2, null, socketCreationCb2)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mProvider, times(2)).requestSocket(eq(null), callback2Captor.capture()); + final SocketCallback callback2 = callback2Captor.getAllValues().get(1); + + // Notify socket created for all networks. + callback2.onSocketCreated(mNetwork, mSocket, List.of()); + callback2.onSocketCreated(null, socket2, List.of()); + callback2.onSocketCreated(null, socket3, List.of()); + verify(socketCreationCb2).onSocketCreated(mNetwork); + verify(socketCreationCb2, times(2)).onSocketCreated(null); + + // Send IPv4 packet to null network and verify sending to the 2 tethered interface sockets. + mSocketClient.sendMulticastPacket(ipv4Packet, null); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + // ipv4Packet still sent only once on mSocket: times(1) matches the packet sent earlier on + // mNetwork + verify(mSocket, times(1)).send(ipv4Packet); + verify(socket2).send(ipv4Packet); + verify(socket3).send(ipv4Packet); + + // Unregister the second request + mHandler.post(() -> mSocketClient.notifyNetworkUnrequested(listener2)); + verify(mProvider, timeout(DEFAULT_TIMEOUT)).unrequestSocket(callback2); + + // Send IPv4 packet again and verify it's still sent a second time + mSocketClient.sendMulticastPacket(ipv4Packet, null); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(socket2, times(2)).send(ipv4Packet); + verify(socket3, times(2)).send(ipv4Packet); + + // Unrequest remaining sockets + mHandler.post(() -> mSocketClient.notifyNetworkUnrequested(mListener)); + verify(mProvider, timeout(DEFAULT_TIMEOUT)).unrequestSocket(callback); + + // Send IPv4 packet and verify no more sending. + mSocketClient.sendMulticastPacket(ipv4Packet, null); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mSocket, times(1)).send(ipv4Packet); + verify(socket2, times(2)).send(ipv4Packet); + verify(socket3, times(2)).send(ipv4Packet); + } + + @Test + public void testNotifyNetworkUnrequested_SocketsOnNullNetwork() { + final MdnsInterfaceSocket otherSocket = mock(MdnsInterfaceSocket.class); + final SocketCallback callback = expectSocketCallback( + mListener, null /* requestedNetwork */); + doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface(); + doReturn(createEmptyNetworkInterface()).when(otherSocket).getInterface(); + + callback.onSocketCreated(null /* network */, mSocket, List.of()); + verify(mSocketCreationCallback).onSocketCreated(null); + callback.onSocketCreated(null /* network */, otherSocket, List.of()); + verify(mSocketCreationCallback, times(2)).onSocketCreated(null); + + verify(mSocketCreationCallback, never()).onAllSocketsDestroyed(null /* network */); + mHandler.post(() -> mSocketClient.notifyNetworkUnrequested(mListener)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + + verify(mProvider).unrequestSocket(callback); + verify(mSocketCreationCallback).onAllSocketsDestroyed(null /* network */); + } + + @Test + public void testSocketCreatedAndDestroyed_NullNetwork() throws IOException { + final MdnsInterfaceSocket otherSocket = mock(MdnsInterfaceSocket.class); + final SocketCallback callback = expectSocketCallback(mListener, null /* network */); + doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface(); + doReturn(createEmptyNetworkInterface()).when(otherSocket).getInterface(); + + callback.onSocketCreated(null /* network */, mSocket, List.of()); + verify(mSocketCreationCallback).onSocketCreated(null); + callback.onSocketCreated(null /* network */, otherSocket, List.of()); + verify(mSocketCreationCallback, times(2)).onSocketCreated(null); + + // Notify socket destroyed + callback.onInterfaceDestroyed(null /* network */, mSocket); + verifyNoMoreInteractions(mSocketCreationCallback); + callback.onInterfaceDestroyed(null /* network */, otherSocket); + verify(mSocketCreationCallback).onAllSocketsDestroyed(null /* network */); + } +}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketTest.kt new file mode 100644 index 0000000..f88da1f --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketTest.kt
@@ -0,0 +1,70 @@ +/* + * 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 android.net.InetAddresses +import com.android.net.module.util.HexDump +import com.android.testutils.DevSdkIgnoreRunner +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(DevSdkIgnoreRunner::class) +class MdnsPacketTest { + @Test + fun testParseQuery() { + // Probe packet with 1 question for Android.local, and 4 additionalRecords with 4 addresses + // for Android.local (similar to legacy mdnsresponder probes, although it used to put 4 + // identical questions(!!) for Android.local when there were 4 addresses). + val packetHex = "00000000000100000004000007416e64726f6964056c6f63616c0000ff0001c00c000100" + + "01000000780004c000027bc00c001c000100000078001020010db8000000000000000000000123c0" + + "0c001c000100000078001020010db8000000000000000000000456c00c001c000100000078001020" + + "010db8000000000000000000000789" + + val bytes = HexDump.hexStringToByteArray(packetHex) + val reader = MdnsPacketReader(bytes, bytes.size) + val packet = MdnsPacket.parse(reader) + + assertEquals(1, packet.questions.size) + assertEquals(0, packet.answers.size) + assertEquals(4, packet.authorityRecords.size) + assertEquals(0, packet.additionalRecords.size) + + val hostname = arrayOf("Android", "local") + packet.questions[0].let { + assertTrue(it is MdnsAnyRecord) + assertContentEquals(hostname, it.name) + } + + packet.authorityRecords.forEach { + assertTrue(it is MdnsInetAddressRecord) + assertContentEquals(hostname, it.name) + assertEquals(120000, it.ttl) + } + + assertEquals(InetAddresses.parseNumericAddress("192.0.2.123"), + (packet.authorityRecords[0] as MdnsInetAddressRecord).inet4Address) + assertEquals(InetAddresses.parseNumericAddress("2001:db8::123"), + (packet.authorityRecords[1] as MdnsInetAddressRecord).inet6Address) + assertEquals(InetAddresses.parseNumericAddress("2001:db8::456"), + (packet.authorityRecords[2] as MdnsInetAddressRecord).inet6Address) + assertEquals(InetAddresses.parseNumericAddress("2001:db8::789"), + (packet.authorityRecords[3] as MdnsInetAddressRecord).inet6Address) + } +}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt new file mode 100644 index 0000000..a545373 --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt
@@ -0,0 +1,55 @@ +/* + * 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 android.net.InetAddresses +import android.os.Build +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.DevSdkIgnoreRunner +import java.net.InetSocketAddress +import kotlin.test.assertContentEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(DevSdkIgnoreRunner::class) +@IgnoreUpTo(Build.VERSION_CODES.S_V2) +class MdnsPacketWriterTest { + @Test + fun testNameCompression() { + val writer = MdnsPacketWriter(ByteArray(1000)) + writer.writeLabels(arrayOf("my", "FIRST", "name")) + writer.writeLabels(arrayOf("my", "second", "name")) + writer.writeLabels(arrayOf("other", "first", "name")) + writer.writeLabels(arrayOf("my", "second", "name")) + writer.writeLabels(arrayOf("unrelated")) + + val packet = writer.getPacket( + InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::123"), 123)) + + // Each label takes length + 1. So "first.name" offset = 3, "name" offset = 9 + val expected = "my".label() + "FIRST".label() + "name".label() + 0x00.toByte() + + // "my.second.name" offset = 15 + "my".label() + "second".label() + byteArrayOf(0xC0.toByte(), 9) + + "other".label() + byteArrayOf(0xC0.toByte(), 3) + + byteArrayOf(0xC0.toByte(), 15) + + "unrelated".label() + 0x00.toByte() + + assertContentEquals(expected, packet.data.copyOfRange(0, packet.length)) + } +} + +private fun String.label() = byteArrayOf(length.toByte()) + encodeToByteArray()
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt new file mode 100644 index 0000000..0a8d78d --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt
@@ -0,0 +1,206 @@ +/* + * 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 android.os.Build +import android.os.Handler +import android.os.HandlerThread +import android.os.Looper +import com.android.internal.util.HexDump +import com.android.server.connectivity.mdns.MdnsProber.ProbingInfo +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.DevSdkIgnoreRunner +import java.net.DatagramPacket +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mockito.any +import org.mockito.Mockito.atLeast +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.timeout +import org.mockito.Mockito.times +import org.mockito.Mockito.verify + +private const val TEST_TIMEOUT_MS = 10_000L +private const val SHORT_TIMEOUT_MS = 200L + +private val TEST_SERVICE_NAME_1 = arrayOf("testservice", "_nmt", "_tcp", "local") +private val TEST_SERVICE_NAME_2 = arrayOf("testservice2", "_nmt", "_tcp", "local") +private val TEST_SERVICE_NAME_3 = arrayOf("Testservice", "_nmt", "_tcp", "local") + +@RunWith(DevSdkIgnoreRunner::class) +@IgnoreUpTo(Build.VERSION_CODES.S_V2) +class MdnsProberTest { + private val thread = HandlerThread(MdnsProberTest::class.simpleName) + private val socket = mock(MdnsInterfaceSocket::class.java) + @Suppress("UNCHECKED_CAST") + private val cb = mock(MdnsPacketRepeater.PacketRepeaterCallback::class.java) + as MdnsPacketRepeater.PacketRepeaterCallback<ProbingInfo> + private val buffer = ByteArray(1500) + + @Before + fun setUp() { + doReturn(true).`when`(socket).hasJoinedIpv6() + thread.start() + } + + @After + fun tearDown() { + thread.quitSafely() + thread.join() + } + + private class TestProbeInfo(probeRecords: List<MdnsRecord>, private val delayMs: Long = 1L) : + ProbingInfo(1 /* serviceId */, probeRecords) { + // Just send the packets quickly. Timing-related tests for MdnsPacketRepeater are already + // done in MdnsAnnouncerTest. + override fun getDelayMs(nextIndex: Int) = delayMs + } + + private class TestProber( + looper: Looper, + replySender: MdnsReplySender, + cb: PacketRepeaterCallback<ProbingInfo> + ) : MdnsProber("testiface", looper, replySender, cb) { + override fun getInitialDelay() = 0L + } + + private fun assertProbesSent(probeInfo: TestProbeInfo, expectedHex: String) { + repeat(probeInfo.numSends) { i -> + verify(cb, timeout(TEST_TIMEOUT_MS)).onSent(i, probeInfo) + // If the probe interval is short, more than (i+1) probes may have been sent already + verify(socket, atLeast(i + 1)).send(any()) + } + + val captor = ArgumentCaptor.forClass(DatagramPacket::class.java) + // There should be exactly numSends probes sent at the end + verify(socket, times(probeInfo.numSends)).send(captor.capture()) + + captor.allValues.forEach { + assertEquals(expectedHex, HexDump.toHexString(it.data)) + } + verify(cb, timeout(TEST_TIMEOUT_MS)).onFinished(probeInfo) + } + + private fun makeServiceRecord(name: Array<String>, port: Int) = MdnsServiceRecord( + name, + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 120_000L /* ttlMillis */, + 0 /* servicePriority */, + 0 /* serviceWeight */, + port, + arrayOf("myhostname", "local")) + + @Test + fun testProbe() { + val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer) + val prober = TestProber(thread.looper, replySender, cb) + val probeInfo = TestProbeInfo( + listOf(makeServiceRecord(TEST_SERVICE_NAME_1, 37890))) + prober.startProbing(probeInfo) + + // Inspect with python3: + // import scapy.all as scapy; scapy.DNS(bytes.fromhex('[bytes]')).show2() + val expected = "0000000000010000000100000B7465737473657276696365045F6E6D74045F746370056C" + + "6F63616C0000FF0001C00C002100010000007800130000000094020A6D79686F73746E616D65C022" + assertProbesSent(probeInfo, expected) + } + + @Test + fun testCreateProberCaseInsensitive() { + val probeInfo = TestProbeInfo( + listOf(makeServiceRecord(TEST_SERVICE_NAME_1, 37890), + makeServiceRecord(TEST_SERVICE_NAME_2, 37890), + makeServiceRecord(TEST_SERVICE_NAME_3, 37890))) + assertEquals(2, probeInfo.getPacket(0).questions.size) + } + + @Test + fun testProbeMultipleRecords() { + val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer) + val prober = TestProber(thread.looper, replySender, cb) + val probeInfo = TestProbeInfo(listOf( + makeServiceRecord(TEST_SERVICE_NAME_1, 37890), + makeServiceRecord(TEST_SERVICE_NAME_2, 37891), + MdnsTextRecord( + // Same name as the first record; there should not be 2 duplicated questions + TEST_SERVICE_NAME_1, + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 120_000L /* ttlMillis */, + listOf(MdnsServiceInfo.TextEntry("testKey", "testValue"))))) + prober.startProbing(probeInfo) + + /* + Expected data obtained with: + scapy.raw(scapy.dns_compress(scapy.DNS(rd=0, + qd = + scapy.DNSQR(qname='testservice._nmt._tcp.local.', qtype='ALL') / + scapy.DNSQR(qname='testservice2._nmt._tcp.local.', qtype='ALL'), + ns= + scapy.DNSRRSRV(rrname='testservice._nmt._tcp.local.', type='SRV', ttl=120, + port=37890, target='myhostname.local.') / + scapy.DNSRRSRV(rrname='testservice2._nmt._tcp.local.', type='SRV', ttl=120, + port=37891, target='myhostname.local.') / + scapy.DNSRR(type='TXT', ttl=120, rrname='testservice._nmt._tcp.local.', + rdata='testKey=testValue')) + )).hex().upper() + */ + val expected = "0000000000020000000300000B7465737473657276696365045F6E6D74045F746370056C6" + + "F63616C0000FF00010C746573747365727669636532C01800FF0001C00C002100010000007800130" + + "000000094020A6D79686F73746E616D65C022C02D00210001000000780008000000009403C052C00" + + "C0010000100000078001211746573744B65793D7465737456616C7565" + assertProbesSent(probeInfo, expected) + } + + @Test + fun testStopProbing() { + val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer) + val prober = TestProber(thread.looper, replySender, cb) + val probeInfo = TestProbeInfo( + listOf(makeServiceRecord(TEST_SERVICE_NAME_1, 37890)), + // delayMs is the delay between each probe, so does not apply to the first one + delayMs = SHORT_TIMEOUT_MS) + prober.startProbing(probeInfo) + + // Expect the initial probe + verify(cb, timeout(TEST_TIMEOUT_MS)).onSent(0, probeInfo) + + // Stop probing + val stopResult = CompletableFuture<Boolean>() + Handler(thread.looper).post { stopResult.complete(prober.stop(probeInfo.serviceId)) } + assertTrue(stopResult.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS), + "stop should return true when probing was in progress") + + // Wait for a bit (more than the probe delay) to ensure no more probes were sent + Thread.sleep(SHORT_TIMEOUT_MS * 2) + verify(cb, never()).onSent(1, probeInfo) + verify(cb, never()).onFinished(probeInfo) + + // Only one sent packet + verify(socket, times(1)).send(any()) + } +}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt new file mode 100644 index 0000000..0033b5a --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
@@ -0,0 +1,620 @@ +/* + * 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 android.net.InetAddresses.parseNumericAddress +import android.net.LinkAddress +import android.net.nsd.NsdServiceInfo +import android.os.Build +import android.os.HandlerThread +import com.android.server.connectivity.mdns.MdnsAnnouncer.AnnouncementInfo +import com.android.server.connectivity.mdns.MdnsRecordRepository.Dependencies +import com.android.server.connectivity.mdns.MdnsRecordRepository.getReverseDnsAddress +import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import java.net.InetSocketAddress +import java.net.NetworkInterface +import java.util.Collections +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +private const val TEST_SERVICE_ID_1 = 42 +private const val TEST_SERVICE_ID_2 = 43 +private const val TEST_SERVICE_ID_3 = 44 +private const val TEST_PORT = 12345 +private const val TEST_SUBTYPE = "_subtype" +private val TEST_HOSTNAME = arrayOf("Android_000102030405060708090A0B0C0D0E0F", "local") +private val TEST_ADDRESSES = listOf( + LinkAddress(parseNumericAddress("192.0.2.111"), 24), + LinkAddress(parseNumericAddress("2001:db8::111"), 64), + LinkAddress(parseNumericAddress("2001:db8::222"), 64)) + +private val TEST_SERVICE_1 = NsdServiceInfo().apply { + serviceType = "_testservice._tcp" + serviceName = "MyTestService" + port = TEST_PORT +} + +private val TEST_SERVICE_2 = NsdServiceInfo().apply { + serviceType = "_testservice._tcp" + serviceName = "MyOtherTestService" + port = TEST_PORT +} + +private val TEST_SERVICE_3 = NsdServiceInfo().apply { + serviceType = "_TESTSERVICE._tcp" + serviceName = "MyTESTSERVICE" + port = TEST_PORT +} + +@RunWith(DevSdkIgnoreRunner::class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) +class MdnsRecordRepositoryTest { + private val thread = HandlerThread(MdnsRecordRepositoryTest::class.simpleName) + private val deps = object : Dependencies() { + override fun getInterfaceInetAddresses(iface: NetworkInterface) = + Collections.enumeration(TEST_ADDRESSES.map { it.address }) + } + + @Before + fun setUp() { + thread.start() + } + + @After + fun tearDown() { + thread.quitSafely() + thread.join() + } + + @Test + fun testAddServiceAndProbe() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + assertEquals(0, repository.servicesCount) + assertEquals(-1, repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, + null /* subtype */)) + assertEquals(1, repository.servicesCount) + + val probingInfo = repository.setServiceProbing(TEST_SERVICE_ID_1) + assertNotNull(probingInfo) + assertTrue(repository.isProbing(TEST_SERVICE_ID_1)) + + assertEquals(TEST_SERVICE_ID_1, probingInfo.serviceId) + val packet = probingInfo.getPacket(0) + + assertEquals(MdnsConstants.FLAGS_QUERY, packet.flags) + assertEquals(0, packet.answers.size) + assertEquals(0, packet.additionalRecords.size) + + assertEquals(1, packet.questions.size) + val expectedName = arrayOf("MyTestService", "_testservice", "_tcp", "local") + assertEquals(MdnsAnyRecord(expectedName, false /* unicast */), packet.questions[0]) + + assertEquals(1, packet.authorityRecords.size) + assertEquals(MdnsServiceRecord(expectedName, + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 120_000L /* ttlMillis */, + 0 /* servicePriority */, 0 /* serviceWeight */, + TEST_PORT, TEST_HOSTNAME), packet.authorityRecords[0]) + + assertContentEquals(intArrayOf(TEST_SERVICE_ID_1), repository.clearServices()) + } + + @Test + fun testAddAndConflicts() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */) + assertFailsWith(NameConflictException::class) { + repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_1, null /* subtype */) + } + assertFailsWith(NameConflictException::class) { + repository.addService(TEST_SERVICE_ID_3, TEST_SERVICE_3, null /* subtype */) + } + } + + @Test + fun testInvalidReuseOfServiceId() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */) + assertFailsWith(IllegalArgumentException::class) { + repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_2, null /* subtype */) + } + } + + @Test + fun testHasActiveService() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + assertFalse(repository.hasActiveService(TEST_SERVICE_ID_1)) + + repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */) + assertTrue(repository.hasActiveService(TEST_SERVICE_ID_1)) + + val probingInfo = repository.setServiceProbing(TEST_SERVICE_ID_1) + repository.onProbingSucceeded(probingInfo) + repository.onAdvertisementSent(TEST_SERVICE_ID_1) + assertTrue(repository.hasActiveService(TEST_SERVICE_ID_1)) + + repository.exitService(TEST_SERVICE_ID_1) + assertFalse(repository.hasActiveService(TEST_SERVICE_ID_1)) + } + + @Test + fun testExitAnnouncements() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1) + repository.onAdvertisementSent(TEST_SERVICE_ID_1) + + val exitAnnouncement = repository.exitService(TEST_SERVICE_ID_1) + assertNotNull(exitAnnouncement) + assertEquals(1, repository.servicesCount) + val packet = exitAnnouncement.getPacket(0) + + assertEquals(0x8400 /* response, authoritative */, packet.flags) + assertEquals(0, packet.questions.size) + assertEquals(0, packet.authorityRecords.size) + assertEquals(0, packet.additionalRecords.size) + + assertContentEquals(listOf( + MdnsPointerRecord( + arrayOf("_testservice", "_tcp", "local"), + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 0L /* ttlMillis */, + arrayOf("MyTestService", "_testservice", "_tcp", "local")) + ), packet.answers) + + repository.removeService(TEST_SERVICE_ID_1) + assertEquals(0, repository.servicesCount) + } + + @Test + fun testExitAnnouncements_WithSubtype() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1, TEST_SUBTYPE) + repository.onAdvertisementSent(TEST_SERVICE_ID_1) + + val exitAnnouncement = repository.exitService(TEST_SERVICE_ID_1) + assertNotNull(exitAnnouncement) + assertEquals(1, repository.servicesCount) + val packet = exitAnnouncement.getPacket(0) + + assertEquals(0x8400 /* response, authoritative */, packet.flags) + assertEquals(0, packet.questions.size) + assertEquals(0, packet.authorityRecords.size) + assertEquals(0, packet.additionalRecords.size) + + assertContentEquals(listOf( + MdnsPointerRecord( + arrayOf("_testservice", "_tcp", "local"), + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 0L /* ttlMillis */, + arrayOf("MyTestService", "_testservice", "_tcp", "local")), + MdnsPointerRecord( + arrayOf("_subtype", "_sub", "_testservice", "_tcp", "local"), + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 0L /* ttlMillis */, + arrayOf("MyTestService", "_testservice", "_tcp", "local")), + ), packet.answers) + + repository.removeService(TEST_SERVICE_ID_1) + assertEquals(0, repository.servicesCount) + } + + @Test + fun testExitingServiceReAdded() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1) + repository.onAdvertisementSent(TEST_SERVICE_ID_1) + repository.exitService(TEST_SERVICE_ID_1) + + assertEquals(TEST_SERVICE_ID_1, + repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_1, null /* subtype */)) + assertEquals(1, repository.servicesCount) + + repository.removeService(TEST_SERVICE_ID_2) + assertEquals(0, repository.servicesCount) + } + + @Test + fun testOnProbingSucceeded() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + val announcementInfo = repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1, + TEST_SUBTYPE) + repository.onAdvertisementSent(TEST_SERVICE_ID_1) + val packet = announcementInfo.getPacket(0) + + assertEquals(0x8400 /* response, authoritative */, packet.flags) + assertEquals(0, packet.questions.size) + assertEquals(0, packet.authorityRecords.size) + + val serviceType = arrayOf("_testservice", "_tcp", "local") + val serviceSubtype = arrayOf(TEST_SUBTYPE, "_sub", "_testservice", "_tcp", "local") + val serviceName = arrayOf("MyTestService", "_testservice", "_tcp", "local") + val v4AddrRev = getReverseDnsAddress(TEST_ADDRESSES[0].address) + val v6Addr1Rev = getReverseDnsAddress(TEST_ADDRESSES[1].address) + val v6Addr2Rev = getReverseDnsAddress(TEST_ADDRESSES[2].address) + + assertContentEquals(listOf( + // Reverse address and address records for the hostname + MdnsPointerRecord(v4AddrRev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + TEST_HOSTNAME), + MdnsInetAddressRecord(TEST_HOSTNAME, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + TEST_ADDRESSES[0].address), + MdnsPointerRecord(v6Addr1Rev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + TEST_HOSTNAME), + MdnsInetAddressRecord(TEST_HOSTNAME, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + TEST_ADDRESSES[1].address), + MdnsPointerRecord(v6Addr2Rev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + TEST_HOSTNAME), + MdnsInetAddressRecord(TEST_HOSTNAME, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + TEST_ADDRESSES[2].address), + // Service registration records (RFC6763) + MdnsPointerRecord( + serviceType, + 0L /* receiptTimeMillis */, + // Not a unique name owned by the announcer, so cacheFlush=false + false /* cacheFlush */, + 4500000L /* ttlMillis */, + serviceName), + MdnsPointerRecord( + serviceSubtype, + 0L /* receiptTimeMillis */, + // Not a unique name owned by the announcer, so cacheFlush=false + false /* cacheFlush */, + 4500000L /* ttlMillis */, + serviceName), + MdnsServiceRecord( + serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + 0 /* servicePriority */, + 0 /* serviceWeight */, + TEST_PORT /* servicePort */, + TEST_HOSTNAME), + MdnsTextRecord( + serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 4500000L /* ttlMillis */, + emptyList() /* entries */), + // Service type enumeration record (RFC6763 9.) + MdnsPointerRecord( + arrayOf("_services", "_dns-sd", "_udp", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 4500000L /* ttlMillis */, + serviceType) + ), packet.answers) + + assertContentEquals(listOf( + MdnsNsecRecord(v4AddrRev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + v4AddrRev, + intArrayOf(MdnsRecord.TYPE_PTR)), + MdnsNsecRecord(TEST_HOSTNAME, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + TEST_HOSTNAME, + intArrayOf(MdnsRecord.TYPE_A, MdnsRecord.TYPE_AAAA)), + MdnsNsecRecord(v6Addr1Rev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + v6Addr1Rev, + intArrayOf(MdnsRecord.TYPE_PTR)), + MdnsNsecRecord(v6Addr2Rev, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 120000L /* ttlMillis */, + v6Addr2Rev, + intArrayOf(MdnsRecord.TYPE_PTR)), + MdnsNsecRecord(serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 4500000L /* ttlMillis */, + serviceName, + intArrayOf(MdnsRecord.TYPE_TXT, MdnsRecord.TYPE_SRV)) + ), packet.additionalRecords) + } + + @Test + fun testGetReverseDnsAddress() { + val expectedV6 = "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa" + .split(".").toTypedArray() + assertContentEquals(expectedV6, getReverseDnsAddress(parseNumericAddress("2001:db8::1"))) + val expectedV4 = "123.2.0.192.in-addr.arpa".split(".").toTypedArray() + assertContentEquals(expectedV4, getReverseDnsAddress(parseNumericAddress("192.0.2.123"))) + } + + @Test + fun testGetReplyCaseInsensitive() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1) + val questionsCaseInSensitive = + listOf(MdnsPointerRecord(arrayOf("_TESTSERVICE", "_TCP", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + // TTL and data is empty for a question + 0L /* ttlMillis */, + null /* pointer */)) + val queryCaseInsensitive = MdnsPacket(0 /* flags */, questionsCaseInSensitive, + listOf() /* answers */, listOf() /* authorityRecords */, + listOf() /* additionalRecords */) + val src = InetSocketAddress(parseNumericAddress("192.0.2.123"), 5353) + val replyCaseInsensitive = repository.getReply(queryCaseInsensitive, src) + assertNotNull(replyCaseInsensitive) + assertEquals(1, replyCaseInsensitive.answers.size) + assertEquals(7, replyCaseInsensitive.additionalAnswers.size) + } + + @Test + fun testGetReply() { + doGetReplyTest(subtype = null) + } + + @Test + fun testGetReply_WithSubtype() { + doGetReplyTest(TEST_SUBTYPE) + } + + private fun doGetReplyTest(subtype: String?) { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1, subtype) + val queriedName = if (subtype == null) arrayOf("_testservice", "_tcp", "local") + else arrayOf(subtype, "_sub", "_testservice", "_tcp", "local") + + val questions = listOf(MdnsPointerRecord(queriedName, + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + // TTL and data is empty for a question + 0L /* ttlMillis */, + null /* pointer */)) + val query = MdnsPacket(0 /* flags */, questions, listOf() /* answers */, + listOf() /* authorityRecords */, listOf() /* additionalRecords */) + val src = InetSocketAddress(parseNumericAddress("192.0.2.123"), 5353) + val reply = repository.getReply(query, src) + + assertNotNull(reply) + // Source address is IPv4 + assertEquals(MdnsConstants.getMdnsIPv4Address(), reply.destination.address) + assertEquals(MdnsConstants.MDNS_PORT, reply.destination.port) + + // TTLs as per RFC6762 10. + val longTtl = 4_500_000L + val shortTtl = 120_000L + val serviceName = arrayOf("MyTestService", "_testservice", "_tcp", "local") + + assertEquals(listOf( + MdnsPointerRecord( + queriedName, + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + longTtl, + serviceName), + ), reply.answers) + + assertEquals(listOf( + MdnsTextRecord( + serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + longTtl, + listOf() /* entries */), + MdnsServiceRecord( + serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + shortTtl, + 0 /* servicePriority */, + 0 /* serviceWeight */, + TEST_PORT, + TEST_HOSTNAME), + MdnsInetAddressRecord( + TEST_HOSTNAME, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + shortTtl, + TEST_ADDRESSES[0].address), + MdnsInetAddressRecord( + TEST_HOSTNAME, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + shortTtl, + TEST_ADDRESSES[1].address), + MdnsInetAddressRecord( + TEST_HOSTNAME, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + shortTtl, + TEST_ADDRESSES[2].address), + MdnsNsecRecord( + serviceName, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + longTtl, + serviceName /* nextDomain */, + intArrayOf(MdnsRecord.TYPE_TXT, MdnsRecord.TYPE_SRV)), + MdnsNsecRecord( + TEST_HOSTNAME, + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + shortTtl, + TEST_HOSTNAME /* nextDomain */, + intArrayOf(MdnsRecord.TYPE_A, MdnsRecord.TYPE_AAAA)), + ), reply.additionalAnswers) + } + + @Test + fun testGetConflictingServices() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */) + repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_2, null /* subtype */) + + val packet = MdnsPacket( + 0 /* flags */, + emptyList() /* questions */, + listOf( + MdnsServiceRecord( + arrayOf("MyTestService", "_testservice", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, 0L /* ttlMillis */, + 0 /* servicePriority */, 0 /* serviceWeight */, + TEST_SERVICE_1.port + 1, + TEST_HOSTNAME), + MdnsTextRecord( + arrayOf("MyOtherTestService", "_testservice", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, 0L /* ttlMillis */, + listOf(TextEntry.fromString("somedifferent=entry"))), + ) /* answers */, + emptyList() /* authorityRecords */, + emptyList() /* additionalRecords */) + + assertEquals(setOf(TEST_SERVICE_ID_1, TEST_SERVICE_ID_2), + repository.getConflictingServices(packet)) + } + + @Test + fun testGetConflictingServicesCaseInsensitive() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */) + repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_2, null /* subtype */) + + val packet = MdnsPacket( + 0 /* flags */, + emptyList() /* questions */, + listOf( + MdnsServiceRecord( + arrayOf("MYTESTSERVICE", "_TESTSERVICE", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, 0L /* ttlMillis */, + 0 /* servicePriority */, 0 /* serviceWeight */, + TEST_SERVICE_1.port + 1, + TEST_HOSTNAME), + MdnsTextRecord( + arrayOf("MYOTHERTESTSERVICE", "_TESTSERVICE", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, 0L /* ttlMillis */, + listOf(TextEntry.fromString("somedifferent=entry"))), + ) /* answers */, + emptyList() /* authorityRecords */, + emptyList() /* additionalRecords */) + + assertEquals(setOf(TEST_SERVICE_ID_1, TEST_SERVICE_ID_2), + repository.getConflictingServices(packet)) + } + + @Test + fun testGetConflictingServices_IdenticalService() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */) + repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_2, null /* subtype */) + + val otherTtlMillis = 1234L + val packet = MdnsPacket( + 0 /* flags */, + emptyList() /* questions */, + listOf( + MdnsServiceRecord( + arrayOf("MyTestService", "_testservice", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, + otherTtlMillis, 0 /* servicePriority */, 0 /* serviceWeight */, + TEST_SERVICE_1.port, + arrayOf("ANDROID_000102030405060708090A0B0C0D0E0F", "local")), + MdnsTextRecord( + arrayOf("MyOtherTestService", "_testservice", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, + otherTtlMillis, emptyList()), + ) /* answers */, + emptyList() /* authorityRecords */, + emptyList() /* additionalRecords */) + + // Above records are identical to the actual registrations: no conflict + assertEquals(emptySet(), repository.getConflictingServices(packet)) + } + + @Test + fun testGetConflictingServicesCaseInsensitive_IdenticalService() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */) + repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_2, null /* subtype */) + + val otherTtlMillis = 1234L + val packet = MdnsPacket( + 0 /* flags */, + emptyList() /* questions */, + listOf( + MdnsServiceRecord( + arrayOf("MYTESTSERVICE", "_TESTSERVICE", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, + otherTtlMillis, 0 /* servicePriority */, 0 /* serviceWeight */, + TEST_SERVICE_1.port, + TEST_HOSTNAME), + MdnsTextRecord( + arrayOf("MyOtherTestService", "_TESTSERVICE", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, + otherTtlMillis, emptyList()), + ) /* answers */, + emptyList() /* authorityRecords */, + emptyList() /* additionalRecords */) + + // Above records are identical to the actual registrations: no conflict + assertEquals(emptySet(), repository.getConflictingServices(packet)) + } +} + +private fun MdnsRecordRepository.initWithService( + serviceId: Int, + serviceInfo: NsdServiceInfo, + subtype: String? = null +): AnnouncementInfo { + updateAddresses(TEST_ADDRESSES) + addService(serviceId, serviceInfo, subtype) + val probingInfo = setServiceProbing(serviceId) + assertNotNull(probingInfo) + return onProbingSucceeded(probingInfo) +}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTest.kt new file mode 100644 index 0000000..8f819b7 --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTest.kt
@@ -0,0 +1,124 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns + +import android.os.Build +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(DevSdkIgnoreRunner::class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) +class MdnsRecordTest { + + @Test + fun testPointerRecordHasSubType() { + val ptrRecord1 = MdnsPointerRecord( + arrayOf("_testtype", "_sub", "_tcp", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 4500000 /* ttlMillis */, + arrayOf("testservice", "_testtype", "_tcp", "local") + ) + val ptrRecord2 = MdnsPointerRecord( + arrayOf("_testtype", "_SUB", "_tcp", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 4500000 /* ttlMillis */, + arrayOf("testservice", "_testtype", "_tcp", "local") + ) + assertTrue(ptrRecord1.hasSubtype()) + assertTrue(ptrRecord2.hasSubtype()) + } + + @Test + fun testEqualsCaseInsensitive() { + val ptrRecord1 = MdnsPointerRecord( + arrayOf("_testtype", "_tcp", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 4500000 /* ttlMillis */, + arrayOf("testservice", "_testtype", "_tcp", "local") + ) + val ptrRecord2 = MdnsPointerRecord( + arrayOf("_testType", "_tcp", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 4500000 /* ttlMillis */, + arrayOf("testsErvice", "_testtype", "_Tcp", "local") + ) + assertEquals(ptrRecord1, ptrRecord2) + assertEquals(ptrRecord1.hashCode(), ptrRecord2.hashCode()) + + val srvRecord1 = MdnsServiceRecord( + arrayOf("testservice", "_testtype", "_tcp", "local"), + 123 /* receiptTimeMillis */, + false /* cacheFlush */, + 2000 /* ttlMillis */, + 0 /* servicePriority */, + 0 /* serviceWeight */, + 80 /* port */, + arrayOf("hostname") + ) + val srvRecord2 = MdnsServiceRecord( + arrayOf("Testservice", "_testtype", "_tcp", "local"), + 123 /* receiptTimeMillis */, + false /* cacheFlush */, + 2000 /* ttlMillis */, + 0 /* servicePriority */, + 0 /* serviceWeight */, + 80 /* port */, + arrayOf("Hostname") + ) + assertEquals(srvRecord1, srvRecord2) + assertEquals(srvRecord1.hashCode(), srvRecord2.hashCode()) + + val nsecRecord1 = MdnsNsecRecord( + arrayOf("hostname"), + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 2000L, /* ttlMillis */ + arrayOf("hostname"), + intArrayOf(1, 2, 3) /* types */ + ) + val nsecRecord2 = MdnsNsecRecord( + arrayOf("HOSTNAME"), + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 2000L, /* ttlMillis */ + arrayOf("HOSTNAME"), + intArrayOf(1, 2, 3) /* types */ + ) + assertEquals(nsecRecord1, nsecRecord2) + assertEquals(nsecRecord1.hashCode(), nsecRecord2.hashCode()) + } + + @Test + fun testLabelsAreSuffix() { + val labels1 = arrayOf("a", "b", "c") + val labels2 = arrayOf("B", "C") + val labels3 = arrayOf("b", "c") + val labels4 = arrayOf("b", "d") + assertTrue(MdnsRecord.labelsAreSuffix(labels2, labels1)) + assertTrue(MdnsRecord.labelsAreSuffix(labels3, labels1)) + assertFalse(MdnsRecord.labelsAreSuffix(labels4, labels1)) + } +}
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 7d800d8..55c2846 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTests.java
@@ -281,9 +281,9 @@ // TTL 0x0000003c (60 secs) + "0000003C" // Data length - + "003C" - // nextdomain.android.com - + "0A6E657874646F6D61696E07616E64726F696403636F6D00" + + "0031" + // nextdomain.android.com, with compression for android.com + + "0A6E657874646F6D61696EC007" // Type bitmaps: window block 0x00, bitmap length 0x05, // bits 16 (TXT) and 33 (SRV) set: 0x0000800040 + "00050000800040"
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 4cae447..e16c448 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java
@@ -16,20 +16,26 @@ package com.android.server.connectivity.mdns; +import static android.net.InetAddresses.parseNumericAddress; + import static com.android.server.connectivity.mdns.MdnsResponseDecoder.Clock; 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.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; -import android.net.InetAddresses; import android.net.Network; +import android.util.ArraySet; import com.android.net.module.util.HexDump; +import com.android.server.connectivity.mdns.MdnsResponseTests.MdnsInet4AddressRecord; +import com.android.server.connectivity.mdns.MdnsResponseTests.MdnsInet6AddressRecord; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; @@ -43,8 +49,11 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetSocketAddress; -import java.util.LinkedList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; @RunWith(DevSdkIgnoreRunner.class) @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) @@ -147,6 +156,48 @@ + "010001000000780004C0A8018A0000000000000000000000000000" + "000000"); + // MDNS record for name "testhost1" with an IPv4 address of 10.1.2.3. Also set cache flush bit + // for the records changed. + private static final byte[] DATAIN_IPV4_1 = HexDump.hexStringToByteArray( + "0974657374686f73743100000180010000007800040a010203"); + // MDNS record for name "testhost1" with an IPv4 address of 10.1.2.4. Also set cache flush bit + // for the records changed. + private static final byte[] DATAIN_IPV4_2 = HexDump.hexStringToByteArray( + "0974657374686f73743100000180010000007800040a010204"); + // MDNS record w/name "testhost1" & IPv6 address of aabb:ccdd:1122:3344:a0b0:c0d0:1020:3040. + // Also set cache flush bit for the records changed. + private static final byte[] DATAIN_IPV6_1 = HexDump.hexStringToByteArray( + "0974657374686f73743100001c8001000000780010aabbccdd11223344a0b0c0d010203040"); + // MDNS record w/name "testhost1" & IPv6 address of aabb:ccdd:1122:3344:a0b0:c0d0:1020:3030. + // Also set cache flush bit for the records changed. + private static final byte[] DATAIN_IPV6_2 = HexDump.hexStringToByteArray( + "0974657374686f73743100001c8001000000780010aabbccdd11223344a0b0c0d010203030"); + // MDNS record w/name "test" & PTR to foo.bar.quxx + private static final byte[] DATAIN_PTR_1 = HexDump.hexStringToByteArray( + "047465737400000C000100001194000E03666F6F03626172047175787800"); + // MDNS record w/name "test" & PTR to foo.bar.quxy + private static final byte[] DATAIN_PTR_2 = HexDump.hexStringToByteArray( + "047465737400000C000100001194000E03666F6F03626172047175787900"); + // SRV record for: scapy.DNSRRSRV(rrname='foo.bar.quxx', ttl=120, port=1234, target='testhost1') + private static final byte[] DATAIN_SERVICE_1 = HexDump.hexStringToByteArray( + "03666f6f03626172047175787800002100010000007800110000000004d20974657374686f73743100"); + // SRV record for: scapy.DNSRRSRV(rrname='foo.bar.quxx', ttl=120, port=1234, target='testhost2') + private static final byte[] DATAIN_SERVICE_2 = HexDump.hexStringToByteArray( + "03666f6f03626172047175787800002100010000007800110000000004d20974657374686f73743200"); + // TXT record for: scapy.DNSRR(rrname='foo.bar.quxx', type='TXT', ttl=120, + // rdata=[b'a=hello there', b'b=1234567890', b'xyz=!$$$']) + private static final byte[] DATAIN_TEXT_1 = HexDump.hexStringToByteArray( + "03666f6f03626172047175787800001000010000007800240d613d68656c6c6f2074686572650c623d3132" + + "33343536373839300878797a3d21242424"); + + // TXT record for: scapy.DNSRR(rrname='foo.bar.quxx', type='TXT', ttl=120, + // rdata=[b'a=hello there', b'b=1234567890', b'xyz=!$$$']) + private static final byte[] DATAIN_TEXT_2 = HexDump.hexStringToByteArray( + "03666f6f03626172047175787800001000010000007800240d613d68656c6c6f2074686572650c623d3132" + + "33343536373839300878797a3d21402324"); + + private static final String[] DATAIN_SERVICE_NAME_1 = new String[] { "foo", "bar", "quxx" }; + private static final String CAST_SERVICE_NAME = "_googlecast"; private static final String[] CAST_SERVICE_TYPE = new String[] {CAST_SERVICE_NAME, "_tcp", "local"}; @@ -154,41 +205,28 @@ private static final String[] MATTER_SERVICE_TYPE = new String[] {MATTER_SERVICE_NAME, "_tcp", "local"}; - private final List<MdnsResponse> responses = new LinkedList<>(); + private ArraySet<MdnsResponse> responses; private final Clock mClock = mock(Clock.class); @Before - public void setUp() { + public void setUp() throws Exception { 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, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED, mock(Network.class)); - assertEquals(MdnsResponseDecoder.SUCCESS, errorCode); + responses = decode(decoder, data); assertEquals(1, responses.size()); } @Test - public void testDecodeWithNullServiceType() { + public void testDecodeWithNullServiceType() throws Exception { MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, null); - 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, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED, mock(Network.class)); - assertEquals(MdnsResponseDecoder.SUCCESS, errorCode); + responses = decode(decoder, data); assertEquals(2, responses.size()); } @Test public void testDecodeMultipleAnswerPacket() throws IOException { - MdnsResponse response = responses.get(0); + MdnsResponse response = responses.valueAt(0); assertTrue(response.isComplete()); MdnsInetAddressRecord inet4AddressRecord = response.getInet4AddressRecord(); @@ -231,20 +269,9 @@ assertEquals("st=0", textStrings.get(6)); } - @Test - public void testDecodeIPv6AnswerPacket() throws IOException { - 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, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED, mock(Network.class)); - assertEquals(MdnsResponseDecoder.SUCCESS, errorCode); - - MdnsResponse response = responses.get(0); + private void verifyResponse(ArraySet<MdnsResponse> responseArraySet) { + assertEquals(1, responseArraySet.size()); + MdnsResponse response = responseArraySet.valueAt(0); assertTrue(response.isComplete()); MdnsInetAddressRecord inet6AddressRecord = response.getInet6AddressRecord(); @@ -258,105 +285,314 @@ } @Test + public void testDecodeIPv6AnswerPacket() throws IOException { + MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE); + assertNotNull(data6); + verifyResponse(decode(decoder, data6)); + } + + @Test + public void testDecodeCaseInsensitiveMatch() throws IOException { + final String[] castServiceTypeUpperCase = + new String[] {"_GOOGLECAST", "_TCP", "LOCAL"}; + MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, castServiceTypeUpperCase); + assertNotNull(data6); + verifyResponse(decode(decoder, data6)); + } + + @Test public void testIsComplete() { - MdnsResponse response = responses.get(0); + MdnsResponse response = new MdnsResponse(responses.valueAt(0)); assertTrue(response.isComplete()); response.clearPointerRecords(); + // The service name is still known in MdnsResponse#getServiceName + assertTrue(response.isComplete()); + + response = new MdnsResponse(responses.valueAt(0)); + response.clearInet4AddressRecords(); assertFalse(response.isComplete()); - response = responses.get(0); - response.setInet4AddressRecord(null); + response.addInet6AddressRecord(new MdnsInetAddressRecord(new String[] { "testhostname" }, + 0L /* receiptTimeMillis */, false /* cacheFlush */, 1234L /* ttlMillis */, + parseNumericAddress("2008:db1::123"))); + assertTrue(response.isComplete()); + + response.clearInet6AddressRecords(); assertFalse(response.isComplete()); - response = responses.get(0); - response.setInet6AddressRecord(null); - assertFalse(response.isComplete()); - - response = responses.get(0); + response = new MdnsResponse(responses.valueAt(0)); response.setServiceRecord(null); assertFalse(response.isComplete()); - response = responses.get(0); + response = new MdnsResponse(responses.valueAt(0)); response.setTextRecord(null); assertFalse(response.isComplete()); } @Test - public void decode_withInterfaceIndex_populatesInterfaceIndex() { + public void decode_withInterfaceIndex_populatesInterfaceIndex() throws Exception { 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(); + final MdnsPacket parsedPacket = MdnsResponseDecoder.parseResponse(data6, data6.length); + assertNotNull(parsedPacket); + final Network network = mock(Network.class); - int errorCode = decoder.decode( - packet, responses, /* interfaceIndex= */ 10, network); - assertEquals(errorCode, MdnsResponseDecoder.SUCCESS); + responses = decoder.augmentResponses(parsedPacket, + /* existingResponses= */ Collections.emptyList(), + /* interfaceIndex= */ 10, network /* expireOnExit= */); + assertEquals(responses.size(), 1); - assertEquals(responses.get(0).getInterfaceIndex(), 10); - assertEquals(network, responses.get(0).getNetwork()); + assertEquals(responses.valueAt(0).getInterfaceIndex(), 10); + assertEquals(network, responses.valueAt(0).getNetwork()); } @Test - public void decode_singleHostname_multipleSrvRecords_flagEnabled_multipleCompleteResponses() { + public void decode_singleHostname_multipleSrvRecords_flagEnabled_multipleCompleteResponses() + throws Exception { //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, mock(Network.class)); - assertEquals(MdnsResponseDecoder.SUCCESS, errorCode); + responses = decode(decoder, matterDuplicateHostname); // This should emit two records: assertEquals(2, responses.size()); - MdnsResponse response1 = responses.get(0); - MdnsResponse response2 = responses.get(0); + MdnsResponse response1 = responses.valueAt(0); + MdnsResponse response2 = responses.valueAt(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()); + assertTrue(response1.getInet6AddressRecords().stream().anyMatch( + record -> record.getInet6Address().equals( + parseNumericAddress("2605:a601:a846:5700:3e61:5ff:fe0c:89f8")))); + assertTrue(response2.getInet6AddressRecords().stream().anyMatch( + record -> record.getInet6Address().equals( + parseNumericAddress("2605:a601:a846:5700:3e61:5ff:fe0c:89f8")))); } @Test @Ignore("MdnsConfigs is not configurable currently.") - public void decode_singleHostname_multipleSrvRecords_flagDisabled_singleCompleteResponse() { + public void decode_singleHostname_multipleSrvRecords_flagDisabled_singleCompleteResponse() + throws Exception { //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, mock(Network.class)); - assertEquals(MdnsResponseDecoder.SUCCESS, errorCode); + responses = decode(decoder, matterDuplicateHostname); // 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()); + assertTrue(responses.valueAt(0).isComplete()); + assertFalse(responses.valueAt(1).isComplete()); + } + + @Test + public void testDecodeWithIpv4AddressChange() throws IOException { + MdnsResponse response = makeMdnsResponse(0, DATAIN_SERVICE_NAME_1, List.of( + new PacketAndRecordClass(DATAIN_PTR_1, + MdnsPointerRecord.class), + new PacketAndRecordClass(DATAIN_SERVICE_1, + MdnsServiceRecord.class), + new PacketAndRecordClass(DATAIN_IPV4_1, + MdnsInet4AddressRecord.class))); + // Now update the response with another address + final MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, null); + final ArraySet<MdnsResponse> updatedResponses = decode( + decoder, makeResponsePacket(DATAIN_IPV4_2), List.of(response)); + assertEquals(1, updatedResponses.size()); + assertEquals(parseNumericAddress("10.1.2.4"), + updatedResponses.valueAt(0).getInet4AddressRecord().getInet4Address()); + assertEquals(parseNumericAddress("10.1.2.3"), + response.getInet4AddressRecord().getInet4Address()); + } + + @Test + public void testDecodeWithIpv6AddressChange() throws IOException { + MdnsResponse response = makeMdnsResponse(0, DATAIN_SERVICE_NAME_1, List.of( + new PacketAndRecordClass(DATAIN_PTR_1, + MdnsPointerRecord.class), + new PacketAndRecordClass(DATAIN_SERVICE_1, + MdnsServiceRecord.class), + new PacketAndRecordClass(DATAIN_IPV6_1, + MdnsInet6AddressRecord.class))); + // Now update the response with another address + final MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, null); + final ArraySet<MdnsResponse> updatedResponses = decode( + decoder, makeResponsePacket(DATAIN_IPV6_2), List.of(response)); + assertEquals(1, updatedResponses.size()); + assertEquals(parseNumericAddress("aabb:ccdd:1122:3344:a0b0:c0d0:1020:3030"), + updatedResponses.valueAt(0).getInet6AddressRecord().getInet6Address()); + assertEquals(parseNumericAddress("aabb:ccdd:1122:3344:a0b0:c0d0:1020:3040"), + response.getInet6AddressRecord().getInet6Address()); + } + + @Test + public void testDecodeWithChangeOnText() throws IOException { + MdnsResponse response = makeMdnsResponse(0, DATAIN_SERVICE_NAME_1, List.of( + new PacketAndRecordClass(DATAIN_PTR_1, + MdnsPointerRecord.class), + new PacketAndRecordClass(DATAIN_SERVICE_1, + MdnsServiceRecord.class), + new PacketAndRecordClass(DATAIN_TEXT_1, + MdnsTextRecord.class))); + // Now update the response with another address + final MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, null); + final ArraySet<MdnsResponse> updatedResponses = decode( + decoder, makeResponsePacket(DATAIN_TEXT_2), List.of(response)); + assertEquals(1, updatedResponses.size()); + assertEquals(List.of( + new MdnsServiceInfo.TextEntry("a", "hello there"), + new MdnsServiceInfo.TextEntry("b", "1234567890"), + new MdnsServiceInfo.TextEntry("xyz", "!@#$")), + updatedResponses.valueAt(0).getTextRecord().getEntries()); + } + + @Test + public void testDecodeWithChangeOnService() throws IOException { + MdnsResponse response = makeMdnsResponse(0, DATAIN_SERVICE_NAME_1, List.of( + new PacketAndRecordClass(DATAIN_PTR_1, + MdnsPointerRecord.class), + new PacketAndRecordClass(DATAIN_SERVICE_1, + MdnsServiceRecord.class), + new PacketAndRecordClass(DATAIN_IPV4_1, + MdnsInet4AddressRecord.class))); + assertArrayEquals(new String[] { "testhost1" }, + response.getServiceRecord().getServiceHost()); + assertNotNull(response.getInet4AddressRecord()); + // Now update the response with another hostname + final MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, null); + final ArraySet<MdnsResponse> updatedResponses = decode( + decoder, makeResponsePacket(DATAIN_SERVICE_2), List.of(response)); + assertEquals(1, updatedResponses.size()); + assertArrayEquals(new String[] { "testhost2" }, + updatedResponses.valueAt(0).getServiceRecord().getServiceHost()); + // Hostname changed, so address records are dropped + assertNull(updatedResponses.valueAt(0).getInet4AddressRecord()); + } + + @Test + public void testDecodeWithChangeOnPtr() throws IOException { + MdnsResponse response = makeMdnsResponse(0, DATAIN_SERVICE_NAME_1, List.of( + new PacketAndRecordClass(DATAIN_PTR_1, + MdnsPointerRecord.class), + new PacketAndRecordClass(DATAIN_SERVICE_1, + MdnsServiceRecord.class))); + // Now update the response with another address + final MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, null); + final ArraySet<MdnsResponse> updatedResponses = decode( + decoder, makeResponsePacket(DATAIN_PTR_2), List.of(response)); + assertEquals(1, updatedResponses.size()); + assertArrayEquals(new String[] { "foo", "bar", "quxy" }, + updatedResponses.valueAt(0).getPointerRecords().get(0).getPointer()); + } + + @Test + public void testDecodeWithNoChange() throws IOException { + List<PacketAndRecordClass> recordList = + Arrays.asList( + new PacketAndRecordClass(DATAIN_IPV4_1, MdnsInet4AddressRecord.class), + new PacketAndRecordClass(DATAIN_IPV6_1, MdnsInet6AddressRecord.class), + new PacketAndRecordClass(DATAIN_PTR_1, MdnsPointerRecord.class), + new PacketAndRecordClass(DATAIN_SERVICE_2, MdnsServiceRecord.class), + new PacketAndRecordClass(DATAIN_TEXT_1, MdnsTextRecord.class)); + // Create a two identical responses. + MdnsResponse response = makeMdnsResponse(0, DATAIN_SERVICE_NAME_1, recordList); + + final MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, null); + final byte[] identicalResponse = makeResponsePacket( + recordList.stream().map(p -> p.packetData).collect(Collectors.toList())); + final ArraySet<MdnsResponse> changes = decode( + decoder, identicalResponse, List.of(response)); + + // Decoding should not indicate any change. + assertEquals(0, changes.size()); + } + + private static MdnsResponse makeMdnsResponse(long time, String[] serviceName, + List<PacketAndRecordClass> responseList) throws IOException { + final MdnsResponse response = new MdnsResponse( + time, serviceName, 999 /* interfaceIndex */, mock(Network.class)); + for (PacketAndRecordClass responseData : responseList) { + DatagramPacket packet = + new DatagramPacket(responseData.packetData, responseData.packetData.length); + MdnsPacketReader reader = new MdnsPacketReader(packet); + String[] name = reader.readLabels(); + reader.skip(2); // skip record type indication. + // Apply the right kind of record to the response. + if (responseData.recordClass == MdnsInet4AddressRecord.class) { + response.addInet4AddressRecord(new MdnsInet4AddressRecord(name, reader)); + } else if (responseData.recordClass == MdnsInet6AddressRecord.class) { + response.addInet6AddressRecord(new MdnsInet6AddressRecord(name, reader)); + } else if (responseData.recordClass == MdnsPointerRecord.class) { + response.addPointerRecord(new MdnsPointerRecord(name, reader)); + } else if (responseData.recordClass == MdnsServiceRecord.class) { + response.setServiceRecord(new MdnsServiceRecord(name, reader)); + } else if (responseData.recordClass == MdnsTextRecord.class) { + response.setTextRecord(new MdnsTextRecord(name, reader)); + } else { + fail("Unsupported/unexpected MdnsRecord subtype used in test - invalid test!"); + } + } + return response; + } + + private static byte[] makeResponsePacket(byte[] responseRecord) throws IOException { + return makeResponsePacket(List.of(responseRecord)); + } + + private static byte[] makeResponsePacket(List<byte[]> responseRecords) throws IOException { + final MdnsPacketWriter writer = new MdnsPacketWriter(1500); + writer.writeUInt16(0); // Transaction ID (advertisement: 0) + writer.writeUInt16(0x8400); // Flags: response, authoritative + writer.writeUInt16(0); // questions count + writer.writeUInt16(responseRecords.size()); // answers count + writer.writeUInt16(0); // authority entries count + writer.writeUInt16(0); // additional records count + + for (byte[] record : responseRecords) { + writer.writeBytes(record); + } + final DatagramPacket packet = writer.getPacket(new InetSocketAddress(0 /* port */)); + return Arrays.copyOf(packet.getData(), packet.getLength()); + } + + + // This helper class just wraps the data bytes of a response packet with the contained record + // type. + // Its only purpose is to make the test code a bit more readable. + private static class PacketAndRecordClass { + public final byte[] packetData; + public final Class<?> recordClass; + + PacketAndRecordClass(byte[] data, Class<?> c) { + packetData = data; + recordClass = c; + } + } + + private ArraySet<MdnsResponse> decode(MdnsResponseDecoder decoder, byte[] data) + throws MdnsPacket.ParseException { + return decode(decoder, data, Collections.emptyList()); + } + + private ArraySet<MdnsResponse> decode(MdnsResponseDecoder decoder, byte[] data, + Collection<MdnsResponse> existingResponses) throws MdnsPacket.ParseException { + final MdnsPacket parsedPacket = MdnsResponseDecoder.parseResponse(data, data.length); + assertNotNull(parsedPacket); + + return decoder.augmentResponses(parsedPacket, + existingResponses, + MdnsSocket.INTERFACE_INDEX_UNSPECIFIED, mock(Network.class)); } } \ 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 ec57dc8..dc0e646 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java
@@ -16,6 +16,8 @@ package com.android.server.connectivity.mdns; +import static android.net.InetAddresses.parseNumericAddress; + import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2; import static org.junit.Assert.assertEquals; @@ -23,22 +25,21 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; +import static java.util.Collections.emptyList; + import android.net.Network; import com.android.net.module.util.HexDump; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import java.io.IOException; import java.net.DatagramPacket; -import java.util.Arrays; import java.util.List; // The record test data does not use compressed names (label pointers), since that would require @@ -48,36 +49,24 @@ public class MdnsResponseTests { private static final String TAG = "MdnsResponseTests"; // MDNS response packet for name "test" with an IPv4 address of 10.1.2.3 - private static final byte[] dataIn_ipv4_1 = HexDump.hexStringToByteArray( + private static final byte[] DATAIN_IPV4 = HexDump.hexStringToByteArray( "0474657374000001" + "0001000011940004" + "0A010203"); - // MDNS response packet for name "tess" with an IPv4 address of 10.1.2.4 - private static final byte[] dataIn_ipv4_2 = HexDump.hexStringToByteArray( - "0474657373000001" + "0001000011940004" + "0A010204"); // MDNS response w/name "test" & IPv6 address of aabb:ccdd:1122:3344:a0b0:c0d0:1020:3040 - private static final byte[] dataIn_ipv6_1 = HexDump.hexStringToByteArray( + private static final byte[] DATAIN_IPV6 = HexDump.hexStringToByteArray( "047465737400001C" + "0001000011940010" + "AABBCCDD11223344" + "A0B0C0D010203040"); - // MDNS response w/name "test" & IPv6 address of aabb:ccdd:1122:3344:a0b0:c0d0:1020:3030 - private static final byte[] dataIn_ipv6_2 = HexDump.hexStringToByteArray( - "047465737400001C" + "0001000011940010" + "AABBCCDD11223344" + "A0B0C0D010203030"); // MDNS response w/name "test" & PTR to foo.bar.quxx - private static final byte[] dataIn_ptr_1 = HexDump.hexStringToByteArray( + private static final byte[] DATAIN_PTR = HexDump.hexStringToByteArray( "047465737400000C" + "000100001194000E" + "03666F6F03626172" + "047175787800"); - // MDNS response w/name "test" & PTR to foo.bar.quxy - private static final byte[] dataIn_ptr_2 = HexDump.hexStringToByteArray( - "047465737400000C" + "000100001194000E" + "03666F6F03626172" + "047175787900"); // MDNS response w/name "test" & Service for host foo.bar.quxx - private static final byte[] dataIn_service_1 = HexDump.hexStringToByteArray( + private static final byte[] DATAIN_SERVICE = HexDump.hexStringToByteArray( "0474657374000021" + "0001000011940014" + "000100FF1F480366" + "6F6F036261720471" + "75787800"); - // MDNS response w/name "test" & Service for host test - private static final byte[] dataIn_service_2 = HexDump.hexStringToByteArray( - "0474657374000021" + "000100001194000B" + "000100FF1F480474" + "657374"); // MDNS response w/name "test" & the following text strings: // "a=hello there", "b=1234567890", and "xyz=!$$$" - private static final byte[] dataIn_text_1 = HexDump.hexStringToByteArray( + private static final byte[] DATAIN_TEXT = HexDump.hexStringToByteArray( "0474657374000010" + "0001000011940024" + "0D613D68656C6C6F" @@ -85,18 +74,11 @@ + "3D31323334353637" + "3839300878797A3D" + "21242424"); - // MDNS response w/name "test" & the following text strings: - // "a=hello there", "b=1234567890", and "xyz=!@#$" - private static final byte[] dataIn_text_2 = HexDump.hexStringToByteArray( - "0474657374000010" - + "0001000011940024" - + "0D613D68656C6C6F" - + "2074686572650C62" - + "3D31323334353637" - + "3839300878797A3D" - + "21402324"); + private static final String[] TEST_SERVICE_NAME = + new String[] { "test", "_type", "_tcp", "local" }; private static final int INTERFACE_INDEX = 999; + private static final int TEST_TTL_MS = 120_000; private final Network mNetwork = mock(Network.class); // The following helper classes act as wrappers so that IPv4 and IPv6 address records can @@ -113,87 +95,63 @@ } } - // This helper class just wraps the data bytes of a response packet with the contained record - // type. - // Its only purpose is to make the test code a bit more readable. - static class PacketAndRecordClass { - public final byte[] packetData; - public final Class<?> recordClass; - - public PacketAndRecordClass() { - packetData = null; - recordClass = null; - } - - public PacketAndRecordClass(byte[] data, Class<?> c) { - packetData = data; - recordClass = c; - } - } - - // Construct an MdnsResponse with the specified data packets applied. - private MdnsResponse makeMdnsResponse(long time, List<PacketAndRecordClass> responseList) - throws IOException { - MdnsResponse response = new MdnsResponse(time, INTERFACE_INDEX, mNetwork); - for (PacketAndRecordClass responseData : responseList) { - DatagramPacket packet = - new DatagramPacket(responseData.packetData, responseData.packetData.length); - MdnsPacketReader reader = new MdnsPacketReader(packet); - String[] name = reader.readLabels(); - reader.skip(2); // skip record type indication. - // Apply the right kind of record to the response. - if (responseData.recordClass == MdnsInet4AddressRecord.class) { - response.setInet4AddressRecord(new MdnsInet4AddressRecord(name, reader)); - } else if (responseData.recordClass == MdnsInet6AddressRecord.class) { - response.setInet6AddressRecord(new MdnsInet6AddressRecord(name, reader)); - } else if (responseData.recordClass == MdnsPointerRecord.class) { - response.addPointerRecord(new MdnsPointerRecord(name, reader)); - } else if (responseData.recordClass == MdnsServiceRecord.class) { - response.setServiceRecord(new MdnsServiceRecord(name, reader)); - } else if (responseData.recordClass == MdnsTextRecord.class) { - response.setTextRecord(new MdnsTextRecord(name, reader)); - } else { - fail("Unsupported/unexpected MdnsRecord subtype used in test - invalid test!"); - } - } + private MdnsResponse makeCompleteResponse(int recordsTtlMillis) { + final String[] hostname = new String[] { "MyHostname" }; + final String[] serviceName = new String[] { "MyService", "_type", "_tcp", "local" }; + final String[] serviceType = new String[] { "_type", "_tcp", "local" }; + final MdnsResponse response = new MdnsResponse(/* now= */ 0, serviceName, INTERFACE_INDEX, + mNetwork); + response.addPointerRecord(new MdnsPointerRecord(serviceType, 0L /* receiptTimeMillis */, + false /* cacheFlush */, recordsTtlMillis, serviceName)); + response.setServiceRecord(new MdnsServiceRecord(serviceName, 0L /* receiptTimeMillis */, + true /* cacheFlush */, recordsTtlMillis, 0 /* servicePriority */, + 0 /* serviceWeight */, 0 /* servicePort */, hostname)); + response.setTextRecord(new MdnsTextRecord(serviceName, 0L /* receiptTimeMillis */, + true /* cacheFlush */, recordsTtlMillis, emptyList() /* entries */)); + response.addInet4AddressRecord(new MdnsInetAddressRecord( + hostname, 0L /* receiptTimeMillis */, true /* cacheFlush */, + recordsTtlMillis, parseNumericAddress("192.0.2.123"))); + response.addInet6AddressRecord(new MdnsInetAddressRecord( + hostname, 0L /* receiptTimeMillis */, true /* cacheFlush */, + recordsTtlMillis, parseNumericAddress("2001:db8::123"))); return response; } @Test public void getInet4AddressRecord_returnsAddedRecord() throws IOException { - DatagramPacket packet = new DatagramPacket(dataIn_ipv4_1, dataIn_ipv4_1.length); + DatagramPacket packet = new DatagramPacket(DATAIN_IPV4, DATAIN_IPV4.length); MdnsPacketReader reader = new MdnsPacketReader(packet); String[] name = reader.readLabels(); reader.skip(2); // skip record type indication. MdnsInetAddressRecord record = new MdnsInetAddressRecord(name, MdnsRecord.TYPE_A, reader); - MdnsResponse response = new MdnsResponse(0, INTERFACE_INDEX, mNetwork); + MdnsResponse response = new MdnsResponse(0, TEST_SERVICE_NAME, INTERFACE_INDEX, mNetwork); assertFalse(response.hasInet4AddressRecord()); - assertTrue(response.setInet4AddressRecord(record)); + assertTrue(response.addInet4AddressRecord(record)); assertEquals(response.getInet4AddressRecord(), record); } @Test public void getInet6AddressRecord_returnsAddedRecord() throws IOException { - DatagramPacket packet = new DatagramPacket(dataIn_ipv6_1, dataIn_ipv6_1.length); + DatagramPacket packet = new DatagramPacket(DATAIN_IPV6, DATAIN_IPV6.length); MdnsPacketReader reader = new MdnsPacketReader(packet); String[] name = reader.readLabels(); reader.skip(2); // skip record type indication. MdnsInetAddressRecord record = new MdnsInetAddressRecord(name, MdnsRecord.TYPE_AAAA, reader); - MdnsResponse response = new MdnsResponse(0, INTERFACE_INDEX, mNetwork); + MdnsResponse response = new MdnsResponse(0, TEST_SERVICE_NAME, INTERFACE_INDEX, mNetwork); assertFalse(response.hasInet6AddressRecord()); - assertTrue(response.setInet6AddressRecord(record)); + assertTrue(response.addInet6AddressRecord(record)); assertEquals(response.getInet6AddressRecord(), record); } @Test public void getPointerRecords_returnsAddedRecord() throws IOException { - DatagramPacket packet = new DatagramPacket(dataIn_ptr_1, dataIn_ptr_1.length); + DatagramPacket packet = new DatagramPacket(DATAIN_PTR, DATAIN_PTR.length); MdnsPacketReader reader = new MdnsPacketReader(packet); String[] name = reader.readLabels(); reader.skip(2); // skip record type indication. MdnsPointerRecord record = new MdnsPointerRecord(name, reader); - MdnsResponse response = new MdnsResponse(0, INTERFACE_INDEX, mNetwork); + MdnsResponse response = new MdnsResponse(0, record.getPointer(), INTERFACE_INDEX, mNetwork); assertFalse(response.hasPointerRecords()); assertTrue(response.addPointerRecord(record)); List<MdnsPointerRecord> recordList = response.getPointerRecords(); @@ -204,12 +162,12 @@ @Test public void getServiceRecord_returnsAddedRecord() throws IOException { - DatagramPacket packet = new DatagramPacket(dataIn_service_1, dataIn_service_1.length); + DatagramPacket packet = new DatagramPacket(DATAIN_SERVICE, DATAIN_SERVICE.length); MdnsPacketReader reader = new MdnsPacketReader(packet); String[] name = reader.readLabels(); reader.skip(2); // skip record type indication. MdnsServiceRecord record = new MdnsServiceRecord(name, reader); - MdnsResponse response = new MdnsResponse(0, INTERFACE_INDEX, mNetwork); + MdnsResponse response = new MdnsResponse(0, name, INTERFACE_INDEX, mNetwork); assertFalse(response.hasServiceRecord()); assertTrue(response.setServiceRecord(record)); assertEquals(response.getServiceRecord(), record); @@ -217,12 +175,12 @@ @Test public void getTextRecord_returnsAddedRecord() throws IOException { - DatagramPacket packet = new DatagramPacket(dataIn_text_1, dataIn_text_1.length); + DatagramPacket packet = new DatagramPacket(DATAIN_TEXT, DATAIN_TEXT.length); MdnsPacketReader reader = new MdnsPacketReader(packet); String[] name = reader.readLabels(); reader.skip(2); // skip record type indication. MdnsTextRecord record = new MdnsTextRecord(name, reader); - MdnsResponse response = new MdnsResponse(0, INTERFACE_INDEX, mNetwork); + MdnsResponse response = new MdnsResponse(0, name, INTERFACE_INDEX, mNetwork); assertFalse(response.hasTextRecord()); assertTrue(response.setTextRecord(record)); assertEquals(response.getTextRecord(), record); @@ -230,104 +188,118 @@ @Test public void getInterfaceIndex() { - final MdnsResponse response1 = new MdnsResponse(/* now= */ 0, INTERFACE_INDEX, mNetwork); + final MdnsResponse response1 = new MdnsResponse(/* now= */ 0, TEST_SERVICE_NAME, + INTERFACE_INDEX, mNetwork); assertEquals(INTERFACE_INDEX, response1.getInterfaceIndex()); - final MdnsResponse response2 = - new MdnsResponse(/* now= */ 0, 1234 /* interfaceIndex */, mNetwork); + final MdnsResponse response2 = new MdnsResponse(/* now= */ 0, TEST_SERVICE_NAME, + 1234 /* interfaceIndex */, mNetwork); assertEquals(1234, response2.getInterfaceIndex()); } @Test public void testGetNetwork() { - final MdnsResponse response1 = - new MdnsResponse(/* now= */ 0, INTERFACE_INDEX, null /* network */); + final MdnsResponse response1 = new MdnsResponse(/* now= */ 0, TEST_SERVICE_NAME, + INTERFACE_INDEX, null /* network */); assertNull(response1.getNetwork()); - final MdnsResponse response2 = - new MdnsResponse(/* now= */ 0, 1234 /* interfaceIndex */, mNetwork); + final MdnsResponse response2 = new MdnsResponse(/* now= */ 0, TEST_SERVICE_NAME, + 1234 /* interfaceIndex */, mNetwork); assertEquals(mNetwork, response2.getNetwork()); } @Test - public void mergeRecordsFrom_indicates_change_on_ipv4_address() throws IOException { - MdnsResponse response = makeMdnsResponse( - 0, - Arrays.asList( - new PacketAndRecordClass(dataIn_ipv4_1, MdnsInet4AddressRecord.class))); - // Now create a new response that updates the address. - MdnsResponse response2 = makeMdnsResponse( - 100, - Arrays.asList( - new PacketAndRecordClass(dataIn_ipv4_2, MdnsInet4AddressRecord.class))); - assertTrue(response.mergeRecordsFrom(response2)); + public void copyConstructor() { + final MdnsResponse response = makeCompleteResponse(TEST_TTL_MS); + final MdnsResponse copy = new MdnsResponse(response); + + assertEquals(response.getInet6AddressRecord(), copy.getInet6AddressRecord()); + assertEquals(response.getInet4AddressRecord(), copy.getInet4AddressRecord()); + assertEquals(response.getPointerRecords(), copy.getPointerRecords()); + assertEquals(response.getServiceRecord(), copy.getServiceRecord()); + assertEquals(response.getTextRecord(), copy.getTextRecord()); + assertEquals(response.getRecords(), copy.getRecords()); + assertEquals(response.getNetwork(), copy.getNetwork()); + assertEquals(response.getInterfaceIndex(), copy.getInterfaceIndex()); } @Test - public void mergeRecordsFrom_indicates_change_on_ipv6_address() throws IOException { - MdnsResponse response = makeMdnsResponse( - 0, - Arrays.asList( - new PacketAndRecordClass(dataIn_ipv6_1, MdnsInet6AddressRecord.class))); - // Now create a new response that updates the address. - MdnsResponse response2 = makeMdnsResponse( - 100, - Arrays.asList( - new PacketAndRecordClass(dataIn_ipv6_2, MdnsInet6AddressRecord.class))); - assertTrue(response.mergeRecordsFrom(response2)); + public void addRecords_noChange() { + final MdnsResponse response = makeCompleteResponse(TEST_TTL_MS); + + assertFalse(response.addPointerRecord(response.getPointerRecords().get(0))); + final String[] serviceName = new String[] { "MYSERVICE", "_TYPE", "_tcp", "local" }; + final String[] serviceType = new String[] { "_TYPE", "_tcp", "local" }; + MdnsPointerRecord pointerRecordCaseInsensitive = + new MdnsPointerRecord(serviceType, 0L /* receiptTimeMillis */, + false /* cacheFlush */, TEST_TTL_MS, serviceName); + assertFalse(response.addPointerRecord(pointerRecordCaseInsensitive)); + assertFalse(response.addInet6AddressRecord(response.getInet6AddressRecord())); + assertFalse(response.addInet4AddressRecord(response.getInet4AddressRecord())); + assertFalse(response.setServiceRecord(response.getServiceRecord())); + assertFalse(response.setTextRecord(response.getTextRecord())); } @Test - public void mergeRecordsFrom_indicates_change_on_text() throws IOException { - MdnsResponse response = makeMdnsResponse( - 0, - Arrays.asList(new PacketAndRecordClass(dataIn_text_1, MdnsTextRecord.class))); - // Now create a new response that updates the address. - MdnsResponse response2 = makeMdnsResponse( - 100, - Arrays.asList(new PacketAndRecordClass(dataIn_text_2, MdnsTextRecord.class))); - assertTrue(response.mergeRecordsFrom(response2)); + public void addRecords_ttlChange() { + final MdnsResponse response = makeCompleteResponse(TEST_TTL_MS); + final MdnsResponse ttlZeroResponse = makeCompleteResponse(0); + + assertTrue(response.addPointerRecord(ttlZeroResponse.getPointerRecords().get(0))); + assertEquals(1, response.getPointerRecords().size()); + assertEquals(0, response.getPointerRecords().get(0).getTtl()); + assertTrue(response.getRecords().stream().anyMatch(r -> + r == response.getPointerRecords().get(0))); + + assertTrue(response.addInet6AddressRecord(ttlZeroResponse.getInet6AddressRecord())); + assertEquals(1, response.getInet6AddressRecords().size()); + assertEquals(0, response.getInet6AddressRecord().getTtl()); + assertTrue(response.getRecords().stream().anyMatch(r -> + r == response.getInet6AddressRecord())); + + assertTrue(response.addInet4AddressRecord(ttlZeroResponse.getInet4AddressRecord())); + assertEquals(1, response.getInet4AddressRecords().size()); + assertEquals(0, response.getInet4AddressRecord().getTtl()); + assertTrue(response.getRecords().stream().anyMatch(r -> + r == response.getInet4AddressRecord())); + + assertTrue(response.setServiceRecord(ttlZeroResponse.getServiceRecord())); + assertEquals(0, response.getServiceRecord().getTtl()); + assertTrue(response.getRecords().stream().anyMatch(r -> + r == response.getServiceRecord())); + + assertTrue(response.setTextRecord(ttlZeroResponse.getTextRecord())); + assertEquals(0, response.getTextRecord().getTtl()); + assertTrue(response.getRecords().stream().anyMatch(r -> + r == response.getTextRecord())); + + // All records were replaced, not added + assertEquals(ttlZeroResponse.getRecords().size(), response.getRecords().size()); } @Test - public void mergeRecordsFrom_indicates_change_on_service() throws IOException { - MdnsResponse response = makeMdnsResponse( - 0, - Arrays.asList(new PacketAndRecordClass(dataIn_service_1, MdnsServiceRecord.class))); - // Now create a new response that updates the address. - MdnsResponse response2 = makeMdnsResponse( - 100, - Arrays.asList(new PacketAndRecordClass(dataIn_service_2, MdnsServiceRecord.class))); - assertTrue(response.mergeRecordsFrom(response2)); - } + public void dropUnmatchedAddressRecords_caseInsensitive() { - @Test - public void mergeRecordsFrom_indicates_change_on_pointer() throws IOException { - MdnsResponse response = makeMdnsResponse( - 0, - Arrays.asList(new PacketAndRecordClass(dataIn_ptr_1, MdnsPointerRecord.class))); - // Now create a new response that updates the address. - MdnsResponse response2 = makeMdnsResponse( - 100, - Arrays.asList(new PacketAndRecordClass(dataIn_ptr_2, MdnsPointerRecord.class))); - assertTrue(response.mergeRecordsFrom(response2)); - } + final String[] hostname = new String[] { "MyHostname" }; + final String[] upperCaseHostName = new String[] { "MYHOSTNAME" }; + final String[] serviceName = new String[] { "MyService", "_type", "_tcp", "local" }; + final String[] serviceType = new String[] { "_type", "_tcp", "local" }; + final MdnsResponse response = new MdnsResponse(/* now= */ 0, serviceName, INTERFACE_INDEX, + mNetwork); + response.addPointerRecord(new MdnsPointerRecord(serviceType, 0L /* receiptTimeMillis */, + false /* cacheFlush */, TEST_TTL_MS, serviceName)); + response.setServiceRecord(new MdnsServiceRecord(serviceName, 0L /* receiptTimeMillis */, + true /* cacheFlush */, TEST_TTL_MS, 0 /* servicePriority */, + 0 /* serviceWeight */, 0 /* servicePort */, hostname)); + response.setTextRecord(new MdnsTextRecord(serviceName, 0L /* receiptTimeMillis */, + true /* cacheFlush */, TEST_TTL_MS, emptyList() /* entries */)); + response.addInet4AddressRecord(new MdnsInetAddressRecord( + upperCaseHostName , 0L /* receiptTimeMillis */, true /* cacheFlush */, + TEST_TTL_MS, parseNumericAddress("192.0.2.123"))); + response.addInet6AddressRecord(new MdnsInetAddressRecord( + upperCaseHostName, 0L /* receiptTimeMillis */, true /* cacheFlush */, + TEST_TTL_MS, parseNumericAddress("2001:db8::123"))); - @Test - @Ignore("MdnsConfigs is not configurable currently.") - public void mergeRecordsFrom_indicates_noChange() throws IOException { - //MdnsConfigsFlagsImpl.useReducedMergeRecordUpdateEvents.override(true); - List<PacketAndRecordClass> recordList = - Arrays.asList( - new PacketAndRecordClass(dataIn_ipv4_1, MdnsInet4AddressRecord.class), - new PacketAndRecordClass(dataIn_ipv6_1, MdnsInet6AddressRecord.class), - new PacketAndRecordClass(dataIn_ptr_1, MdnsPointerRecord.class), - new PacketAndRecordClass(dataIn_service_2, MdnsServiceRecord.class), - new PacketAndRecordClass(dataIn_text_1, MdnsTextRecord.class)); - // Create a two identical responses. - MdnsResponse response = makeMdnsResponse(0, recordList); - MdnsResponse response2 = makeMdnsResponse(100, recordList); - // Merging should not indicate any change. - assertFalse(response.mergeRecordsFrom(response2)); + assertFalse(response.dropUnmatchedAddressRecords()); } } \ No newline at end of file
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceCacheTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceCacheTest.kt new file mode 100644 index 0000000..f091eea --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceCacheTest.kt
@@ -0,0 +1,136 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns + +import android.net.Network +import android.os.Build +import android.os.Handler +import android.os.HandlerThread +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit +import kotlin.test.assertNotNull +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.mock + +private const val SERVICE_NAME_1 = "service-instance-1" +private const val SERVICE_NAME_2 = "service-instance-2" +private const val SERVICE_TYPE_1 = "_test1._tcp.local" +private const val SERVICE_TYPE_2 = "_test2._tcp.local" +private const val INTERFACE_INDEX = 999 +private const val DEFAULT_TIMEOUT_MS = 2000L + +@RunWith(DevSdkIgnoreRunner::class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) +class MdnsServiceCacheTest { + private val network = mock(Network::class.java) + private val thread = HandlerThread(MdnsServiceCacheTest::class.simpleName) + private val handler by lazy { + Handler(thread.looper) + } + private val serviceCache by lazy { + MdnsServiceCache(thread.looper) + } + + @Before + fun setUp() { + thread.start() + } + + @After + fun tearDown() { + thread.quitSafely() + } + + private fun <T> runningOnHandlerAndReturn(functor: (() -> T)): T { + val future = CompletableFuture<T>() + handler.post { + future.complete(functor()) + } + return future.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS) + } + + private fun addOrUpdateService(serviceType: String, network: Network, service: MdnsResponse): + Unit = runningOnHandlerAndReturn { + serviceCache.addOrUpdateService(serviceType, network, service) } + + private fun removeService(serviceName: String, serviceType: String, network: Network): + Unit = runningOnHandlerAndReturn { + serviceCache.removeService(serviceName, serviceType, network) } + + private fun getService(serviceName: String, serviceType: String, network: Network): + MdnsResponse? = runningOnHandlerAndReturn { + serviceCache.getCachedService(serviceName, serviceType, network) } + + private fun getServices(serviceType: String, network: Network): List<MdnsResponse> = + runningOnHandlerAndReturn { serviceCache.getCachedServices(serviceType, network) } + + @Test + fun testAddAndRemoveService() { + addOrUpdateService(SERVICE_TYPE_1, network, createResponse(SERVICE_NAME_1, SERVICE_TYPE_1)) + var response = getService(SERVICE_NAME_1, SERVICE_TYPE_1, network) + assertNotNull(response) + assertEquals(SERVICE_NAME_1, response.serviceInstanceName) + removeService(SERVICE_NAME_1, SERVICE_TYPE_1, network) + response = getService(SERVICE_NAME_1, SERVICE_TYPE_1, network) + assertNull(response) + } + + @Test + fun testGetCachedServices_multipleServiceTypes() { + addOrUpdateService(SERVICE_TYPE_1, network, createResponse(SERVICE_NAME_1, SERVICE_TYPE_1)) + addOrUpdateService(SERVICE_TYPE_1, network, createResponse(SERVICE_NAME_2, SERVICE_TYPE_1)) + addOrUpdateService(SERVICE_TYPE_2, network, createResponse(SERVICE_NAME_2, SERVICE_TYPE_2)) + + val responses1 = getServices(SERVICE_TYPE_1, network) + assertEquals(2, responses1.size) + assertTrue(responses1.stream().anyMatch { response -> + response.serviceInstanceName == SERVICE_NAME_1 + }) + assertTrue(responses1.any { response -> + response.serviceInstanceName == SERVICE_NAME_2 + }) + val responses2 = getServices(SERVICE_TYPE_2, network) + assertEquals(1, responses2.size) + assertTrue(responses2.any { response -> + response.serviceInstanceName == SERVICE_NAME_2 + }) + + removeService(SERVICE_NAME_2, SERVICE_TYPE_1, network) + val responses3 = getServices(SERVICE_TYPE_1, network) + assertEquals(1, responses3.size) + assertTrue(responses3.any { response -> + response.serviceInstanceName == SERVICE_NAME_1 + }) + val responses4 = getServices(SERVICE_TYPE_2, network) + assertEquals(1, responses4.size) + assertTrue(responses4.any { response -> + response.serviceInstanceName == SERVICE_NAME_2 + }) + } + + private fun createResponse(serviceInstanceName: String, serviceType: String) = MdnsResponse( + 0 /* now */, "$serviceInstanceName.$serviceType".split(".").toTypedArray(), + INTERFACE_INDEX, network) +}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java index 76728cf..e7d7a98 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceInfoTest.java
@@ -119,6 +119,26 @@ } @Test + public void constructor_createWithUppercaseKeys_correctAttributes() { + MdnsServiceInfo info = + new MdnsServiceInfo( + "my-mdns-service", + new String[] {"_testtype", "_tcp"}, + List.of(), + new String[] {"my-host", "local"}, + 12345, + "192.168.1.1", + "2001::1", + List.of("KEY=Value"), + /* textEntries= */ null); + + assertEquals("Value", info.getAttributeByKey("key")); + assertEquals("Value", info.getAttributeByKey("KEY")); + assertEquals(1, info.getAttributes().size()); + assertEquals("KEY", info.getAttributes().keySet().iterator().next()); + } + + @Test public void getInterfaceIndex_constructorWithDefaultValues_returnsMinusOne() { MdnsServiceInfo info = new MdnsServiceInfo( @@ -177,8 +197,8 @@ List.of(), new String[] {"my-host", "local"}, 12345, - "192.168.1.1", - "2001::1", + List.of("192.168.1.1"), + List.of("2001::1"), List.of(), /* textEntries= */ null, /* interfaceIndex= */ 20, @@ -197,8 +217,8 @@ List.of(), new String[] {"my-host", "local"}, 12345, - "192.168.1.1", - "2001::1", + List.of("192.168.1.1", "192.168.1.2"), + List.of("2001::1", "2001::2"), List.of("vn=Alphabet Inc.", "mn=Google Nest Hub Max", "id=12345"), List.of( MdnsServiceInfo.TextEntry.fromString("vn=Google Inc."), @@ -217,7 +237,9 @@ assertArrayEquals(beforeParcel.getHostName(), afterParcel.getHostName()); assertEquals(beforeParcel.getPort(), afterParcel.getPort()); assertEquals(beforeParcel.getIpv4Address(), afterParcel.getIpv4Address()); + assertEquals(beforeParcel.getIpv4Addresses(), afterParcel.getIpv4Addresses()); assertEquals(beforeParcel.getIpv6Address(), afterParcel.getIpv6Address()); + assertEquals(beforeParcel.getIpv6Addresses(), afterParcel.getIpv6Addresses()); assertEquals(beforeParcel.getAttributes(), afterParcel.getAttributes()); assertEquals(beforeParcel.getInterfaceIndex(), afterParcel.getInterfaceIndex()); assertEquals(beforeParcel.getNetwork(), afterParcel.getNetwork());
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java index 697116c..f15e8ff 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
@@ -21,16 +21,16 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -42,6 +42,8 @@ import android.net.Network; import android.text.TextUtils; +import com.android.net.module.util.CollectionUtils; +import com.android.net.module.util.SharedLog; import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry; import com.android.server.connectivity.mdns.MdnsServiceTypeClient.QueryTaskConfig; import com.android.testutils.DevSdkIgnoreRule; @@ -52,6 +54,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatcher; import org.mockito.Captor; import org.mockito.InOrder; import org.mockito.Mock; @@ -60,9 +63,8 @@ import java.io.IOException; import java.net.DatagramPacket; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.SocketAddress; +import java.net.InetAddress; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -72,6 +74,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; /** Tests for {@link MdnsServiceTypeClient}. */ @RunWith(DevSdkIgnoreRunner.class) @@ -80,7 +83,14 @@ private static final int INTERFACE_INDEX = 999; private static final String SERVICE_TYPE = "_googlecast._tcp.local"; private static final String[] SERVICE_TYPE_LABELS = TextUtils.split(SERVICE_TYPE, "\\."); - private static final Network NETWORK = mock(Network.class); + private static final InetSocketAddress IPV4_ADDRESS = new InetSocketAddress( + MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT); + private static final InetSocketAddress IPV6_ADDRESS = new InetSocketAddress( + MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT); + + private static final long TEST_TTL = 120000L; + private static final long TEST_ELAPSED_REALTIME = 123L; + private static final long TEST_TIMEOUT_MS = 10_000L; @Mock private MdnsServiceBrowserListener mockListenerOne; @@ -89,13 +99,20 @@ @Mock private MdnsPacketWriter mockPacketWriter; @Mock - private MdnsSocketClient mockSocketClient; + private MdnsMultinetworkSocketClient mockSocketClient; + @Mock + private Network mockNetwork; + @Mock + private MdnsResponseDecoder.Clock mockDecoderClock; + @Mock + private SharedLog mockSharedLog; @Captor private ArgumentCaptor<MdnsServiceInfo> serviceInfoCaptor; private final byte[] buf = new byte[10]; - private DatagramPacket[] expectedPackets; + private DatagramPacket[] expectedIPv4Packets; + private DatagramPacket[] expectedIPv6Packets; private ScheduledFuture<?>[] expectedSendFutures; private FakeExecutor currentThreadExecutor = new FakeExecutor(); @@ -105,34 +122,58 @@ @SuppressWarnings("DoNotMock") public void setUp() throws IOException { MockitoAnnotations.initMocks(this); + doReturn(TEST_ELAPSED_REALTIME).when(mockDecoderClock).elapsedRealtime(); - expectedPackets = new DatagramPacket[16]; + expectedIPv4Packets = new DatagramPacket[16]; + expectedIPv6Packets = new DatagramPacket[16]; expectedSendFutures = new ScheduledFuture<?>[16]; for (int i = 0; i < expectedSendFutures.length; ++i) { - expectedPackets[i] = new DatagramPacket(buf, 0, 5); + expectedIPv4Packets[i] = new DatagramPacket(buf, 0 /* offset */, 5 /* length */, + MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT); + expectedIPv6Packets[i] = new DatagramPacket(buf, 0 /* offset */, 5 /* length */, + MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT); expectedSendFutures[i] = Mockito.mock(ScheduledFuture.class); } - when(mockPacketWriter.getPacket(any(SocketAddress.class))) - .thenReturn(expectedPackets[0]) - .thenReturn(expectedPackets[1]) - .thenReturn(expectedPackets[2]) - .thenReturn(expectedPackets[3]) - .thenReturn(expectedPackets[4]) - .thenReturn(expectedPackets[5]) - .thenReturn(expectedPackets[6]) - .thenReturn(expectedPackets[7]) - .thenReturn(expectedPackets[8]) - .thenReturn(expectedPackets[9]) - .thenReturn(expectedPackets[10]) - .thenReturn(expectedPackets[11]) - .thenReturn(expectedPackets[12]) - .thenReturn(expectedPackets[13]) - .thenReturn(expectedPackets[14]) - .thenReturn(expectedPackets[15]); + when(mockPacketWriter.getPacket(IPV4_ADDRESS)) + .thenReturn(expectedIPv4Packets[0]) + .thenReturn(expectedIPv4Packets[1]) + .thenReturn(expectedIPv4Packets[2]) + .thenReturn(expectedIPv4Packets[3]) + .thenReturn(expectedIPv4Packets[4]) + .thenReturn(expectedIPv4Packets[5]) + .thenReturn(expectedIPv4Packets[6]) + .thenReturn(expectedIPv4Packets[7]) + .thenReturn(expectedIPv4Packets[8]) + .thenReturn(expectedIPv4Packets[9]) + .thenReturn(expectedIPv4Packets[10]) + .thenReturn(expectedIPv4Packets[11]) + .thenReturn(expectedIPv4Packets[12]) + .thenReturn(expectedIPv4Packets[13]) + .thenReturn(expectedIPv4Packets[14]) + .thenReturn(expectedIPv4Packets[15]); + + when(mockPacketWriter.getPacket(IPV6_ADDRESS)) + .thenReturn(expectedIPv6Packets[0]) + .thenReturn(expectedIPv6Packets[1]) + .thenReturn(expectedIPv6Packets[2]) + .thenReturn(expectedIPv6Packets[3]) + .thenReturn(expectedIPv6Packets[4]) + .thenReturn(expectedIPv6Packets[5]) + .thenReturn(expectedIPv6Packets[6]) + .thenReturn(expectedIPv6Packets[7]) + .thenReturn(expectedIPv6Packets[8]) + .thenReturn(expectedIPv6Packets[9]) + .thenReturn(expectedIPv6Packets[10]) + .thenReturn(expectedIPv6Packets[11]) + .thenReturn(expectedIPv6Packets[12]) + .thenReturn(expectedIPv6Packets[13]) + .thenReturn(expectedIPv6Packets[14]) + .thenReturn(expectedIPv6Packets[15]); client = - new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor) { + new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, + mockDecoderClock, mockNetwork, mockSharedLog) { @Override MdnsPacketWriter createMdnsPacketWriter() { return mockPacketWriter; @@ -282,8 +323,8 @@ //MdnsConfigsFlagsImpl.alwaysAskForUnicastResponseInEachBurst.override(true); MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(false).build(); - QueryTaskConfig config = - new QueryTaskConfig(searchOptions.getSubtypes(), searchOptions.isPassiveMode(), 1); + QueryTaskConfig config = new QueryTaskConfig( + searchOptions.getSubtypes(), searchOptions.isPassiveMode(), 1, mockNetwork); // This is the first query. We will ask for unicast response. assertTrue(config.expectUnicastResponse); @@ -311,8 +352,8 @@ public void testQueryTaskConfig_askForUnicastInFirstQuery() { MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(false).build(); - QueryTaskConfig config = - new QueryTaskConfig(searchOptions.getSubtypes(), searchOptions.isPassiveMode(), 1); + QueryTaskConfig config = new QueryTaskConfig( + searchOptions.getSubtypes(), searchOptions.isPassiveMode(), 1, mockNetwork); // This is the first query. We will ask for unicast response. assertTrue(config.expectUnicastResponse); @@ -385,17 +426,46 @@ assertNull(currentThreadExecutor.getAndClearLastScheduledRunnable()); } + @Test + public void testQueryScheduledWhenAnsweredFromCache() { + final MdnsSearchOptions searchOptions = MdnsSearchOptions.getDefaultOptions(); + client.startSendAndReceive(mockListenerOne, searchOptions); + assertNotNull(currentThreadExecutor.getAndClearSubmittedRunnable()); + + client.processResponse(createResponse( + "service-instance-1", "192.0.2.123", 5353, + SERVICE_TYPE_LABELS, + Collections.emptyMap(), TEST_TTL), /* interfaceIndex= */ 20, mockNetwork); + + verify(mockListenerOne).onServiceNameDiscovered(any()); + verify(mockListenerOne).onServiceFound(any()); + + // File another identical query + client.startSendAndReceive(mockListenerTwo, searchOptions); + + verify(mockListenerTwo).onServiceNameDiscovered(any()); + verify(mockListenerTwo).onServiceFound(any()); + + // This time no query is submitted, only scheduled + assertNull(currentThreadExecutor.getAndClearSubmittedRunnable()); + assertNotNull(currentThreadExecutor.getAndClearLastScheduledRunnable()); + // This just skips the first query of the first burst + assertEquals(MdnsConfigs.timeBetweenQueriesInBurstMs(), + currentThreadExecutor.getAndClearLastScheduledDelayInMs()); + } + private static void verifyServiceInfo(MdnsServiceInfo serviceInfo, String serviceName, - String[] serviceType, String ipv4Address, String ipv6Address, int port, + String[] serviceType, List<String> ipv4Addresses, List<String> ipv6Addresses, int port, List<String> subTypes, Map<String, String> attributes, int interfaceIndex, Network network) { assertEquals(serviceName, serviceInfo.getServiceInstanceName()); assertArrayEquals(serviceType, serviceInfo.getServiceType()); - assertEquals(ipv4Address, serviceInfo.getIpv4Address()); - assertEquals(ipv6Address, serviceInfo.getIpv6Address()); + assertEquals(ipv4Addresses, serviceInfo.getIpv4Addresses()); + assertEquals(ipv6Addresses, serviceInfo.getIpv6Addresses()); assertEquals(port, serviceInfo.getPort()); assertEquals(subTypes, serviceInfo.getSubtypes()); for (String key : attributes.keySet()) { + assertTrue(attributes.containsKey(key)); assertEquals(attributes.get(key), serviceInfo.getAttributeByKey(key)); } assertEquals(interfaceIndex, serviceInfo.getInterfaceIndex()); @@ -406,24 +476,21 @@ public void processResponse_incompleteResponse() { client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); - MdnsResponse response = mock(MdnsResponse.class); - when(response.getServiceInstanceName()).thenReturn("service-instance-1"); - doReturn(INTERFACE_INDEX).when(response).getInterfaceIndex(); - doReturn(NETWORK).when(response).getNetwork(); - when(response.isComplete()).thenReturn(false); - - client.processResponse(response); + client.processResponse(createResponse( + "service-instance-1", null /* host */, 0 /* port */, + SERVICE_TYPE_LABELS, + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); verify(mockListenerOne).onServiceNameDiscovered(serviceInfoCaptor.capture()); verifyServiceInfo(serviceInfoCaptor.getAllValues().get(0), "service-instance-1", SERVICE_TYPE_LABELS, - null /* ipv4Address */, - null /* ipv6Address */, - 0 /* port */, - List.of() /* subTypes */, - Collections.singletonMap("key", null) /* attributes */, + /* ipv4Addresses= */ List.of(), + /* ipv6Addresses= */ List.of(), + /* port= */ 0, + /* subTypes= */ List.of(), + Collections.emptyMap(), INTERFACE_INDEX, - NETWORK); + mockNetwork); verify(mockListenerOne, never()).onServiceFound(any(MdnsServiceInfo.class)); verify(mockListenerOne, never()).onServiceUpdated(any(MdnsServiceInfo.class)); @@ -435,41 +502,30 @@ client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); // Process the initial response. - MdnsResponse initialResponse = - createResponse( - "service-instance-1", - ipV4Address, - 5353, - /* subtype= */ "ABCDE", - Collections.emptyMap(), - /* interfaceIndex= */ 20, - NETWORK); - client.processResponse(initialResponse); + client.processResponse(createResponse( + "service-instance-1", ipV4Address, 5353, + /* subtype= */ "ABCDE", + Collections.emptyMap(), TEST_TTL), /* interfaceIndex= */ 20, mockNetwork); // Process a second response with a different port and updated text attributes. - MdnsResponse secondResponse = - createResponse( - "service-instance-1", - ipV4Address, - 5354, - /* subtype= */ "ABCDE", - Collections.singletonMap("key", "value"), - /* interfaceIndex= */ 20, - NETWORK); - client.processResponse(secondResponse); + client.processResponse(createResponse( + "service-instance-1", ipV4Address, 5354, + /* subtype= */ "ABCDE", + Collections.singletonMap("key", "value"), TEST_TTL), + /* interfaceIndex= */ 20, mockNetwork); // Verify onServiceNameDiscovered was called once for the initial response. verify(mockListenerOne).onServiceNameDiscovered(serviceInfoCaptor.capture()); verifyServiceInfo(serviceInfoCaptor.getAllValues().get(0), "service-instance-1", SERVICE_TYPE_LABELS, - ipV4Address /* ipv4Address */, - null /* ipv6Address */, + List.of(ipV4Address) /* ipv4Address */, + List.of() /* ipv6Address */, 5353 /* port */, Collections.singletonList("ABCDE") /* subTypes */, Collections.singletonMap("key", null) /* attributes */, 20 /* interfaceIndex */, - NETWORK); + mockNetwork); // Verify onServiceFound was called once for the initial response. verify(mockListenerOne).onServiceFound(serviceInfoCaptor.capture()); @@ -480,7 +536,7 @@ assertEquals(initialServiceInfo.getSubtypes(), Collections.singletonList("ABCDE")); assertNull(initialServiceInfo.getAttributeByKey("key")); assertEquals(initialServiceInfo.getInterfaceIndex(), 20); - assertEquals(NETWORK, initialServiceInfo.getNetwork()); + assertEquals(mockNetwork, initialServiceInfo.getNetwork()); // Verify onServiceUpdated was called once for the second response. verify(mockListenerOne).onServiceUpdated(serviceInfoCaptor.capture()); @@ -492,7 +548,7 @@ assertEquals(updatedServiceInfo.getSubtypes(), Collections.singletonList("ABCDE")); assertEquals(updatedServiceInfo.getAttributeByKey("key"), "value"); assertEquals(updatedServiceInfo.getInterfaceIndex(), 20); - assertEquals(NETWORK, updatedServiceInfo.getNetwork()); + assertEquals(mockNetwork, updatedServiceInfo.getNetwork()); } @Test @@ -501,44 +557,30 @@ client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); // Process the initial response. - MdnsResponse initialResponse = - createResponse( - "service-instance-1", - ipV6Address, - 5353, - /* subtype= */ "ABCDE", - Collections.emptyMap(), - /* interfaceIndex= */ 20, - NETWORK); - client.processResponse(initialResponse); + client.processResponse(createResponse( + "service-instance-1", ipV6Address, 5353, + /* subtype= */ "ABCDE", + Collections.emptyMap(), TEST_TTL), /* interfaceIndex= */ 20, mockNetwork); // Process a second response with a different port and updated text attributes. - MdnsResponse secondResponse = - createResponse( - "service-instance-1", - ipV6Address, - 5354, - /* subtype= */ "ABCDE", - Collections.singletonMap("key", "value"), - /* interfaceIndex= */ 20, - NETWORK); - client.processResponse(secondResponse); - - System.out.println("secondResponses ip" - + secondResponse.getInet6AddressRecord().getInet6Address().getHostAddress()); + client.processResponse(createResponse( + "service-instance-1", ipV6Address, 5354, + /* subtype= */ "ABCDE", + Collections.singletonMap("key", "value"), TEST_TTL), + /* interfaceIndex= */ 20, mockNetwork); // Verify onServiceNameDiscovered was called once for the initial response. verify(mockListenerOne).onServiceNameDiscovered(serviceInfoCaptor.capture()); verifyServiceInfo(serviceInfoCaptor.getAllValues().get(0), "service-instance-1", SERVICE_TYPE_LABELS, - null /* ipv4Address */, - ipV6Address /* ipv6Address */, + List.of() /* ipv4Address */, + List.of(ipV6Address) /* ipv6Address */, 5353 /* port */, Collections.singletonList("ABCDE") /* subTypes */, Collections.singletonMap("key", null) /* attributes */, 20 /* interfaceIndex */, - NETWORK); + mockNetwork); // Verify onServiceFound was called once for the initial response. verify(mockListenerOne).onServiceFound(serviceInfoCaptor.capture()); @@ -549,7 +591,7 @@ assertEquals(initialServiceInfo.getSubtypes(), Collections.singletonList("ABCDE")); assertNull(initialServiceInfo.getAttributeByKey("key")); assertEquals(initialServiceInfo.getInterfaceIndex(), 20); - assertEquals(NETWORK, initialServiceInfo.getNetwork()); + assertEquals(mockNetwork, initialServiceInfo.getNetwork()); // Verify onServiceUpdated was called once for the second response. verify(mockListenerOne).onServiceUpdated(serviceInfoCaptor.capture()); @@ -561,7 +603,7 @@ assertEquals(updatedServiceInfo.getSubtypes(), Collections.singletonList("ABCDE")); assertEquals(updatedServiceInfo.getAttributeByKey("key"), "value"); assertEquals(updatedServiceInfo.getInterfaceIndex(), 20); - assertEquals(NETWORK, updatedServiceInfo.getNetwork()); + assertEquals(mockNetwork, updatedServiceInfo.getNetwork()); } private void verifyServiceRemovedNoCallback(MdnsServiceBrowserListener listener) { @@ -591,48 +633,38 @@ final String serviceName = "service-instance-1"; final String ipV6Address = "2000:3333::da6c:63ff:fe7c:7483"; // Process the initial response. - final MdnsResponse initialResponse = - createResponse( - serviceName, - ipV6Address, - 5353 /* port */, - /* subtype= */ "ABCDE", - Collections.emptyMap(), - INTERFACE_INDEX, - NETWORK); - client.processResponse(initialResponse); - MdnsResponse response = mock(MdnsResponse.class); - doReturn("goodbye-service").when(response).getServiceInstanceName(); - doReturn(INTERFACE_INDEX).when(response).getInterfaceIndex(); - doReturn(NETWORK).when(response).getNetwork(); - doReturn(true).when(response).isGoodbye(); - client.processResponse(response); + client.processResponse(createResponse( + serviceName, ipV6Address, 5353, + SERVICE_TYPE_LABELS, + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); + + client.processResponse(createResponse( + "goodbye-service", ipV6Address, 5353, + SERVICE_TYPE_LABELS, + Collections.emptyMap(), /* ptrTtlMillis= */ 0L), INTERFACE_INDEX, mockNetwork); + // Verify removed callback won't be called if the service is not existed. verifyServiceRemovedNoCallback(mockListenerOne); verifyServiceRemovedNoCallback(mockListenerTwo); // Verify removed callback would be called. - doReturn(serviceName).when(response).getServiceInstanceName(); - client.processResponse(response); + client.processResponse(createResponse( + serviceName, ipV6Address, 5353, + SERVICE_TYPE_LABELS, + Collections.emptyMap(), 0L), INTERFACE_INDEX, mockNetwork); verifyServiceRemovedCallback( - mockListenerOne, serviceName, SERVICE_TYPE_LABELS, INTERFACE_INDEX, NETWORK); + mockListenerOne, serviceName, SERVICE_TYPE_LABELS, INTERFACE_INDEX, mockNetwork); verifyServiceRemovedCallback( - mockListenerTwo, serviceName, SERVICE_TYPE_LABELS, INTERFACE_INDEX, NETWORK); + mockListenerTwo, serviceName, SERVICE_TYPE_LABELS, INTERFACE_INDEX, mockNetwork); } @Test public void reportExistingServiceToNewlyRegisteredListeners() throws Exception { // Process the initial response. - MdnsResponse initialResponse = - createResponse( - "service-instance-1", - "192.168.1.1", - 5353, - /* subtype= */ "ABCDE", - Collections.emptyMap(), - INTERFACE_INDEX, - NETWORK); - client.processResponse(initialResponse); + client.processResponse(createResponse( + "service-instance-1", "192.168.1.1", 5353, + /* subtype= */ "ABCDE", + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); @@ -641,13 +673,13 @@ verifyServiceInfo(serviceInfoCaptor.getAllValues().get(0), "service-instance-1", SERVICE_TYPE_LABELS, - "192.168.1.1" /* ipv4Address */, - null /* ipv6Address */, + List.of("192.168.1.1") /* ipv4Address */, + List.of() /* ipv6Address */, 5353 /* port */, Collections.singletonList("ABCDE") /* subTypes */, Collections.singletonMap("key", null) /* attributes */, INTERFACE_INDEX, - NETWORK); + mockNetwork); // Verify onServiceFound was called once for the existing response. verify(mockListenerOne).onServiceFound(serviceInfoCaptor.capture()); @@ -659,10 +691,10 @@ assertNull(existingServiceInfo.getAttributeByKey("key")); // Process a goodbye message for the existing response. - MdnsResponse goodByeResponse = mock(MdnsResponse.class); - when(goodByeResponse.getServiceInstanceName()).thenReturn("service-instance-1"); - when(goodByeResponse.isGoodbye()).thenReturn(true); - client.processResponse(goodByeResponse); + client.processResponse(createResponse( + "service-instance-1", "192.168.1.1", 5353, + SERVICE_TYPE_LABELS, + Collections.emptyMap(), /* ptrTtlMillis= */ 0L), INTERFACE_INDEX, mockNetwork); client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); @@ -681,17 +713,15 @@ Runnable firstMdnsTask = currentThreadExecutor.getAndClearSubmittedRunnable(); // Process the initial response. - MdnsResponse initialResponse = - createMockResponse( - serviceInstanceName, "192.168.1.1", 5353, List.of("ABCDE"), - Map.of(), INTERFACE_INDEX, NETWORK); - client.processResponse(initialResponse); + client.processResponse(createResponse( + serviceInstanceName, "192.168.1.1", 5353, /* subtype= */ "ABCDE", + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); // Clear the scheduled runnable. currentThreadExecutor.getAndClearLastScheduledRunnable(); // Simulate the case where the response is after TTL. - when(initialResponse.getServiceRecord().getRemainingTTL(anyLong())).thenReturn((long) 0); + doReturn(TEST_ELAPSED_REALTIME + TEST_TTL + 1L).when(mockDecoderClock).elapsedRealtime(); firstMdnsTask.run(); // Verify removed callback was not called. @@ -705,7 +735,8 @@ //MdnsConfigsFlagsImpl.allowSearchOptionsToRemoveExpiredService.override(true); final String serviceInstanceName = "service-instance-1"; client = - new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor) { + new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, + mockDecoderClock, mockNetwork, mockSharedLog) { @Override MdnsPacketWriter createMdnsPacketWriter() { return mockPacketWriter; @@ -715,29 +746,27 @@ Runnable firstMdnsTask = currentThreadExecutor.getAndClearSubmittedRunnable(); // Process the initial response. - MdnsResponse initialResponse = - createMockResponse( - serviceInstanceName, "192.168.1.1", 5353, List.of("ABCDE"), - Map.of(), INTERFACE_INDEX, NETWORK); - client.processResponse(initialResponse); + client.processResponse(createResponse( + serviceInstanceName, "192.168.1.1", 5353, /* subtype= */ "ABCDE", + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); // Clear the scheduled runnable. currentThreadExecutor.getAndClearLastScheduledRunnable(); // Simulate the case where the response is under TTL. - when(initialResponse.getServiceRecord().getRemainingTTL(anyLong())).thenReturn((long) 1000); + doReturn(TEST_ELAPSED_REALTIME + TEST_TTL - 1L).when(mockDecoderClock).elapsedRealtime(); firstMdnsTask.run(); // Verify removed callback was not called. verifyServiceRemovedNoCallback(mockListenerOne); // Simulate the case where the response is after TTL. - when(initialResponse.getServiceRecord().getRemainingTTL(anyLong())).thenReturn((long) 0); + doReturn(TEST_ELAPSED_REALTIME + TEST_TTL + 1L).when(mockDecoderClock).elapsedRealtime(); firstMdnsTask.run(); // Verify removed callback was called. verifyServiceRemovedCallback(mockListenerOne, serviceInstanceName, SERVICE_TYPE_LABELS, - INTERFACE_INDEX, NETWORK); + INTERFACE_INDEX, mockNetwork); } @Test @@ -745,7 +774,8 @@ throws Exception { final String serviceInstanceName = "service-instance-1"; client = - new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor) { + new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, + mockDecoderClock, mockNetwork, mockSharedLog) { @Override MdnsPacketWriter createMdnsPacketWriter() { return mockPacketWriter; @@ -755,17 +785,15 @@ Runnable firstMdnsTask = currentThreadExecutor.getAndClearSubmittedRunnable(); // Process the initial response. - MdnsResponse initialResponse = - createMockResponse( - serviceInstanceName, "192.168.1.1", 5353, List.of("ABCDE"), - Map.of(), INTERFACE_INDEX, NETWORK); - client.processResponse(initialResponse); + client.processResponse(createResponse( + serviceInstanceName, "192.168.1.1", 5353, /* subtype= */ "ABCDE", + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); // Clear the scheduled runnable. currentThreadExecutor.getAndClearLastScheduledRunnable(); // Simulate the case where the response is after TTL. - when(initialResponse.getServiceRecord().getRemainingTTL(anyLong())).thenReturn((long) 0); + doReturn(TEST_ELAPSED_REALTIME + TEST_TTL + 1L).when(mockDecoderClock).elapsedRealtime(); firstMdnsTask.run(); // Verify removed callback was not called. @@ -779,7 +807,8 @@ //MdnsConfigsFlagsImpl.removeServiceAfterTtlExpires.override(true); final String serviceInstanceName = "service-instance-1"; client = - new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor) { + new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, + mockDecoderClock, mockNetwork, mockSharedLog) { @Override MdnsPacketWriter createMdnsPacketWriter() { return mockPacketWriter; @@ -789,22 +818,20 @@ Runnable firstMdnsTask = currentThreadExecutor.getAndClearSubmittedRunnable(); // Process the initial response. - MdnsResponse initialResponse = - createMockResponse( - serviceInstanceName, "192.168.1.1", 5353, List.of("ABCDE"), - Map.of(), INTERFACE_INDEX, NETWORK); - client.processResponse(initialResponse); + client.processResponse(createResponse( + serviceInstanceName, "192.168.1.1", 5353, /* subtype= */ "ABCDE", + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); // Clear the scheduled runnable. currentThreadExecutor.getAndClearLastScheduledRunnable(); // Simulate the case where the response is after TTL. - when(initialResponse.getServiceRecord().getRemainingTTL(anyLong())).thenReturn((long) 0); + doReturn(TEST_ELAPSED_REALTIME + TEST_TTL + 1L).when(mockDecoderClock).elapsedRealtime(); firstMdnsTask.run(); // Verify removed callback was called. verifyServiceRemovedCallback(mockListenerOne, serviceInstanceName, SERVICE_TYPE_LABELS, - INTERFACE_INDEX, NETWORK); + INTERFACE_INDEX, mockNetwork); } @Test @@ -816,122 +843,430 @@ InOrder inOrder = inOrder(mockListenerOne); // Process the initial response which is incomplete. - final MdnsResponse initialResponse = - createResponse( - serviceName, - null, - 5353, - "ABCDE" /* subtype */, - Collections.emptyMap(), - INTERFACE_INDEX, - NETWORK); - client.processResponse(initialResponse); + final String subtype = "ABCDE"; + client.processResponse(createResponse( + serviceName, null, 5353, subtype, + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); // Process a second response which has ip address to make response become complete. - final MdnsResponse secondResponse = - createResponse( - serviceName, - ipV4Address, - 5353, - "ABCDE" /* subtype */, - Collections.emptyMap(), - INTERFACE_INDEX, - NETWORK); - client.processResponse(secondResponse); + client.processResponse(createResponse( + serviceName, ipV4Address, 5353, subtype, + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); // Process a third response with a different ip address, port and updated text attributes. - final MdnsResponse thirdResponse = - createResponse( - serviceName, - ipV6Address, - 5354, - "ABCDE" /* subtype */, - Collections.singletonMap("key", "value"), - INTERFACE_INDEX, - NETWORK); - client.processResponse(thirdResponse); + client.processResponse(createResponse( + serviceName, ipV6Address, 5354, subtype, + Collections.singletonMap("key", "value"), TEST_TTL), INTERFACE_INDEX, mockNetwork); - // Process the last response which is goodbye message. - final MdnsResponse lastResponse = mock(MdnsResponse.class); - doReturn(serviceName).when(lastResponse).getServiceInstanceName(); - doReturn(true).when(lastResponse).isGoodbye(); - client.processResponse(lastResponse); + // Process the last response which is goodbye message (with the main type, not subtype). + client.processResponse(createResponse( + serviceName, ipV6Address, 5354, SERVICE_TYPE_LABELS, + Collections.singletonMap("key", "value"), /* ptrTtlMillis= */ 0L), + INTERFACE_INDEX, mockNetwork); // Verify onServiceNameDiscovered was first called for the initial response. inOrder.verify(mockListenerOne).onServiceNameDiscovered(serviceInfoCaptor.capture()); verifyServiceInfo(serviceInfoCaptor.getAllValues().get(0), serviceName, SERVICE_TYPE_LABELS, - null /* ipv4Address */, - null /* ipv6Address */, + List.of() /* ipv4Address */, + List.of() /* ipv6Address */, 5353 /* port */, - Collections.singletonList("ABCDE") /* subTypes */, + Collections.singletonList(subtype) /* subTypes */, Collections.singletonMap("key", null) /* attributes */, INTERFACE_INDEX, - NETWORK); + mockNetwork); // Verify onServiceFound was second called for the second response. inOrder.verify(mockListenerOne).onServiceFound(serviceInfoCaptor.capture()); verifyServiceInfo(serviceInfoCaptor.getAllValues().get(1), serviceName, SERVICE_TYPE_LABELS, - ipV4Address /* ipv4Address */, - null /* ipv6Address */, + List.of(ipV4Address) /* ipv4Address */, + List.of() /* ipv6Address */, 5353 /* port */, - Collections.singletonList("ABCDE") /* subTypes */, + Collections.singletonList(subtype) /* subTypes */, Collections.singletonMap("key", null) /* attributes */, INTERFACE_INDEX, - NETWORK); + mockNetwork); // Verify onServiceUpdated was third called for the third response. inOrder.verify(mockListenerOne).onServiceUpdated(serviceInfoCaptor.capture()); verifyServiceInfo(serviceInfoCaptor.getAllValues().get(2), serviceName, SERVICE_TYPE_LABELS, - ipV4Address /* ipv4Address */, - ipV6Address /* ipv6Address */, + List.of(ipV4Address) /* ipv4Address */, + List.of(ipV6Address) /* ipv6Address */, 5354 /* port */, - Collections.singletonList("ABCDE") /* subTypes */, + Collections.singletonList(subtype) /* subTypes */, Collections.singletonMap("key", "value") /* attributes */, INTERFACE_INDEX, - NETWORK); + mockNetwork); // Verify onServiceRemoved was called for the last response. inOrder.verify(mockListenerOne).onServiceRemoved(serviceInfoCaptor.capture()); verifyServiceInfo(serviceInfoCaptor.getAllValues().get(3), serviceName, SERVICE_TYPE_LABELS, - ipV4Address /* ipv4Address */, - ipV6Address /* ipv6Address */, + List.of(ipV4Address) /* ipv4Address */, + List.of(ipV6Address) /* ipv6Address */, 5354 /* port */, Collections.singletonList("ABCDE") /* subTypes */, Collections.singletonMap("key", "value") /* attributes */, INTERFACE_INDEX, - NETWORK); + mockNetwork); // Verify onServiceNameRemoved was called for the last response. inOrder.verify(mockListenerOne).onServiceNameRemoved(serviceInfoCaptor.capture()); verifyServiceInfo(serviceInfoCaptor.getAllValues().get(4), serviceName, SERVICE_TYPE_LABELS, - ipV4Address /* ipv4Address */, - ipV6Address /* ipv6Address */, + List.of(ipV4Address) /* ipv4Address */, + List.of(ipV6Address) /* ipv6Address */, 5354 /* port */, Collections.singletonList("ABCDE") /* subTypes */, Collections.singletonMap("key", "value") /* attributes */, INTERFACE_INDEX, - NETWORK); + mockNetwork); + } + + @Test + public void testProcessResponse_Resolve() throws Exception { + client = new MdnsServiceTypeClient( + SERVICE_TYPE, mockSocketClient, currentThreadExecutor, mockNetwork, mockSharedLog); + + final String instanceName = "service-instance"; + final String[] hostname = new String[] { "testhost "}; + final String ipV4Address = "192.0.2.0"; + final String ipV6Address = "2001:db8::"; + + final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder() + .setResolveInstanceName(instanceName).build(); + + client.startSendAndReceive(mockListenerOne, resolveOptions); + InOrder inOrder = inOrder(mockListenerOne, mockSocketClient); + + // Verify a query for SRV/TXT was sent, but no PTR query + final ArgumentCaptor<DatagramPacket> srvTxtQueryCaptor = + ArgumentCaptor.forClass(DatagramPacket.class); + currentThreadExecutor.getAndClearLastScheduledRunnable().run(); + // Send twice for IPv4 and IPv6 + inOrder.verify(mockSocketClient, times(2)).sendUnicastPacket(srvTxtQueryCaptor.capture(), + eq(mockNetwork)); + + final MdnsPacket srvTxtQueryPacket = MdnsPacket.parse( + new MdnsPacketReader(srvTxtQueryCaptor.getValue())); + final List<MdnsRecord> srvTxtQuestions = srvTxtQueryPacket.questions; + + final String[] serviceName = Stream.concat(Stream.of(instanceName), + Arrays.stream(SERVICE_TYPE_LABELS)).toArray(String[]::new); + assertFalse(srvTxtQuestions.stream().anyMatch(q -> q.getType() == MdnsRecord.TYPE_PTR)); + assertTrue(srvTxtQuestions.stream().anyMatch(q -> + q.getType() == MdnsRecord.TYPE_SRV && Arrays.equals(q.name, serviceName))); + assertTrue(srvTxtQuestions.stream().anyMatch(q -> + q.getType() == MdnsRecord.TYPE_TXT && Arrays.equals(q.name, serviceName))); + + // Process a response with SRV+TXT + final MdnsPacket srvTxtResponse = new MdnsPacket( + 0 /* flags */, + Collections.emptyList() /* questions */, + List.of( + new MdnsServiceRecord(serviceName, 0L /* receiptTimeMillis */, + true /* cacheFlush */, TEST_TTL, 0 /* servicePriority */, + 0 /* serviceWeight */, 1234 /* servicePort */, hostname), + new MdnsTextRecord(serviceName, 0L /* receiptTimeMillis */, + true /* cacheFlush */, TEST_TTL, + Collections.emptyList() /* entries */)), + Collections.emptyList() /* authorityRecords */, + Collections.emptyList() /* additionalRecords */); + + client.processResponse(srvTxtResponse, INTERFACE_INDEX, mockNetwork); + + // Expect a query for A/AAAA + final ArgumentCaptor<DatagramPacket> addressQueryCaptor = + ArgumentCaptor.forClass(DatagramPacket.class); + currentThreadExecutor.getAndClearLastScheduledRunnable().run(); + inOrder.verify(mockSocketClient, times(2)).sendMulticastPacket(addressQueryCaptor.capture(), + eq(mockNetwork)); + + final MdnsPacket addressQueryPacket = MdnsPacket.parse( + new MdnsPacketReader(addressQueryCaptor.getValue())); + final List<MdnsRecord> addressQueryQuestions = addressQueryPacket.questions; + assertTrue(addressQueryQuestions.stream().anyMatch(q -> + q.getType() == MdnsRecord.TYPE_A && Arrays.equals(q.name, hostname))); + assertTrue(addressQueryQuestions.stream().anyMatch(q -> + q.getType() == MdnsRecord.TYPE_AAAA && Arrays.equals(q.name, hostname))); + + // Process a response with address records + final MdnsPacket addressResponse = new MdnsPacket( + 0 /* flags */, + Collections.emptyList() /* questions */, + List.of( + new MdnsInetAddressRecord(hostname, 0L /* receiptTimeMillis */, + true /* cacheFlush */, TEST_TTL, + InetAddresses.parseNumericAddress(ipV4Address)), + new MdnsInetAddressRecord(hostname, 0L /* receiptTimeMillis */, + true /* cacheFlush */, TEST_TTL, + InetAddresses.parseNumericAddress(ipV6Address))), + Collections.emptyList() /* authorityRecords */, + Collections.emptyList() /* additionalRecords */); + + inOrder.verify(mockListenerOne, never()).onServiceNameDiscovered(any()); + client.processResponse(addressResponse, INTERFACE_INDEX, mockNetwork); + + inOrder.verify(mockListenerOne).onServiceFound(serviceInfoCaptor.capture()); + verifyServiceInfo(serviceInfoCaptor.getValue(), + instanceName, + SERVICE_TYPE_LABELS, + List.of(ipV4Address), + List.of(ipV6Address), + 1234 /* port */, + Collections.emptyList() /* subTypes */, + Collections.emptyMap() /* attributes */, + INTERFACE_INDEX, + mockNetwork); + } + + @Test + public void testProcessResponse_ResolveExcludesOtherServices() { + client = new MdnsServiceTypeClient( + SERVICE_TYPE, mockSocketClient, currentThreadExecutor, mockNetwork, mockSharedLog); + + final String requestedInstance = "instance1"; + final String otherInstance = "instance2"; + final String ipV4Address = "192.0.2.0"; + final String ipV6Address = "2001:db8::"; + final String capitalizedRequestInstance = "Instance1"; + + final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder() + // Use different case in the options + .setResolveInstanceName(capitalizedRequestInstance).build(); + + client.startSendAndReceive(mockListenerOne, resolveOptions); + client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); + + // Complete response from instanceName + client.processResponse(createResponse( + requestedInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, + Collections.emptyMap() /* textAttributes */, TEST_TTL), + INTERFACE_INDEX, mockNetwork); + + // Complete response from otherInstanceName + client.processResponse(createResponse( + otherInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, + Collections.emptyMap() /* textAttributes */, TEST_TTL), + INTERFACE_INDEX, mockNetwork); + + // Address update from otherInstanceName + client.processResponse(createResponse( + otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS, + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); + + // Goodbye from otherInstanceName + client.processResponse(createResponse( + otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS, + Collections.emptyMap(), 0L /* ttl */), INTERFACE_INDEX, mockNetwork); + + // mockListenerOne gets notified for the requested instance + verify(mockListenerOne).onServiceNameDiscovered( + matchServiceName(capitalizedRequestInstance)); + verify(mockListenerOne).onServiceFound(matchServiceName(capitalizedRequestInstance)); + + // ...but does not get any callback for the other instance + verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance)); + verify(mockListenerOne, never()).onServiceNameDiscovered(matchServiceName(otherInstance)); + verify(mockListenerOne, never()).onServiceUpdated(matchServiceName(otherInstance)); + verify(mockListenerOne, never()).onServiceRemoved(matchServiceName(otherInstance)); + + // mockListenerTwo gets notified for both though + final InOrder inOrder = inOrder(mockListenerTwo); + inOrder.verify(mockListenerTwo).onServiceNameDiscovered( + matchServiceName(capitalizedRequestInstance)); + inOrder.verify(mockListenerTwo).onServiceFound( + matchServiceName(capitalizedRequestInstance)); + + inOrder.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance)); + inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance)); + inOrder.verify(mockListenerTwo).onServiceUpdated(matchServiceName(otherInstance)); + inOrder.verify(mockListenerTwo).onServiceRemoved(matchServiceName(otherInstance)); + } + + @Test + public void testProcessResponse_SubtypeDiscoveryLimitedToSubtype() { + client = new MdnsServiceTypeClient( + SERVICE_TYPE, mockSocketClient, currentThreadExecutor, mockNetwork, mockSharedLog); + + final String matchingInstance = "instance1"; + final String subtype = "_subtype"; + final String otherInstance = "instance2"; + final String ipV4Address = "192.0.2.0"; + final String ipV6Address = "2001:db8::"; + + final MdnsSearchOptions options = MdnsSearchOptions.newBuilder() + // Search with different case. Note MdnsSearchOptions subtype doesn't start with "_" + .addSubtype("Subtype").build(); + + client.startSendAndReceive(mockListenerOne, options); + client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); + + // Complete response from instanceName + final MdnsPacket packetWithoutSubtype = createResponse( + matchingInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, + Collections.emptyMap() /* textAttributes */, TEST_TTL); + final MdnsPointerRecord originalPtr = (MdnsPointerRecord) CollectionUtils.findFirst( + packetWithoutSubtype.answers, r -> r instanceof MdnsPointerRecord); + + // Add a subtype PTR record + final ArrayList<MdnsRecord> newAnswers = new ArrayList<>(packetWithoutSubtype.answers); + newAnswers.add(new MdnsPointerRecord( + // PTR should be _subtype._sub._type._tcp.local -> instance1._type._tcp.local + Stream.concat(Stream.of(subtype, "_sub"), Arrays.stream(SERVICE_TYPE_LABELS)) + .toArray(String[]::new), + originalPtr.getReceiptTime(), originalPtr.getCacheFlush(), originalPtr.getTtl(), + originalPtr.getPointer())); + final MdnsPacket packetWithSubtype = new MdnsPacket( + packetWithoutSubtype.flags, + packetWithoutSubtype.questions, + newAnswers, + packetWithoutSubtype.authorityRecords, + packetWithoutSubtype.additionalRecords); + client.processResponse(packetWithSubtype, INTERFACE_INDEX, mockNetwork); + + // Complete response from otherInstanceName, without subtype + client.processResponse(createResponse( + otherInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, + Collections.emptyMap() /* textAttributes */, TEST_TTL), + INTERFACE_INDEX, mockNetwork); + + // Address update from otherInstanceName + client.processResponse(createResponse( + otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS, + Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork); + + // Goodbye from otherInstanceName + client.processResponse(createResponse( + otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS, + Collections.emptyMap(), 0L /* ttl */), INTERFACE_INDEX, mockNetwork); + + // mockListenerOne gets notified for the requested instance + final ArgumentMatcher<MdnsServiceInfo> subtypeInstanceMatcher = info -> + info.getServiceInstanceName().equals(matchingInstance) + && info.getSubtypes().equals(Collections.singletonList(subtype)); + verify(mockListenerOne).onServiceNameDiscovered(argThat(subtypeInstanceMatcher)); + verify(mockListenerOne).onServiceFound(argThat(subtypeInstanceMatcher)); + + // ...but does not get any callback for the other instance + verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance)); + verify(mockListenerOne, never()).onServiceNameDiscovered(matchServiceName(otherInstance)); + verify(mockListenerOne, never()).onServiceUpdated(matchServiceName(otherInstance)); + verify(mockListenerOne, never()).onServiceRemoved(matchServiceName(otherInstance)); + + // mockListenerTwo gets notified for both though + final InOrder inOrder = inOrder(mockListenerTwo); + inOrder.verify(mockListenerTwo).onServiceNameDiscovered(argThat(subtypeInstanceMatcher)); + inOrder.verify(mockListenerTwo).onServiceFound(argThat(subtypeInstanceMatcher)); + + inOrder.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance)); + inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance)); + inOrder.verify(mockListenerTwo).onServiceUpdated(matchServiceName(otherInstance)); + inOrder.verify(mockListenerTwo).onServiceRemoved(matchServiceName(otherInstance)); + } + + @Test + public void testNotifySocketDestroyed() throws Exception { + client = new MdnsServiceTypeClient( + SERVICE_TYPE, mockSocketClient, currentThreadExecutor, mockNetwork, mockSharedLog); + + final String requestedInstance = "instance1"; + final String otherInstance = "instance2"; + final String ipV4Address = "192.0.2.0"; + + final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder() + .setResolveInstanceName("instance1").build(); + + client.startSendAndReceive(mockListenerOne, resolveOptions); + // Ensure the first task is executed so it schedules a future task + currentThreadExecutor.getAndClearSubmittedFuture().get( + TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); + client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); + + // Filing the second request cancels the first future + verify(expectedSendFutures[0]).cancel(true); + + // Ensure it gets executed too + currentThreadExecutor.getAndClearSubmittedFuture().get( + TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); + + // Complete response from instanceName + client.processResponse(createResponse( + requestedInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, + Collections.emptyMap() /* textAttributes */, TEST_TTL), + INTERFACE_INDEX, mockNetwork); + + // Complete response from otherInstanceName + client.processResponse(createResponse( + otherInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, + Collections.emptyMap() /* textAttributes */, TEST_TTL), + INTERFACE_INDEX, mockNetwork); + + verify(expectedSendFutures[1], never()).cancel(true); + client.notifySocketDestroyed(); + verify(expectedSendFutures[1]).cancel(true); + + // mockListenerOne gets notified for the requested instance + final InOrder inOrder1 = inOrder(mockListenerOne); + inOrder1.verify(mockListenerOne).onServiceNameDiscovered( + matchServiceName(requestedInstance)); + inOrder1.verify(mockListenerOne).onServiceFound(matchServiceName(requestedInstance)); + inOrder1.verify(mockListenerOne).onServiceRemoved(matchServiceName(requestedInstance)); + inOrder1.verify(mockListenerOne).onServiceNameRemoved(matchServiceName(requestedInstance)); + verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance)); + verify(mockListenerOne, never()).onServiceNameDiscovered(matchServiceName(otherInstance)); + verify(mockListenerOne, never()).onServiceRemoved(matchServiceName(otherInstance)); + verify(mockListenerOne, never()).onServiceNameRemoved(matchServiceName(otherInstance)); + + // mockListenerTwo gets notified for both though + final InOrder inOrder2 = inOrder(mockListenerTwo); + inOrder2.verify(mockListenerTwo).onServiceNameDiscovered( + matchServiceName(requestedInstance)); + inOrder2.verify(mockListenerTwo).onServiceFound(matchServiceName(requestedInstance)); + inOrder2.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance)); + inOrder2.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance)); + inOrder2.verify(mockListenerTwo).onServiceRemoved(matchServiceName(otherInstance)); + inOrder2.verify(mockListenerTwo).onServiceNameRemoved(matchServiceName(otherInstance)); + inOrder2.verify(mockListenerTwo).onServiceRemoved(matchServiceName(requestedInstance)); + inOrder2.verify(mockListenerTwo).onServiceNameRemoved(matchServiceName(requestedInstance)); + } + + private static MdnsServiceInfo matchServiceName(String name) { + return argThat(info -> info.getServiceInstanceName().equals(name)); } // verifies that the right query was enqueued with the right delay, and send query by executing // the runnable. private void verifyAndSendQuery(int index, long timeInMs, boolean expectsUnicastResponse) { + verifyAndSendQuery( + index, timeInMs, expectsUnicastResponse, true /* multipleSocketDiscovery */); + } + + private void verifyAndSendQuery(int index, long timeInMs, boolean expectsUnicastResponse, + boolean multipleSocketDiscovery) { assertEquals(currentThreadExecutor.getAndClearLastScheduledDelayInMs(), timeInMs); currentThreadExecutor.getAndClearLastScheduledRunnable().run(); if (expectsUnicastResponse) { - verify(mockSocketClient).sendUnicastPacket(expectedPackets[index]); + verify(mockSocketClient).sendUnicastPacket( + expectedIPv4Packets[index], mockNetwork); + if (multipleSocketDiscovery) { + verify(mockSocketClient).sendUnicastPacket( + expectedIPv6Packets[index], mockNetwork); + } } else { - verify(mockSocketClient).sendMulticastPacket(expectedPackets[index]); + verify(mockSocketClient).sendMulticastPacket( + expectedIPv4Packets[index], mockNetwork); + if (multipleSocketDiscovery) { + verify(mockSocketClient).sendMulticastPacket( + expectedIPv6Packets[index], mockNetwork); + } } } @@ -941,6 +1276,7 @@ private long lastScheduledDelayInMs; private Runnable lastScheduledRunnable; private Runnable lastSubmittedRunnable; + private Future<?> lastSubmittedFuture; private int futureIndex; FakeExecutor() { @@ -952,6 +1288,7 @@ public Future<?> submit(Runnable command) { Future<?> future = super.submit(command); lastSubmittedRunnable = command; + lastSubmittedFuture = future; return future; } @@ -983,108 +1320,76 @@ lastSubmittedRunnable = null; return val; } + + Future<?> getAndClearSubmittedFuture() { + Future<?> val = lastSubmittedFuture; + lastSubmittedFuture = null; + return val; + } } - // Creates a mock mDNS response. - private MdnsResponse createMockResponse( - @NonNull String serviceInstanceName, - @NonNull String host, - int port, - @NonNull List<String> subtypes, - @NonNull Map<String, String> textAttributes, - int interfaceIndex, - Network network) - throws Exception { - String[] hostName = new String[]{"hostname"}; - MdnsServiceRecord serviceRecord = mock(MdnsServiceRecord.class); - when(serviceRecord.getServiceHost()).thenReturn(hostName); - when(serviceRecord.getServicePort()).thenReturn(port); - - MdnsResponse response = spy(new MdnsResponse(0, interfaceIndex, network)); - - MdnsInetAddressRecord inetAddressRecord = mock(MdnsInetAddressRecord.class); - if (host.contains(":")) { - when(inetAddressRecord.getInet6Address()) - .thenReturn((Inet6Address) Inet6Address.getByName(host)); - response.setInet6AddressRecord(inetAddressRecord); - } else { - when(inetAddressRecord.getInet4Address()) - .thenReturn((Inet4Address) Inet4Address.getByName(host)); - response.setInet4AddressRecord(inetAddressRecord); - } - - 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); - - doReturn(false).when(response).isGoodbye(); - doReturn(true).when(response).isComplete(); - doReturn(serviceInstanceName).when(response).getServiceInstanceName(); - doReturn(new ArrayList<>(subtypes)).when(response).getSubtypes(); - return response; - } - - // Creates a mDNS response. - private MdnsResponse createResponse( + private MdnsPacket createResponse( @NonNull String serviceInstanceName, @Nullable String host, int port, @NonNull String subtype, @NonNull Map<String, String> textAttributes, - int interfaceIndex, - Network network) + long ptrTtlMillis) throws Exception { - MdnsResponse response = new MdnsResponse(0, interfaceIndex, network); + final ArrayList<String> type = new ArrayList<>(); + type.add(subtype); + type.add(MdnsConstants.SUBTYPE_LABEL); + type.addAll(Arrays.asList(SERVICE_TYPE_LABELS)); + return createResponse(serviceInstanceName, host, port, type.toArray(new String[0]), + textAttributes, ptrTtlMillis); + } + + // Creates a mDNS response. + private MdnsPacket createResponse( + @NonNull String serviceInstanceName, + @Nullable String host, + int port, + @NonNull String[] type, + @NonNull Map<String, String> textAttributes, + long ptrTtlMillis) { + + final ArrayList<MdnsRecord> answerRecords = new ArrayList<>(); // Set PTR record + final ArrayList<String> serviceNameList = new ArrayList<>(); + serviceNameList.add(serviceInstanceName); + serviceNameList.addAll(Arrays.asList(type)); + final String[] serviceName = serviceNameList.toArray(new String[0]); final MdnsPointerRecord pointerRecord = new MdnsPointerRecord( - new String[]{subtype, MdnsConstants.SUBTYPE_LABEL, "test"} /* name */, - 0L /* receiptTimeMillis */, + type, + TEST_ELAPSED_REALTIME /* receiptTimeMillis */, false /* cacheFlush */, - 120000L /* ttlMillis */, - new String[]{serviceInstanceName}); - response.addPointerRecord(pointerRecord); + ptrTtlMillis, + serviceName); + answerRecords.add(pointerRecord); // Set SRV record. final MdnsServiceRecord serviceRecord = new MdnsServiceRecord( - new String[] {"service"} /* name */, - 0L /* receiptTimeMillis */, + serviceName, + TEST_ELAPSED_REALTIME /* receiptTimeMillis */, false /* cacheFlush */, - 120000L /* ttlMillis */, + TEST_TTL, 0 /* servicePriority */, 0 /* serviceWeight */, port, new String[]{"hostname"}); - response.setServiceRecord(serviceRecord); + answerRecords.add(serviceRecord); // Set A/AAAA record. if (host != null) { - if (InetAddresses.parseNumericAddress(host) instanceof Inet6Address) { - final MdnsInetAddressRecord inetAddressRecord = new MdnsInetAddressRecord( - new String[] {"address"} /* name */, - 0L /* receiptTimeMillis */, - false /* cacheFlush */, - 120000L /* ttlMillis */, - Inet6Address.getByName(host)); - response.setInet6AddressRecord(inetAddressRecord); - } else { - final MdnsInetAddressRecord inetAddressRecord = new MdnsInetAddressRecord( - new String[] {"address"} /* name */, - 0L /* receiptTimeMillis */, - false /* cacheFlush */, - 120000L /* ttlMillis */, - Inet4Address.getByName(host)); - response.setInet4AddressRecord(inetAddressRecord); - } + final InetAddress addr = InetAddresses.parseNumericAddress(host); + final MdnsInetAddressRecord inetAddressRecord = new MdnsInetAddressRecord( + new String[] {"hostname"} /* name */, + TEST_ELAPSED_REALTIME /* receiptTimeMillis */, + false /* cacheFlush */, + TEST_TTL, + addr); + answerRecords.add(inetAddressRecord); } // Set TXT record. @@ -1093,12 +1398,18 @@ textEntries.add(new TextEntry(kv.getKey(), kv.getValue().getBytes(UTF_8))); } final MdnsTextRecord textRecord = new MdnsTextRecord( - new String[] {"text"} /* name */, - 0L /* receiptTimeMillis */, + serviceName, + TEST_ELAPSED_REALTIME /* receiptTimeMillis */, false /* cacheFlush */, - 120000L /* ttlMillis */, + TEST_TTL, textEntries); - response.setTextRecord(textRecord); - return response; + answerRecords.add(textRecord); + return new MdnsPacket( + 0 /* flags */, + Collections.emptyList() /* questions */, + answerRecords, + Collections.emptyList() /* authorityRecords */, + Collections.emptyList() /* additionalRecords */ + ); } } \ No newline at end of file
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 1d61cd3..abb1747 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,11 @@ 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; @@ -48,7 +46,6 @@ 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; @@ -373,7 +370,7 @@ mdnsClient.startDiscovery(); verify(mockCallback, timeout(TIMEOUT).atLeast(1)) - .onResponseReceived(any(MdnsResponse.class)); + .onResponseReceived(any(MdnsPacket.class), anyInt(), any()); } @Test @@ -382,7 +379,7 @@ mdnsClient.startDiscovery(); verify(mockCallback, timeout(TIMEOUT).atLeastOnce()) - .onResponseReceived(any(MdnsResponse.class)); + .onResponseReceived(any(MdnsPacket.class), anyInt(), any()); mdnsClient.stopDiscovery(); } @@ -415,7 +412,8 @@ mdnsClient.startDiscovery(); verify(mockCallback, timeout(TIMEOUT).atLeast(1)) - .onFailedToParseMdnsResponse(anyInt(), eq(MdnsResponseErrorCode.ERROR_END_OF_FILE)); + .onFailedToParseMdnsResponse( + anyInt(), eq(MdnsResponseErrorCode.ERROR_END_OF_FILE), any()); mdnsClient.stopDiscovery(); } @@ -436,7 +434,8 @@ mdnsClient.startDiscovery(); verify(mockCallback, timeout(TIMEOUT).atLeast(1)) - .onFailedToParseMdnsResponse(1, MdnsResponseErrorCode.ERROR_END_OF_FILE); + .onFailedToParseMdnsResponse( + eq(1), eq(MdnsResponseErrorCode.ERROR_END_OF_FILE), any()); mdnsClient.stopDiscovery(); } @@ -514,7 +513,7 @@ mdnsClient.startDiscovery(); verify(mockCallback, timeout(TIMEOUT).atLeastOnce()) - .onResponseReceived(argThat(response -> response.getInterfaceIndex() == 21)); + .onResponseReceived(any(), eq(21), any()); } @Test @@ -536,11 +535,7 @@ 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()); + verify(mockCallback, timeout(TIMEOUT).atLeast(1)).onResponseReceived(any(), eq(-1), any()); } } \ No newline at end of file
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java index 2bb61a6a..4b87556 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
@@ -16,6 +16,13 @@ package com.android.server.connectivity.mdns; +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; import static com.android.testutils.ContextUtils.mockService; import static org.junit.Assert.assertEquals; @@ -23,27 +30,41 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; -import android.net.INetd; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.TetheringManager; import android.net.TetheringManager.TetheringEventCallback; import android.os.Build; import android.os.Handler; import android.os.HandlerThread; +import android.system.OsConstants; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.net.module.util.ArrayTrackRecord; +import com.android.net.module.util.SharedLog; +import com.android.net.module.util.netlink.NetlinkConstants; +import com.android.net.module.util.netlink.RtNetlinkAddressMessage; +import com.android.net.module.util.netlink.StructIfaddrMsg; +import com.android.net.module.util.netlink.StructNlMsgHdr; import com.android.server.connectivity.mdns.MdnsSocketProvider.Dependencies; +import com.android.server.connectivity.mdns.internal.SocketNetlinkMonitor; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; import com.android.testutils.HandlerUtils; @@ -56,23 +77,29 @@ import org.mockito.MockitoAnnotations; import java.io.IOException; +import java.net.Inet6Address; +import java.net.InetAddress; import java.util.Collections; import java.util.List; @RunWith(DevSdkIgnoreRunner.class) @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) public class MdnsSocketProviderTest { + private static final String TAG = MdnsSocketProviderTest.class.getSimpleName(); private static final String TEST_IFACE_NAME = "test"; private static final String LOCAL_ONLY_IFACE_NAME = "local_only"; private static final String TETHERED_IFACE_NAME = "tethered"; + private static final int TETHERED_IFACE_IDX = 32; private static final long DEFAULT_TIMEOUT = 2000L; private static final long NO_CALLBACK_TIMEOUT = 200L; private static final LinkAddress LINKADDRV4 = new LinkAddress("192.0.2.0/24"); private static final LinkAddress LINKADDRV6 = new LinkAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"); - private static final Network TEST_NETWORK = new Network(123); - private static final Network LOCAL_NETWORK = new Network(INetd.LOCAL_NET_ID); + private static final LinkAddress LINKADDRV6_FLAG_CHANGE = + new LinkAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64", 1 /* flags */, + 0 /* scope */); + private static final Network TEST_NETWORK = new Network(123); @Mock private Context mContext; @Mock private Dependencies mDeps; @Mock private ConnectivityManager mCm; @@ -84,28 +111,58 @@ private MdnsSocketProvider mSocketProvider; private NetworkCallback mNetworkCallback; private TetheringEventCallback mTetheringEventCallback; + private SharedLog mLog = new SharedLog("MdnsSocketProviderTest"); + private TestNetlinkMonitor mTestSocketNetLinkMonitor; @Before public void setUp() throws IOException { MockitoAnnotations.initMocks(this); mockService(mContext, ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mCm); + if (mContext.getSystemService(ConnectivityManager.class) == null) { + // Test is using mockito-extended + doCallRealMethod().when(mContext).getSystemService(ConnectivityManager.class); + } mockService(mContext, TetheringManager.class, Context.TETHERING_SERVICE, mTm); - doReturn(true).when(mDeps).canScanOnInterface(any()); - doReturn(mTestNetworkIfaceWrapper).when(mDeps).getNetworkInterfaceByName(TEST_IFACE_NAME); + if (mContext.getSystemService(TetheringManager.class) == null) { + // Test is using mockito-extended + doCallRealMethod().when(mContext).getSystemService(TetheringManager.class); + } + doReturn(mTestNetworkIfaceWrapper).when(mDeps).getNetworkInterfaceByName(anyString()); + doReturn(true).when(mTestNetworkIfaceWrapper).isUp(); + doReturn(true).when(mLocalOnlyIfaceWrapper).isUp(); + doReturn(true).when(mTetheredIfaceWrapper).isUp(); + doReturn(true).when(mTestNetworkIfaceWrapper).supportsMulticast(); + doReturn(true).when(mLocalOnlyIfaceWrapper).supportsMulticast(); + doReturn(true).when(mTetheredIfaceWrapper).supportsMulticast(); doReturn(mLocalOnlyIfaceWrapper).when(mDeps) .getNetworkInterfaceByName(LOCAL_ONLY_IFACE_NAME); doReturn(mTetheredIfaceWrapper).when(mDeps).getNetworkInterfaceByName(TETHERED_IFACE_NAME); doReturn(mock(MdnsInterfaceSocket.class)) - .when(mDeps).createMdnsInterfaceSocket(any(), anyInt()); + .when(mDeps).createMdnsInterfaceSocket(any(), anyInt(), any(), any()); + doReturn(TETHERED_IFACE_IDX).when(mDeps).getNetworkInterfaceIndexByName( + TETHERED_IFACE_NAME); final HandlerThread thread = new HandlerThread("MdnsSocketProviderTest"); thread.start(); mHandler = new Handler(thread.getLooper()); + doReturn(mTestSocketNetLinkMonitor).when(mDeps).createSocketNetlinkMonitor(any(), any(), + any()); + doAnswer(inv -> { + mTestSocketNetLinkMonitor = new TestNetlinkMonitor(inv.getArgument(0), + inv.getArgument(1), + inv.getArgument(2)); + return mTestSocketNetLinkMonitor; + }).when(mDeps).createSocketNetlinkMonitor(any(), any(), + any()); + mSocketProvider = new MdnsSocketProvider(mContext, thread.getLooper(), mDeps, mLog); + } + + private void startMonitoringSockets() { final ArgumentCaptor<NetworkCallback> nwCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class); final ArgumentCaptor<TetheringEventCallback> teCallbackCaptor = ArgumentCaptor.forClass(TetheringEventCallback.class); - mSocketProvider = new MdnsSocketProvider(mContext, thread.getLooper(), mDeps); + mHandler.post(mSocketProvider::startMonitoringSockets); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); verify(mCm).registerNetworkCallback(any(), nwCallbackCaptor.capture(), any()); @@ -113,6 +170,23 @@ mNetworkCallback = nwCallbackCaptor.getValue(); mTetheringEventCallback = teCallbackCaptor.getValue(); + + mHandler.post(mSocketProvider::startNetLinkMonitor); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + } + + private static class TestNetlinkMonitor extends SocketNetlinkMonitor { + TestNetlinkMonitor(@NonNull Handler handler, + @NonNull SharedLog log, + @Nullable MdnsSocketProvider.NetLinkMonitorCallBack cb) { + super(handler, log, cb); + } + + @Override + public void startMonitoring() { } + + @Override + public void stopMonitoring() { } } private class TestSocketCallback implements MdnsSocketProvider.SocketCallback { @@ -159,12 +233,13 @@ } @Override - public void onAddressesChanged(Network network, List<LinkAddress> addresses) { + public void onAddressesChanged(Network network, MdnsInterfaceSocket socket, + List<LinkAddress> addresses) { mHistory.add(new AddressesChangedEvent(network, addresses)); } public void expectedSocketCreatedForNetwork(Network network, List<LinkAddress> addresses) { - final SocketEvent event = mHistory.poll(DEFAULT_TIMEOUT, c -> true); + final SocketEvent event = mHistory.poll(0L /* timeoutMs */, c -> true); assertNotNull(event); assertTrue(event instanceof SocketCreatedEvent); assertEquals(network, event.mNetwork); @@ -172,7 +247,7 @@ } public void expectedInterfaceDestroyedForNetwork(Network network) { - final SocketEvent event = mHistory.poll(DEFAULT_TIMEOUT, c -> true); + final SocketEvent event = mHistory.poll(0L /* timeoutMs */, c -> true); assertNotNull(event); assertTrue(event instanceof InterfaceDestroyedEvent); assertEquals(network, event.mNetwork); @@ -180,7 +255,7 @@ public void expectedAddressesChangedForNetwork(Network network, List<LinkAddress> addresses) { - final SocketEvent event = mHistory.poll(DEFAULT_TIMEOUT, c -> true); + final SocketEvent event = mHistory.poll(0L /* timeoutMs */, c -> true); assertNotNull(event); assertTrue(event instanceof AddressesChangedEvent); assertEquals(network, event.mNetwork); @@ -193,19 +268,34 @@ } } + private static NetworkCapabilities makeCapabilities(int... transports) { + final NetworkCapabilities nc = new NetworkCapabilities(); + for (int transport : transports) { + nc.addTransportType(transport); + } + return nc; + } + + private void postNetworkAvailable(int... transports) { + final LinkProperties testLp = new LinkProperties(); + testLp.setInterfaceName(TEST_IFACE_NAME); + testLp.setLinkAddresses(List.of(LINKADDRV4)); + final NetworkCapabilities testNc = makeCapabilities(transports); + mHandler.post(() -> mNetworkCallback.onCapabilitiesChanged(TEST_NETWORK, testNc)); + mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, testLp)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + } + @Test public void testSocketRequestAndUnrequestSocket() { + startMonitoringSockets(); + final TestSocketCallback testCallback1 = new TestSocketCallback(); mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback1)); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); testCallback1.expectedNoCallback(); - final LinkProperties testLp = new LinkProperties(); - testLp.setInterfaceName(TEST_IFACE_NAME); - testLp.setLinkAddresses(List.of(LINKADDRV4)); - mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, testLp)); - HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); - verify(mTestNetworkIfaceWrapper).getNetworkInterface(); + postNetworkAvailable(TRANSPORT_WIFI); testCallback1.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4)); final TestSocketCallback testCallback2 = new TestSocketCallback(); @@ -227,7 +317,7 @@ verify(mLocalOnlyIfaceWrapper).getNetworkInterface(); testCallback1.expectedNoCallback(); testCallback2.expectedNoCallback(); - testCallback3.expectedSocketCreatedForNetwork(LOCAL_NETWORK, List.of()); + testCallback3.expectedSocketCreatedForNetwork(null /* network */, List.of()); mHandler.post(() -> mTetheringEventCallback.onTetheredInterfacesChanged( List.of(TETHERED_IFACE_NAME))); @@ -235,7 +325,7 @@ verify(mTetheredIfaceWrapper).getNetworkInterface(); testCallback1.expectedNoCallback(); testCallback2.expectedNoCallback(); - testCallback3.expectedSocketCreatedForNetwork(LOCAL_NETWORK, List.of()); + testCallback3.expectedSocketCreatedForNetwork(null /* network */, List.of()); mHandler.post(() -> mSocketProvider.unrequestSocket(testCallback1)); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); @@ -253,22 +343,178 @@ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); testCallback1.expectedNoCallback(); testCallback2.expectedNoCallback(); - testCallback3.expectedInterfaceDestroyedForNetwork(LOCAL_NETWORK); + testCallback3.expectedInterfaceDestroyedForNetwork(null /* network */); mHandler.post(() -> mSocketProvider.unrequestSocket(testCallback3)); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); testCallback1.expectedNoCallback(); testCallback2.expectedNoCallback(); + // There was still a tethered interface, but no callback should be sent once unregistered testCallback3.expectedNoCallback(); } + private RtNetlinkAddressMessage createNetworkAddressUpdateNetLink( + short msgType, LinkAddress linkAddress, int ifIndex, int flags) { + final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); + nlmsghdr.nlmsg_type = msgType; + nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlmsghdr.nlmsg_seq = 1; + + InetAddress ip = linkAddress.getAddress(); + + final byte family = + (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); + StructIfaddrMsg structIfaddrMsg = new StructIfaddrMsg(family, + (short) linkAddress.getPrefixLength(), + (short) linkAddress.getFlags(), (short) linkAddress.getScope(), ifIndex); + + return new RtNetlinkAddressMessage(nlmsghdr, structIfaddrMsg, ip, + null /* structIfacacheInfo */, flags); + } + + @Test + public void testDownstreamNetworkAddressUpdateFromNetlink() { + startMonitoringSockets(); + final TestSocketCallback testCallbackAll = new TestSocketCallback(); + mHandler.post(() -> mSocketProvider.requestSocket(null /* network */, testCallbackAll)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + + // Address add message arrived before the interface is created. + RtNetlinkAddressMessage addIpv4AddrMsg = createNetworkAddressUpdateNetLink( + NetlinkConstants.RTM_NEWADDR, + LINKADDRV4, + TETHERED_IFACE_IDX, + 0 /* flags */); + mHandler.post( + () -> mTestSocketNetLinkMonitor.processNetlinkMessage(addIpv4AddrMsg, + 0 /* whenMs */)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + + // Interface is created. + mHandler.post(() -> mTetheringEventCallback.onTetheredInterfacesChanged( + List.of(TETHERED_IFACE_NAME))); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mTetheredIfaceWrapper).getNetworkInterface(); + testCallbackAll.expectedSocketCreatedForNetwork(null /* network */, List.of(LINKADDRV4)); + + // Old Address removed. + RtNetlinkAddressMessage removeIpv4AddrMsg = createNetworkAddressUpdateNetLink( + NetlinkConstants.RTM_DELADDR, + LINKADDRV4, + TETHERED_IFACE_IDX, + 0 /* flags */); + mHandler.post( + () -> mTestSocketNetLinkMonitor.processNetlinkMessage(removeIpv4AddrMsg, + 0 /* whenMs */)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + testCallbackAll.expectedAddressesChangedForNetwork(null /* network */, List.of()); + + // New address added. + RtNetlinkAddressMessage addIpv6AddrMsg = createNetworkAddressUpdateNetLink( + NetlinkConstants.RTM_NEWADDR, + LINKADDRV6, + TETHERED_IFACE_IDX, + 0 /* flags */); + mHandler.post(() -> mTestSocketNetLinkMonitor.processNetlinkMessage(addIpv6AddrMsg, + 0 /* whenMs */)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + testCallbackAll.expectedAddressesChangedForNetwork(null /* network */, List.of(LINKADDRV6)); + + // Address updated + RtNetlinkAddressMessage updateIpv6AddrMsg = createNetworkAddressUpdateNetLink( + NetlinkConstants.RTM_NEWADDR, + LINKADDRV6, + TETHERED_IFACE_IDX, + 1 /* flags */); + mHandler.post( + () -> mTestSocketNetLinkMonitor.processNetlinkMessage(updateIpv6AddrMsg, + 0 /* whenMs */)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + testCallbackAll.expectedAddressesChangedForNetwork(null /* network */, + List.of(LINKADDRV6_FLAG_CHANGE)); + } + @Test public void testAddressesChanged() throws Exception { + startMonitoringSockets(); + final TestSocketCallback testCallback = new TestSocketCallback(); mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback)); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); testCallback.expectedNoCallback(); + postNetworkAvailable(TRANSPORT_WIFI); + testCallback.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4)); + + final LinkProperties newTestLp = new LinkProperties(); + newTestLp.setInterfaceName(TEST_IFACE_NAME); + newTestLp.setLinkAddresses(List.of(LINKADDRV4, LINKADDRV6)); + mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, newTestLp)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + testCallback.expectedAddressesChangedForNetwork( + TEST_NETWORK, List.of(LINKADDRV4, LINKADDRV6)); + } + + @Test + public void testStartAndStopMonitoringSockets() { + // Stop monitoring sockets before start. Should not unregister any network callback. + mHandler.post(mSocketProvider::requestStopWhenInactive); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mCm, never()).unregisterNetworkCallback(any(NetworkCallback.class)); + verify(mTm, never()).unregisterTetheringEventCallback(any(TetheringEventCallback.class)); + + // Start sockets monitoring. + startMonitoringSockets(); + // Request a socket then unrequest it. Expect no network callback unregistration. + final TestSocketCallback testCallback = new TestSocketCallback(); + mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + testCallback.expectedNoCallback(); + mHandler.post(()-> mSocketProvider.unrequestSocket(testCallback)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mCm, never()).unregisterNetworkCallback(any(NetworkCallback.class)); + verify(mTm, never()).unregisterTetheringEventCallback(any(TetheringEventCallback.class)); + // Request stop and it should unregister network callback immediately because there is no + // socket request. + mHandler.post(mSocketProvider::requestStopWhenInactive); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mCm, times(1)).unregisterNetworkCallback(any(NetworkCallback.class)); + verify(mTm, times(1)).unregisterTetheringEventCallback(any(TetheringEventCallback.class)); + + // Start sockets monitoring and request a socket again. + mHandler.post(mSocketProvider::startMonitoringSockets); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mCm, times(2)).registerNetworkCallback(any(), any(NetworkCallback.class), any()); + verify(mTm, times(2)).registerTetheringEventCallback( + any(), any(TetheringEventCallback.class)); + final TestSocketCallback testCallback2 = new TestSocketCallback(); + mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback2)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + testCallback2.expectedNoCallback(); + // Try to stop monitoring sockets but should be ignored and wait until all socket are + // unrequested. + mHandler.post(mSocketProvider::requestStopWhenInactive); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mCm, times(1)).unregisterNetworkCallback(any(NetworkCallback.class)); + verify(mTm, times(1)).unregisterTetheringEventCallback(any()); + // Unrequest the socket then network callbacks should be unregistered. + mHandler.post(()-> mSocketProvider.unrequestSocket(testCallback2)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mCm, times(2)).unregisterNetworkCallback(any(NetworkCallback.class)); + verify(mTm, times(2)).unregisterTetheringEventCallback(any(TetheringEventCallback.class)); + } + + @Test + public void testLinkPropertiesAreClearedAfterStopMonitoringSockets() { + startMonitoringSockets(); + + // Request a socket with null network. + final TestSocketCallback testCallback = new TestSocketCallback(); + mHandler.post(() -> mSocketProvider.requestSocket(null, testCallback)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + testCallback.expectedNoCallback(); + + // Notify a LinkPropertiesChanged with TEST_NETWORK. final LinkProperties testLp = new LinkProperties(); testLp.setInterfaceName(TEST_IFACE_NAME); testLp.setLinkAddresses(List.of(LINKADDRV4)); @@ -277,13 +523,109 @@ verify(mTestNetworkIfaceWrapper, times(1)).getNetworkInterface(); testCallback.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4)); - final LinkProperties newTestLp = new LinkProperties(); - newTestLp.setInterfaceName(TEST_IFACE_NAME); - newTestLp.setLinkAddresses(List.of(LINKADDRV4, LINKADDRV6)); - mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, newTestLp)); + // Try to stop monitoring and unrequest the socket. + mHandler.post(mSocketProvider::requestStopWhenInactive); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); - verify(mTestNetworkIfaceWrapper, times(1)).getNetworkInterface(); - testCallback.expectedAddressesChangedForNetwork( - TEST_NETWORK, List.of(LINKADDRV4, LINKADDRV6)); + mHandler.post(()-> mSocketProvider.unrequestSocket(testCallback)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + // No callback sent when unregistered + testCallback.expectedNoCallback(); + verify(mCm, times(1)).unregisterNetworkCallback(any(NetworkCallback.class)); + verify(mTm, times(1)).unregisterTetheringEventCallback(any()); + + // Start sockets monitoring and request a socket again. Expected no socket created callback + // because all saved LinkProperties has been cleared. + mHandler.post(mSocketProvider::startMonitoringSockets); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mCm, times(2)).registerNetworkCallback(any(), any(NetworkCallback.class), any()); + verify(mTm, times(2)).registerTetheringEventCallback( + any(), any(TetheringEventCallback.class)); + mHandler.post(() -> mSocketProvider.requestSocket(null, testCallback)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + testCallback.expectedNoCallback(); + + // Notify a LinkPropertiesChanged with another network. + final LinkProperties otherLp = new LinkProperties(); + final LinkAddress otherAddress = new LinkAddress("192.0.2.1/24"); + final Network otherNetwork = new Network(456); + otherLp.setInterfaceName("test2"); + otherLp.setLinkAddresses(List.of(otherAddress)); + mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(otherNetwork, otherLp)); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mTestNetworkIfaceWrapper, times(2)).getNetworkInterface(); + testCallback.expectedSocketCreatedForNetwork(otherNetwork, List.of(otherAddress)); + } + + @Test + public void testNoSocketCreatedForCellular() { + startMonitoringSockets(); + + final TestSocketCallback testCallback = new TestSocketCallback(); + mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback)); + + postNetworkAvailable(TRANSPORT_CELLULAR); + testCallback.expectedNoCallback(); + } + + @Test + public void testNoSocketCreatedForNonMulticastInterface() throws Exception { + doReturn(false).when(mTestNetworkIfaceWrapper).supportsMulticast(); + startMonitoringSockets(); + + final TestSocketCallback testCallback = new TestSocketCallback(); + mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback)); + + postNetworkAvailable(TRANSPORT_BLUETOOTH); + testCallback.expectedNoCallback(); + } + + @Test + public void testSocketCreatedForMulticastInterface() throws Exception { + doReturn(true).when(mTestNetworkIfaceWrapper).supportsMulticast(); + startMonitoringSockets(); + + final TestSocketCallback testCallback = new TestSocketCallback(); + mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback)); + + postNetworkAvailable(TRANSPORT_BLUETOOTH); + testCallback.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4)); + } + + @Test + public void testNoSocketCreatedForPTPInterface() throws Exception { + doReturn(true).when(mTestNetworkIfaceWrapper).isPointToPoint(); + startMonitoringSockets(); + + final TestSocketCallback testCallback = new TestSocketCallback(); + mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback)); + + postNetworkAvailable(TRANSPORT_BLUETOOTH); + testCallback.expectedNoCallback(); + } + + @Test + public void testNoSocketCreatedForVPNInterface() throws Exception { + // VPN interfaces generally also have IFF_POINTOPOINT, but even if they don't, they should + // not be included even with TRANSPORT_WIFI. + doReturn(false).when(mTestNetworkIfaceWrapper).supportsMulticast(); + startMonitoringSockets(); + + final TestSocketCallback testCallback = new TestSocketCallback(); + mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback)); + + postNetworkAvailable(TRANSPORT_VPN, TRANSPORT_WIFI); + testCallback.expectedNoCallback(); + } + + @Test + public void testSocketCreatedForWifiWithoutMulticastFlag() throws Exception { + doReturn(false).when(mTestNetworkIfaceWrapper).supportsMulticast(); + startMonitoringSockets(); + + final TestSocketCallback testCallback = new TestSocketCallback(); + mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback)); + + postNetworkAvailable(TRANSPORT_WIFI); + testCallback.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4)); } }
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitorTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitorTest.kt new file mode 100644 index 0000000..c62a081 --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitorTest.kt
@@ -0,0 +1,90 @@ +package com.android.server.connectivity.mdns.internal + +import android.net.LinkAddress +import android.os.Build +import android.os.Handler +import android.os.HandlerThread +import android.system.OsConstants +import com.android.net.module.util.SharedLog +import com.android.net.module.util.netlink.NetlinkConstants +import com.android.net.module.util.netlink.RtNetlinkAddressMessage +import com.android.net.module.util.netlink.StructIfaddrMsg +import com.android.net.module.util.netlink.StructNlMsgHdr +import com.android.server.connectivity.mdns.MdnsAdvertiserTest +import com.android.server.connectivity.mdns.MdnsSocketProvider +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito +import org.mockito.Mockito.argThat +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +private val LINKADDRV4 = LinkAddress("192.0.2.0/24") +private val IFACE_IDX = 32 + +@RunWith(DevSdkIgnoreRunner::class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) +internal class SocketNetlinkMonitorTest { + private val thread = HandlerThread(MdnsAdvertiserTest::class.simpleName) + private val sharedlog = Mockito.mock(SharedLog::class.java) + private val netlinkMonitorCallBack = + Mockito.mock(MdnsSocketProvider.NetLinkMonitorCallBack::class.java) + + @Before + fun setUp() { + thread.start() + } + + @After + fun tearDown() { + thread.quitSafely() + } + + @Test + fun testHandleDeprecatedNetlinkMessage() { + val socketNetlinkMonitor = SocketNetlinkMonitor(Handler(thread.looper), sharedlog, + netlinkMonitorCallBack) + val nlmsghdr = StructNlMsgHdr().apply { + nlmsg_type = NetlinkConstants.RTM_NEWADDR + nlmsg_flags = (StructNlMsgHdr.NLM_F_REQUEST.toInt() + or StructNlMsgHdr.NLM_F_ACK.toInt()).toShort() + nlmsg_seq = 1 + } + val structIfaddrMsg = StructIfaddrMsg(OsConstants.AF_INET.toShort(), + LINKADDRV4.prefixLength.toShort(), + LINKADDRV4.flags.toShort(), + LINKADDRV4.scope.toShort(), IFACE_IDX) + // If the LinkAddress is not preferred, RTM_NEWADDR will not trigger + // addOrUpdateInterfaceAddress() callback. + val deprecatedAddNetLinkMessage = RtNetlinkAddressMessage(nlmsghdr, structIfaddrMsg, + LINKADDRV4.address, null /* structIfacacheInfo */, + LINKADDRV4.flags or OsConstants.IFA_F_DEPRECATED) + socketNetlinkMonitor.processNetlinkMessage(deprecatedAddNetLinkMessage, 0L /* whenMs */) + verify(netlinkMonitorCallBack, never()).addOrUpdateInterfaceAddress(eq(IFACE_IDX), + argThat { it.address == LINKADDRV4.address }) + + // If the LinkAddress is preferred, RTM_NEWADDR will trigger addOrUpdateInterfaceAddress() + // callback. + val preferredAddNetLinkMessage = RtNetlinkAddressMessage(nlmsghdr, structIfaddrMsg, + LINKADDRV4.address, null /* structIfacacheInfo */, + LINKADDRV4.flags or OsConstants.IFA_F_OPTIMISTIC) + socketNetlinkMonitor.processNetlinkMessage(preferredAddNetLinkMessage, 0L /* whenMs */) + verify(netlinkMonitorCallBack).addOrUpdateInterfaceAddress(eq(IFACE_IDX), + argThat { it.address == LINKADDRV4.address }) + + // Even if the LinkAddress is not preferred, RTM_DELADDR will trigger + // deleteInterfaceAddress() callback. + nlmsghdr.nlmsg_type = NetlinkConstants.RTM_DELADDR + val deprecatedDelNetLinkMessage = RtNetlinkAddressMessage(nlmsghdr, structIfaddrMsg, + LINKADDRV4.address, null /* structIfacacheInfo */, + LINKADDRV4.flags or OsConstants.IFA_F_DEPRECATED) + socketNetlinkMonitor.processNetlinkMessage(deprecatedDelNetLinkMessage, 0L /* whenMs */) + verify(netlinkMonitorCallBack).deleteInterfaceAddress(eq(IFACE_IDX), + argThat { it.address == LINKADDRV4.address }) + } +}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt new file mode 100644 index 0000000..f705bcb --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
@@ -0,0 +1,105 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns.util + +import android.os.Build +import com.android.server.connectivity.mdns.util.MdnsUtils.equalsDnsLabelIgnoreDnsCase +import com.android.server.connectivity.mdns.util.MdnsUtils.equalsIgnoreDnsCase +import com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLabelsLowerCase +import com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLowerCase +import com.android.server.connectivity.mdns.util.MdnsUtils.truncateServiceName +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import org.junit.Assert.assertArrayEquals +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(DevSdkIgnoreRunner::class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) +class MdnsUtilsTest { + @Test + fun testToDnsLowerCase() { + assertEquals("test", toDnsLowerCase("TEST")) + assertEquals("test", toDnsLowerCase("TeSt")) + assertEquals("test", toDnsLowerCase("test")) + assertEquals("tÉst", toDnsLowerCase("TÉST")) + assertEquals("ţést", toDnsLowerCase("ţést")) + // Unicode characters 0x10000 (𐀀), 0x10001 (𐀁), 0x10041 (𐁁) + // Note the last 2 bytes of 0x10041 are identical to 'A', but it should remain unchanged. + assertEquals("test: -->\ud800\udc00 \ud800\udc01 \ud800\udc41<-- ", + toDnsLowerCase("Test: -->\ud800\udc00 \ud800\udc01 \ud800\udc41<-- ")) + // Also test some characters where the first surrogate is not \ud800 + assertEquals("test: >\ud83c\udff4\udb40\udc67\udb40\udc62\udb40" + + "\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<", + toDnsLowerCase("Test: >\ud83c\udff4\udb40\udc67\udb40\udc62\udb40" + + "\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<")) + } + + @Test + fun testToDnsLabelsLowerCase() { + assertArrayEquals(arrayOf("test", "tÉst", "ţést"), + toDnsLabelsLowerCase(arrayOf("TeSt", "TÉST", "ţést"))) + } + + @Test + fun testEqualsIgnoreDnsCase() { + assertTrue(equalsIgnoreDnsCase("TEST", "Test")) + assertTrue(equalsIgnoreDnsCase("TEST", "test")) + assertTrue(equalsIgnoreDnsCase("test", "TeSt")) + assertTrue(equalsIgnoreDnsCase("Tést", "tést")) + assertFalse(equalsIgnoreDnsCase("ŢÉST", "ţést")) + // Unicode characters 0x10000 (𐀀), 0x10001 (𐀁), 0x10041 (𐁁) + // Note the last 2 bytes of 0x10041 are identical to 'A', but it should remain unchanged. + assertTrue(equalsIgnoreDnsCase("test: -->\ud800\udc00 \ud800\udc01 \ud800\udc41<-- ", + "Test: -->\ud800\udc00 \ud800\udc01 \ud800\udc41<-- ")) + // Also test some characters where the first surrogate is not \ud800 + assertTrue(equalsIgnoreDnsCase("test: >\ud83c\udff4\udb40\udc67\udb40\udc62\udb40" + + "\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<", + "Test: >\ud83c\udff4\udb40\udc67\udb40\udc62\udb40" + + "\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<")) + } + + @Test + fun testTruncateServiceName() { + assertEquals(truncateServiceName("测试abcde", 7), "测试a") + assertEquals(truncateServiceName("测试abcde", 100), "测试abcde") + } + + @Test + fun testEqualsLabelIgnoreDnsCase() { + assertTrue(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test", "test"))) + assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test"))) + assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("Test"), arrayOf("test", "test"))) + assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test", "tést"))) + } + + @Test + fun testTypeEqualsOrIsSubtype() { + assertTrue(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_type", "_tcp", "local"), + arrayOf("_type", "_TCP", "local"))) + assertTrue(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_type", "_tcp", "local"), + arrayOf("a", "_SUB", "_type", "_TCP", "local"))) + assertFalse(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_sub", "_type", "_tcp", "local"), + arrayOf("_type", "_TCP", "local"))) + assertFalse(MdnsUtils.typeEqualsOrIsSubtype( + arrayOf("a", "_other", "_type", "_tcp", "local"), + arrayOf("a", "_SUB", "_type", "_TCP", "local"))) + } +}
diff --git a/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java index 5e7f0ff..e6aba22 100644 --- a/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java
@@ -86,8 +86,9 @@ } @After - public void cleanUp() { + public void cleanUp() throws InterruptedException { mHandlerThread.quitSafely(); + mHandlerThread.join(); } private void initMockResources() {
diff --git a/tests/unit/java/com/android/server/net/IpConfigStoreTest.java b/tests/unit/java/com/android/server/net/IpConfigStoreTest.java index 4adc999..dcf0f75 100644 --- a/tests/unit/java/com/android/server/net/IpConfigStoreTest.java +++ b/tests/unit/java/com/android/server/net/IpConfigStoreTest.java
@@ -36,7 +36,6 @@ import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; -import com.android.testutils.HandlerUtils; import org.junit.Test; import org.junit.runner.RunWith; @@ -58,7 +57,7 @@ @RunWith(DevSdkIgnoreRunner.class) @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) public class IpConfigStoreTest { - private static final int TIMEOUT_MS = 2_000; + private static final int TIMEOUT_MS = 5_000; private static final int KEY_CONFIG = 17; private static final String IFACE_1 = "eth0"; private static final String IFACE_2 = "eth1"; @@ -139,6 +138,8 @@ } @Override public void quitHandlerThread(HandlerThread handlerThread) { + // Don't join in here, quitHandlerThread runs on the + // handler thread itself. testHandlerThread.quitSafely(); } }; @@ -155,7 +156,7 @@ final DelayedDiskWrite writer = new DelayedDiskWrite(dependencies); final IpConfigStore store = new IpConfigStore(writer); store.writeIpConfigurations(configFile.getPath(), expectedNetworks); - HandlerUtils.waitForIdle(testHandlerThread, TIMEOUT_MS); + testHandlerThread.join(); // Read IP config from the file path. final ArrayMap<String, IpConfiguration> actualNetworks =
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java index 04db6d3..63daebc 100644 --- a/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java +++ b/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -472,8 +472,7 @@ 256L, 16L, 512L, 32L, 0L) .insertEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 64L, 3L, 1024L, 8L, 0L); - doReturn(stats).when(mDeps).getNetworkStatsDetail(anyInt(), any(), - anyInt()); + doReturn(stats).when(mDeps).getNetworkStatsDetail(); final String[] ifaces = new String[]{TEST_IFACE}; final NetworkStats res = mFactory.readNetworkStatsDetail(UID_ALL, ifaces, TAG_ALL); @@ -488,8 +487,7 @@ mFactory.removeUidsLocked(removedUids); // Return empty stats for reading the result of removing uids stats later. - doReturn(buildEmptyStats()).when(mDeps).getNetworkStatsDetail(anyInt(), any(), - anyInt()); + doReturn(buildEmptyStats()).when(mDeps).getNetworkStatsDetail(); final NetworkStats removedUidsStats = mFactory.readNetworkStatsDetail(UID_ALL, ifaces, TAG_ALL); @@ -574,8 +572,7 @@ final NetworkStats statsFromResource = parseNetworkStatsFromGoldenSample(resourceId, 24 /* initialSize */, true /* consumeHeader */, false /* checkActive */, true /* isUidData */); - doReturn(statsFromResource).when(mDeps).getNetworkStatsDetail(anyInt(), any(), - anyInt()); + doReturn(statsFromResource).when(mDeps).getNetworkStatsDetail(); return mFactory.readNetworkStatsDetail(); }
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java index d7c90d8..b8b0289 100644 --- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -82,7 +82,6 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -97,7 +96,6 @@ import android.content.Intent; import android.content.res.Resources; import android.database.ContentObserver; -import android.net.ConnectivityResources; import android.net.DataUsageRequest; import android.net.INetd; import android.net.INetworkStatsSession; @@ -146,6 +144,7 @@ import com.android.net.module.util.bpf.CookieTagMapKey; import com.android.net.module.util.bpf.CookieTagMapValue; import com.android.server.BpfNetMaps; +import com.android.server.connectivity.ConnectivityResources; import com.android.server.net.NetworkStatsService.AlertObserver; import com.android.server.net.NetworkStatsService.NetworkStatsSettings; import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config; @@ -395,10 +394,6 @@ verify(mNetd).registerUnsolicitedEventListener(alertObserver.capture()); mAlertObserver = alertObserver.getValue(); - // Make augmentWithStackedInterfaces returns the interfaces that was passed to it. - doAnswer(inv -> ((String[]) inv.getArgument(0)).clone()) - .when(mStatsFactory).augmentWithStackedInterfaces(any()); - // Catch TetheringEventCallback during systemReady(). ArgumentCaptor<TetheringManager.TetheringEventCallback> tetheringEventCbCaptor = ArgumentCaptor.forClass(TetheringManager.TetheringEventCallback.class); @@ -544,6 +539,7 @@ mService = null; mHandlerThread.quitSafely(); + mHandlerThread.join(); } private void initWifiStats(NetworkStateSnapshot snapshot) throws Exception { @@ -1930,12 +1926,17 @@ // Templates w/o wifi network keys can query stats as usual. assertNetworkTotal(sTemplateCarrierWifi1, 0L, 0L, 0L, 0L, 0); assertNetworkTotal(sTemplateImsi1, 0L, 0L, 0L, 0L, 0); + // Templates for test network does not need to enforce location permission. + final NetworkTemplate templateTestIface1 = new NetworkTemplate.Builder(MATCH_TEST) + .setWifiNetworkKeys(Set.of(TEST_IFACE)).build(); + assertNetworkTotal(templateTestIface1, 0L, 0L, 0L, 0L, 0); doReturn(true).when(mLocationPermissionChecker) .checkCallersLocationPermission(any(), any(), anyInt(), anyBoolean(), any()); assertNetworkTotal(sTemplateCarrierWifi1, 0L, 0L, 0L, 0L, 0); assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); assertNetworkTotal(sTemplateImsi1, 0L, 0L, 0L, 0L, 0); + assertNetworkTotal(templateTestIface1, 0L, 0L, 0L, 0L, 0); } /** @@ -2198,7 +2199,7 @@ private NetworkStatsCollection getLegacyCollection(String prefix, boolean includeTags) { final NetworkStatsRecorder recorder = makeTestRecorder(mLegacyStatsDir, prefix, - mSettings.getDevConfig(), includeTags, false); + mSettings.getXtConfig(), includeTags, false); return recorder.getOrLoadCompleteLocked(); } @@ -2255,14 +2256,9 @@ } private void mockNetworkStatsSummary(NetworkStats summary) throws Exception { - mockNetworkStatsSummaryDev(summary.clone()); mockNetworkStatsSummaryXt(summary.clone()); } - private void mockNetworkStatsSummaryDev(NetworkStats summary) throws Exception { - doReturn(summary).when(mStatsFactory).readNetworkStatsSummaryDev(); - } - private void mockNetworkStatsSummaryXt(NetworkStats summary) throws Exception { doReturn(summary).when(mStatsFactory).readNetworkStatsSummaryXt(); } @@ -2293,13 +2289,11 @@ doReturn(false).when(mSettings).getCombineSubtypeEnabled(); final Config config = new Config(bucketDuration, deleteAge, deleteAge); - doReturn(config).when(mSettings).getDevConfig(); doReturn(config).when(mSettings).getXtConfig(); doReturn(config).when(mSettings).getUidConfig(); doReturn(config).when(mSettings).getUidTagConfig(); doReturn(MB_IN_BYTES).when(mSettings).getGlobalAlertBytes(anyLong()); - doReturn(MB_IN_BYTES).when(mSettings).getDevPersistBytes(anyLong()); doReturn(MB_IN_BYTES).when(mSettings).getXtPersistBytes(anyLong()); doReturn(MB_IN_BYTES).when(mSettings).getUidPersistBytes(anyLong()); doReturn(MB_IN_BYTES).when(mSettings).getUidTagPersistBytes(anyLong());
diff --git a/tests/unit/res/xml/self_certified_capabilities_bandwidth.xml b/tests/unit/res/xml/self_certified_capabilities_bandwidth.xml new file mode 100644 index 0000000..01fdca1 --- /dev/null +++ b/tests/unit/res/xml/self_certified_capabilities_bandwidth.xml
@@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<network-capabilities-declaration xmlns:android="http://schemas.android.com/apk/res/android"> + <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_BANDWIDTH"/> +</network-capabilities-declaration>
diff --git a/tests/unit/res/xml/self_certified_capabilities_both.xml b/tests/unit/res/xml/self_certified_capabilities_both.xml new file mode 100644 index 0000000..4066be2 --- /dev/null +++ b/tests/unit/res/xml/self_certified_capabilities_both.xml
@@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<network-capabilities-declaration xmlns:android="http://schemas.android.com/apk/res/android"> + <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_LATENCY"/> + <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_BANDWIDTH"/> +</network-capabilities-declaration>
diff --git a/tests/unit/res/xml/self_certified_capabilities_latency.xml b/tests/unit/res/xml/self_certified_capabilities_latency.xml new file mode 100644 index 0000000..1c4a0e0 --- /dev/null +++ b/tests/unit/res/xml/self_certified_capabilities_latency.xml
@@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<network-capabilities-declaration xmlns:android="http://schemas.android.com/apk/res/android"> + <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_LATENCY"/> +</network-capabilities-declaration>
diff --git a/tests/unit/res/xml/self_certified_capabilities_other.xml b/tests/unit/res/xml/self_certified_capabilities_other.xml new file mode 100644 index 0000000..5b6649c --- /dev/null +++ b/tests/unit/res/xml/self_certified_capabilities_other.xml
@@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<network-capabilities-declaration xmlns:android="http://schemas.android.com/apk/res/android"> + <uses-network-capability android:name="other"/> +</network-capabilities-declaration>
diff --git a/tests/unit/res/xml/self_certified_capabilities_wrong_declaration.xml b/tests/unit/res/xml/self_certified_capabilities_wrong_declaration.xml new file mode 100644 index 0000000..6082356 --- /dev/null +++ b/tests/unit/res/xml/self_certified_capabilities_wrong_declaration.xml
@@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<network-capabilities-declaration1 xmlns:android="http://schemas.android.com/apk/res/android"> + <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_LATENCY"/> +</network-capabilities-declaration1>
diff --git a/tests/unit/res/xml/self_certified_capabilities_wrong_tag.xml b/tests/unit/res/xml/self_certified_capabilities_wrong_tag.xml new file mode 100644 index 0000000..c9ecc0b --- /dev/null +++ b/tests/unit/res/xml/self_certified_capabilities_wrong_tag.xml
@@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<network-capabilities-declaration xmlns:android="http://schemas.android.com/apk/res/android"> + <uses-network-capability1 android:name="NET_CAPABILITY_PRIORITIZE_LATENCY"/> + <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_LATENCY"/> + <uses-network-capability android:name="NET_CAPABILITY_PRIORITIZE_BANDWIDTH"/> +</network-capabilities-declaration>
diff --git a/tests/unit/vpn-jarjar-rules.txt b/tests/unit/vpn-jarjar-rules.txt index 16661b9..1a6bddc 100644 --- a/tests/unit/vpn-jarjar-rules.txt +++ b/tests/unit/vpn-jarjar-rules.txt
@@ -1,4 +1,4 @@ # Only keep classes imported by ConnectivityServiceTest -keep com.android.server.VpnManagerService keep com.android.server.connectivity.Vpn -keep com.android.server.connectivity.VpnProfileStore \ No newline at end of file +keep com.android.server.connectivity.VpnProfileStore +keep com.android.server.net.LockdownVpnTracker
diff --git a/tools/gen_jarjar.py b/tools/gen_jarjar.py index eb686ce..5129128 100755 --- a/tools/gen_jarjar.py +++ b/tools/gen_jarjar.py
@@ -120,9 +120,11 @@ _get_toplevel_class(clazz) not in excluded_classes and not any(r.fullmatch(clazz) for r in exclude_regexes)): outfile.write(f'rule {clazz} {args.prefix}.@0\n') - # Also include jarjar rules for unit tests of the class, so the package matches - outfile.write(f'rule {clazz}Test {args.prefix}.@0\n') - outfile.write(f'rule {clazz}Test$* {args.prefix}.@0\n') + # Also include jarjar rules for unit tests of the class if it's not explicitly + # excluded, so the package matches + if not any(r.fullmatch(clazz + 'Test') for r in exclude_regexes): + outfile.write(f'rule {clazz}Test {args.prefix}.@0\n') + outfile.write(f'rule {clazz}Test$* {args.prefix}.@0\n') def _main():
diff --git a/tools/gn2bp/Android.bp.swp b/tools/gn2bp/Android.bp.swp deleted file mode 100644 index 212735a..0000000 --- a/tools/gn2bp/Android.bp.swp +++ /dev/null
@@ -1,26467 +0,0 @@ -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is automatically generated by gen_android_bp. Do not edit. - -// GN: //base/allocator:buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_allocator_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator:buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_allocator_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator:buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_allocator_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator:buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_allocator_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator:buildflags__host -cc_genrule { - name: "cronet_aml_base_allocator_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/allocator/buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:chromecast_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:chromecast_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:chromecast_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:chromecast_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:chromecast_buildflags__host -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/allocator/partition_allocator/chromecast_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:chromeos_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:chromeos_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:chromeos_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:chromeos_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:chromeos_buildflags__host -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/allocator/partition_allocator/chromeos_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:debugging_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:debugging_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:debugging_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:debugging_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:debugging_buildflags__host -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:logging_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:logging_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:logging_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:logging_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:logging_buildflags__host -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_logging_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/allocator/partition_allocator/logging_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:partition_alloc -cc_library_static { - name: "cronet_aml_base_allocator_partition_allocator_partition_alloc", - srcs: [ - "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_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/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_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/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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - "base/allocator/partition_allocator/partition_alloc_base/files/file_path.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/time/time_android.cc", - "base/allocator/partition_allocator/starscan/stack/asm/arm/push_registers_asm.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - generated_headers: [ - "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_arm", - "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_arm", - "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_arm", - "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_arm", - "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_arm", - ], - export_generated_headers: [ - "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_arm", - "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_arm", - "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_arm", - "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_arm", - "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_arm", - ], - }, - android_arm64: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - "base/allocator/partition_allocator/partition_alloc_base/files/file_path.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/time/time_android.cc", - "base/allocator/partition_allocator/starscan/stack/asm/arm64/push_registers_asm.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-march=armv8-a+memtag", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - generated_headers: [ - "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_arm64", - "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_arm64", - "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_arm64", - "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_arm64", - "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_arm64", - ], - export_generated_headers: [ - "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_arm64", - "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_arm64", - "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_arm64", - "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_arm64", - "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_arm64", - ], - }, - android_x86: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - "base/allocator/partition_allocator/partition_alloc_base/files/file_path.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/time/time_android.cc", - "base/allocator/partition_allocator/starscan/stack/asm/x86/push_registers_asm.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - generated_headers: [ - "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_x86", - "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_x86", - "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_x86", - "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_x86", - "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_x86", - ], - export_generated_headers: [ - "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_x86", - "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_x86", - "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_x86", - "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_x86", - "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_x86", - ], - }, - android_x86_64: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - "base/allocator/partition_allocator/partition_alloc_base/files/file_path.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/time/time_android.cc", - "base/allocator/partition_allocator/starscan/stack/asm/x64/push_registers_asm.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - generated_headers: [ - "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_x86_64", - "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_x86_64", - "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_x86_64", - "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_x86_64", - "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_x86_64", - ], - export_generated_headers: [ - "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__android_x86_64", - "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__android_x86_64", - "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__android_x86_64", - "cronet_aml_base_allocator_partition_allocator_logging_buildflags__android_x86_64", - "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_x86_64", - ], - }, - host: { - srcs: [ - "base/allocator/partition_allocator/starscan/stack/asm/x64/push_registers_asm.cc", - ], - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__host", - "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__host", - "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__host", - "cronet_aml_base_allocator_partition_allocator_logging_buildflags__host", - "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__host", - ], - export_generated_headers: [ - "cronet_aml_base_allocator_partition_allocator_chromecast_buildflags__host", - "cronet_aml_base_allocator_partition_allocator_chromeos_buildflags__host", - "cronet_aml_base_allocator_partition_allocator_debugging_buildflags__host", - "cronet_aml_base_allocator_partition_allocator_logging_buildflags__host", - "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__host", - ], - }, - }, -} - -// GN: //base/allocator/partition_allocator:partition_alloc_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:partition_alloc_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:partition_alloc_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:partition_alloc_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/allocator/partition_allocator:partition_alloc_buildflags__host -cc_genrule { - name: "cronet_aml_base_allocator_partition_allocator_partition_alloc_buildflags__host", - 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=\"true\"' | " + - "$(location build/write_buildflag_header.py) --output " + - "$(out) " + - "--rulename " + - "//base/allocator/partition_allocator:partition_alloc_buildflags " + - "--gen-dir " + - ". " + - "--definitions " + - "/dev/stdin", - host_supported: true, - device_supported: false, - out: [ - "base/allocator/partition_allocator/partition_alloc_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:anchor_functions_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_anchor_functions_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:anchor_functions_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_anchor_functions_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:anchor_functions_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_anchor_functions_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:anchor_functions_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_anchor_functions_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:anchor_functions_buildflags__host -cc_genrule { - name: "cronet_aml_base_anchor_functions_buildflags__host", - cmd: "echo '--flags USE_LLD=\"true\" SUPPORTS_CODE_ORDERING=\"false\"' | " + - "$(location build/write_buildflag_header.py) --output " + - "$(out) " + - "--rulename " + - "//base:anchor_functions_buildflags " + - "--gen-dir " + - ". " + - "--definitions " + - "/dev/stdin", - host_supported: true, - device_supported: false, - out: [ - "base/android/library_loader/anchor_functions_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:android_runtime_jni_headers__android_arm -cc_genrule { - name: "cronet_aml_base_android_runtime_jni_headers__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:android_runtime_jni_headers__android_arm64 -cc_genrule { - name: "cronet_aml_base_android_runtime_jni_headers__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:android_runtime_jni_headers__android_x86 -cc_genrule { - name: "cronet_aml_base_android_runtime_jni_headers__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:android_runtime_jni_headers__android_x86_64 -cc_genrule { - name: "cronet_aml_base_android_runtime_jni_headers__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:base -cc_library_static { - name: "cronet_aml_base_base", - srcs: [ - ":cronet_aml_third_party_abseil_cpp_absl_base_base", - ":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_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_container_hashtablez_sampler", - ":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_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_numeric_int128", - ":cronet_aml_third_party_abseil_cpp_absl_profiling_exponential_biased", - ":cronet_aml_third_party_abseil_cpp_absl_random_distributions", - ":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_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_seed_material", - ":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_internal", - ":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_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", - "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/at_exit.cc", - "base/barrier_closure.cc", - "base/base64.cc", - "base/base64url.cc", - "base/base_paths.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/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_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_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_region.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_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/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_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_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_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_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_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_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", - ], - 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_boringssl_boringssl", - "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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DBASE_IMPLEMENTATION", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/boringssl/src/include/", - "third_party/icu/source/common/", - "third_party/icu/source/i18n/", - ], - cpp_std: "c++20", - target: { - android: { - shared_libs: [ - "libandroid", - "liblog", - ], - }, - android_arm: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - ":cronet_aml_third_party_ashmem_ashmem", - "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.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/base_paths_android.cc", - "base/debug/stack_trace_android.cc", - "base/files/file_util_android.cc", - "base/files/scoped_file_android.cc", - "base/memory/platform_shared_memory_mapper_android.cc", - "base/memory/platform_shared_memory_region_android.cc", - "base/message_loop/message_pump_android.cc", - "base/os_compat_android.cc", - "base/power_monitor/power_monitor_device_source_android.cc", - "base/process/process_android.cc", - "base/profiler/chrome_unwind_info_android.cc", - "base/profiler/chrome_unwinder_android.cc", - "base/profiler/chrome_unwinder_android_v2.cc", - "base/profiler/stack_sampler_android.cc", - "base/system/sys_info_android.cc", - "base/threading/platform_thread_android.cc", - "base/time/time_android.cc", - "base/trace_event/cfi_backtrace_android.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - generated_headers: [ - "cronet_aml_base_allocator_buildflags__android_arm", - "cronet_aml_base_anchor_functions_buildflags__android_arm", - "cronet_aml_base_android_runtime_jni_headers__android_arm", - "cronet_aml_base_base_jni_headers__android_arm", - "cronet_aml_base_build_date__android_arm", - "cronet_aml_base_cfi_buildflags__android_arm", - "cronet_aml_base_clang_profiling_buildflags__android_arm", - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_feature_list_buildflags__android_arm", - "cronet_aml_base_ios_cronet_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_base_message_pump_buildflags__android_arm", - "cronet_aml_base_orderfile_buildflags__android_arm", - "cronet_aml_base_parsing_buildflags__android_arm", - "cronet_aml_base_power_monitor_buildflags__android_arm", - "cronet_aml_base_profiler_buildflags__android_arm", - "cronet_aml_base_sanitizer_buildflags__android_arm", - "cronet_aml_base_synchronization_buildflags__android_arm", - "cronet_aml_base_tracing_buildflags__android_arm", - "cronet_aml_build_branding_buildflags__android_arm", - "cronet_aml_build_chromecast_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_build_config_compiler_compiler_buildflags__android_arm", - ], - export_generated_headers: [ - "cronet_aml_base_allocator_buildflags__android_arm", - "cronet_aml_base_anchor_functions_buildflags__android_arm", - "cronet_aml_base_android_runtime_jni_headers__android_arm", - "cronet_aml_base_base_jni_headers__android_arm", - "cronet_aml_base_build_date__android_arm", - "cronet_aml_base_cfi_buildflags__android_arm", - "cronet_aml_base_clang_profiling_buildflags__android_arm", - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_feature_list_buildflags__android_arm", - "cronet_aml_base_ios_cronet_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_base_message_pump_buildflags__android_arm", - "cronet_aml_base_orderfile_buildflags__android_arm", - "cronet_aml_base_parsing_buildflags__android_arm", - "cronet_aml_base_power_monitor_buildflags__android_arm", - "cronet_aml_base_profiler_buildflags__android_arm", - "cronet_aml_base_sanitizer_buildflags__android_arm", - "cronet_aml_base_synchronization_buildflags__android_arm", - "cronet_aml_base_tracing_buildflags__android_arm", - "cronet_aml_build_branding_buildflags__android_arm", - "cronet_aml_build_chromecast_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_build_config_compiler_compiler_buildflags__android_arm", - ], - }, - android_arm64: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - ":cronet_aml_third_party_ashmem_ashmem", - "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.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/base_paths_android.cc", - "base/debug/stack_trace_android.cc", - "base/files/file_util_android.cc", - "base/files/scoped_file_android.cc", - "base/memory/platform_shared_memory_mapper_android.cc", - "base/memory/platform_shared_memory_region_android.cc", - "base/message_loop/message_pump_android.cc", - "base/os_compat_android.cc", - "base/power_monitor/power_monitor_device_source_android.cc", - "base/process/process_android.cc", - "base/profiler/stack_sampler_android.cc", - "base/system/sys_info_android.cc", - "base/threading/platform_thread_android.cc", - "base/time/time_android.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - generated_headers: [ - "cronet_aml_base_allocator_buildflags__android_arm64", - "cronet_aml_base_anchor_functions_buildflags__android_arm64", - "cronet_aml_base_android_runtime_jni_headers__android_arm64", - "cronet_aml_base_base_jni_headers__android_arm64", - "cronet_aml_base_build_date__android_arm64", - "cronet_aml_base_cfi_buildflags__android_arm64", - "cronet_aml_base_clang_profiling_buildflags__android_arm64", - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_feature_list_buildflags__android_arm64", - "cronet_aml_base_ios_cronet_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_base_message_pump_buildflags__android_arm64", - "cronet_aml_base_orderfile_buildflags__android_arm64", - "cronet_aml_base_parsing_buildflags__android_arm64", - "cronet_aml_base_power_monitor_buildflags__android_arm64", - "cronet_aml_base_profiler_buildflags__android_arm64", - "cronet_aml_base_sanitizer_buildflags__android_arm64", - "cronet_aml_base_synchronization_buildflags__android_arm64", - "cronet_aml_base_tracing_buildflags__android_arm64", - "cronet_aml_build_branding_buildflags__android_arm64", - "cronet_aml_build_chromecast_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_build_config_compiler_compiler_buildflags__android_arm64", - ], - export_generated_headers: [ - "cronet_aml_base_allocator_buildflags__android_arm64", - "cronet_aml_base_anchor_functions_buildflags__android_arm64", - "cronet_aml_base_android_runtime_jni_headers__android_arm64", - "cronet_aml_base_base_jni_headers__android_arm64", - "cronet_aml_base_build_date__android_arm64", - "cronet_aml_base_cfi_buildflags__android_arm64", - "cronet_aml_base_clang_profiling_buildflags__android_arm64", - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_feature_list_buildflags__android_arm64", - "cronet_aml_base_ios_cronet_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_base_message_pump_buildflags__android_arm64", - "cronet_aml_base_orderfile_buildflags__android_arm64", - "cronet_aml_base_parsing_buildflags__android_arm64", - "cronet_aml_base_power_monitor_buildflags__android_arm64", - "cronet_aml_base_profiler_buildflags__android_arm64", - "cronet_aml_base_sanitizer_buildflags__android_arm64", - "cronet_aml_base_synchronization_buildflags__android_arm64", - "cronet_aml_base_tracing_buildflags__android_arm64", - "cronet_aml_build_branding_buildflags__android_arm64", - "cronet_aml_build_chromecast_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_build_config_compiler_compiler_buildflags__android_arm64", - ], - }, - android_x86: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - ":cronet_aml_third_party_ashmem_ashmem", - "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/base_paths_android.cc", - "base/debug/stack_trace_android.cc", - "base/files/file_util_android.cc", - "base/files/scoped_file_android.cc", - "base/memory/platform_shared_memory_mapper_android.cc", - "base/memory/platform_shared_memory_region_android.cc", - "base/message_loop/message_pump_android.cc", - "base/os_compat_android.cc", - "base/power_monitor/power_monitor_device_source_android.cc", - "base/process/process_android.cc", - "base/profiler/stack_sampler_android.cc", - "base/system/sys_info_android.cc", - "base/threading/platform_thread_android.cc", - "base/time/time_android.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - generated_headers: [ - "cronet_aml_base_allocator_buildflags__android_x86", - "cronet_aml_base_anchor_functions_buildflags__android_x86", - "cronet_aml_base_android_runtime_jni_headers__android_x86", - "cronet_aml_base_base_jni_headers__android_x86", - "cronet_aml_base_build_date__android_x86", - "cronet_aml_base_cfi_buildflags__android_x86", - "cronet_aml_base_clang_profiling_buildflags__android_x86", - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_feature_list_buildflags__android_x86", - "cronet_aml_base_ios_cronet_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_base_message_pump_buildflags__android_x86", - "cronet_aml_base_orderfile_buildflags__android_x86", - "cronet_aml_base_parsing_buildflags__android_x86", - "cronet_aml_base_power_monitor_buildflags__android_x86", - "cronet_aml_base_profiler_buildflags__android_x86", - "cronet_aml_base_sanitizer_buildflags__android_x86", - "cronet_aml_base_synchronization_buildflags__android_x86", - "cronet_aml_base_tracing_buildflags__android_x86", - "cronet_aml_build_branding_buildflags__android_x86", - "cronet_aml_build_chromecast_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_build_config_compiler_compiler_buildflags__android_x86", - ], - export_generated_headers: [ - "cronet_aml_base_allocator_buildflags__android_x86", - "cronet_aml_base_anchor_functions_buildflags__android_x86", - "cronet_aml_base_android_runtime_jni_headers__android_x86", - "cronet_aml_base_base_jni_headers__android_x86", - "cronet_aml_base_build_date__android_x86", - "cronet_aml_base_cfi_buildflags__android_x86", - "cronet_aml_base_clang_profiling_buildflags__android_x86", - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_feature_list_buildflags__android_x86", - "cronet_aml_base_ios_cronet_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_base_message_pump_buildflags__android_x86", - "cronet_aml_base_orderfile_buildflags__android_x86", - "cronet_aml_base_parsing_buildflags__android_x86", - "cronet_aml_base_power_monitor_buildflags__android_x86", - "cronet_aml_base_profiler_buildflags__android_x86", - "cronet_aml_base_sanitizer_buildflags__android_x86", - "cronet_aml_base_synchronization_buildflags__android_x86", - "cronet_aml_base_tracing_buildflags__android_x86", - "cronet_aml_build_branding_buildflags__android_x86", - "cronet_aml_build_chromecast_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_build_config_compiler_compiler_buildflags__android_x86", - ], - }, - android_x86_64: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - ":cronet_aml_third_party_ashmem_ashmem", - "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/base_paths_android.cc", - "base/debug/stack_trace_android.cc", - "base/files/file_util_android.cc", - "base/files/scoped_file_android.cc", - "base/memory/platform_shared_memory_mapper_android.cc", - "base/memory/platform_shared_memory_region_android.cc", - "base/message_loop/message_pump_android.cc", - "base/os_compat_android.cc", - "base/power_monitor/power_monitor_device_source_android.cc", - "base/process/process_android.cc", - "base/profiler/stack_sampler_android.cc", - "base/system/sys_info_android.cc", - "base/threading/platform_thread_android.cc", - "base/time/time_android.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - generated_headers: [ - "cronet_aml_base_allocator_buildflags__android_x86_64", - "cronet_aml_base_anchor_functions_buildflags__android_x86_64", - "cronet_aml_base_android_runtime_jni_headers__android_x86_64", - "cronet_aml_base_base_jni_headers__android_x86_64", - "cronet_aml_base_build_date__android_x86_64", - "cronet_aml_base_cfi_buildflags__android_x86_64", - "cronet_aml_base_clang_profiling_buildflags__android_x86_64", - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_feature_list_buildflags__android_x86_64", - "cronet_aml_base_ios_cronet_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_base_message_pump_buildflags__android_x86_64", - "cronet_aml_base_orderfile_buildflags__android_x86_64", - "cronet_aml_base_parsing_buildflags__android_x86_64", - "cronet_aml_base_power_monitor_buildflags__android_x86_64", - "cronet_aml_base_profiler_buildflags__android_x86_64", - "cronet_aml_base_sanitizer_buildflags__android_x86_64", - "cronet_aml_base_synchronization_buildflags__android_x86_64", - "cronet_aml_base_tracing_buildflags__android_x86_64", - "cronet_aml_build_branding_buildflags__android_x86_64", - "cronet_aml_build_chromecast_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_build_config_compiler_compiler_buildflags__android_x86_64", - ], - export_generated_headers: [ - "cronet_aml_base_allocator_buildflags__android_x86_64", - "cronet_aml_base_anchor_functions_buildflags__android_x86_64", - "cronet_aml_base_android_runtime_jni_headers__android_x86_64", - "cronet_aml_base_base_jni_headers__android_x86_64", - "cronet_aml_base_build_date__android_x86_64", - "cronet_aml_base_cfi_buildflags__android_x86_64", - "cronet_aml_base_clang_profiling_buildflags__android_x86_64", - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_feature_list_buildflags__android_x86_64", - "cronet_aml_base_ios_cronet_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_base_message_pump_buildflags__android_x86_64", - "cronet_aml_base_orderfile_buildflags__android_x86_64", - "cronet_aml_base_parsing_buildflags__android_x86_64", - "cronet_aml_base_power_monitor_buildflags__android_x86_64", - "cronet_aml_base_profiler_buildflags__android_x86_64", - "cronet_aml_base_sanitizer_buildflags__android_x86_64", - "cronet_aml_base_synchronization_buildflags__android_x86_64", - "cronet_aml_base_tracing_buildflags__android_x86_64", - "cronet_aml_build_branding_buildflags__android_x86_64", - "cronet_aml_build_chromecast_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_build_config_compiler_compiler_buildflags__android_x86_64", - ], - }, - host: { - srcs: [ - "base/allocator/partition_allocator/shim/allocator_shim_default_dispatch_to_glibc.cc", - "base/base_paths_posix.cc", - "base/debug/stack_trace_posix.cc", - "base/files/file_util_linux.cc", - "base/files/scoped_file_linux.cc", - "base/memory/platform_shared_memory_mapper_posix.cc", - "base/memory/platform_shared_memory_region_posix.cc", - "base/nix/mime_util_xdg.cc", - "base/nix/xdg_util.cc", - "base/power_monitor/power_monitor_device_source_stub.cc", - "base/process/process_linux.cc", - "base/profiler/stack_sampler_posix.cc", - "base/stack_canary_linux.cc", - "base/threading/platform_thread_linux.cc", - ], - static_libs: [ - "cronet_aml_base_third_party_symbolize_symbolize", - "cronet_aml_base_third_party_xdg_mime_xdg_mime", - "cronet_aml_base_third_party_xdg_user_dirs_xdg_user_dirs", - ], - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DGLOG_EXPORT=", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_SYMBOLIZE", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_allocator_buildflags__host", - "cronet_aml_base_anchor_functions_buildflags__host", - "cronet_aml_base_build_date__host", - "cronet_aml_base_cfi_buildflags__host", - "cronet_aml_base_clang_profiling_buildflags__host", - "cronet_aml_base_debugging_buildflags__host", - "cronet_aml_base_feature_list_buildflags__host", - "cronet_aml_base_ios_cronet_buildflags__host", - "cronet_aml_base_logging_buildflags__host", - "cronet_aml_base_message_pump_buildflags__host", - "cronet_aml_base_orderfile_buildflags__host", - "cronet_aml_base_parsing_buildflags__host", - "cronet_aml_base_power_monitor_buildflags__host", - "cronet_aml_base_profiler_buildflags__host", - "cronet_aml_base_sanitizer_buildflags__host", - "cronet_aml_base_synchronization_buildflags__host", - "cronet_aml_base_tracing_buildflags__host", - "cronet_aml_build_branding_buildflags__host", - "cronet_aml_build_chromecast_buildflags__host", - "cronet_aml_build_chromeos_buildflags__host", - "cronet_aml_build_config_compiler_compiler_buildflags__host", - ], - export_generated_headers: [ - "cronet_aml_base_allocator_buildflags__host", - "cronet_aml_base_anchor_functions_buildflags__host", - "cronet_aml_base_build_date__host", - "cronet_aml_base_cfi_buildflags__host", - "cronet_aml_base_clang_profiling_buildflags__host", - "cronet_aml_base_debugging_buildflags__host", - "cronet_aml_base_feature_list_buildflags__host", - "cronet_aml_base_ios_cronet_buildflags__host", - "cronet_aml_base_logging_buildflags__host", - "cronet_aml_base_message_pump_buildflags__host", - "cronet_aml_base_orderfile_buildflags__host", - "cronet_aml_base_parsing_buildflags__host", - "cronet_aml_base_power_monitor_buildflags__host", - "cronet_aml_base_profiler_buildflags__host", - "cronet_aml_base_sanitizer_buildflags__host", - "cronet_aml_base_synchronization_buildflags__host", - "cronet_aml_base_tracing_buildflags__host", - "cronet_aml_build_branding_buildflags__host", - "cronet_aml_build_chromecast_buildflags__host", - "cronet_aml_build_chromeos_buildflags__host", - "cronet_aml_build_config_compiler_compiler_buildflags__host", - ], - }, - }, -} - -// GN: //base:base_android_java_enums_srcjar -java_genrule { - name: "cronet_aml_base_base_android_java_enums_srcjar", - cmd: "$(location build/android/gyp/java_cpp_enum.py) --srcjar " + - "$(out) " + - "$(location base/android/application_status_listener.h) " + - "$(location base/android/child_process_binding_types.h) " + - "$(location base/android/library_loader/library_loader_hooks.h) " + - "$(location base/android/linker/modern_linker_jni.h) " + - "$(location base/android/task_scheduler/task_runner_android.h) " + - "$(location base/memory/memory_pressure_listener.h) " + - "$(location base/metrics/histogram_base.h) " + - "$(location base/task/task_traits.h)", - out: [ - "base/base_android_java_enums_srcjar.srcjar", - ], - tool_files: [ - "base/android/application_status_listener.h", - "base/android/child_process_binding_types.h", - "base/android/library_loader/library_loader_hooks.h", - "base/android/linker/modern_linker_jni.h", - "base/android/task_scheduler/task_runner_android.h", - "base/memory/memory_pressure_listener.h", - "base/metrics/histogram_base.h", - "base/task/task_traits.h", - "build/android/gyp/java_cpp_enum.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - ], -} - -// GN: //base:base_jni_headers__android_arm -cc_genrule { - name: "cronet_aml_base_base_jni_headers__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:base_jni_headers__android_arm64 -cc_genrule { - name: "cronet_aml_base_base_jni_headers__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:base_jni_headers__android_x86 -cc_genrule { - name: "cronet_aml_base_base_jni_headers__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:base_jni_headers__android_x86_64 -cc_genrule { - name: "cronet_aml_base_base_jni_headers__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:base_static -cc_library_static { - name: "cronet_aml_base_base_static", - srcs: [ - "base/base_switches.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - export_generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - export_generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - export_generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - export_generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - export_generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //base:build_date__android_arm -cc_genrule { - name: "cronet_aml_base_build_date__android_arm", - cmd: "$(location build/write_build_date_header.py) $(out) " + - "1664686800", - out: [ - "base/generated_build_date.h", - ], - tool_files: [ - "build/write_build_date_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:build_date__android_arm64 -cc_genrule { - name: "cronet_aml_base_build_date__android_arm64", - cmd: "$(location build/write_build_date_header.py) $(out) " + - "1664686800", - out: [ - "base/generated_build_date.h", - ], - tool_files: [ - "build/write_build_date_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:build_date__android_x86 -cc_genrule { - name: "cronet_aml_base_build_date__android_x86", - cmd: "$(location build/write_build_date_header.py) $(out) " + - "1664686800", - out: [ - "base/generated_build_date.h", - ], - tool_files: [ - "build/write_build_date_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:build_date__android_x86_64 -cc_genrule { - name: "cronet_aml_base_build_date__android_x86_64", - cmd: "$(location build/write_build_date_header.py) $(out) " + - "1664686800", - out: [ - "base/generated_build_date.h", - ], - tool_files: [ - "build/write_build_date_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:build_date__host -cc_genrule { - name: "cronet_aml_base_build_date__host", - cmd: "$(location build/write_build_date_header.py) $(out) " + - "1664686800", - host_supported: true, - device_supported: false, - out: [ - "base/generated_build_date.h", - ], - tool_files: [ - "build/write_build_date_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:cfi_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_cfi_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:cfi_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_cfi_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:cfi_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_cfi_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:cfi_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_cfi_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:cfi_buildflags__host -cc_genrule { - name: "cronet_aml_base_cfi_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/cfi_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:clang_profiling_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_clang_profiling_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:clang_profiling_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_clang_profiling_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:clang_profiling_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_clang_profiling_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:clang_profiling_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_clang_profiling_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:clang_profiling_buildflags__host -cc_genrule { - name: "cronet_aml_base_clang_profiling_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/clang_profiling_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:debugging_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_debugging_buildflags__android_arm", - 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=\"true\" 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:debugging_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_debugging_buildflags__android_arm64", - cmd: "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"true\" 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:debugging_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_debugging_buildflags__android_x86", - cmd: "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"true\" 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:debugging_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_debugging_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:debugging_buildflags__host -cc_genrule { - name: "cronet_aml_base_debugging_buildflags__host", - cmd: "echo '--flags DCHECK_IS_CONFIGURABLE=\"false\" ENABLE_LOCATION_SOURCE=\"true\" ENABLE_PROFILING=\"false\" CAN_UNWIND_WITH_FRAME_POINTERS=\"true\" 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", - host_supported: true, - device_supported: false, - out: [ - "base/debug/debugging_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:feature_list_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_feature_list_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:feature_list_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_feature_list_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:feature_list_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_feature_list_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:feature_list_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_feature_list_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:feature_list_buildflags__host -cc_genrule { - name: "cronet_aml_base_feature_list_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/feature_list_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:ios_cronet_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_ios_cronet_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:ios_cronet_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_ios_cronet_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:ios_cronet_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_ios_cronet_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:ios_cronet_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_ios_cronet_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:ios_cronet_buildflags__host -cc_genrule { - name: "cronet_aml_base_ios_cronet_buildflags__host", - cmd: "echo '--flags CRONET_BUILD=\"false\"' | " + - "$(location build/write_buildflag_header.py) --output " + - "$(out) " + - "--rulename " + - "//base:ios_cronet_buildflags " + - "--gen-dir " + - ". " + - "--definitions " + - "/dev/stdin", - host_supported: true, - device_supported: false, - out: [ - "base/message_loop/ios_cronet_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:java_features_srcjar -java_genrule { - name: "cronet_aml_base_java_features_srcjar", - srcs: [ - "base/android/base_features.cc", - "base/features.cc", - "base/task/task_features.cc", - ], - cmd: "$(location build/android/gyp/java_cpp_features.py) --srcjar " + - "$(out) " + - "--template " + - "$(location base/android/java/src/org/chromium/base/BaseFeatures.java.tmpl) " + - "$(location base/android/base_features.cc) " + - "$(location base/features.cc) " + - "$(location base/task/task_features.cc)", - out: [ - "base/java_features_srcjar.srcjar", - ], - tool_files: [ - "base/android/java/src/org/chromium/base/BaseFeatures.java.tmpl", - "build/android/gyp/java_cpp_features.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - ], -} - -// GN: //base:java_switches_srcjar -java_genrule { - name: "cronet_aml_base_java_switches_srcjar", - srcs: [ - "base/base_switches.cc", - ], - cmd: "$(location build/android/gyp/java_cpp_strings.py) --srcjar " + - "$(out) " + - "--template " + - "$(location base/android/java/src/org/chromium/base/BaseSwitches.java.tmpl) " + - "$(location base/base_switches.cc)", - out: [ - "base/java_switches_srcjar.srcjar", - ], - tool_files: [ - "base/android/java/src/org/chromium/base/BaseSwitches.java.tmpl", - "build/android/gyp/java_cpp_strings.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - ], -} - -// GN: //base:logging_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_logging_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:logging_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_logging_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:logging_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_logging_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:logging_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_logging_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:logging_buildflags__host -cc_genrule { - name: "cronet_aml_base_logging_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/logging_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:message_pump_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_message_pump_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:message_pump_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_message_pump_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:message_pump_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_message_pump_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:message_pump_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_message_pump_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:message_pump_buildflags__host -cc_genrule { - name: "cronet_aml_base_message_pump_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/message_loop/message_pump_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base/numerics:base_numerics -cc_object { - name: "cronet_aml_base_numerics_base_numerics", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //base:orderfile_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_orderfile_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:orderfile_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_orderfile_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:orderfile_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_orderfile_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:orderfile_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_orderfile_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:orderfile_buildflags__host -cc_genrule { - name: "cronet_aml_base_orderfile_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/android/orderfile/orderfile_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:parsing_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_parsing_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:parsing_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_parsing_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:parsing_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_parsing_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:parsing_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_parsing_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:parsing_buildflags__host -cc_genrule { - name: "cronet_aml_base_parsing_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/parsing_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:power_monitor_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_power_monitor_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:power_monitor_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_power_monitor_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:power_monitor_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_power_monitor_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:power_monitor_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_power_monitor_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:power_monitor_buildflags__host -cc_genrule { - name: "cronet_aml_base_power_monitor_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/power_monitor/power_monitor_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:profiler_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_profiler_buildflags__android_arm", - cmd: "echo '--flags ENABLE_ARM_CFI_TABLE=\"true\" 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:profiler_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_profiler_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:profiler_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_profiler_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:profiler_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_profiler_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:profiler_buildflags__host -cc_genrule { - name: "cronet_aml_base_profiler_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/profiler/profiler_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:sanitizer_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_sanitizer_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:sanitizer_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_sanitizer_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:sanitizer_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_sanitizer_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:sanitizer_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_sanitizer_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:sanitizer_buildflags__host -cc_genrule { - name: "cronet_aml_base_sanitizer_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/sanitizer_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:synchronization_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_synchronization_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:synchronization_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_synchronization_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:synchronization_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_synchronization_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:synchronization_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_synchronization_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:synchronization_buildflags__host -cc_genrule { - name: "cronet_aml_base_synchronization_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "base/synchronization/synchronization_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //base/third_party/symbolize:symbolize -cc_library_static { - name: "cronet_aml_base_third_party_symbolize_symbolize", - srcs: [ - "base/third_party/symbolize/demangle.cc", - "base/third_party/symbolize/symbolize.cc", - ], - host_supported: true, - device_supported: false, - 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", - "-DGLOG_EXPORT=", - "-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_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1", - "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", - "-msse3", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - ], - cpp_std: "c++20", -} - -// GN: //base/third_party/xdg_mime:xdg_mime -cc_library_static { - name: "cronet_aml_base_third_party_xdg_mime_xdg_mime", - srcs: [ - "base/third_party/xdg_mime/xdgmime.c", - "base/third_party/xdg_mime/xdgmimealias.c", - "base/third_party/xdg_mime/xdgmimecache.c", - "base/third_party/xdg_mime/xdgmimeglob.c", - "base/third_party/xdg_mime/xdgmimeicon.c", - "base/third_party/xdg_mime/xdgmimeint.c", - "base/third_party/xdg_mime/xdgmimemagic.c", - "base/third_party/xdg_mime/xdgmimeparent.c", - ], - host_supported: true, - device_supported: false, - 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", - "-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_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1", - "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", - "-msse3", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - ], - cpp_std: "c++20", -} - -// GN: //base/third_party/xdg_user_dirs:xdg_user_dirs -cc_library_static { - name: "cronet_aml_base_third_party_xdg_user_dirs_xdg_user_dirs", - srcs: [ - "base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc", - ], - host_supported: true, - device_supported: false, - 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", - "-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_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1", - "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", - "-D__STDC_CONSTANT_MACROS", - "-D__STDC_FORMAT_MACROS", - "-msse3", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - ], - cpp_std: "c++20", -} - -// GN: //base:tracing_buildflags__android_arm -cc_genrule { - name: "cronet_aml_base_tracing_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:tracing_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_base_tracing_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:tracing_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_base_tracing_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:tracing_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_base_tracing_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //base:tracing_buildflags__host -cc_genrule { - name: "cronet_aml_base_tracing_buildflags__host", - cmd: "echo '--flags ENABLE_BASE_TRACING=\"false\" USE_PERFETTO_CLIENT_LIBRARY=\"false\" OPTIONAL_TRACE_EVENTS_ENABLED=\"true\"' | " + - "$(location build/write_buildflag_header.py) --output " + - "$(out) " + - "--rulename " + - "//base:tracing_buildflags " + - "--gen-dir " + - ". " + - "--definitions " + - "/dev/stdin", - host_supported: true, - device_supported: false, - out: [ - "base/tracing_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build/android:build_config_gen -genrule { - name: "cronet_aml_build_android_build_config_gen", - srcs: [ - ":cronet_aml_build_android_build_config_gen_preprocess", - ], - tools: [ - "soong_zip", - ], - cmd: "cp $(in) $(genDir)/BuildConfig.java && " + - "$(location soong_zip) -o $(out) -srcjar -f $(genDir)/BuildConfig.java", - out: [ - "BuildConfig.srcjar", - ], -} - -// GN: //build/android:build_config_gen -cc_object { - name: "cronet_aml_build_android_build_config_gen_preprocess", - srcs: [ - ":cronet_aml_build_android_build_config_gen_rename", - ], - cflags: [ - "-DANDROID", - "-D_ENABLE_ASSERTS", - "-E", - "-P", - ], - compile_multilib: "first", -} - -// GN: //build/android:build_config_gen -genrule { - name: "cronet_aml_build_android_build_config_gen_rename", - srcs: [ - "build/android/java/templates/BuildConfig.template", - ], - cmd: "cp $(in) $(out)", - out: [ - "BuildConfig.cc", - ], -} - -// GN: //build/android:native_libraries_gen -java_genrule { - name: "cronet_aml_build_android_native_libraries_gen", - cmd: "$(location build/android/gyp/write_native_libraries_java.py) --output " + - "$(out) " + - "--cpu-family " + - "CPU_FAMILY_ARM", - out: [ - "build/android/native_libraries_gen.srcjar", - ], - tool_files: [ - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/write_native_libraries_java.py", - "build/gn_helpers.py", - ], -} - -// GN: //build:branding_buildflags__android_arm -cc_genrule { - name: "cronet_aml_build_branding_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:branding_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_build_branding_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:branding_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_build_branding_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:branding_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_build_branding_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:branding_buildflags__host -cc_genrule { - name: "cronet_aml_build_branding_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "build/branding_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:buildflag_header_h -cc_object { - name: "cronet_aml_build_buildflag_header_h", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //build:chromecast_buildflags__android_arm -cc_genrule { - name: "cronet_aml_build_chromecast_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:chromecast_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_build_chromecast_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:chromecast_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_build_chromecast_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:chromecast_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_build_chromecast_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:chromecast_buildflags__host -cc_genrule { - name: "cronet_aml_build_chromecast_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "build/chromecast_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:chromeos_buildflags__android_arm -cc_genrule { - name: "cronet_aml_build_chromeos_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:chromeos_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_build_chromeos_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:chromeos_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_build_chromeos_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:chromeos_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_build_chromeos_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build:chromeos_buildflags__host -cc_genrule { - name: "cronet_aml_build_chromeos_buildflags__host", - 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", - host_supported: true, - device_supported: false, - out: [ - "build/chromeos_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build/config/compiler:compiler_buildflags__android_arm -cc_genrule { - name: "cronet_aml_build_config_compiler_compiler_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build/config/compiler:compiler_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_build_config_compiler_compiler_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build/config/compiler:compiler_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_build_config_compiler_compiler_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build/config/compiler:compiler_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_build_config_compiler_compiler_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //build/config/compiler:compiler_buildflags__host -cc_genrule { - name: "cronet_aml_build_config_compiler_compiler_buildflags__host", - cmd: "echo '--flags CLANG_PGO=\"0\" SYMBOL_LEVEL=\"2\"' | " + - "$(location build/write_buildflag_header.py) --output " + - "$(out) " + - "--rulename " + - "//build/config/compiler:compiler_buildflags " + - "--gen-dir " + - ". " + - "--definitions " + - "/dev/stdin", - host_supported: true, - device_supported: false, - out: [ - "build/config/compiler/compiler_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //buildtools/third_party/libc++:libc++ -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-DLIBCXX_BUILDING_LIBCXXABI", - "-D_DEBUG", - "-D_GNU_SOURCE", - "-D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED=1", - "-D_LIBCPP_BUILDING_LIBRARY", - "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1", - "-D_LIBCPP_OVERRIDABLE_FUNC_VIS=__attribute__((__visibility__(\"default\")))", - "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", - ], - 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", - ], - cpp_std: "c++20", - cppflags: [ - "-fexceptions", - ], - rtti: true, - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //buildtools/third_party/libc++abi:libc++abi -cc_object { - name: "cronet_aml_buildtools_third_party_libc__abi_libc__abi", - srcs: [ - "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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-DLIBCXXABI_SILENT_TERMINATE", - "-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_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", - ], - 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", - ], - cpp_std: "c++20", - cppflags: [ - "-fexceptions", - ], - rtti: true, - target: { - android_arm: { - srcs: [ - "buildtools/third_party/libc++abi/cxa_demangle_stub.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - srcs: [ - "buildtools/third_party/libc++abi/cxa_demangle_stub.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - srcs: [ - "buildtools/third_party/libc++abi/cxa_demangle_stub.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - srcs: [ - "buildtools/third_party/libc++abi/cxa_demangle_stub.cc", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - srcs: [ - "buildtools/third_party/libc++abi/trunk/src/cxa_demangle.cpp", - ], - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //buildtools/third_party/libunwind:libunwind -cc_object { - 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", - ], - 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_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBUNWIND_IS_NATIVE_ONLY", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - "buildtools/third_party/libunwind/trunk/include/", - ], - cpp_std: "c++20", - cppflags: [ - "-fexceptions", - ], - rtti: true, - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //components/cronet/android:buildflags__android_arm -cc_genrule { - name: "cronet_aml_components_cronet_android_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_components_cronet_android_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:buildflags__android_x86 -cc_genrule { - name: "cronet_aml_components_cronet_android_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_components_cronet_android_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// 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_metrics_util", - ":cronet_aml_components_cronet_native_cronet_native_impl", - ":cronet_aml_components_grpc_support_grpc_support", - ":cronet_aml_components_metrics_library_support", - "components/cronet/android/cronet_jni.cc", - ], - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_components_prefs_prefs", - "cronet_aml_crypto_crypto", - "cronet_aml_net_net", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_third_party_metrics_proto_metrics_proto_gen_headers", - ], - export_generated_headers: [ - "cronet_aml_third_party_metrics_proto_metrics_proto_gen_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", - "-DGOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0", - "-DGOOGLE_PROTOBUF_NO_RTTI", - "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER", - "-DHAVE_PTHREAD", - "-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", - "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/protobuf/src/", - ], - cpp_std: "c++20", - linker_scripts: [ - "base/android/library_loader/anchor_functions.lds", - ], - stem: "libcronet.109.0.5386.0", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_components_cronet_android_buildflags__android_arm", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_arm", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_arm", - "cronet_aml_components_cronet_cronet_buildflags__android_arm", - "cronet_aml_components_cronet_cronet_version_header_action__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_components_cronet_android_buildflags__android_arm", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_arm", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_arm", - "cronet_aml_components_cronet_cronet_buildflags__android_arm", - "cronet_aml_components_cronet_cronet_version_header_action__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_components_cronet_android_buildflags__android_arm64", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_arm64", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_arm64", - "cronet_aml_components_cronet_cronet_buildflags__android_arm64", - "cronet_aml_components_cronet_cronet_version_header_action__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_components_cronet_android_buildflags__android_arm64", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_arm64", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_arm64", - "cronet_aml_components_cronet_cronet_buildflags__android_arm64", - "cronet_aml_components_cronet_cronet_version_header_action__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_components_cronet_android_buildflags__android_x86", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_x86", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_x86", - "cronet_aml_components_cronet_cronet_buildflags__android_x86", - "cronet_aml_components_cronet_cronet_version_header_action__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_components_cronet_android_buildflags__android_x86", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_x86", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_x86", - "cronet_aml_components_cronet_cronet_buildflags__android_x86", - "cronet_aml_components_cronet_cronet_version_header_action__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_components_cronet_android_buildflags__android_x86_64", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_x86_64", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_x86_64", - "cronet_aml_components_cronet_cronet_buildflags__android_x86_64", - "cronet_aml_components_cronet_cronet_version_header_action__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_components_cronet_android_buildflags__android_x86_64", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_x86_64", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_x86_64", - "cronet_aml_components_cronet_cronet_buildflags__android_x86_64", - "cronet_aml_components_cronet_cronet_version_header_action__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //components/cronet/android:cronet_jni_headers__android_arm -cc_genrule { - name: "cronet_aml_components_cronet_android_cronet_jni_headers__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:cronet_jni_headers__android_arm64 -cc_genrule { - name: "cronet_aml_components_cronet_android_cronet_jni_headers__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:cronet_jni_headers__android_x86 -cc_genrule { - name: "cronet_aml_components_cronet_android_cronet_jni_headers__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:cronet_jni_headers__android_x86_64 -cc_genrule { - name: "cronet_aml_components_cronet_android_cronet_jni_headers__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:cronet_jni_registration__android_arm -cc_genrule { - name: "cronet_aml_components_cronet_android_cronet_jni_registration__android_arm", - srcs: [ - "base/android/java/src/org/chromium/base/ActivityState.java", - "base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java", - "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/ByteArrayGenerator.java", - "base/android/java/src/org/chromium/base/Callback.java", - "base/android/java/src/org/chromium/base/CallbackController.java", - "base/android/java/src/org/chromium/base/CollectionUtil.java", - "base/android/java/src/org/chromium/base/CommandLine.java", - "base/android/java/src/org/chromium/base/CommandLineInitUtil.java", - "base/android/java/src/org/chromium/base/Consumer.java", - "base/android/java/src/org/chromium/base/ContentUriUtils.java", - "base/android/java/src/org/chromium/base/ContextUtils.java", - "base/android/java/src/org/chromium/base/CpuFeatures.java", - "base/android/java/src/org/chromium/base/DiscardableReferencePool.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/Function.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/IntentUtils.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/JniException.java", - "base/android/java/src/org/chromium/base/JniStaticTestMocker.java", - "base/android/java/src/org/chromium/base/LifetimeAssert.java", - "base/android/java/src/org/chromium/base/LocaleUtils.java", - "base/android/java/src/org/chromium/base/Log.java", - "base/android/java/src/org/chromium/base/MathUtils.java", - "base/android/java/src/org/chromium/base/MemoryPressureListener.java", - "base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java", - "base/android/java/src/org/chromium/base/ObserverList.java", - "base/android/java/src/org/chromium/base/PackageManagerUtils.java", - "base/android/java/src/org/chromium/base/PackageUtils.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/PiiElider.java", - "base/android/java/src/org/chromium/base/PowerMonitor.java", - "base/android/java/src/org/chromium/base/PowerMonitorForQ.java", - "base/android/java/src/org/chromium/base/Predicate.java", - "base/android/java/src/org/chromium/base/Promise.java", - "base/android/java/src/org/chromium/base/RadioUtils.java", - "base/android/java/src/org/chromium/base/StreamUtil.java", - "base/android/java/src/org/chromium/base/StrictModeContext.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/TimeUtils.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/UnownedUserData.java", - "base/android/java/src/org/chromium/base/UnownedUserDataHost.java", - "base/android/java/src/org/chromium/base/UnownedUserDataKey.java", - "base/android/java/src/org/chromium/base/UserData.java", - "base/android/java/src/org/chromium/base/UserDataHost.java", - "base/android/java/src/org/chromium/base/WrappedClassLoader.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", - "base/android/java/src/org/chromium/base/compat/ApiHelperForM.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForN.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForO.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForOMR1.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForP.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForQ.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForR.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForS.java", - "base/android/java/src/org/chromium/base/jank_tracker/DummyJankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricCalculator.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankScenario.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java", - "base/android/java/src/org/chromium/base/library_loader/LegacyLinker.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/library_loader/Linker.java", - "base/android/java/src/org/chromium/base/library_loader/LinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/NativeLibraryPreloader.java", - "base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java", - "base/android/java/src/org/chromium/base/lifetime/DestroyChecker.java", - "base/android/java/src/org/chromium/base/lifetime/Destroyable.java", - "base/android/java/src/org/chromium/base/memory/JavaHeapDumpGenerator.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureCallback.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureMonitor.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureUma.java", - "base/android/java/src/org/chromium/base/memory/MemoryPurgeManager.java", - "base/android/java/src/org/chromium/base/metrics/CachingUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NativeUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NoopUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/RecordHistogram.java", - "base/android/java/src/org/chromium/base/metrics/RecordUserAction.java", - "base/android/java/src/org/chromium/base/metrics/ScopedSysTraceEvent.java", - "base/android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java", - "base/android/java/src/org/chromium/base/metrics/TimingMetric.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java", - "base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java", - "base/android/java/src/org/chromium/base/process_launcher/BindService.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConstants.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionFactory.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionImpl.java", - "base/android/java/src/org/chromium/base/process_launcher/FileDescriptorInfo.java", - "base/android/java/src/org/chromium/base/supplier/BooleanSupplier.java", - "base/android/java/src/org/chromium/base/supplier/DestroyableObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/OneShotCallback.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplier.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/Supplier.java", - "base/android/java/src/org/chromium/base/supplier/UnownedUserDataSupplier.java", - "base/android/java/src/org/chromium/base/task/AsyncTask.java", - "base/android/java/src/org/chromium/base/task/BackgroundOnlyAsyncTask.java", - "base/android/java/src/org/chromium/base/task/ChainedTasks.java", - "base/android/java/src/org/chromium/base/task/ChoreographerTaskRunner.java", - "base/android/java/src/org/chromium/base/task/ChromeThreadPoolExecutor.java", - "base/android/java/src/org/chromium/base/task/DefaultTaskExecutor.java", - "base/android/java/src/org/chromium/base/task/PostTask.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/SerialExecutor.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskExecutor.java", - "base/android/java/src/org/chromium/base/task/TaskRunner.java", - "base/android/java/src/org/chromium/base/task/TaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskTraits.java", - "base/android/java/src/org/chromium/base/task/TaskTraitsExtensionDescriptor.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/api/src/org/chromium/net/BidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/CallbackException.java", - "components/cronet/android/api/src/org/chromium/net/CronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/CronetException.java", - "components/cronet/android/api/src/org/chromium/net/CronetProvider.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalBidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalUrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/ICronetEngineBuilder.java", - "components/cronet/android/api/src/org/chromium/net/InlineExecutionProhibitedException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityRttListener.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityThroughputListener.java", - "components/cronet/android/api/src/org/chromium/net/QuicException.java", - "components/cronet/android/api/src/org/chromium/net/RequestFinishedInfo.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProvider.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataSink.java", - "components/cronet/android/api/src/org/chromium/net/UrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ByteArrayCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ContentTypeParametersParser.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetRequestCompletionListener.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetResponse.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ImplicitFlowControlCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/InMemoryTransformCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/JsonCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandler.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandlers.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/StringCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UrlRequestCallbacks.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetController.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetEngine.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetProvider.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlRequest.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlResponse.java", - "components/cronet/android/fake/java/org/chromium/net/test/ResponseMatcher.java", - "components/cronet/android/fake/java/org/chromium/net/test/UrlResponseMatcher.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java", - "components/cronet/android/java/src/org/chromium/net/impl/CallbackExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLoggerFactory.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetManifest.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetMetrics.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", - "components/cronet/android/java/src/org/chromium/net/impl/InputStreamChannel.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngine.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUploadDataSinkBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequestUtils.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderWithLibraryLoaderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NoOpLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/Preconditions.java", - "components/cronet/android/java/src/org/chromium/net/impl/QuicExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlResponseInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UserAgent.java", - "components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetChunkedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetInputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactory.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java", - "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/ChromiumNetworkAdapter.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/HttpNegotiateConstants.java", - "net/android/java/src/org/chromium/net/HttpUtil.java", - "net/android/java/src/org/chromium/net/MimeTypeFilter.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/NetworkChangeNotifierAutoDetect.java", - "net/android/java/src/org/chromium/net/NetworkTrafficAnnotationTag.java", - "net/android/java/src/org/chromium/net/ProxyBroadcastReceiver.java", - "net/android/java/src/org/chromium/net/ProxyChangeListener.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyAlwaysRegister.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java", - "net/android/java/src/org/chromium/net/ThreadStatsUid.java", - "net/android/java/src/org/chromium/net/X509Util.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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:cronet_jni_registration__android_arm64 -cc_genrule { - name: "cronet_aml_components_cronet_android_cronet_jni_registration__android_arm64", - srcs: [ - "base/android/java/src/org/chromium/base/ActivityState.java", - "base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java", - "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/ByteArrayGenerator.java", - "base/android/java/src/org/chromium/base/Callback.java", - "base/android/java/src/org/chromium/base/CallbackController.java", - "base/android/java/src/org/chromium/base/CollectionUtil.java", - "base/android/java/src/org/chromium/base/CommandLine.java", - "base/android/java/src/org/chromium/base/CommandLineInitUtil.java", - "base/android/java/src/org/chromium/base/Consumer.java", - "base/android/java/src/org/chromium/base/ContentUriUtils.java", - "base/android/java/src/org/chromium/base/ContextUtils.java", - "base/android/java/src/org/chromium/base/CpuFeatures.java", - "base/android/java/src/org/chromium/base/DiscardableReferencePool.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/Function.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/IntentUtils.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/JniException.java", - "base/android/java/src/org/chromium/base/JniStaticTestMocker.java", - "base/android/java/src/org/chromium/base/LifetimeAssert.java", - "base/android/java/src/org/chromium/base/LocaleUtils.java", - "base/android/java/src/org/chromium/base/Log.java", - "base/android/java/src/org/chromium/base/MathUtils.java", - "base/android/java/src/org/chromium/base/MemoryPressureListener.java", - "base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java", - "base/android/java/src/org/chromium/base/ObserverList.java", - "base/android/java/src/org/chromium/base/PackageManagerUtils.java", - "base/android/java/src/org/chromium/base/PackageUtils.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/PiiElider.java", - "base/android/java/src/org/chromium/base/PowerMonitor.java", - "base/android/java/src/org/chromium/base/PowerMonitorForQ.java", - "base/android/java/src/org/chromium/base/Predicate.java", - "base/android/java/src/org/chromium/base/Promise.java", - "base/android/java/src/org/chromium/base/RadioUtils.java", - "base/android/java/src/org/chromium/base/StreamUtil.java", - "base/android/java/src/org/chromium/base/StrictModeContext.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/TimeUtils.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/UnownedUserData.java", - "base/android/java/src/org/chromium/base/UnownedUserDataHost.java", - "base/android/java/src/org/chromium/base/UnownedUserDataKey.java", - "base/android/java/src/org/chromium/base/UserData.java", - "base/android/java/src/org/chromium/base/UserDataHost.java", - "base/android/java/src/org/chromium/base/WrappedClassLoader.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", - "base/android/java/src/org/chromium/base/compat/ApiHelperForM.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForN.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForO.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForOMR1.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForP.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForQ.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForR.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForS.java", - "base/android/java/src/org/chromium/base/jank_tracker/DummyJankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricCalculator.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankScenario.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java", - "base/android/java/src/org/chromium/base/library_loader/LegacyLinker.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/library_loader/Linker.java", - "base/android/java/src/org/chromium/base/library_loader/LinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/NativeLibraryPreloader.java", - "base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java", - "base/android/java/src/org/chromium/base/lifetime/DestroyChecker.java", - "base/android/java/src/org/chromium/base/lifetime/Destroyable.java", - "base/android/java/src/org/chromium/base/memory/JavaHeapDumpGenerator.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureCallback.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureMonitor.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureUma.java", - "base/android/java/src/org/chromium/base/memory/MemoryPurgeManager.java", - "base/android/java/src/org/chromium/base/metrics/CachingUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NativeUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NoopUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/RecordHistogram.java", - "base/android/java/src/org/chromium/base/metrics/RecordUserAction.java", - "base/android/java/src/org/chromium/base/metrics/ScopedSysTraceEvent.java", - "base/android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java", - "base/android/java/src/org/chromium/base/metrics/TimingMetric.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java", - "base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java", - "base/android/java/src/org/chromium/base/process_launcher/BindService.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConstants.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionFactory.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionImpl.java", - "base/android/java/src/org/chromium/base/process_launcher/FileDescriptorInfo.java", - "base/android/java/src/org/chromium/base/supplier/BooleanSupplier.java", - "base/android/java/src/org/chromium/base/supplier/DestroyableObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/OneShotCallback.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplier.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/Supplier.java", - "base/android/java/src/org/chromium/base/supplier/UnownedUserDataSupplier.java", - "base/android/java/src/org/chromium/base/task/AsyncTask.java", - "base/android/java/src/org/chromium/base/task/BackgroundOnlyAsyncTask.java", - "base/android/java/src/org/chromium/base/task/ChainedTasks.java", - "base/android/java/src/org/chromium/base/task/ChoreographerTaskRunner.java", - "base/android/java/src/org/chromium/base/task/ChromeThreadPoolExecutor.java", - "base/android/java/src/org/chromium/base/task/DefaultTaskExecutor.java", - "base/android/java/src/org/chromium/base/task/PostTask.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/SerialExecutor.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskExecutor.java", - "base/android/java/src/org/chromium/base/task/TaskRunner.java", - "base/android/java/src/org/chromium/base/task/TaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskTraits.java", - "base/android/java/src/org/chromium/base/task/TaskTraitsExtensionDescriptor.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/api/src/org/chromium/net/BidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/CallbackException.java", - "components/cronet/android/api/src/org/chromium/net/CronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/CronetException.java", - "components/cronet/android/api/src/org/chromium/net/CronetProvider.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalBidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalUrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/ICronetEngineBuilder.java", - "components/cronet/android/api/src/org/chromium/net/InlineExecutionProhibitedException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityRttListener.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityThroughputListener.java", - "components/cronet/android/api/src/org/chromium/net/QuicException.java", - "components/cronet/android/api/src/org/chromium/net/RequestFinishedInfo.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProvider.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataSink.java", - "components/cronet/android/api/src/org/chromium/net/UrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ByteArrayCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ContentTypeParametersParser.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetRequestCompletionListener.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetResponse.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ImplicitFlowControlCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/InMemoryTransformCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/JsonCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandler.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandlers.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/StringCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UrlRequestCallbacks.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetController.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetEngine.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetProvider.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlRequest.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlResponse.java", - "components/cronet/android/fake/java/org/chromium/net/test/ResponseMatcher.java", - "components/cronet/android/fake/java/org/chromium/net/test/UrlResponseMatcher.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java", - "components/cronet/android/java/src/org/chromium/net/impl/CallbackExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLoggerFactory.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetManifest.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetMetrics.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", - "components/cronet/android/java/src/org/chromium/net/impl/InputStreamChannel.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngine.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUploadDataSinkBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequestUtils.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderWithLibraryLoaderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NoOpLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/Preconditions.java", - "components/cronet/android/java/src/org/chromium/net/impl/QuicExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlResponseInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UserAgent.java", - "components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetChunkedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetInputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactory.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java", - "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/ChromiumNetworkAdapter.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/HttpNegotiateConstants.java", - "net/android/java/src/org/chromium/net/HttpUtil.java", - "net/android/java/src/org/chromium/net/MimeTypeFilter.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/NetworkChangeNotifierAutoDetect.java", - "net/android/java/src/org/chromium/net/NetworkTrafficAnnotationTag.java", - "net/android/java/src/org/chromium/net/ProxyBroadcastReceiver.java", - "net/android/java/src/org/chromium/net/ProxyChangeListener.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyAlwaysRegister.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java", - "net/android/java/src/org/chromium/net/ThreadStatsUid.java", - "net/android/java/src/org/chromium/net/X509Util.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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:cronet_jni_registration__android_x86 -cc_genrule { - name: "cronet_aml_components_cronet_android_cronet_jni_registration__android_x86", - srcs: [ - "base/android/java/src/org/chromium/base/ActivityState.java", - "base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java", - "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/ByteArrayGenerator.java", - "base/android/java/src/org/chromium/base/Callback.java", - "base/android/java/src/org/chromium/base/CallbackController.java", - "base/android/java/src/org/chromium/base/CollectionUtil.java", - "base/android/java/src/org/chromium/base/CommandLine.java", - "base/android/java/src/org/chromium/base/CommandLineInitUtil.java", - "base/android/java/src/org/chromium/base/Consumer.java", - "base/android/java/src/org/chromium/base/ContentUriUtils.java", - "base/android/java/src/org/chromium/base/ContextUtils.java", - "base/android/java/src/org/chromium/base/CpuFeatures.java", - "base/android/java/src/org/chromium/base/DiscardableReferencePool.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/Function.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/IntentUtils.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/JniException.java", - "base/android/java/src/org/chromium/base/JniStaticTestMocker.java", - "base/android/java/src/org/chromium/base/LifetimeAssert.java", - "base/android/java/src/org/chromium/base/LocaleUtils.java", - "base/android/java/src/org/chromium/base/Log.java", - "base/android/java/src/org/chromium/base/MathUtils.java", - "base/android/java/src/org/chromium/base/MemoryPressureListener.java", - "base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java", - "base/android/java/src/org/chromium/base/ObserverList.java", - "base/android/java/src/org/chromium/base/PackageManagerUtils.java", - "base/android/java/src/org/chromium/base/PackageUtils.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/PiiElider.java", - "base/android/java/src/org/chromium/base/PowerMonitor.java", - "base/android/java/src/org/chromium/base/PowerMonitorForQ.java", - "base/android/java/src/org/chromium/base/Predicate.java", - "base/android/java/src/org/chromium/base/Promise.java", - "base/android/java/src/org/chromium/base/RadioUtils.java", - "base/android/java/src/org/chromium/base/StreamUtil.java", - "base/android/java/src/org/chromium/base/StrictModeContext.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/TimeUtils.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/UnownedUserData.java", - "base/android/java/src/org/chromium/base/UnownedUserDataHost.java", - "base/android/java/src/org/chromium/base/UnownedUserDataKey.java", - "base/android/java/src/org/chromium/base/UserData.java", - "base/android/java/src/org/chromium/base/UserDataHost.java", - "base/android/java/src/org/chromium/base/WrappedClassLoader.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", - "base/android/java/src/org/chromium/base/compat/ApiHelperForM.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForN.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForO.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForOMR1.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForP.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForQ.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForR.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForS.java", - "base/android/java/src/org/chromium/base/jank_tracker/DummyJankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricCalculator.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankScenario.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java", - "base/android/java/src/org/chromium/base/library_loader/LegacyLinker.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/library_loader/Linker.java", - "base/android/java/src/org/chromium/base/library_loader/LinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/NativeLibraryPreloader.java", - "base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java", - "base/android/java/src/org/chromium/base/lifetime/DestroyChecker.java", - "base/android/java/src/org/chromium/base/lifetime/Destroyable.java", - "base/android/java/src/org/chromium/base/memory/JavaHeapDumpGenerator.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureCallback.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureMonitor.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureUma.java", - "base/android/java/src/org/chromium/base/memory/MemoryPurgeManager.java", - "base/android/java/src/org/chromium/base/metrics/CachingUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NativeUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NoopUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/RecordHistogram.java", - "base/android/java/src/org/chromium/base/metrics/RecordUserAction.java", - "base/android/java/src/org/chromium/base/metrics/ScopedSysTraceEvent.java", - "base/android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java", - "base/android/java/src/org/chromium/base/metrics/TimingMetric.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java", - "base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java", - "base/android/java/src/org/chromium/base/process_launcher/BindService.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConstants.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionFactory.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionImpl.java", - "base/android/java/src/org/chromium/base/process_launcher/FileDescriptorInfo.java", - "base/android/java/src/org/chromium/base/supplier/BooleanSupplier.java", - "base/android/java/src/org/chromium/base/supplier/DestroyableObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/OneShotCallback.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplier.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/Supplier.java", - "base/android/java/src/org/chromium/base/supplier/UnownedUserDataSupplier.java", - "base/android/java/src/org/chromium/base/task/AsyncTask.java", - "base/android/java/src/org/chromium/base/task/BackgroundOnlyAsyncTask.java", - "base/android/java/src/org/chromium/base/task/ChainedTasks.java", - "base/android/java/src/org/chromium/base/task/ChoreographerTaskRunner.java", - "base/android/java/src/org/chromium/base/task/ChromeThreadPoolExecutor.java", - "base/android/java/src/org/chromium/base/task/DefaultTaskExecutor.java", - "base/android/java/src/org/chromium/base/task/PostTask.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/SerialExecutor.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskExecutor.java", - "base/android/java/src/org/chromium/base/task/TaskRunner.java", - "base/android/java/src/org/chromium/base/task/TaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskTraits.java", - "base/android/java/src/org/chromium/base/task/TaskTraitsExtensionDescriptor.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/api/src/org/chromium/net/BidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/CallbackException.java", - "components/cronet/android/api/src/org/chromium/net/CronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/CronetException.java", - "components/cronet/android/api/src/org/chromium/net/CronetProvider.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalBidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalUrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/ICronetEngineBuilder.java", - "components/cronet/android/api/src/org/chromium/net/InlineExecutionProhibitedException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityRttListener.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityThroughputListener.java", - "components/cronet/android/api/src/org/chromium/net/QuicException.java", - "components/cronet/android/api/src/org/chromium/net/RequestFinishedInfo.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProvider.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataSink.java", - "components/cronet/android/api/src/org/chromium/net/UrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ByteArrayCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ContentTypeParametersParser.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetRequestCompletionListener.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetResponse.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ImplicitFlowControlCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/InMemoryTransformCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/JsonCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandler.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandlers.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/StringCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UrlRequestCallbacks.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetController.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetEngine.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetProvider.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlRequest.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlResponse.java", - "components/cronet/android/fake/java/org/chromium/net/test/ResponseMatcher.java", - "components/cronet/android/fake/java/org/chromium/net/test/UrlResponseMatcher.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java", - "components/cronet/android/java/src/org/chromium/net/impl/CallbackExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLoggerFactory.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetManifest.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetMetrics.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", - "components/cronet/android/java/src/org/chromium/net/impl/InputStreamChannel.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngine.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUploadDataSinkBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequestUtils.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderWithLibraryLoaderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NoOpLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/Preconditions.java", - "components/cronet/android/java/src/org/chromium/net/impl/QuicExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlResponseInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UserAgent.java", - "components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetChunkedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetInputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactory.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java", - "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/ChromiumNetworkAdapter.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/HttpNegotiateConstants.java", - "net/android/java/src/org/chromium/net/HttpUtil.java", - "net/android/java/src/org/chromium/net/MimeTypeFilter.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/NetworkChangeNotifierAutoDetect.java", - "net/android/java/src/org/chromium/net/NetworkTrafficAnnotationTag.java", - "net/android/java/src/org/chromium/net/ProxyBroadcastReceiver.java", - "net/android/java/src/org/chromium/net/ProxyChangeListener.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyAlwaysRegister.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java", - "net/android/java/src/org/chromium/net/ThreadStatsUid.java", - "net/android/java/src/org/chromium/net/X509Util.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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:cronet_jni_registration__android_x86_64 -cc_genrule { - name: "cronet_aml_components_cronet_android_cronet_jni_registration__android_x86_64", - srcs: [ - "base/android/java/src/org/chromium/base/ActivityState.java", - "base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java", - "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/ByteArrayGenerator.java", - "base/android/java/src/org/chromium/base/Callback.java", - "base/android/java/src/org/chromium/base/CallbackController.java", - "base/android/java/src/org/chromium/base/CollectionUtil.java", - "base/android/java/src/org/chromium/base/CommandLine.java", - "base/android/java/src/org/chromium/base/CommandLineInitUtil.java", - "base/android/java/src/org/chromium/base/Consumer.java", - "base/android/java/src/org/chromium/base/ContentUriUtils.java", - "base/android/java/src/org/chromium/base/ContextUtils.java", - "base/android/java/src/org/chromium/base/CpuFeatures.java", - "base/android/java/src/org/chromium/base/DiscardableReferencePool.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/Function.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/IntentUtils.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/JniException.java", - "base/android/java/src/org/chromium/base/JniStaticTestMocker.java", - "base/android/java/src/org/chromium/base/LifetimeAssert.java", - "base/android/java/src/org/chromium/base/LocaleUtils.java", - "base/android/java/src/org/chromium/base/Log.java", - "base/android/java/src/org/chromium/base/MathUtils.java", - "base/android/java/src/org/chromium/base/MemoryPressureListener.java", - "base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java", - "base/android/java/src/org/chromium/base/ObserverList.java", - "base/android/java/src/org/chromium/base/PackageManagerUtils.java", - "base/android/java/src/org/chromium/base/PackageUtils.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/PiiElider.java", - "base/android/java/src/org/chromium/base/PowerMonitor.java", - "base/android/java/src/org/chromium/base/PowerMonitorForQ.java", - "base/android/java/src/org/chromium/base/Predicate.java", - "base/android/java/src/org/chromium/base/Promise.java", - "base/android/java/src/org/chromium/base/RadioUtils.java", - "base/android/java/src/org/chromium/base/StreamUtil.java", - "base/android/java/src/org/chromium/base/StrictModeContext.java", - "base/android/java/src/org/chromium/base/ThreadUtils.java", - "base/android/java/src/org/chromium/base/TimeUtils.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/UnownedUserData.java", - "base/android/java/src/org/chromium/base/UnownedUserDataHost.java", - "base/android/java/src/org/chromium/base/UnownedUserDataKey.java", - "base/android/java/src/org/chromium/base/UserData.java", - "base/android/java/src/org/chromium/base/UserDataHost.java", - "base/android/java/src/org/chromium/base/WrappedClassLoader.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", - "base/android/java/src/org/chromium/base/compat/ApiHelperForM.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForN.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForO.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForOMR1.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForP.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForQ.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForR.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForS.java", - "base/android/java/src/org/chromium/base/jank_tracker/DummyJankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricCalculator.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankScenario.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java", - "base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - "base/android/java/src/org/chromium/base/library_loader/Linker.java", - "base/android/java/src/org/chromium/base/library_loader/LinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/NativeLibraryPreloader.java", - "base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java", - "base/android/java/src/org/chromium/base/lifetime/DestroyChecker.java", - "base/android/java/src/org/chromium/base/lifetime/Destroyable.java", - "base/android/java/src/org/chromium/base/memory/JavaHeapDumpGenerator.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureCallback.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureMonitor.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureUma.java", - "base/android/java/src/org/chromium/base/memory/MemoryPurgeManager.java", - "base/android/java/src/org/chromium/base/metrics/CachingUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NativeUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NoopUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/RecordHistogram.java", - "base/android/java/src/org/chromium/base/metrics/RecordUserAction.java", - "base/android/java/src/org/chromium/base/metrics/ScopedSysTraceEvent.java", - "base/android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java", - "base/android/java/src/org/chromium/base/metrics/TimingMetric.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java", - "base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java", - "base/android/java/src/org/chromium/base/process_launcher/BindService.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConstants.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionFactory.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionImpl.java", - "base/android/java/src/org/chromium/base/process_launcher/FileDescriptorInfo.java", - "base/android/java/src/org/chromium/base/supplier/BooleanSupplier.java", - "base/android/java/src/org/chromium/base/supplier/DestroyableObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/OneShotCallback.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplier.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/Supplier.java", - "base/android/java/src/org/chromium/base/supplier/UnownedUserDataSupplier.java", - "base/android/java/src/org/chromium/base/task/AsyncTask.java", - "base/android/java/src/org/chromium/base/task/BackgroundOnlyAsyncTask.java", - "base/android/java/src/org/chromium/base/task/ChainedTasks.java", - "base/android/java/src/org/chromium/base/task/ChoreographerTaskRunner.java", - "base/android/java/src/org/chromium/base/task/ChromeThreadPoolExecutor.java", - "base/android/java/src/org/chromium/base/task/DefaultTaskExecutor.java", - "base/android/java/src/org/chromium/base/task/PostTask.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/SerialExecutor.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskExecutor.java", - "base/android/java/src/org/chromium/base/task/TaskRunner.java", - "base/android/java/src/org/chromium/base/task/TaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskTraits.java", - "base/android/java/src/org/chromium/base/task/TaskTraitsExtensionDescriptor.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/api/src/org/chromium/net/BidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/CallbackException.java", - "components/cronet/android/api/src/org/chromium/net/CronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/CronetException.java", - "components/cronet/android/api/src/org/chromium/net/CronetProvider.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalBidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalUrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/ICronetEngineBuilder.java", - "components/cronet/android/api/src/org/chromium/net/InlineExecutionProhibitedException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityRttListener.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityThroughputListener.java", - "components/cronet/android/api/src/org/chromium/net/QuicException.java", - "components/cronet/android/api/src/org/chromium/net/RequestFinishedInfo.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProvider.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataSink.java", - "components/cronet/android/api/src/org/chromium/net/UrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ByteArrayCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ContentTypeParametersParser.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetRequestCompletionListener.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetResponse.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ImplicitFlowControlCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/InMemoryTransformCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/JsonCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandler.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandlers.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/StringCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UrlRequestCallbacks.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetController.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetEngine.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetProvider.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlRequest.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlResponse.java", - "components/cronet/android/fake/java/org/chromium/net/test/ResponseMatcher.java", - "components/cronet/android/fake/java/org/chromium/net/test/UrlResponseMatcher.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java", - "components/cronet/android/java/src/org/chromium/net/impl/CallbackExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLoggerFactory.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetManifest.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetMetrics.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", - "components/cronet/android/java/src/org/chromium/net/impl/InputStreamChannel.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngine.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUploadDataSinkBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequestUtils.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderWithLibraryLoaderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NoOpLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/Preconditions.java", - "components/cronet/android/java/src/org/chromium/net/impl/QuicExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlResponseInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UserAgent.java", - "components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetChunkedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetInputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactory.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java", - "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/ChromiumNetworkAdapter.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/HttpNegotiateConstants.java", - "net/android/java/src/org/chromium/net/HttpUtil.java", - "net/android/java/src/org/chromium/net/MimeTypeFilter.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/NetworkChangeNotifierAutoDetect.java", - "net/android/java/src/org/chromium/net/NetworkTrafficAnnotationTag.java", - "net/android/java/src/org/chromium/net/ProxyBroadcastReceiver.java", - "net/android/java/src/org/chromium/net/ProxyChangeListener.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyAlwaysRegister.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java", - "net/android/java/src/org/chromium/net/ThreadStatsUid.java", - "net/android/java/src/org/chromium/net/X509Util.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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet/android:cronet_jni_registration -java_genrule { - name: "cronet_aml_components_cronet_android_cronet_jni_registration__java", - srcs: [ - "base/android/java/src/org/chromium/base/ActivityState.java", - "base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java", - "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/ByteArrayGenerator.java", - "base/android/java/src/org/chromium/base/Callback.java", - "base/android/java/src/org/chromium/base/CallbackController.java", - "base/android/java/src/org/chromium/base/CollectionUtil.java", - "base/android/java/src/org/chromium/base/CommandLine.java", - "base/android/java/src/org/chromium/base/CommandLineInitUtil.java", - "base/android/java/src/org/chromium/base/Consumer.java", - "base/android/java/src/org/chromium/base/ContentUriUtils.java", - "base/android/java/src/org/chromium/base/ContextUtils.java", - "base/android/java/src/org/chromium/base/CpuFeatures.java", - "base/android/java/src/org/chromium/base/DiscardableReferencePool.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/Function.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/IntentUtils.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/JniException.java", - "base/android/java/src/org/chromium/base/JniStaticTestMocker.java", - "base/android/java/src/org/chromium/base/LifetimeAssert.java", - "base/android/java/src/org/chromium/base/LocaleUtils.java", - "base/android/java/src/org/chromium/base/Log.java", - "base/android/java/src/org/chromium/base/MathUtils.java", - "base/android/java/src/org/chromium/base/MemoryPressureListener.java", - "base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java", - "base/android/java/src/org/chromium/base/ObserverList.java", - "base/android/java/src/org/chromium/base/PackageManagerUtils.java", - "base/android/java/src/org/chromium/base/PackageUtils.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/PiiElider.java", - "base/android/java/src/org/chromium/base/PowerMonitor.java", - "base/android/java/src/org/chromium/base/PowerMonitorForQ.java", - "base/android/java/src/org/chromium/base/Predicate.java", - "base/android/java/src/org/chromium/base/Promise.java", - "base/android/java/src/org/chromium/base/RadioUtils.java", - "base/android/java/src/org/chromium/base/StreamUtil.java", - "base/android/java/src/org/chromium/base/StrictModeContext.java", - "base/android/java/src/org/chromium/base/ThreadUtils.java", - "base/android/java/src/org/chromium/base/TimeUtils.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/UnownedUserData.java", - "base/android/java/src/org/chromium/base/UnownedUserDataHost.java", - "base/android/java/src/org/chromium/base/UnownedUserDataKey.java", - "base/android/java/src/org/chromium/base/UserData.java", - "base/android/java/src/org/chromium/base/UserDataHost.java", - "base/android/java/src/org/chromium/base/WrappedClassLoader.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", - "base/android/java/src/org/chromium/base/compat/ApiHelperForM.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForN.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForO.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForOMR1.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForP.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForQ.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForR.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForS.java", - "base/android/java/src/org/chromium/base/jank_tracker/DummyJankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricCalculator.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankScenario.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java", - "base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java", - "base/android/java/src/org/chromium/base/library_loader/Linker.java", - "base/android/java/src/org/chromium/base/library_loader/LinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/NativeLibraryPreloader.java", - "base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java", - "base/android/java/src/org/chromium/base/lifetime/DestroyChecker.java", - "base/android/java/src/org/chromium/base/lifetime/Destroyable.java", - "base/android/java/src/org/chromium/base/memory/JavaHeapDumpGenerator.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureCallback.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureMonitor.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureUma.java", - "base/android/java/src/org/chromium/base/memory/MemoryPurgeManager.java", - "base/android/java/src/org/chromium/base/metrics/CachingUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NativeUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NoopUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/RecordHistogram.java", - "base/android/java/src/org/chromium/base/metrics/RecordUserAction.java", - "base/android/java/src/org/chromium/base/metrics/ScopedSysTraceEvent.java", - "base/android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java", - "base/android/java/src/org/chromium/base/metrics/TimingMetric.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java", - "base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java", - "base/android/java/src/org/chromium/base/process_launcher/BindService.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConstants.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionFactory.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionImpl.java", - "base/android/java/src/org/chromium/base/process_launcher/FileDescriptorInfo.java", - "base/android/java/src/org/chromium/base/supplier/BooleanSupplier.java", - "base/android/java/src/org/chromium/base/supplier/DestroyableObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/OneShotCallback.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplier.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/Supplier.java", - "base/android/java/src/org/chromium/base/supplier/UnownedUserDataSupplier.java", - "base/android/java/src/org/chromium/base/task/AsyncTask.java", - "base/android/java/src/org/chromium/base/task/BackgroundOnlyAsyncTask.java", - "base/android/java/src/org/chromium/base/task/ChainedTasks.java", - "base/android/java/src/org/chromium/base/task/ChoreographerTaskRunner.java", - "base/android/java/src/org/chromium/base/task/ChromeThreadPoolExecutor.java", - "base/android/java/src/org/chromium/base/task/DefaultTaskExecutor.java", - "base/android/java/src/org/chromium/base/task/PostTask.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/SerialExecutor.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskExecutor.java", - "base/android/java/src/org/chromium/base/task/TaskRunner.java", - "base/android/java/src/org/chromium/base/task/TaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskTraits.java", - "base/android/java/src/org/chromium/base/task/TaskTraitsExtensionDescriptor.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/api/src/org/chromium/net/BidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/CallbackException.java", - "components/cronet/android/api/src/org/chromium/net/CronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/CronetException.java", - "components/cronet/android/api/src/org/chromium/net/CronetProvider.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalBidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalUrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/ICronetEngineBuilder.java", - "components/cronet/android/api/src/org/chromium/net/InlineExecutionProhibitedException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityRttListener.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityThroughputListener.java", - "components/cronet/android/api/src/org/chromium/net/QuicException.java", - "components/cronet/android/api/src/org/chromium/net/RequestFinishedInfo.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProvider.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataSink.java", - "components/cronet/android/api/src/org/chromium/net/UrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ByteArrayCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ContentTypeParametersParser.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetRequestCompletionListener.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetResponse.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ImplicitFlowControlCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/InMemoryTransformCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/JsonCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandler.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandlers.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/StringCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UrlRequestCallbacks.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetController.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetEngine.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetProvider.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlRequest.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlResponse.java", - "components/cronet/android/fake/java/org/chromium/net/test/ResponseMatcher.java", - "components/cronet/android/fake/java/org/chromium/net/test/UrlResponseMatcher.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java", - "components/cronet/android/java/src/org/chromium/net/impl/CallbackExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLoggerFactory.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetManifest.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetMetrics.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", - "components/cronet/android/java/src/org/chromium/net/impl/InputStreamChannel.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngine.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUploadDataSinkBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequestUtils.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderWithLibraryLoaderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NoOpLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/Preconditions.java", - "components/cronet/android/java/src/org/chromium/net/impl/QuicExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlResponseInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UserAgent.java", - "components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetChunkedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetInputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactory.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java", - "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/ChromiumNetworkAdapter.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/HttpNegotiateConstants.java", - "net/android/java/src/org/chromium/net/HttpUtil.java", - "net/android/java/src/org/chromium/net/MimeTypeFilter.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/NetworkChangeNotifierAutoDetect.java", - "net/android/java/src/org/chromium/net/NetworkTrafficAnnotationTag.java", - "net/android/java/src/org/chromium/net/ProxyBroadcastReceiver.java", - "net/android/java/src/org/chromium/net/ProxyChangeListener.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyAlwaysRegister.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java", - "net/android/java/src/org/chromium/net/ThreadStatsUid.java", - "net/android/java/src/org/chromium/net/X509Util.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.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 -cc_object { - 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", - ], - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_components_prefs_prefs", - "cronet_aml_crypto_crypto", - "cronet_aml_net_net", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_third_party_metrics_proto_metrics_proto_gen_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", - "-DGOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0", - "-DGOOGLE_PROTOBUF_NO_RTTI", - "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER", - "-DHAVE_PTHREAD", - "-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", - "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/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_components_cronet_android_buildflags__android_arm", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_arm", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_arm", - "cronet_aml_components_cronet_cronet_buildflags__android_arm", - "cronet_aml_components_cronet_cronet_version_header_action__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_components_cronet_android_buildflags__android_arm64", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_arm64", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_arm64", - "cronet_aml_components_cronet_cronet_buildflags__android_arm64", - "cronet_aml_components_cronet_cronet_version_header_action__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_components_cronet_android_buildflags__android_x86", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_x86", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_x86", - "cronet_aml_components_cronet_cronet_buildflags__android_x86", - "cronet_aml_components_cronet_cronet_version_header_action__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_components_cronet_android_buildflags__android_x86_64", - "cronet_aml_components_cronet_android_cronet_jni_headers__android_x86_64", - "cronet_aml_components_cronet_android_cronet_jni_registration__android_x86_64", - "cronet_aml_components_cronet_cronet_buildflags__android_x86_64", - "cronet_aml_components_cronet_cronet_version_header_action__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //components/cronet/android:http_cache_type_java -java_genrule { - name: "cronet_aml_components_cronet_android_http_cache_type_java", - cmd: "$(location build/android/gyp/java_cpp_enum.py) --srcjar " + - "$(out) " + - "$(location components/cronet/url_request_context_config.h)", - out: [ - "components/cronet/android/http_cache_type_java.srcjar", - ], - tool_files: [ - "build/android/gyp/java_cpp_enum.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - "components/cronet/url_request_context_config.h", - ], -} - -// GN: //components/cronet/android:implementation_api_version -java_genrule { - name: "cronet_aml_components_cronet_android_implementation_api_version", - cmd: "$(location build/util/version.py) -f " + - "$(location chrome/VERSION) " + - "-f " + - "$(location build/util/LASTCHANGE) " + - "-e " + - "'API_LEVEL=20' " + - "-o " + - "$(out) " + - "$(location components/cronet/android/java/src/org/chromium/net/impl/ImplVersion.template)", - out: [ - "components/cronet/android/templates/org/chromium/net/impl/ImplVersion.java", - ], - tool_files: [ - "build/util/LASTCHANGE", - "build/util/android_chrome_version.py", - "build/util/version.py", - "chrome/VERSION", - "components/cronet/android/java/src/org/chromium/net/impl/ImplVersion.template", - ], -} - -// GN: //components/cronet/android:integrated_mode_state -genrule { - name: "cronet_aml_components_cronet_android_integrated_mode_state", - srcs: [ - ":cronet_aml_components_cronet_android_integrated_mode_state_preprocess", - ], - tools: [ - "soong_zip", - ], - cmd: "cp $(in) $(genDir)/IntegratedModeState.java && " + - "$(location soong_zip) -o $(out) -srcjar -f $(genDir)/IntegratedModeState.java", - out: [ - "IntegratedModeState.srcjar", - ], -} - -// GN: //components/cronet/android:integrated_mode_state -cc_object { - name: "cronet_aml_components_cronet_android_integrated_mode_state_preprocess", - srcs: [ - ":cronet_aml_components_cronet_android_integrated_mode_state_rename", - ], - cflags: [ - "-DANDROID", - "-E", - "-P", - ], - compile_multilib: "first", -} - -// GN: //components/cronet/android:integrated_mode_state -genrule { - name: "cronet_aml_components_cronet_android_integrated_mode_state_rename", - srcs: [ - "components/cronet/android/java/src/org/chromium/net/impl/IntegratedModeState.template", - ], - cmd: "cp $(in) $(out)", - out: [ - "IntegratedModeState.cc", - ], -} - -// GN: //components/cronet/android:interface_api_version -java_genrule { - name: "cronet_aml_components_cronet_android_interface_api_version", - cmd: "$(location build/util/version.py) -f " + - "$(location chrome/VERSION) " + - "-f " + - "$(location build/util/LASTCHANGE) " + - "-e " + - "'API_LEVEL=20' " + - "-o " + - "$(out) " + - "$(location components/cronet/android/api/src/org/chromium/net/ApiVersion.template)", - out: [ - "components/cronet/android/templates/org/chromium/net/ApiVersion.java", - ], - tool_files: [ - "build/util/LASTCHANGE", - "build/util/android_chrome_version.py", - "build/util/version.py", - "chrome/VERSION", - "components/cronet/android/api/src/org/chromium/net/ApiVersion.template", - ], -} - -// GN: //components/cronet/android:load_states_list -genrule { - name: "cronet_aml_components_cronet_android_load_states_list", - srcs: [ - ":cronet_aml_components_cronet_android_load_states_list_preprocess", - ], - tools: [ - "soong_zip", - ], - cmd: "cp $(in) $(genDir)/LoadState.java && " + - "$(location soong_zip) -o $(out) -srcjar -f $(genDir)/LoadState.java", - out: [ - "LoadState.srcjar", - ], -} - -// GN: //components/cronet/android:load_states_list -cc_object { - name: "cronet_aml_components_cronet_android_load_states_list_preprocess", - srcs: [ - ":cronet_aml_components_cronet_android_load_states_list_rename", - ], - cflags: [ - "-DANDROID", - "-E", - "-P", - ], - compile_multilib: "first", -} - -// GN: //components/cronet/android:load_states_list -genrule { - name: "cronet_aml_components_cronet_android_load_states_list_rename", - srcs: [ - "components/cronet/android/java/src/org/chromium/net/impl/LoadState.template", - ], - cmd: "cp $(in) $(out)", - out: [ - "LoadState.cc", - ], -} - -// GN: //components/cronet/android:net_idempotency_java -java_genrule { - name: "cronet_aml_components_cronet_android_net_idempotency_java", - cmd: "$(location build/android/gyp/java_cpp_enum.py) --srcjar " + - "$(out) " + - "$(location net/base/idempotency.h)", - out: [ - "components/cronet/android/net_idempotency_java.srcjar", - ], - tool_files: [ - "build/android/gyp/java_cpp_enum.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - "net/base/idempotency.h", - ], -} - -// GN: //components/cronet/android:net_request_priority_java -java_genrule { - name: "cronet_aml_components_cronet_android_net_request_priority_java", - cmd: "$(location build/android/gyp/java_cpp_enum.py) --srcjar " + - "$(out) " + - "$(location net/base/request_priority.h)", - out: [ - "components/cronet/android/net_request_priority_java.srcjar", - ], - tool_files: [ - "build/android/gyp/java_cpp_enum.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - "net/base/request_priority.h", - ], -} - -// GN: //components/cronet/android:network_quality_observation_source_java -java_genrule { - name: "cronet_aml_components_cronet_android_network_quality_observation_source_java", - cmd: "$(location build/android/gyp/java_cpp_enum.py) --srcjar " + - "$(out) " + - "$(location net/nqe/network_quality_observation_source.h)", - out: [ - "components/cronet/android/network_quality_observation_source_java.srcjar", - ], - tool_files: [ - "build/android/gyp/java_cpp_enum.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - "net/nqe/network_quality_observation_source.h", - ], -} - -// GN: //components/cronet/android:rtt_throughput_values_java -java_genrule { - name: "cronet_aml_components_cronet_android_rtt_throughput_values_java", - cmd: "$(location build/android/gyp/java_cpp_enum.py) --srcjar " + - "$(out) " + - "$(location net/nqe/network_quality.h)", - out: [ - "components/cronet/android/rtt_throughput_values_java.srcjar", - ], - tool_files: [ - "build/android/gyp/java_cpp_enum.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - "net/nqe/network_quality.h", - ], -} - -// GN: //components/cronet/android:url_request_error_java -java_genrule { - name: "cronet_aml_components_cronet_android_url_request_error_java", - cmd: "$(location build/android/gyp/java_cpp_enum.py) --srcjar " + - "$(out) " + - "$(location components/cronet/android/url_request_error.h)", - out: [ - "components/cronet/android/url_request_error_java.srcjar", - ], - tool_files: [ - "build/android/gyp/java_cpp_enum.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - "components/cronet/android/url_request_error.h", - ], -} - -// GN: //components/cronet:cronet_buildflags__android_arm -cc_genrule { - name: "cronet_aml_components_cronet_cronet_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet:cronet_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_components_cronet_cronet_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet:cronet_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_components_cronet_cronet_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet:cronet_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_components_cronet_cronet_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet:cronet_common -cc_object { - 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", - ], - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_components_prefs_prefs", - "cronet_aml_crypto_crypto", - "cronet_aml_net_net", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_third_party_metrics_proto_metrics_proto_gen_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", - "-DGOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0", - "-DGOOGLE_PROTOBUF_NO_RTTI", - "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER", - "-DHAVE_PTHREAD", - "-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", - "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/protobuf/src/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_components_cronet_cronet_buildflags__android_arm", - "cronet_aml_components_cronet_cronet_version_header_action__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_components_cronet_cronet_buildflags__android_arm64", - "cronet_aml_components_cronet_cronet_version_header_action__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_components_cronet_cronet_buildflags__android_x86", - "cronet_aml_components_cronet_cronet_version_header_action__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_components_cronet_cronet_buildflags__android_x86_64", - "cronet_aml_components_cronet_cronet_version_header_action__android_x86_64", - ], - }, - }, -} - -// GN: //components/cronet:cronet_version_header -cc_object { - name: "cronet_aml_components_cronet_cronet_version_header", - 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", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_components_cronet_cronet_version_header_action__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_components_cronet_cronet_version_header_action__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_components_cronet_cronet_version_header_action__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_components_cronet_cronet_version_header_action__android_x86_64", - ], - }, - }, -} - -// GN: //components/cronet:cronet_version_header_action__android_arm -cc_genrule { - name: "cronet_aml_components_cronet_cronet_version_header_action__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet:cronet_version_header_action__android_arm64 -cc_genrule { - name: "cronet_aml_components_cronet_cronet_version_header_action__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet:cronet_version_header_action__android_x86 -cc_genrule { - name: "cronet_aml_components_cronet_cronet_version_header_action__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet:cronet_version_header_action__android_x86_64 -cc_genrule { - name: "cronet_aml_components_cronet_cronet_version_header_action__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/cronet:metrics_util -cc_object { - name: "cronet_aml_components_cronet_metrics_util", - srcs: [ - "components/cronet/metrics_util.cc", - ], - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_boringssl_boringssl", - "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", - ], - 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/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //components/cronet/native:cronet_native_headers -cc_object { - name: "cronet_aml_components_cronet_native_cronet_native_headers", - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_boringssl_boringssl", - "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", - ], - 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", - "components/cronet/native/generated/", - "components/cronet/native/include/", - "components/grpc_support/include/", - "third_party/abseil-cpp/", - "third_party/boringssl/src/include/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //components/cronet/native:cronet_native_impl -cc_object { - 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", - ], - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_components_prefs_prefs", - "cronet_aml_crypto_crypto", - "cronet_aml_net_net", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_third_party_metrics_proto_metrics_proto_gen_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", - "-DGOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0", - "-DGOOGLE_PROTOBUF_NO_RTTI", - "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER", - "-DHAVE_PTHREAD", - "-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", - "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/protobuf/src/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_components_cronet_cronet_buildflags__android_arm", - "cronet_aml_components_cronet_cronet_version_header_action__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_components_cronet_cronet_buildflags__android_arm64", - "cronet_aml_components_cronet_cronet_version_header_action__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_components_cronet_cronet_buildflags__android_x86", - "cronet_aml_components_cronet_cronet_version_header_action__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_components_cronet_cronet_buildflags__android_x86_64", - "cronet_aml_components_cronet_cronet_version_header_action__android_x86_64", - ], - }, - }, -} - -// GN: //components/grpc_support:grpc_support -cc_object { - name: "cronet_aml_components_grpc_support_grpc_support", - srcs: [ - "components/grpc_support/bidirectional_stream.cc", - "components/grpc_support/bidirectional_stream_c.cc", - ], - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_crypto_crypto", - "cronet_aml_net_net", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - 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", - "-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/protobuf/src/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //components/grpc_support:headers -cc_object { - name: "cronet_aml_components_grpc_support_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", - "-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", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //components/metrics:library_support -cc_object { - name: "cronet_aml_components_metrics_library_support", - srcs: [ - ":cronet_aml_third_party_metrics_proto_metrics_proto_gen", - "components/metrics/histogram_encoder.cc", - "components/metrics/library_support/histogram_manager.cc", - ], - shared_libs: [ - "libandroid", - "liblog", - "libprotobuf-cpp-lite", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_boringssl_boringssl", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - ], - generated_headers: [ - "cronet_aml_third_party_metrics_proto_metrics_proto_gen_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", - "-DGOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0", - "-DGOOGLE_PROTOBUF_NO_RTTI", - "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER", - "-DHAVE_PTHREAD", - "-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/protobuf/src/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //components/nacl/common:buildflags__host -cc_genrule { - name: "cronet_aml_components_nacl_common_buildflags__host", - cmd: "echo '--flags ENABLE_NACL=\"true\" IS_MINIMAL_TOOLCHAIN=\"false\"' | " + - "$(location build/write_buildflag_header.py) --output " + - "$(out) " + - "--rulename " + - "//components/nacl/common:buildflags " + - "--gen-dir " + - ". " + - "--definitions " + - "/dev/stdin", - host_supported: true, - device_supported: false, - out: [ - "components/nacl/common/buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/prefs/android:jni_headers__android_arm -cc_genrule { - name: "cronet_aml_components_prefs_android_jni_headers__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/prefs/android:jni_headers__android_arm64 -cc_genrule { - name: "cronet_aml_components_prefs_android_jni_headers__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/prefs/android:jni_headers__android_x86 -cc_genrule { - name: "cronet_aml_components_prefs_android_jni_headers__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //components/prefs/android:jni_headers__android_x86_64 -cc_genrule { - name: "cronet_aml_components_prefs_android_jni_headers__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// 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_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_boringssl_boringssl", - "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", - ], - 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/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_components_prefs_android_jni_headers__android_arm", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_components_prefs_android_jni_headers__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_components_prefs_android_jni_headers__android_arm64", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_components_prefs_android_jni_headers__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_components_prefs_android_jni_headers__android_x86", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_components_prefs_android_jni_headers__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_components_prefs_android_jni_headers__android_x86_64", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_components_prefs_android_jni_headers__android_x86_64", - ], - }, - }, -} - -// GN: //crypto:buildflags__android_arm -cc_genrule { - name: "cronet_aml_crypto_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //crypto:buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_crypto_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //crypto:buildflags__android_x86 -cc_genrule { - name: "cronet_aml_crypto_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //crypto:buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_crypto_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //crypto:buildflags__host -cc_genrule { - name: "cronet_aml_crypto_buildflags__host", - cmd: "echo '--flags USE_NSS_CERTS=\"true\"' | " + - "$(location build/write_buildflag_header.py) --output " + - "$(out) " + - "--rulename " + - "//crypto:buildflags " + - "--gen-dir " + - ". " + - "--definitions " + - "/dev/stdin", - host_supported: true, - device_supported: false, - out: [ - "crypto/crypto_buildflags.h", - ], - tool_files: [ - "build/write_buildflag_header.py", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// 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", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_boringssl_boringssl", - "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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCRYPTO_IMPLEMENTATION", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/", - ], - cpp_std: "c++20", - target: { - android: { - shared_libs: [ - "libandroid", - "liblog", - ], - }, - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_crypto_buildflags__android_arm", - ], - export_generated_headers: [ - "cronet_aml_crypto_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_crypto_buildflags__android_arm64", - ], - export_generated_headers: [ - "cronet_aml_crypto_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_crypto_buildflags__android_x86", - ], - export_generated_headers: [ - "cronet_aml_crypto_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_crypto_buildflags__android_x86_64", - ], - export_generated_headers: [ - "cronet_aml_crypto_buildflags__android_x86_64", - ], - }, - host: { - srcs: [ - "crypto/nss_key_util.cc", - "crypto/nss_util.cc", - ], - static_libs: [ - "cronet_aml_base_third_party_symbolize_symbolize", - "cronet_aml_base_third_party_xdg_mime_xdg_mime", - "cronet_aml_base_third_party_xdg_user_dirs_xdg_user_dirs", - ], - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - local_include_dirs: [ - "build/linux/debian_bullseye_amd64-sysroot/usr/include/nspr", - "build/linux/debian_bullseye_amd64-sysroot/usr/include/nss", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - "cronet_aml_components_nacl_common_buildflags__host", - "cronet_aml_crypto_buildflags__host", - ], - export_generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - "cronet_aml_components_nacl_common_buildflags__host", - "cronet_aml_crypto_buildflags__host", - ], - }, - }, -} - -// GN: //gn:default_deps -cc_defaults { - name: "cronet_aml_defaults", - cflags: [ - "-DGOOGLE_PROTOBUF_NO_RTTI", - "-O2", - "-Wno-ambiguous-reversed-operator", - "-Wno-deprecated-non-prototype", - "-Wno-error=return-type", - "-Wno-macro-redefined", - "-Wno-missing-field-initializers", - "-Wno-non-virtual-dtor", - "-Wno-null-pointer-subtraction", - "-Wno-sign-compare", - "-Wno-sign-promo", - "-Wno-unreachable-code-loop-increment", - "-Wno-unused-parameter", - "-fPIC", - "-fvisibility=hidden", - ], - stl: "none", - apex_available: [ - "com.android.tethering", - ], - min_sdk_version: "29", - target: { - android: { - header_libs: [ - "jni_headers", - "media_ndk_headers", - ], - }, - host: { - cflags: [ - "-UANDROID", - ], - }, - }, -} - -// GN: //ipc:param_traits -cc_object { - name: "cronet_aml_ipc_param_traits", - 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", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //gn:java -java_library { - name: "cronet_aml_java", - srcs: [ - ":cronet_aml_base_base_android_java_enums_srcjar", - ":cronet_aml_base_java_features_srcjar", - ":cronet_aml_base_java_switches_srcjar", - ":cronet_aml_build_android_build_config_gen", - ":cronet_aml_build_android_native_libraries_gen", - ":cronet_aml_components_cronet_android_cronet_jni_registration__java", - ":cronet_aml_components_cronet_android_http_cache_type_java", - ":cronet_aml_components_cronet_android_implementation_api_version", - ":cronet_aml_components_cronet_android_integrated_mode_state", - ":cronet_aml_components_cronet_android_interface_api_version", - ":cronet_aml_components_cronet_android_load_states_list", - ":cronet_aml_components_cronet_android_net_idempotency_java", - ":cronet_aml_components_cronet_android_net_request_priority_java", - ":cronet_aml_components_cronet_android_network_quality_observation_source_java", - ":cronet_aml_components_cronet_android_rtt_throughput_values_java", - ":cronet_aml_components_cronet_android_url_request_error_java", - ":cronet_aml_net_android_net_android_java_enums_srcjar", - ":cronet_aml_net_android_net_errors_java", - ":cronet_aml_net_effective_connection_type_java", - "base/android/java/src/org/chromium/base/ActivityState.java", - "base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java", - "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/ByteArrayGenerator.java", - "base/android/java/src/org/chromium/base/Callback.java", - "base/android/java/src/org/chromium/base/CallbackController.java", - "base/android/java/src/org/chromium/base/CollectionUtil.java", - "base/android/java/src/org/chromium/base/CommandLine.java", - "base/android/java/src/org/chromium/base/CommandLineInitUtil.java", - "base/android/java/src/org/chromium/base/Consumer.java", - "base/android/java/src/org/chromium/base/ContentUriUtils.java", - "base/android/java/src/org/chromium/base/ContextUtils.java", - "base/android/java/src/org/chromium/base/CpuFeatures.java", - "base/android/java/src/org/chromium/base/DiscardableReferencePool.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/Function.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/IntentUtils.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/JniException.java", - "base/android/java/src/org/chromium/base/JniStaticTestMocker.java", - "base/android/java/src/org/chromium/base/LifetimeAssert.java", - "base/android/java/src/org/chromium/base/LocaleUtils.java", - "base/android/java/src/org/chromium/base/Log.java", - "base/android/java/src/org/chromium/base/MathUtils.java", - "base/android/java/src/org/chromium/base/MemoryPressureListener.java", - "base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java", - "base/android/java/src/org/chromium/base/ObserverList.java", - "base/android/java/src/org/chromium/base/PackageManagerUtils.java", - "base/android/java/src/org/chromium/base/PackageUtils.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/PiiElider.java", - "base/android/java/src/org/chromium/base/PowerMonitor.java", - "base/android/java/src/org/chromium/base/PowerMonitorForQ.java", - "base/android/java/src/org/chromium/base/Predicate.java", - "base/android/java/src/org/chromium/base/Promise.java", - "base/android/java/src/org/chromium/base/RadioUtils.java", - "base/android/java/src/org/chromium/base/StreamUtil.java", - "base/android/java/src/org/chromium/base/StrictModeContext.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/TimeUtils.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/UnownedUserData.java", - "base/android/java/src/org/chromium/base/UnownedUserDataHost.java", - "base/android/java/src/org/chromium/base/UnownedUserDataKey.java", - "base/android/java/src/org/chromium/base/UserData.java", - "base/android/java/src/org/chromium/base/UserDataHost.java", - "base/android/java/src/org/chromium/base/WrappedClassLoader.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", - "base/android/java/src/org/chromium/base/compat/ApiHelperForM.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForN.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForO.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForOMR1.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForP.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForQ.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForR.java", - "base/android/java/src/org/chromium/base/compat/ApiHelperForS.java", - "base/android/java/src/org/chromium/base/jank_tracker/DummyJankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsListener.java", - "base/android/java/src/org/chromium/base/jank_tracker/FrameMetricsStore.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankActivityTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricCalculator.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetricUMARecorder.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankMetrics.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingRunnable.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankReportingScheduler.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankScenario.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTracker.java", - "base/android/java/src/org/chromium/base/jank_tracker/JankTrackerImpl.java", - "base/android/java/src/org/chromium/base/library_loader/LegacyLinker.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/library_loader/Linker.java", - "base/android/java/src/org/chromium/base/library_loader/LinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinker.java", - "base/android/java/src/org/chromium/base/library_loader/ModernLinkerJni.java", - "base/android/java/src/org/chromium/base/library_loader/NativeLibraryPreloader.java", - "base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java", - "base/android/java/src/org/chromium/base/lifetime/DestroyChecker.java", - "base/android/java/src/org/chromium/base/lifetime/Destroyable.java", - "base/android/java/src/org/chromium/base/memory/JavaHeapDumpGenerator.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureCallback.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureMonitor.java", - "base/android/java/src/org/chromium/base/memory/MemoryPressureUma.java", - "base/android/java/src/org/chromium/base/memory/MemoryPurgeManager.java", - "base/android/java/src/org/chromium/base/metrics/CachingUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NativeUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/NoopUmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/RecordHistogram.java", - "base/android/java/src/org/chromium/base/metrics/RecordUserAction.java", - "base/android/java/src/org/chromium/base/metrics/ScopedSysTraceEvent.java", - "base/android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java", - "base/android/java/src/org/chromium/base/metrics/TimingMetric.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorder.java", - "base/android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java", - "base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java", - "base/android/java/src/org/chromium/base/process_launcher/BindService.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessConstants.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnection.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionDelegate.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionFactory.java", - "base/android/java/src/org/chromium/base/process_launcher/ChildServiceConnectionImpl.java", - "base/android/java/src/org/chromium/base/process_launcher/FileDescriptorInfo.java", - "base/android/java/src/org/chromium/base/process_launcher/IChildProcessService.aidl", - "base/android/java/src/org/chromium/base/process_launcher/IParentProcess.aidl", - "base/android/java/src/org/chromium/base/supplier/BooleanSupplier.java", - "base/android/java/src/org/chromium/base/supplier/DestroyableObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplier.java", - "base/android/java/src/org/chromium/base/supplier/ObservableSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/OneShotCallback.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplier.java", - "base/android/java/src/org/chromium/base/supplier/OneshotSupplierImpl.java", - "base/android/java/src/org/chromium/base/supplier/Supplier.java", - "base/android/java/src/org/chromium/base/supplier/UnownedUserDataSupplier.java", - "base/android/java/src/org/chromium/base/task/AsyncTask.java", - "base/android/java/src/org/chromium/base/task/BackgroundOnlyAsyncTask.java", - "base/android/java/src/org/chromium/base/task/ChainedTasks.java", - "base/android/java/src/org/chromium/base/task/ChoreographerTaskRunner.java", - "base/android/java/src/org/chromium/base/task/ChromeThreadPoolExecutor.java", - "base/android/java/src/org/chromium/base/task/DefaultTaskExecutor.java", - "base/android/java/src/org/chromium/base/task/PostTask.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SequencedTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/SerialExecutor.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunner.java", - "base/android/java/src/org/chromium/base/task/SingleThreadTaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskExecutor.java", - "base/android/java/src/org/chromium/base/task/TaskRunner.java", - "base/android/java/src/org/chromium/base/task/TaskRunnerImpl.java", - "base/android/java/src/org/chromium/base/task/TaskTraits.java", - "base/android/java/src/org/chromium/base/task/TaskTraitsExtensionDescriptor.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/api/src/org/chromium/net/BidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/CallbackException.java", - "components/cronet/android/api/src/org/chromium/net/CronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/CronetException.java", - "components/cronet/android/api/src/org/chromium/net/CronetProvider.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalBidirectionalStream.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java", - "components/cronet/android/api/src/org/chromium/net/ExperimentalUrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/ICronetEngineBuilder.java", - "components/cronet/android/api/src/org/chromium/net/InlineExecutionProhibitedException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkException.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityRttListener.java", - "components/cronet/android/api/src/org/chromium/net/NetworkQualityThroughputListener.java", - "components/cronet/android/api/src/org/chromium/net/QuicException.java", - "components/cronet/android/api/src/org/chromium/net/RequestFinishedInfo.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProvider.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/UploadDataSink.java", - "components/cronet/android/api/src/org/chromium/net/UrlRequest.java", - "components/cronet/android/api/src/org/chromium/net/UrlResponseInfo.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ByteArrayCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ContentTypeParametersParser.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetRequestCompletionListener.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/CronetResponse.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/ImplicitFlowControlCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/InMemoryTransformCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/JsonCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandler.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/RedirectHandlers.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/StringCronetCallback.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UploadDataProviders.java", - "components/cronet/android/api/src/org/chromium/net/apihelpers/UrlRequestCallbacks.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetController.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetEngine.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeCronetProvider.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlRequest.java", - "components/cronet/android/fake/java/org/chromium/net/test/FakeUrlResponse.java", - "components/cronet/android/fake/java/org/chromium/net/test/ResponseMatcher.java", - "components/cronet/android/fake/java/org/chromium/net/test/UrlResponseMatcher.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java", - "components/cronet/android/java/src/org/chromium/net/impl/CallbackExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetLoggerFactory.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetManifest.java", - "components/cronet/android/java/src/org/chromium/net/impl/CronetMetrics.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", - "components/cronet/android/java/src/org/chromium/net/impl/InputStreamChannel.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngine.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUploadDataSinkBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequest.java", - "components/cronet/android/java/src/org/chromium/net/impl/JavaUrlRequestUtils.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetEngineBuilderWithLibraryLoaderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NativeCronetProvider.java", - "components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/NoOpLogger.java", - "components/cronet/android/java/src/org/chromium/net/impl/Preconditions.java", - "components/cronet/android/java/src/org/chromium/net/impl/QuicExceptionImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/RequestFinishedInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBase.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlRequestBuilderImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UrlResponseInfoImpl.java", - "components/cronet/android/java/src/org/chromium/net/impl/UserAgent.java", - "components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetChunkedOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetInputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetOutputStream.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactory.java", - "components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java", - "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/ChromiumNetworkAdapter.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/HttpNegotiateConstants.java", - "net/android/java/src/org/chromium/net/HttpUtil.java", - "net/android/java/src/org/chromium/net/MimeTypeFilter.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/NetworkChangeNotifierAutoDetect.java", - "net/android/java/src/org/chromium/net/NetworkTrafficAnnotationTag.java", - "net/android/java/src/org/chromium/net/ProxyBroadcastReceiver.java", - "net/android/java/src/org/chromium/net/ProxyChangeListener.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyAlwaysRegister.java", - "net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java", - "net/android/java/src/org/chromium/net/ThreadStatsUid.java", - "net/android/java/src/org/chromium/net/X509Util.java", - "url/android/java/src/org/chromium/url/IDNStringUtil.java", - ], - apex_available: [ - "//apex_available:platform", - "com.android.tethering", - ], - libs: [ - "android-support-multidex", - "androidx.annotation_annotation", - "androidx.annotation_annotation-experimental-nodeps", - "androidx.collection_collection", - "androidx.core_core-nodeps", - "framework-connectivity-t.stubs.module_lib", - "framework-connectivity.stubs.module_lib", - "framework-mediaprovider.stubs.module_lib", - "framework-tethering.stubs.module_lib", - "framework-wifi.stubs.module_lib", - "jsr305", - ], - aidl: { - include_dirs: [ - "frameworks/base/core/java/", - ], - local_include_dirs: [ - "base/android/java/src/", - ], - }, - plugins: [ - "cronet_aml_java_jni_annotation_preprocessor", - ], - sdk_version: "module_current", -} - -// GN: //base/android/jni_generator:jni_processor -java_plugin { - name: "cronet_aml_java_jni_annotation_preprocessor", - srcs: [ - ":cronet_aml_build_android_build_config_gen", - "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/NativeMethods.java", - "base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java", - "build/android/java/src/org/chromium/build/annotations/CheckDiscard.java", - "build/android/java/src/org/chromium/build/annotations/MainDex.java", - ], - static_libs: [ - "auto_service_annotations", - "guava", - "javapoet", - ], - processor_class: "org.chromium.jni_generator.JniProcessor", -} - -// GN: //net/android:net_android_java_enums_srcjar -java_genrule { - name: "cronet_aml_net_android_net_android_java_enums_srcjar", - srcs: [ - "net/android/network_change_notifier_android.cc", - "net/android/traffic_stats.cc", - "net/socket/socket_tag.cc", - ], - cmd: "$(location build/android/gyp/java_cpp_enum.py) --srcjar " + - "$(out) " + - "$(location net/base/network_change_notifier.h) " + - "$(location net/socket/socket_tag.cc) " + - "$(location net/android/cert_verify_result_android.h) " + - "$(location net/android/keystore.h) " + - "$(location net/android/network_change_notifier_android.cc) " + - "$(location net/android/traffic_stats.cc)", - out: [ - "net/android/net_android_java_enums_srcjar.srcjar", - ], - tool_files: [ - "build/android/gyp/java_cpp_enum.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - "net/android/cert_verify_result_android.h", - "net/android/keystore.h", - "net/base/network_change_notifier.h", - ], -} - -// GN: //net/android:net_errors_java -genrule { - name: "cronet_aml_net_android_net_errors_java", - srcs: [ - ":cronet_aml_net_android_net_errors_java_preprocess", - ], - tools: [ - "soong_zip", - ], - cmd: "cp $(in) $(genDir)/NetError.java && " + - "$(location soong_zip) -o $(out) -srcjar -f $(genDir)/NetError.java", - out: [ - "NetError.srcjar", - ], -} - -// GN: //net/android:net_errors_java -cc_object { - name: "cronet_aml_net_android_net_errors_java_preprocess", - srcs: [ - ":cronet_aml_net_android_net_errors_java_rename", - ], - cflags: [ - "-DANDROID", - "-E", - "-P", - ], - compile_multilib: "first", -} - -// GN: //net/android:net_errors_java -genrule { - name: "cronet_aml_net_android_net_errors_java_rename", - srcs: [ - "net/android/java/NetError.template", - ], - cmd: "cp $(in) $(out)", - out: [ - "NetError.cc", - ], -} - -// GN: //net/base/registry_controlled_domains:registry_controlled_domains__android_arm -cc_genrule { - name: "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net/base/registry_controlled_domains:registry_controlled_domains__android_arm64 -cc_genrule { - name: "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net/base/registry_controlled_domains:registry_controlled_domains__android_x86 -cc_genrule { - name: "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net/base/registry_controlled_domains:registry_controlled_domains__android_x86_64 -cc_genrule { - name: "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:buildflags__android_arm -cc_genrule { - name: "cronet_aml_net_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_net_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:buildflags__android_x86 -cc_genrule { - name: "cronet_aml_net_buildflags__android_x86", - cmd: "echo '--flags POSIX_BYPASS_MMAP=\"false\" 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_net_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:constants -cc_object { - name: "cronet_aml_net_constants", - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_boringssl_boringssl", - "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", - ], - 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/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //net/data/ssl/chrome_root_store:gen_root_store_inc__android_arm -cc_genrule { - name: "cronet_aml_net_data_ssl_chrome_root_store_gen_root_store_inc__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net/data/ssl/chrome_root_store:gen_root_store_inc__android_arm64 -cc_genrule { - name: "cronet_aml_net_data_ssl_chrome_root_store_gen_root_store_inc__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net/data/ssl/chrome_root_store:gen_root_store_inc__android_x86 -cc_genrule { - name: "cronet_aml_net_data_ssl_chrome_root_store_gen_root_store_inc__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net/data/ssl/chrome_root_store:gen_root_store_inc__android_x86_64 -cc_genrule { - name: "cronet_aml_net_data_ssl_chrome_root_store_gen_root_store_inc__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net/dns:dns -cc_object { - 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", - ], - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_crypto_crypto", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_net_isolation_info_proto_gen_headers", - "cronet_aml_net_net_nqe_proto_gen_headers", - "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_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", - "-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/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - "cronet_aml_net_buildflags__android_arm", - "cronet_aml_net_net_jni_headers__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - "cronet_aml_net_buildflags__android_arm64", - "cronet_aml_net_net_jni_headers__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - "cronet_aml_net_buildflags__android_x86", - "cronet_aml_net_net_jni_headers__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - "cronet_aml_net_buildflags__android_x86_64", - "cronet_aml_net_net_jni_headers__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //net/dns:dns_client -cc_object { - name: "cronet_aml_net_dns_dns_client", - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_crypto_crypto", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_net_isolation_info_proto_gen_headers", - "cronet_aml_net_net_nqe_proto_gen_headers", - "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_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", - "-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/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - "cronet_aml_net_buildflags__android_arm", - "cronet_aml_net_net_jni_headers__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - "cronet_aml_net_buildflags__android_arm64", - "cronet_aml_net_net_jni_headers__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - "cronet_aml_net_buildflags__android_x86", - "cronet_aml_net_net_jni_headers__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - "cronet_aml_net_buildflags__android_x86_64", - "cronet_aml_net_net_jni_headers__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //net/dns:host_resolver -cc_object { - name: "cronet_aml_net_dns_host_resolver", - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_crypto_crypto", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_net_isolation_info_proto_gen_headers", - "cronet_aml_net_net_nqe_proto_gen_headers", - "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_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", - "-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/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - "cronet_aml_net_buildflags__android_arm", - "cronet_aml_net_net_jni_headers__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - "cronet_aml_net_buildflags__android_arm64", - "cronet_aml_net_net_jni_headers__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - "cronet_aml_net_buildflags__android_x86", - "cronet_aml_net_net_jni_headers__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - "cronet_aml_net_buildflags__android_x86_64", - "cronet_aml_net_net_jni_headers__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //net/dns:host_resolver_manager -cc_object { - name: "cronet_aml_net_dns_host_resolver_manager", - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_crypto_crypto", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_net_isolation_info_proto_gen_headers", - "cronet_aml_net_net_nqe_proto_gen_headers", - "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_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", - "-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/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - "cronet_aml_net_buildflags__android_arm", - "cronet_aml_net_net_jni_headers__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - "cronet_aml_net_buildflags__android_arm64", - "cronet_aml_net_net_jni_headers__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - "cronet_aml_net_buildflags__android_x86", - "cronet_aml_net_net_jni_headers__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - "cronet_aml_net_buildflags__android_x86_64", - "cronet_aml_net_net_jni_headers__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //net/dns:mdns_client -cc_object { - name: "cronet_aml_net_dns_mdns_client", - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_crypto_crypto", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_net_isolation_info_proto_gen_headers", - "cronet_aml_net_net_nqe_proto_gen_headers", - "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_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", - "-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/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - "cronet_aml_net_buildflags__android_arm", - "cronet_aml_net_net_jni_headers__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - "cronet_aml_net_buildflags__android_arm64", - "cronet_aml_net_net_jni_headers__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - "cronet_aml_net_buildflags__android_x86", - "cronet_aml_net_net_jni_headers__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - "cronet_aml_net_buildflags__android_x86_64", - "cronet_aml_net_net_jni_headers__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //net/dns/public:public -cc_object { - 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", - ], - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_crypto_crypto", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_net_isolation_info_proto_gen_headers", - "cronet_aml_net_net_nqe_proto_gen_headers", - "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_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", - "-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/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - "cronet_aml_net_buildflags__android_arm", - "cronet_aml_net_net_jni_headers__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - "cronet_aml_net_buildflags__android_arm64", - "cronet_aml_net_net_jni_headers__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - "cronet_aml_net_buildflags__android_x86", - "cronet_aml_net_net_jni_headers__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - "cronet_aml_net_buildflags__android_x86_64", - "cronet_aml_net_net_jni_headers__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //net:effective_connection_type_java -java_genrule { - name: "cronet_aml_net_effective_connection_type_java", - cmd: "$(location build/android/gyp/java_cpp_enum.py) --srcjar " + - "$(out) " + - "$(location net/nqe/effective_connection_type.h)", - out: [ - "net/effective_connection_type_java.srcjar", - ], - tool_files: [ - "build/android/gyp/java_cpp_enum.py", - "build/android/gyp/util/__init__.py", - "build/android/gyp/util/build_utils.py", - "build/android/gyp/util/java_cpp_utils.py", - "build/gn_helpers.py", - "net/nqe/effective_connection_type.h", - ], -} - -// GN: //net/http:transport_security_state_generated_files -cc_object { - name: "cronet_aml_net_http_transport_security_state_generated_files", - srcs: [ - "net/http/transport_security_state.cc", - ], - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_crypto_crypto", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_net_isolation_info_proto_gen_headers", - "cronet_aml_net_net_nqe_proto_gen_headers", - "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_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", - "-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/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_branding_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - "cronet_aml_net_buildflags__android_arm", - "cronet_aml_net_net_jni_headers__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_branding_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - "cronet_aml_net_buildflags__android_arm64", - "cronet_aml_net_net_jni_headers__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_branding_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - "cronet_aml_net_buildflags__android_x86", - "cronet_aml_net_net_jni_headers__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_branding_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - "cronet_aml_net_buildflags__android_x86_64", - "cronet_aml_net_net_jni_headers__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //net:ios_cronet_buildflags__android_arm -cc_genrule { - name: "cronet_aml_net_ios_cronet_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:ios_cronet_buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_net_ios_cronet_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:ios_cronet_buildflags__android_x86 -cc_genrule { - name: "cronet_aml_net_ios_cronet_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:ios_cronet_buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_net_ios_cronet_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:isolation_info_proto -cc_genrule { - name: "cronet_aml_net_isolation_info_proto_gen", - srcs: [ - "net/base/isolation_info.proto", - ], - tools: [ - "cronet_aml_third_party_protobuf_protoc", - ], - cmd: "$(location cronet_aml_third_party_protobuf_protoc) --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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:isolation_info_proto -cc_genrule { - name: "cronet_aml_net_isolation_info_proto_gen_headers", - srcs: [ - "net/base/isolation_info.proto", - ], - tools: [ - "cronet_aml_third_party_protobuf_protoc", - ], - cmd: "$(location cronet_aml_third_party_protobuf_protoc) --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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:net -cc_library_static { - name: "cronet_aml_net_net", - srcs: [ - ":cronet_aml_net_dns_dns", - ":cronet_aml_net_dns_public_public", - ":cronet_aml_net_http_transport_security_state_generated_files", - ":cronet_aml_net_net_deps", - ":cronet_aml_net_net_public_deps", - ":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/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", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_crypto_crypto", - "cronet_aml_net_preload_decoder", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_net_isolation_info_proto_gen_headers", - "cronet_aml_net_net_nqe_proto_gen_headers", - "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_headers", - ], - export_generated_headers: [ - "cronet_aml_net_isolation_info_proto_gen_headers", - "cronet_aml_net_net_nqe_proto_gen_headers", - "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_headers", - ], - 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/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - srcs: [ - "net/disk_cache/blockfile/mapped_file_bypass_mmap_posix.cc", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_branding_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - "cronet_aml_net_buildflags__android_arm", - "cronet_aml_net_ios_cronet_buildflags__android_arm", - "cronet_aml_net_net_jni_headers__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_branding_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - "cronet_aml_net_buildflags__android_arm", - "cronet_aml_net_ios_cronet_buildflags__android_arm", - "cronet_aml_net_net_jni_headers__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - srcs: [ - "net/disk_cache/blockfile/mapped_file_bypass_mmap_posix.cc", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_branding_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - "cronet_aml_net_buildflags__android_arm64", - "cronet_aml_net_ios_cronet_buildflags__android_arm64", - "cronet_aml_net_net_jni_headers__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_branding_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - "cronet_aml_net_buildflags__android_arm64", - "cronet_aml_net_ios_cronet_buildflags__android_arm64", - "cronet_aml_net_net_jni_headers__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - srcs: [ - "net/disk_cache/blockfile/mapped_file_posix.cc", - ], - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_branding_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - "cronet_aml_net_buildflags__android_x86", - "cronet_aml_net_ios_cronet_buildflags__android_x86", - "cronet_aml_net_net_jni_headers__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_branding_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - "cronet_aml_net_buildflags__android_x86", - "cronet_aml_net_ios_cronet_buildflags__android_x86", - "cronet_aml_net_net_jni_headers__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - srcs: [ - "net/disk_cache/blockfile/mapped_file_bypass_mmap_posix.cc", - ], - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_branding_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - "cronet_aml_net_buildflags__android_x86_64", - "cronet_aml_net_ios_cronet_buildflags__android_x86_64", - "cronet_aml_net_net_jni_headers__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_branding_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - "cronet_aml_net_buildflags__android_x86_64", - "cronet_aml_net_ios_cronet_buildflags__android_x86_64", - "cronet_aml_net_net_jni_headers__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //net:net_deps -cc_object { - name: "cronet_aml_net_net_deps", - srcs: [ - ":cronet_aml_net_isolation_info_proto_gen", - ], - shared_libs: [ - "libandroid", - "liblog", - "libprotobuf-cpp-lite", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_net_preload_decoder", - "cronet_aml_third_party_boringssl_boringssl", - "cronet_aml_third_party_brotli_common", - "cronet_aml_third_party_brotli_dec", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - ], - generated_headers: [ - "cronet_aml_net_isolation_info_proto_gen_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", - "-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", - "third_party/abseil-cpp/", - "third_party/boringssl/src/include/", - "third_party/brotli/include/", - "third_party/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm", - "cronet_aml_net_net_jni_headers__android_arm", - "cronet_aml_url_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_arm64", - "cronet_aml_net_net_jni_headers__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86", - "cronet_aml_net_net_jni_headers__android_x86", - "cronet_aml_url_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_base_registry_controlled_domains_registry_controlled_domains__android_x86_64", - "cronet_aml_net_net_jni_headers__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //net:net_export_header -cc_object { - name: "cronet_aml_net_net_export_header", - 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", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //net:net_jni_headers__android_arm -cc_genrule { - name: "cronet_aml_net_net_jni_headers__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:net_jni_headers__android_arm64 -cc_genrule { - name: "cronet_aml_net_net_jni_headers__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:net_jni_headers__android_x86 -cc_genrule { - name: "cronet_aml_net_net_jni_headers__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:net_jni_headers__android_x86_64 -cc_genrule { - name: "cronet_aml_net_net_jni_headers__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:net_nqe_proto -cc_genrule { - name: "cronet_aml_net_net_nqe_proto_gen", - srcs: [ - "net/nqe/proto/network_id_proto.proto", - ], - tools: [ - "cronet_aml_third_party_protobuf_protoc", - ], - cmd: "$(location cronet_aml_third_party_protobuf_protoc) --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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:net_nqe_proto -cc_genrule { - name: "cronet_aml_net_net_nqe_proto_gen_headers", - srcs: [ - "net/nqe/proto/network_id_proto.proto", - ], - tools: [ - "cronet_aml_third_party_protobuf_protoc", - ], - cmd: "$(location cronet_aml_third_party_protobuf_protoc) --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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net:net_public_deps -cc_object { - name: "cronet_aml_net_net_public_deps", - srcs: [ - ":cronet_aml_net_net_nqe_proto_gen", - ":cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen", - ], - shared_libs: [ - "libandroid", - "liblog", - "libprotobuf-cpp-lite", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_crypto_crypto", - "cronet_aml_net_third_party_quiche_quiche", - "cronet_aml_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_net_net_nqe_proto_gen_headers", - "cronet_aml_net_third_party_quiche_net_quic_test_tools_proto_gen_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", - "-DGOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0", - "-DGOOGLE_PROTOBUF_NO_RTTI", - "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER", - "-DHAVE_PTHREAD", - "-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", - "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/protobuf/src/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_net_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_net_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_net_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_net_buildflags__android_x86_64", - ], - }, - }, -} - -// 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_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_boringssl_boringssl", - "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", - ], - 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/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //net/third_party/quiche:net_quic_proto -cc_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: [ - "cronet_aml_third_party_protobuf_protoc", - ], - cmd: "$(location cronet_aml_third_party_protobuf_protoc) --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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net/third_party/quiche:net_quic_proto -cc_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: [ - "cronet_aml_third_party_protobuf_protoc", - ], - cmd: "$(location cronet_aml_third_party_protobuf_protoc) --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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net/third_party/quiche:net_quic_test_tools_proto -cc_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: [ - "cronet_aml_third_party_protobuf_protoc", - ], - cmd: "$(location cronet_aml_third_party_protobuf_protoc) --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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //net/third_party/quiche:net_quic_test_tools_proto -cc_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: [ - "cronet_aml_third_party_protobuf_protoc", - ], - cmd: "$(location cronet_aml_third_party_protobuf_protoc) --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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// 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_base_base", - ":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_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_container_hashtablez_sampler", - ":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_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_numeric_int128", - ":cronet_aml_third_party_abseil_cpp_absl_profiling_exponential_biased", - ":cronet_aml_third_party_abseil_cpp_absl_random_distributions", - ":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_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_seed_material", - ":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_internal", - ":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_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", - "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_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_net_uri_template", - "cronet_aml_third_party_boringssl_boringssl", - "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", - "cronet_aml_third_party_protobuf_protobuf_lite", - "cronet_aml_third_party_zlib_zlib", - "cronet_aml_url_url", - ], - generated_headers: [ - "cronet_aml_net_third_party_quiche_net_quic_proto_gen_headers", - ], - export_generated_headers: [ - "cronet_aml_net_third_party_quiche_net_quic_proto_gen_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", - "-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/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - export_generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - export_generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - export_generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - export_generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - }, -} - -// GN: //net/traffic_annotation:traffic_annotation -cc_object { - name: "cronet_aml_net_traffic_annotation_traffic_annotation", - srcs: [ - "net/traffic_annotation/network_traffic_annotation_android.cc", - ], - shared_libs: [ - "libandroid", - "liblog", - ], - static_libs: [ - "cronet_aml_base_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_boringssl_boringssl", - "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", - ], - 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/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - }, -} - -// 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_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_boringssl_boringssl", - "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", - ], - 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/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp:absl -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/algorithm:algorithm -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_algorithm_algorithm", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/algorithm:container -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_algorithm_container", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:atomic_hook -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_atomic_hook", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:base -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:base_internal -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_base_internal", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:config -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_config", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:core_headers -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_core_headers", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:cycleclock_internal -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_cycleclock_internal", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:dynamic_annotations -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_dynamic_annotations", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:endian -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_endian", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:errno_saver -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_errno_saver", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:fast_type_id -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_fast_type_id", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:log_severity -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_log_severity", - srcs: [ - "third_party/abseil-cpp/absl/base/log_severity.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:malloc_internal -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_malloc_internal", - srcs: [ - "third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:prefetch -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_prefetch", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:raw_logging_internal -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_raw_logging_internal", - srcs: [ - "third_party/abseil-cpp/absl/base/internal/raw_logging.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:spinlock_wait -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_spinlock_wait", - srcs: [ - "third_party/abseil-cpp/absl/base/internal/spinlock_wait.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:strerror -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_strerror", - srcs: [ - "third_party/abseil-cpp/absl/base/internal/strerror.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/base:throw_delegate -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_base_throw_delegate", - srcs: [ - "third_party/abseil-cpp/absl/base/internal/throw_delegate.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/cleanup:cleanup -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_cleanup_cleanup", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/cleanup:cleanup_internal -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_cleanup_cleanup_internal", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:btree -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_btree", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:common -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_common", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:common_policy_traits -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_common_policy_traits", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:compressed_tuple -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_compressed_tuple", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:container_memory -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_container_memory", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:fixed_array -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_fixed_array", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:flat_hash_map -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_flat_hash_map", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:flat_hash_set -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_flat_hash_set", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:hash_function_defaults -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_hash_function_defaults", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:hash_policy_traits -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_hash_policy_traits", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:hashtable_debug_hooks -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_hashtable_debug_hooks", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:hashtablez_sampler -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:inlined_vector -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_inlined_vector", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:inlined_vector_internal -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_inlined_vector_internal", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:layout -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_layout", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:node_hash_map -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_node_hash_map", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:node_hash_set -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_node_hash_set", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:node_slot_policy -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_node_slot_policy", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:raw_hash_map -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_raw_hash_map", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/container:raw_hash_set -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_container_raw_hash_set", - srcs: [ - "third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/debugging:debugging_internal -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/debugging:demangle_internal -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_debugging_demangle_internal", - srcs: [ - "third_party/abseil-cpp/absl/debugging/internal/demangle.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/debugging:examine_stack -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_debugging_examine_stack", - srcs: [ - "third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/debugging:failure_signal_handler -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_debugging_failure_signal_handler", - srcs: [ - "third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/debugging:stacktrace -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_debugging_stacktrace", - srcs: [ - "third_party/abseil-cpp/absl/debugging/stacktrace.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/debugging:symbolize -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_debugging_symbolize", - srcs: [ - "third_party/abseil-cpp/absl/debugging/symbolize.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/functional:any_invocable -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_functional_any_invocable", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/functional:bind_front -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_functional_bind_front", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/functional:function_ref -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_functional_function_ref", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/hash:city -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_hash_city", - srcs: [ - "third_party/abseil-cpp/absl/hash/internal/city.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/hash:hash -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_hash_hash", - srcs: [ - "third_party/abseil-cpp/absl/hash/internal/hash.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/hash:low_level_hash -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_hash_low_level_hash", - srcs: [ - "third_party/abseil-cpp/absl/hash/internal/low_level_hash.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/memory:memory -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_memory_memory", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/meta:type_traits -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_meta_type_traits", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/numeric:bits -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_numeric_bits", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/numeric:int128 -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_numeric_int128", - srcs: [ - "third_party/abseil-cpp/absl/numeric/int128.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/numeric:representation -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_numeric_representation", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/profiling:exponential_biased -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_profiling_exponential_biased", - srcs: [ - "third_party/abseil-cpp/absl/profiling/internal/exponential_biased.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/profiling:sample_recorder -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_profiling_sample_recorder", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random:distributions -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:distribution_caller -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_distribution_caller", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:fast_uniform_bits -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_fast_uniform_bits", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:fastmath -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_fastmath", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:generate_real -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_generate_real", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:iostream_state_saver -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_iostream_state_saver", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:nonsecure_base -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_nonsecure_base", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:pcg_engine -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_pcg_engine", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:platform -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_platform", - srcs: [ - "third_party/abseil-cpp/absl/random/internal/randen_round_keys.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:pool_urbg -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_pool_urbg", - srcs: [ - "third_party/abseil-cpp/absl/random/internal/pool_urbg.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:randen -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_randen", - srcs: [ - "third_party/abseil-cpp/absl/random/internal/randen.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:randen_engine -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_engine", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:randen_hwaes -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_hwaes", - srcs: [ - "third_party/abseil-cpp/absl/random/internal/randen_detect.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:randen_hwaes_impl -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_hwaes_impl", - srcs: [ - "third_party/abseil-cpp/absl/random/internal/randen_hwaes.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:randen_slow -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_randen_slow", - srcs: [ - "third_party/abseil-cpp/absl/random/internal/randen_slow.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:salted_seed_seq -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_salted_seed_seq", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:seed_material -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_seed_material", - srcs: [ - "third_party/abseil-cpp/absl/random/internal/seed_material.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:traits -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_traits", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:uniform_helper -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_uniform_helper", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random/internal:wide_multiply -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_internal_wide_multiply", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random:random -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_random", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random:seed_gen_exception -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_seed_gen_exception", - srcs: [ - "third_party/abseil-cpp/absl/random/seed_gen_exception.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/random:seed_sequences -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_random_seed_sequences", - srcs: [ - "third_party/abseil-cpp/absl/random/seed_sequences.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__android_x86_64", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - generated_headers: [ - "cronet_aml_build_chromeos_buildflags__host", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/status:status -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/status:statusor -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_status_statusor", - srcs: [ - "third_party/abseil-cpp/absl/status/statusor.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:cord -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:cord_internal -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:cordz_functions -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_functions", - srcs: [ - "third_party/abseil-cpp/absl/strings/internal/cordz_functions.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:cordz_handle -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_handle", - srcs: [ - "third_party/abseil-cpp/absl/strings/internal/cordz_handle.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:cordz_info -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_info", - srcs: [ - "third_party/abseil-cpp/absl/strings/internal/cordz_info.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:cordz_statistics -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_statistics", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:cordz_update_scope -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_update_scope", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:cordz_update_tracker -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_strings_cordz_update_tracker", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:internal -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:str_format -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_strings_str_format", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:str_format_internal -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/strings:strings -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/synchronization:graphcycles_internal -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_synchronization_graphcycles_internal", - srcs: [ - "third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/synchronization:kernel_timeout_internal -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_synchronization_kernel_timeout_internal", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/synchronization:synchronization -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/time/internal/cctz:civil_time -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/time/internal/cctz:time_zone -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/time:time -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/types:bad_optional_access -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_types_bad_optional_access", - srcs: [ - "third_party/abseil-cpp/absl/types/bad_optional_access.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/types:bad_variant_access -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_types_bad_variant_access", - srcs: [ - "third_party/abseil-cpp/absl/types/bad_variant_access.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/types:compare -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_types_compare", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/types:optional -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_types_optional", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/types:span -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_types_span", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/types:variant -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_types_variant", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/abseil-cpp/absl/utility:utility -cc_object { - name: "cronet_aml_third_party_abseil_cpp_absl_utility_utility", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DABSL_ALLOCATOR_NOTHROW=1", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/abseil-cpp/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/android_ndk:cpu_features -cc_object { - name: "cronet_aml_third_party_android_ndk_cpu_features", - srcs: [ - "third_party/android_ndk/sources/android/cpufeatures/cpu-features.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/sources/android/cpufeatures/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //third_party/ashmem:ashmem -cc_object { - name: "cronet_aml_third_party_ashmem_ashmem", - srcs: [ - "third_party/ashmem/ashmem-dev.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", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //third_party/boringssl:boringssl -cc_library_static { - name: "cronet_aml_third_party_boringssl_boringssl", - srcs: [ - ":cronet_aml_third_party_boringssl_boringssl_asm", - "third_party/boringssl/err_data.c", - "third_party/boringssl/src/crypto/asn1/a_bitstr.c", - "third_party/boringssl/src/crypto/asn1/a_bool.c", - "third_party/boringssl/src/crypto/asn1/a_d2i_fp.c", - "third_party/boringssl/src/crypto/asn1/a_dup.c", - "third_party/boringssl/src/crypto/asn1/a_gentm.c", - "third_party/boringssl/src/crypto/asn1/a_i2d_fp.c", - "third_party/boringssl/src/crypto/asn1/a_int.c", - "third_party/boringssl/src/crypto/asn1/a_mbstr.c", - "third_party/boringssl/src/crypto/asn1/a_object.c", - "third_party/boringssl/src/crypto/asn1/a_octet.c", - "third_party/boringssl/src/crypto/asn1/a_print.c", - "third_party/boringssl/src/crypto/asn1/a_strex.c", - "third_party/boringssl/src/crypto/asn1/a_strnid.c", - "third_party/boringssl/src/crypto/asn1/a_time.c", - "third_party/boringssl/src/crypto/asn1/a_type.c", - "third_party/boringssl/src/crypto/asn1/a_utctm.c", - "third_party/boringssl/src/crypto/asn1/a_utf8.c", - "third_party/boringssl/src/crypto/asn1/asn1_lib.c", - "third_party/boringssl/src/crypto/asn1/asn1_par.c", - "third_party/boringssl/src/crypto/asn1/asn_pack.c", - "third_party/boringssl/src/crypto/asn1/f_int.c", - "third_party/boringssl/src/crypto/asn1/f_string.c", - "third_party/boringssl/src/crypto/asn1/posix_time.c", - "third_party/boringssl/src/crypto/asn1/tasn_dec.c", - "third_party/boringssl/src/crypto/asn1/tasn_enc.c", - "third_party/boringssl/src/crypto/asn1/tasn_fre.c", - "third_party/boringssl/src/crypto/asn1/tasn_new.c", - "third_party/boringssl/src/crypto/asn1/tasn_typ.c", - "third_party/boringssl/src/crypto/asn1/tasn_utl.c", - "third_party/boringssl/src/crypto/base64/base64.c", - "third_party/boringssl/src/crypto/bio/bio.c", - "third_party/boringssl/src/crypto/bio/bio_mem.c", - "third_party/boringssl/src/crypto/bio/connect.c", - "third_party/boringssl/src/crypto/bio/fd.c", - "third_party/boringssl/src/crypto/bio/file.c", - "third_party/boringssl/src/crypto/bio/hexdump.c", - "third_party/boringssl/src/crypto/bio/pair.c", - "third_party/boringssl/src/crypto/bio/printf.c", - "third_party/boringssl/src/crypto/bio/socket.c", - "third_party/boringssl/src/crypto/bio/socket_helper.c", - "third_party/boringssl/src/crypto/blake2/blake2.c", - "third_party/boringssl/src/crypto/bn_extra/bn_asn1.c", - "third_party/boringssl/src/crypto/bn_extra/convert.c", - "third_party/boringssl/src/crypto/buf/buf.c", - "third_party/boringssl/src/crypto/bytestring/asn1_compat.c", - "third_party/boringssl/src/crypto/bytestring/ber.c", - "third_party/boringssl/src/crypto/bytestring/cbb.c", - "third_party/boringssl/src/crypto/bytestring/cbs.c", - "third_party/boringssl/src/crypto/bytestring/unicode.c", - "third_party/boringssl/src/crypto/chacha/chacha.c", - "third_party/boringssl/src/crypto/cipher_extra/cipher_extra.c", - "third_party/boringssl/src/crypto/cipher_extra/derive_key.c", - "third_party/boringssl/src/crypto/cipher_extra/e_aesctrhmac.c", - "third_party/boringssl/src/crypto/cipher_extra/e_aesgcmsiv.c", - "third_party/boringssl/src/crypto/cipher_extra/e_chacha20poly1305.c", - "third_party/boringssl/src/crypto/cipher_extra/e_des.c", - "third_party/boringssl/src/crypto/cipher_extra/e_null.c", - "third_party/boringssl/src/crypto/cipher_extra/e_rc2.c", - "third_party/boringssl/src/crypto/cipher_extra/e_rc4.c", - "third_party/boringssl/src/crypto/cipher_extra/e_tls.c", - "third_party/boringssl/src/crypto/cipher_extra/tls_cbc.c", - "third_party/boringssl/src/crypto/conf/conf.c", - "third_party/boringssl/src/crypto/cpu_aarch64_apple.c", - "third_party/boringssl/src/crypto/cpu_aarch64_fuchsia.c", - "third_party/boringssl/src/crypto/cpu_aarch64_linux.c", - "third_party/boringssl/src/crypto/cpu_aarch64_win.c", - "third_party/boringssl/src/crypto/cpu_arm.c", - "third_party/boringssl/src/crypto/cpu_arm_linux.c", - "third_party/boringssl/src/crypto/cpu_intel.c", - "third_party/boringssl/src/crypto/cpu_ppc64le.c", - "third_party/boringssl/src/crypto/crypto.c", - "third_party/boringssl/src/crypto/curve25519/curve25519.c", - "third_party/boringssl/src/crypto/curve25519/spake25519.c", - "third_party/boringssl/src/crypto/des/des.c", - "third_party/boringssl/src/crypto/dh_extra/dh_asn1.c", - "third_party/boringssl/src/crypto/dh_extra/params.c", - "third_party/boringssl/src/crypto/digest_extra/digest_extra.c", - "third_party/boringssl/src/crypto/dsa/dsa.c", - "third_party/boringssl/src/crypto/dsa/dsa_asn1.c", - "third_party/boringssl/src/crypto/ec_extra/ec_asn1.c", - "third_party/boringssl/src/crypto/ec_extra/ec_derive.c", - "third_party/boringssl/src/crypto/ec_extra/hash_to_curve.c", - "third_party/boringssl/src/crypto/ecdh_extra/ecdh_extra.c", - "third_party/boringssl/src/crypto/ecdsa_extra/ecdsa_asn1.c", - "third_party/boringssl/src/crypto/engine/engine.c", - "third_party/boringssl/src/crypto/err/err.c", - "third_party/boringssl/src/crypto/evp/evp.c", - "third_party/boringssl/src/crypto/evp/evp_asn1.c", - "third_party/boringssl/src/crypto/evp/evp_ctx.c", - "third_party/boringssl/src/crypto/evp/p_dsa_asn1.c", - "third_party/boringssl/src/crypto/evp/p_ec.c", - "third_party/boringssl/src/crypto/evp/p_ec_asn1.c", - "third_party/boringssl/src/crypto/evp/p_ed25519.c", - "third_party/boringssl/src/crypto/evp/p_ed25519_asn1.c", - "third_party/boringssl/src/crypto/evp/p_hkdf.c", - "third_party/boringssl/src/crypto/evp/p_rsa.c", - "third_party/boringssl/src/crypto/evp/p_rsa_asn1.c", - "third_party/boringssl/src/crypto/evp/p_x25519.c", - "third_party/boringssl/src/crypto/evp/p_x25519_asn1.c", - "third_party/boringssl/src/crypto/evp/pbkdf.c", - "third_party/boringssl/src/crypto/evp/print.c", - "third_party/boringssl/src/crypto/evp/scrypt.c", - "third_party/boringssl/src/crypto/evp/sign.c", - "third_party/boringssl/src/crypto/ex_data.c", - "third_party/boringssl/src/crypto/fipsmodule/bcm.c", - "third_party/boringssl/src/crypto/fipsmodule/fips_shared_support.c", - "third_party/boringssl/src/crypto/hkdf/hkdf.c", - "third_party/boringssl/src/crypto/hpke/hpke.c", - "third_party/boringssl/src/crypto/hrss/hrss.c", - "third_party/boringssl/src/crypto/lhash/lhash.c", - "third_party/boringssl/src/crypto/mem.c", - "third_party/boringssl/src/crypto/obj/obj.c", - "third_party/boringssl/src/crypto/obj/obj_xref.c", - "third_party/boringssl/src/crypto/pem/pem_all.c", - "third_party/boringssl/src/crypto/pem/pem_info.c", - "third_party/boringssl/src/crypto/pem/pem_lib.c", - "third_party/boringssl/src/crypto/pem/pem_oth.c", - "third_party/boringssl/src/crypto/pem/pem_pk8.c", - "third_party/boringssl/src/crypto/pem/pem_pkey.c", - "third_party/boringssl/src/crypto/pem/pem_x509.c", - "third_party/boringssl/src/crypto/pem/pem_xaux.c", - "third_party/boringssl/src/crypto/pkcs7/pkcs7.c", - "third_party/boringssl/src/crypto/pkcs7/pkcs7_x509.c", - "third_party/boringssl/src/crypto/pkcs8/p5_pbev2.c", - "third_party/boringssl/src/crypto/pkcs8/pkcs8.c", - "third_party/boringssl/src/crypto/pkcs8/pkcs8_x509.c", - "third_party/boringssl/src/crypto/poly1305/poly1305.c", - "third_party/boringssl/src/crypto/poly1305/poly1305_arm.c", - "third_party/boringssl/src/crypto/poly1305/poly1305_vec.c", - "third_party/boringssl/src/crypto/pool/pool.c", - "third_party/boringssl/src/crypto/rand_extra/deterministic.c", - "third_party/boringssl/src/crypto/rand_extra/forkunsafe.c", - "third_party/boringssl/src/crypto/rand_extra/fuchsia.c", - "third_party/boringssl/src/crypto/rand_extra/passive.c", - "third_party/boringssl/src/crypto/rand_extra/rand_extra.c", - "third_party/boringssl/src/crypto/rand_extra/windows.c", - "third_party/boringssl/src/crypto/rc4/rc4.c", - "third_party/boringssl/src/crypto/refcount_c11.c", - "third_party/boringssl/src/crypto/refcount_lock.c", - "third_party/boringssl/src/crypto/rsa_extra/rsa_asn1.c", - "third_party/boringssl/src/crypto/rsa_extra/rsa_print.c", - "third_party/boringssl/src/crypto/siphash/siphash.c", - "third_party/boringssl/src/crypto/stack/stack.c", - "third_party/boringssl/src/crypto/thread.c", - "third_party/boringssl/src/crypto/thread_none.c", - "third_party/boringssl/src/crypto/thread_pthread.c", - "third_party/boringssl/src/crypto/thread_win.c", - "third_party/boringssl/src/crypto/trust_token/pmbtoken.c", - "third_party/boringssl/src/crypto/trust_token/trust_token.c", - "third_party/boringssl/src/crypto/trust_token/voprf.c", - "third_party/boringssl/src/crypto/x509/a_digest.c", - "third_party/boringssl/src/crypto/x509/a_sign.c", - "third_party/boringssl/src/crypto/x509/a_verify.c", - "third_party/boringssl/src/crypto/x509/algorithm.c", - "third_party/boringssl/src/crypto/x509/asn1_gen.c", - "third_party/boringssl/src/crypto/x509/by_dir.c", - "third_party/boringssl/src/crypto/x509/by_file.c", - "third_party/boringssl/src/crypto/x509/i2d_pr.c", - "third_party/boringssl/src/crypto/x509/name_print.c", - "third_party/boringssl/src/crypto/x509/rsa_pss.c", - "third_party/boringssl/src/crypto/x509/t_crl.c", - "third_party/boringssl/src/crypto/x509/t_req.c", - "third_party/boringssl/src/crypto/x509/t_x509.c", - "third_party/boringssl/src/crypto/x509/t_x509a.c", - "third_party/boringssl/src/crypto/x509/x509.c", - "third_party/boringssl/src/crypto/x509/x509_att.c", - "third_party/boringssl/src/crypto/x509/x509_cmp.c", - "third_party/boringssl/src/crypto/x509/x509_d2.c", - "third_party/boringssl/src/crypto/x509/x509_def.c", - "third_party/boringssl/src/crypto/x509/x509_ext.c", - "third_party/boringssl/src/crypto/x509/x509_lu.c", - "third_party/boringssl/src/crypto/x509/x509_obj.c", - "third_party/boringssl/src/crypto/x509/x509_req.c", - "third_party/boringssl/src/crypto/x509/x509_set.c", - "third_party/boringssl/src/crypto/x509/x509_trs.c", - "third_party/boringssl/src/crypto/x509/x509_txt.c", - "third_party/boringssl/src/crypto/x509/x509_v3.c", - "third_party/boringssl/src/crypto/x509/x509_vfy.c", - "third_party/boringssl/src/crypto/x509/x509_vpm.c", - "third_party/boringssl/src/crypto/x509/x509cset.c", - "third_party/boringssl/src/crypto/x509/x509name.c", - "third_party/boringssl/src/crypto/x509/x509rset.c", - "third_party/boringssl/src/crypto/x509/x509spki.c", - "third_party/boringssl/src/crypto/x509/x_algor.c", - "third_party/boringssl/src/crypto/x509/x_all.c", - "third_party/boringssl/src/crypto/x509/x_attrib.c", - "third_party/boringssl/src/crypto/x509/x_crl.c", - "third_party/boringssl/src/crypto/x509/x_exten.c", - "third_party/boringssl/src/crypto/x509/x_info.c", - "third_party/boringssl/src/crypto/x509/x_name.c", - "third_party/boringssl/src/crypto/x509/x_pkey.c", - "third_party/boringssl/src/crypto/x509/x_pubkey.c", - "third_party/boringssl/src/crypto/x509/x_req.c", - "third_party/boringssl/src/crypto/x509/x_sig.c", - "third_party/boringssl/src/crypto/x509/x_spki.c", - "third_party/boringssl/src/crypto/x509/x_val.c", - "third_party/boringssl/src/crypto/x509/x_x509.c", - "third_party/boringssl/src/crypto/x509/x_x509a.c", - "third_party/boringssl/src/crypto/x509v3/pcy_cache.c", - "third_party/boringssl/src/crypto/x509v3/pcy_data.c", - "third_party/boringssl/src/crypto/x509v3/pcy_map.c", - "third_party/boringssl/src/crypto/x509v3/pcy_node.c", - "third_party/boringssl/src/crypto/x509v3/pcy_tree.c", - "third_party/boringssl/src/crypto/x509v3/v3_akey.c", - "third_party/boringssl/src/crypto/x509v3/v3_akeya.c", - "third_party/boringssl/src/crypto/x509v3/v3_alt.c", - "third_party/boringssl/src/crypto/x509v3/v3_bcons.c", - "third_party/boringssl/src/crypto/x509v3/v3_bitst.c", - "third_party/boringssl/src/crypto/x509v3/v3_conf.c", - "third_party/boringssl/src/crypto/x509v3/v3_cpols.c", - "third_party/boringssl/src/crypto/x509v3/v3_crld.c", - "third_party/boringssl/src/crypto/x509v3/v3_enum.c", - "third_party/boringssl/src/crypto/x509v3/v3_extku.c", - "third_party/boringssl/src/crypto/x509v3/v3_genn.c", - "third_party/boringssl/src/crypto/x509v3/v3_ia5.c", - "third_party/boringssl/src/crypto/x509v3/v3_info.c", - "third_party/boringssl/src/crypto/x509v3/v3_int.c", - "third_party/boringssl/src/crypto/x509v3/v3_lib.c", - "third_party/boringssl/src/crypto/x509v3/v3_ncons.c", - "third_party/boringssl/src/crypto/x509v3/v3_ocsp.c", - "third_party/boringssl/src/crypto/x509v3/v3_pci.c", - "third_party/boringssl/src/crypto/x509v3/v3_pcia.c", - "third_party/boringssl/src/crypto/x509v3/v3_pcons.c", - "third_party/boringssl/src/crypto/x509v3/v3_pmaps.c", - "third_party/boringssl/src/crypto/x509v3/v3_prn.c", - "third_party/boringssl/src/crypto/x509v3/v3_purp.c", - "third_party/boringssl/src/crypto/x509v3/v3_skey.c", - "third_party/boringssl/src/crypto/x509v3/v3_utl.c", - "third_party/boringssl/src/ssl/bio_ssl.cc", - "third_party/boringssl/src/ssl/d1_both.cc", - "third_party/boringssl/src/ssl/d1_lib.cc", - "third_party/boringssl/src/ssl/d1_pkt.cc", - "third_party/boringssl/src/ssl/d1_srtp.cc", - "third_party/boringssl/src/ssl/dtls_method.cc", - "third_party/boringssl/src/ssl/dtls_record.cc", - "third_party/boringssl/src/ssl/encrypted_client_hello.cc", - "third_party/boringssl/src/ssl/extensions.cc", - "third_party/boringssl/src/ssl/handoff.cc", - "third_party/boringssl/src/ssl/handshake.cc", - "third_party/boringssl/src/ssl/handshake_client.cc", - "third_party/boringssl/src/ssl/handshake_server.cc", - "third_party/boringssl/src/ssl/s3_both.cc", - "third_party/boringssl/src/ssl/s3_lib.cc", - "third_party/boringssl/src/ssl/s3_pkt.cc", - "third_party/boringssl/src/ssl/ssl_aead_ctx.cc", - "third_party/boringssl/src/ssl/ssl_asn1.cc", - "third_party/boringssl/src/ssl/ssl_buffer.cc", - "third_party/boringssl/src/ssl/ssl_cert.cc", - "third_party/boringssl/src/ssl/ssl_cipher.cc", - "third_party/boringssl/src/ssl/ssl_file.cc", - "third_party/boringssl/src/ssl/ssl_key_share.cc", - "third_party/boringssl/src/ssl/ssl_lib.cc", - "third_party/boringssl/src/ssl/ssl_privkey.cc", - "third_party/boringssl/src/ssl/ssl_session.cc", - "third_party/boringssl/src/ssl/ssl_stat.cc", - "third_party/boringssl/src/ssl/ssl_transcript.cc", - "third_party/boringssl/src/ssl/ssl_versions.cc", - "third_party/boringssl/src/ssl/ssl_x509.cc", - "third_party/boringssl/src/ssl/t1_enc.cc", - "third_party/boringssl/src/ssl/tls13_both.cc", - "third_party/boringssl/src/ssl/tls13_client.cc", - "third_party/boringssl/src/ssl/tls13_enc.cc", - "third_party/boringssl/src/ssl/tls13_server.cc", - "third_party/boringssl/src/ssl/tls_method.cc", - "third_party/boringssl/src/ssl/tls_record.cc", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DBORINGSSL_ALLOW_CXX_RUNTIME", - "-DBORINGSSL_IMPLEMENTATION", - "-DBORINGSSL_NO_STATIC_INITIALIZER", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-DOPENSSL_SMALL", - "-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/boringssl/src/include/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/boringssl:boringssl_asm -cc_object { - name: "cronet_aml_third_party_boringssl_boringssl_asm", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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/boringssl/src/include/", - ], - cpp_std: "c++20", - target: { - android_arm: { - srcs: [ - "third_party/boringssl/linux-arm/crypto/chacha/chacha-armv4.S", - "third_party/boringssl/linux-arm/crypto/fipsmodule/aesv8-armx32.S", - "third_party/boringssl/linux-arm/crypto/fipsmodule/armv4-mont.S", - "third_party/boringssl/linux-arm/crypto/fipsmodule/bsaes-armv7.S", - "third_party/boringssl/linux-arm/crypto/fipsmodule/ghash-armv4.S", - "third_party/boringssl/linux-arm/crypto/fipsmodule/ghashv8-armx32.S", - "third_party/boringssl/linux-arm/crypto/fipsmodule/sha1-armv4-large.S", - "third_party/boringssl/linux-arm/crypto/fipsmodule/sha256-armv4.S", - "third_party/boringssl/linux-arm/crypto/fipsmodule/sha512-armv4.S", - "third_party/boringssl/linux-arm/crypto/fipsmodule/vpaes-armv7.S", - "third_party/boringssl/linux-arm/crypto/test/trampoline-armv4.S", - "third_party/boringssl/src/crypto/curve25519/asm/x25519-asm-arm.S", - "third_party/boringssl/src/crypto/poly1305/poly1305_arm_asm.S", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - srcs: [ - "third_party/boringssl/linux-aarch64/crypto/chacha/chacha-armv8.S", - "third_party/boringssl/linux-aarch64/crypto/cipher_extra/chacha20_poly1305_armv8.S", - "third_party/boringssl/linux-aarch64/crypto/fipsmodule/aesv8-armx64.S", - "third_party/boringssl/linux-aarch64/crypto/fipsmodule/armv8-mont.S", - "third_party/boringssl/linux-aarch64/crypto/fipsmodule/ghash-neon-armv8.S", - "third_party/boringssl/linux-aarch64/crypto/fipsmodule/ghashv8-armx64.S", - "third_party/boringssl/linux-aarch64/crypto/fipsmodule/p256-armv8-asm.S", - "third_party/boringssl/linux-aarch64/crypto/fipsmodule/p256_beeu-armv8-asm.S", - "third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha1-armv8.S", - "third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha256-armv8.S", - "third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha512-armv8.S", - "third_party/boringssl/linux-aarch64/crypto/fipsmodule/vpaes-armv8.S", - "third_party/boringssl/linux-aarch64/crypto/test/trampoline-armv8.S", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - srcs: [ - "third_party/boringssl/linux-x86/crypto/chacha/chacha-x86.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/aesni-x86.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/bn-586.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/co-586.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/ghash-ssse3-x86.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/ghash-x86.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/md5-586.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/sha1-586.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/sha256-586.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/sha512-586.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/vpaes-x86.S", - "third_party/boringssl/linux-x86/crypto/fipsmodule/x86-mont.S", - "third_party/boringssl/linux-x86/crypto/test/trampoline-x86.S", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - srcs: [ - "third_party/boringssl/linux-x86_64/crypto/chacha/chacha-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/cipher_extra/aes128gcmsiv-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/cipher_extra/chacha20_poly1305_x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/aesni-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/ghash-ssse3-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/ghash-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/md5-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/p256-x86_64-asm.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/p256_beeu-x86_64-asm.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/rdrand-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/rsaz-avx2.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/sha1-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/sha256-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/sha512-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/vpaes-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/x86_64-mont.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/x86_64-mont5.S", - "third_party/boringssl/linux-x86_64/crypto/test/trampoline-x86_64.S", - "third_party/boringssl/src/crypto/hrss/asm/poly_rq_mul.S", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - srcs: [ - "third_party/boringssl/linux-x86_64/crypto/chacha/chacha-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/cipher_extra/aes128gcmsiv-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/cipher_extra/chacha20_poly1305_x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/aesni-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/ghash-ssse3-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/ghash-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/md5-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/p256-x86_64-asm.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/p256_beeu-x86_64-asm.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/rdrand-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/rsaz-avx2.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/sha1-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/sha256-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/sha512-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/vpaes-x86_64.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/x86_64-mont.S", - "third_party/boringssl/linux-x86_64/crypto/fipsmodule/x86_64-mont5.S", - "third_party/boringssl/linux-x86_64/crypto/test/trampoline-x86_64.S", - "third_party/boringssl/src/crypto/hrss/asm/poly_rq_mul.S", - ], - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/boringssl/src/third_party/fiat:fiat_license -cc_object { - name: "cronet_aml_third_party_boringssl_src_third_party_fiat_fiat_license", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/brotli:common -cc_library_static { - name: "cronet_aml_third_party_brotli_common", - srcs: [ - "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/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //third_party/brotli:dec -cc_library_static { - name: "cronet_aml_third_party_brotli_dec", - srcs: [ - "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", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - "third_party/brotli/include/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //third_party/brotli:headers -cc_object { - name: "cronet_aml_third_party_brotli_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", - "-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", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-DHAVE_DLOPEN=0", - "-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/", - ], - cpp_std: "c++20", - rtti: true, - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/icu:icuuc_private -cc_library_static { - name: "cronet_aml_third_party_icu_icuuc_private", - srcs: [ - "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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-DHAVE_DLOPEN=0", - "-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", - ], - 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/", - ], - cpp_std: "c++20", - rtti: true, - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/icu:icuuc_public -cc_object { - name: "cronet_aml_third_party_icu_icuuc_public", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-DHAVE_CONFIG_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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - local_include_dirs: [ - "third_party/libevent/android/", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - local_include_dirs: [ - "third_party/libevent/android/", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - local_include_dirs: [ - "third_party/libevent/android/", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - local_include_dirs: [ - "third_party/libevent/android/", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - local_include_dirs: [ - "third_party/libevent/linux/", - ], - }, - }, -} - -// GN: //third_party/metrics_proto:metrics_proto -cc_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: [ - "cronet_aml_third_party_protobuf_protoc", - ], - cmd: "$(location cronet_aml_third_party_protobuf_protoc) --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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //third_party/metrics_proto:metrics_proto -cc_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: [ - "cronet_aml_third_party_protobuf_protoc", - ], - cmd: "$(location cronet_aml_third_party_protobuf_protoc) --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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/protobuf:protobuf_full -cc_library_static { - name: "cronet_aml_third_party_protobuf_protobuf_full", - srcs: [ - "third_party/protobuf/src/google/protobuf/any.cc", - "third_party/protobuf/src/google/protobuf/any.pb.cc", - "third_party/protobuf/src/google/protobuf/any_lite.cc", - "third_party/protobuf/src/google/protobuf/api.pb.cc", - "third_party/protobuf/src/google/protobuf/arena.cc", - "third_party/protobuf/src/google/protobuf/arenastring.cc", - "third_party/protobuf/src/google/protobuf/arenaz_sampler.cc", - "third_party/protobuf/src/google/protobuf/compiler/importer.cc", - "third_party/protobuf/src/google/protobuf/compiler/parser.cc", - "third_party/protobuf/src/google/protobuf/descriptor.cc", - "third_party/protobuf/src/google/protobuf/descriptor.pb.cc", - "third_party/protobuf/src/google/protobuf/descriptor_database.cc", - "third_party/protobuf/src/google/protobuf/duration.pb.cc", - "third_party/protobuf/src/google/protobuf/dynamic_message.cc", - "third_party/protobuf/src/google/protobuf/empty.pb.cc", - "third_party/protobuf/src/google/protobuf/extension_set.cc", - "third_party/protobuf/src/google/protobuf/extension_set_heavy.cc", - "third_party/protobuf/src/google/protobuf/field_mask.pb.cc", - "third_party/protobuf/src/google/protobuf/generated_enum_util.cc", - "third_party/protobuf/src/google/protobuf/generated_message_bases.cc", - "third_party/protobuf/src/google/protobuf/generated_message_reflection.cc", - "third_party/protobuf/src/google/protobuf/generated_message_tctable_full.cc", - "third_party/protobuf/src/google/protobuf/generated_message_tctable_lite.cc", - "third_party/protobuf/src/google/protobuf/generated_message_util.cc", - "third_party/protobuf/src/google/protobuf/implicit_weak_message.cc", - "third_party/protobuf/src/google/protobuf/inlined_string_field.cc", - "third_party/protobuf/src/google/protobuf/io/coded_stream.cc", - "third_party/protobuf/src/google/protobuf/io/gzip_stream.cc", - "third_party/protobuf/src/google/protobuf/io/io_win32.cc", - "third_party/protobuf/src/google/protobuf/io/printer.cc", - "third_party/protobuf/src/google/protobuf/io/strtod.cc", - "third_party/protobuf/src/google/protobuf/io/tokenizer.cc", - "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.cc", - "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl.cc", - "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.cc", - "third_party/protobuf/src/google/protobuf/map.cc", - "third_party/protobuf/src/google/protobuf/map_field.cc", - "third_party/protobuf/src/google/protobuf/message.cc", - "third_party/protobuf/src/google/protobuf/message_lite.cc", - "third_party/protobuf/src/google/protobuf/parse_context.cc", - "third_party/protobuf/src/google/protobuf/reflection_ops.cc", - "third_party/protobuf/src/google/protobuf/repeated_field.cc", - "third_party/protobuf/src/google/protobuf/repeated_ptr_field.cc", - "third_party/protobuf/src/google/protobuf/service.cc", - "third_party/protobuf/src/google/protobuf/source_context.pb.cc", - "third_party/protobuf/src/google/protobuf/struct.pb.cc", - "third_party/protobuf/src/google/protobuf/stubs/bytestream.cc", - "third_party/protobuf/src/google/protobuf/stubs/common.cc", - "third_party/protobuf/src/google/protobuf/stubs/int128.cc", - "third_party/protobuf/src/google/protobuf/stubs/status.cc", - "third_party/protobuf/src/google/protobuf/stubs/statusor.cc", - "third_party/protobuf/src/google/protobuf/stubs/stringpiece.cc", - "third_party/protobuf/src/google/protobuf/stubs/stringprintf.cc", - "third_party/protobuf/src/google/protobuf/stubs/structurally_valid.cc", - "third_party/protobuf/src/google/protobuf/stubs/strutil.cc", - "third_party/protobuf/src/google/protobuf/stubs/substitute.cc", - "third_party/protobuf/src/google/protobuf/stubs/time.cc", - "third_party/protobuf/src/google/protobuf/text_format.cc", - "third_party/protobuf/src/google/protobuf/timestamp.pb.cc", - "third_party/protobuf/src/google/protobuf/type.pb.cc", - "third_party/protobuf/src/google/protobuf/unknown_field_set.cc", - "third_party/protobuf/src/google/protobuf/util/delimited_message_util.cc", - "third_party/protobuf/src/google/protobuf/util/field_comparator.cc", - "third_party/protobuf/src/google/protobuf/util/field_mask_util.cc", - "third_party/protobuf/src/google/protobuf/util/internal/datapiece.cc", - "third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc", - "third_party/protobuf/src/google/protobuf/util/internal/error_listener.cc", - "third_party/protobuf/src/google/protobuf/util/internal/field_mask_utility.cc", - "third_party/protobuf/src/google/protobuf/util/internal/json_escaping.cc", - "third_party/protobuf/src/google/protobuf/util/internal/json_objectwriter.cc", - "third_party/protobuf/src/google/protobuf/util/internal/json_stream_parser.cc", - "third_party/protobuf/src/google/protobuf/util/internal/object_writer.cc", - "third_party/protobuf/src/google/protobuf/util/internal/proto_writer.cc", - "third_party/protobuf/src/google/protobuf/util/internal/protostream_objectsource.cc", - "third_party/protobuf/src/google/protobuf/util/internal/protostream_objectwriter.cc", - "third_party/protobuf/src/google/protobuf/util/internal/type_info.cc", - "third_party/protobuf/src/google/protobuf/util/internal/utility.cc", - "third_party/protobuf/src/google/protobuf/util/json_util.cc", - "third_party/protobuf/src/google/protobuf/util/message_differencer.cc", - "third_party/protobuf/src/google/protobuf/util/time_util.cc", - "third_party/protobuf/src/google/protobuf/util/type_resolver_util.cc", - "third_party/protobuf/src/google/protobuf/wire_format.cc", - "third_party/protobuf/src/google/protobuf/wire_format_lite.cc", - "third_party/protobuf/src/google/protobuf/wrappers.pb.cc", - ], - static_libs: [ - "cronet_aml_third_party_zlib_zlib", - ], - host_supported: true, - device_supported: false, - 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", - "-DHAVE_ZLIB", - "-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_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1", - "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", - "-msse3", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - "third_party/protobuf/src/", - "third_party/zlib/", - ], - cpp_std: "c++20", -} - -// GN: //third_party/protobuf:protobuf_lite -cc_library_static { - name: "cronet_aml_third_party_protobuf_protobuf_lite", - srcs: [ - "third_party/protobuf/src/google/protobuf/any_lite.cc", - "third_party/protobuf/src/google/protobuf/arena.cc", - "third_party/protobuf/src/google/protobuf/arenastring.cc", - "third_party/protobuf/src/google/protobuf/arenaz_sampler.cc", - "third_party/protobuf/src/google/protobuf/extension_set.cc", - "third_party/protobuf/src/google/protobuf/generated_enum_util.cc", - "third_party/protobuf/src/google/protobuf/generated_message_tctable_lite.cc", - "third_party/protobuf/src/google/protobuf/generated_message_util.cc", - "third_party/protobuf/src/google/protobuf/implicit_weak_message.cc", - "third_party/protobuf/src/google/protobuf/inlined_string_field.cc", - "third_party/protobuf/src/google/protobuf/io/coded_stream.cc", - "third_party/protobuf/src/google/protobuf/io/io_win32.cc", - "third_party/protobuf/src/google/protobuf/io/strtod.cc", - "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.cc", - "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl.cc", - "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.cc", - "third_party/protobuf/src/google/protobuf/map.cc", - "third_party/protobuf/src/google/protobuf/message_lite.cc", - "third_party/protobuf/src/google/protobuf/parse_context.cc", - "third_party/protobuf/src/google/protobuf/repeated_field.cc", - "third_party/protobuf/src/google/protobuf/repeated_ptr_field.cc", - "third_party/protobuf/src/google/protobuf/stubs/bytestream.cc", - "third_party/protobuf/src/google/protobuf/stubs/common.cc", - "third_party/protobuf/src/google/protobuf/stubs/int128.cc", - "third_party/protobuf/src/google/protobuf/stubs/status.cc", - "third_party/protobuf/src/google/protobuf/stubs/statusor.cc", - "third_party/protobuf/src/google/protobuf/stubs/stringpiece.cc", - "third_party/protobuf/src/google/protobuf/stubs/stringprintf.cc", - "third_party/protobuf/src/google/protobuf/stubs/structurally_valid.cc", - "third_party/protobuf/src/google/protobuf/stubs/strutil.cc", - "third_party/protobuf/src/google/protobuf/stubs/time.cc", - "third_party/protobuf/src/google/protobuf/wire_format_lite.cc", - ], - shared_libs: [ - "liblog", - ], - 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", - "-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/protobuf/src/", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - }, - }, -} - -// GN: //third_party/protobuf:protoc -cc_binary { - name: "cronet_aml_third_party_protobuf_protoc", - srcs: [ - ":cronet_aml_buildtools_third_party_libc___libc__", - ":cronet_aml_buildtools_third_party_libc__abi_libc__abi", - "third_party/protobuf/src/google/protobuf/compiler/main.cc", - ], - static_libs: [ - "cronet_aml_third_party_protobuf_protobuf_full", - "cronet_aml_third_party_protobuf_protoc_lib", - "cronet_aml_third_party_zlib_zlib", - ], - host_supported: true, - device_supported: false, - 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", - "-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_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1", - "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", - "-msse3", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - "third_party/protobuf/src/", - ], - cpp_std: "c++20", -} - -// GN: //third_party/protobuf:protoc_lib -cc_library_static { - name: "cronet_aml_third_party_protobuf_protoc_lib", - srcs: [ - "third_party/protobuf/src/google/protobuf/compiler/code_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/command_line_interface.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_enum.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_enum_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_extension.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_file.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_helpers.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_map_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_message.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_message_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_service.cc", - "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_string_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_enum.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_enum_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_field_base.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_helpers.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_map_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_message.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_message_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc", - "third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_context.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_doc_comment.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_enum.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_enum_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_enum_field_lite.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_enum_lite.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_extension.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_extension_lite.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_file.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_generator_factory.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_helpers.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_kotlin_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_map_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_map_field_lite.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_message.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_message_builder.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_message_builder_lite.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_message_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_message_field_lite.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_message_lite.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_name_resolver.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_primitive_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_primitive_field_lite.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_service.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_shared_code_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_string_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/java/java_string_field_lite.cc", - "third_party/protobuf/src/google/protobuf/compiler/js/js_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/js/well_known_types_embed.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_enum.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_extension.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_file.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_message.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc", - "third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc", - "third_party/protobuf/src/google/protobuf/compiler/php/php_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/plugin.cc", - "third_party/protobuf/src/google/protobuf/compiler/plugin.pb.cc", - "third_party/protobuf/src/google/protobuf/compiler/python/python_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/python/python_helpers.cc", - "third_party/protobuf/src/google/protobuf/compiler/python/python_pyi_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/ruby/ruby_generator.cc", - "third_party/protobuf/src/google/protobuf/compiler/subprocess.cc", - "third_party/protobuf/src/google/protobuf/compiler/zip_writer.cc", - ], - static_libs: [ - "cronet_aml_third_party_protobuf_protobuf_full", - "cronet_aml_third_party_zlib_zlib", - ], - host_supported: true, - device_supported: false, - 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", - "-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_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCPP_ENABLE_ASSERTIONS_DEFAULT=1", - "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", - "-msse3", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - "third_party/protobuf/src/", - ], - cpp_std: "c++20", -} - -// GN: //third_party/zlib:zlib -cc_library_static { - name: "cronet_aml_third_party_zlib_zlib", - srcs: [ - ":cronet_aml_third_party_zlib_zlib_adler32_simd", - ":cronet_aml_third_party_zlib_zlib_inflate_chunk_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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - ":cronet_aml_third_party_zlib_zlib_arm_crc32", - ], - cflags: [ - "-DADLER32_SIMD_NEON", - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DARMV8_OS_ANDROID", - "-DCRC32_ARMV8_CRC32", - "-DDEFLATE_SLIDE_HASH_NEON", - "-DHAVE_SYS_UIO_H", - "-DINFLATE_CHUNK_SIMD_NEON", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - }, - android_arm64: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - ":cronet_aml_third_party_zlib_zlib_arm_crc32", - ], - cflags: [ - "-DADLER32_SIMD_NEON", - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DARMV8_OS_ANDROID", - "-DCRC32_ARMV8_CRC32", - "-DDEFLATE_SLIDE_HASH_NEON", - "-DHAVE_SYS_UIO_H", - "-DINFLATE_CHUNK_READ_64LE", - "-DINFLATE_CHUNK_SIMD_NEON", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - }, - android_x86: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - ":cronet_aml_third_party_zlib_zlib_crc32_simd", - ], - cflags: [ - "-DADLER32_SIMD_SSSE3", - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DCRC32_SIMD_SSE42_PCLMUL", - "-DDEFLATE_SLIDE_HASH_SSE2", - "-DHAVE_SYS_UIO_H", - "-DINFLATE_CHUNK_SIMD_SSE2", - "-DX86_NOT_WINDOWS", - "-msse3", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - }, - android_x86_64: { - srcs: [ - ":cronet_aml_third_party_android_ndk_cpu_features", - ":cronet_aml_third_party_zlib_zlib_crc32_simd", - ], - cflags: [ - "-DADLER32_SIMD_SSSE3", - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DCRC32_SIMD_SSE42_PCLMUL", - "-DDEFLATE_SLIDE_HASH_SSE2", - "-DHAVE_SYS_UIO_H", - "-DINFLATE_CHUNK_READ_64LE", - "-DINFLATE_CHUNK_SIMD_SSE2", - "-DX86_NOT_WINDOWS", - "-msse3", - ], - local_include_dirs: [ - "third_party/android_ndk/sources/android/cpufeatures/", - ], - }, - host: { - srcs: [ - ":cronet_aml_third_party_zlib_zlib_crc32_simd", - ], - cflags: [ - "-DADLER32_SIMD_SSSE3", - "-DCRC32_SIMD_SSE42_PCLMUL", - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DDEFLATE_SLIDE_HASH_SSE2", - "-DINFLATE_CHUNK_READ_64LE", - "-DINFLATE_CHUNK_SIMD_SSE2", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-DX86_NOT_WINDOWS", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/zlib:zlib_adler32_simd -cc_object { - name: "cronet_aml_third_party_zlib_zlib_adler32_simd", - srcs: [ - "third_party/zlib/adler32_simd.c", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DADLER32_SIMD_NEON", - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DADLER32_SIMD_NEON", - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DADLER32_SIMD_SSSE3", - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-DX86_NOT_WINDOWS", - "-msse3", - "-mssse3", - ], - }, - android_x86_64: { - cflags: [ - "-DADLER32_SIMD_SSSE3", - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-DX86_NOT_WINDOWS", - "-msse3", - "-mssse3", - ], - }, - host: { - cflags: [ - "-DADLER32_SIMD_SSSE3", - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-DX86_NOT_WINDOWS", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - "-mssse3", - ], - }, - }, -} - -// GN: //third_party/zlib:zlib_arm_crc32 -cc_object { - name: "cronet_aml_third_party_zlib_zlib_arm_crc32", - srcs: [ - "third_party/zlib/crc32_simd.c", - ], - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DARMV8_OS_ANDROID", - "-DCRC32_ARMV8_CRC32", - "-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", - "-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/zlib/", - ], - cpp_std: "c++20", -} - -// GN: //third_party/zlib:zlib_common_headers -cc_object { - name: "cronet_aml_third_party_zlib_zlib_common_headers", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/zlib:zlib_crc32_simd -cc_object { - name: "cronet_aml_third_party_zlib_zlib_crc32_simd", - srcs: [ - "third_party/zlib/crc32_simd.c", - "third_party/zlib/crc_folding.c", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCRC32_SIMD_SSE42_PCLMUL", - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - "-mpclmul", - "-msse3", - "-msse4.2", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - ], - cpp_std: "c++20", - target: { - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - ], - }, - }, -} - -// GN: //third_party/zlib:zlib_inflate_chunk_simd -cc_object { - 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", - ], - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - local_include_dirs: [ - "./", - "buildtools/third_party/libc++/", - "buildtools/third_party/libc++/trunk/include", - "buildtools/third_party/libc++abi/trunk/include", - "third_party/zlib/", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-DINFLATE_CHUNK_SIMD_NEON", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-DINFLATE_CHUNK_READ_64LE", - "-DINFLATE_CHUNK_SIMD_NEON", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-DINFLATE_CHUNK_SIMD_SSE2", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DHAVE_SYS_UIO_H", - "-DINFLATE_CHUNK_READ_64LE", - "-DINFLATE_CHUNK_SIMD_SSE2", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DINFLATE_CHUNK_READ_64LE", - "-DINFLATE_CHUNK_SIMD_SSE2", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //third_party/zlib:zlib_slide_hash_simd -cc_object { - name: "cronet_aml_third_party_zlib_zlib_slide_hash_simd", - host_supported: true, - defaults: [ - "cronet_aml_defaults", - ], - cflags: [ - "-DCR_CLANG_REVISION=\"llvmorg-16-init-8697-g60809cd2-1\"", - "-DCR_LIBCXX_REVISION=47b31179d10646029c260702650a25d24f555acc", - "-DDCHECK_ALWAYS_ON=1", - "-DDYNAMIC_ANNOTATIONS_ENABLED=1", - "-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", - ], - cpp_std: "c++20", - target: { - android_arm: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DDEFLATE_SLIDE_HASH_NEON", - "-DHAVE_SYS_UIO_H", - ], - }, - android_arm64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DDEFLATE_SLIDE_HASH_NEON", - "-DHAVE_SYS_UIO_H", - ], - }, - android_x86: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DDEFLATE_SLIDE_HASH_SSE2", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - android_x86_64: { - cflags: [ - "-DANDROID", - "-DANDROID_NDK_VERSION_ROLL=r23_1", - "-DDEFLATE_SLIDE_HASH_SSE2", - "-DHAVE_SYS_UIO_H", - "-msse3", - ], - }, - host: { - cflags: [ - "-DCR_SYSROOT_KEY=20220331T153654Z-0", - "-DDEFLATE_SLIDE_HASH_SSE2", - "-DUSE_AURA=1", - "-DUSE_OZONE=1", - "-DUSE_UDEV", - "-D_FILE_OFFSET_BITS=64", - "-D_LARGEFILE64_SOURCE", - "-D_LARGEFILE_SOURCE", - "-msse3", - ], - }, - }, -} - -// GN: //url:buildflags__android_arm -cc_genrule { - name: "cronet_aml_url_buildflags__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //url:buildflags__android_arm64 -cc_genrule { - name: "cronet_aml_url_buildflags__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //url:buildflags__android_x86 -cc_genrule { - name: "cronet_aml_url_buildflags__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //url:buildflags__android_x86_64 -cc_genrule { - name: "cronet_aml_url_buildflags__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //url:url -cc_library_static { - name: "cronet_aml_url_url", - srcs: [ - "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_allocator_partition_allocator_partition_alloc", - "cronet_aml_base_base", - "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_boringssl_boringssl", - "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", - ], - 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/", - ], - cpp_std: "c++20", - target: { - android_arm: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_url_buildflags__android_arm", - "cronet_aml_url_url_jni_headers__android_arm", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm", - "cronet_aml_base_logging_buildflags__android_arm", - "cronet_aml_build_chromeos_buildflags__android_arm", - "cronet_aml_url_buildflags__android_arm", - "cronet_aml_url_url_jni_headers__android_arm", - ], - }, - android_arm64: { - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - "cronet_aml_url_url_jni_headers__android_arm64", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_arm64", - "cronet_aml_base_logging_buildflags__android_arm64", - "cronet_aml_build_chromeos_buildflags__android_arm64", - "cronet_aml_url_buildflags__android_arm64", - "cronet_aml_url_url_jni_headers__android_arm64", - ], - }, - android_x86: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_url_buildflags__android_x86", - "cronet_aml_url_url_jni_headers__android_x86", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86", - "cronet_aml_base_logging_buildflags__android_x86", - "cronet_aml_build_chromeos_buildflags__android_x86", - "cronet_aml_url_buildflags__android_x86", - "cronet_aml_url_url_jni_headers__android_x86", - ], - }, - android_x86_64: { - cflags: [ - "-msse3", - ], - generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - "cronet_aml_url_url_jni_headers__android_x86_64", - ], - export_generated_headers: [ - "cronet_aml_base_debugging_buildflags__android_x86_64", - "cronet_aml_base_logging_buildflags__android_x86_64", - "cronet_aml_build_chromeos_buildflags__android_x86_64", - "cronet_aml_url_buildflags__android_x86_64", - "cronet_aml_url_url_jni_headers__android_x86_64", - ], - }, - }, -} - -// GN: //url:url_jni_headers__android_arm -cc_genrule { - name: "cronet_aml_url_url_jni_headers__android_arm", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //url:url_jni_headers__android_arm64 -cc_genrule { - name: "cronet_aml_url_url_jni_headers__android_arm64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //url:url_jni_headers__android_x86 -cc_genrule { - name: "cronet_aml_url_url_jni_headers__android_x86", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} - -// GN: //url:url_jni_headers__android_x86_64 -cc_genrule { - name: "cronet_aml_url_url_jni_headers__android_x86_64", - 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", - ], - apex_available: [ - "com.android.tethering", - ], -} -
diff --git a/tools/gn2bp/desc_arm.json b/tools/gn2bp/desc_arm.json deleted file mode 100644 index 996b5f5..0000000 --- a/tools/gn2bp/desc_arm.json +++ /dev/null Binary files differ
diff --git a/tools/gn2bp/desc_arm64.json b/tools/gn2bp/desc_arm64.json deleted file mode 100644 index dd8e800..0000000 --- a/tools/gn2bp/desc_arm64.json +++ /dev/null Binary files differ
diff --git a/tools/gn2bp/desc_x64.json b/tools/gn2bp/desc_x64.json deleted file mode 100644 index 555f044..0000000 --- a/tools/gn2bp/desc_x64.json +++ /dev/null Binary files differ
diff --git a/tools/gn2bp/desc_x86.json b/tools/gn2bp/desc_x86.json deleted file mode 100644 index 11e4e95..0000000 --- a/tools/gn2bp/desc_x86.json +++ /dev/null Binary files differ
diff --git a/tools/gn2bp/gen_android_bp b/tools/gn2bp/gen_android_bp deleted file mode 100755 index c57524d..0000000 --- a/tools/gn2bp/gen_android_bp +++ /dev/null
@@ -1,1532 +0,0 @@ -#!/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 operator -import os -import re -import sys -import copy -from pathlib import Path - -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', - '//components/cronet:cronet_package', -] - -# 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 = [ -] - -# 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' - -# put all args on a new line for better diffs. -NEWLINE = ' " +\n "' - -# Compiler flags which are passed through to the blueprint. -cflag_allowlist = [ - # needed for zlib:zlib - "-mpclmul", - # needed for zlib:zlib - "-mssse3", - # needed for zlib:zlib - "-msse3", - # needed for zlib:zlib - "-msse4.2", -] - -# Additional arguments to apply to Android.bp rules. -additional_args = { - # TODO: remove if not needed. - 'cronet_aml_components_cronet_android_cronet': [ - ('linker_scripts', { - 'base/android/library_loader/anchor_functions.lds', - }), - ], - 'cronet_aml_net_net': [ - ('export_static_lib_headers', { - 'cronet_aml_net_third_party_quiche_quiche', - 'cronet_aml_crypto_crypto', - }), - ], -} - -# Android equivalents for third-party libraries that the upstream project -# depends on. -builtin_deps = { - '//net/tools/root_store_tool:root_store_tool': - lambda x: None, -} - -# Name of tethering apex module -tethering_apex = "com.android.tethering" - -# ---------------------------------------------------------------------------- -# 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.srcs = set() - self.shared_libs = set() - self.static_libs = set() - self.whole_static_libs = set() - self.header_libs = set() - self.cflags = set() - self.dist = dict() - self.strip = dict() - self.stl = None - self.cppflags = set() - self.local_include_dirs = set() - self.export_system_include_dirs = set() - self.generated_headers = set() - self.export_generated_headers = set() - - def to_string(self, output): - nested_out = [] - self._output_field(nested_out, 'srcs') - 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, 'header_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') - self._output_field(nested_out, 'cppflags') - self._output_field(nested_out, 'local_include_dirs') - self._output_field(nested_out, 'export_system_include_dirs') - self._output_field(nested_out, 'generated_headers') - self._output_field(nested_out, 'export_generated_headers') - - 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_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.device_supported = True - 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 = set() - self.header_libs = set() - self.required = set() - self.tool_files = set() - # target contains a dict of Targets indexed by os_arch. - # example: { 'android_x86': Target('android_x86') - self.target = dict() - self.target['android'] = Target('android') - self.target['android_x86'] = Target('android_x86') - self.target['android_x86_64'] = Target('android_x86_64') - self.target['android_arm'] = Target('android_arm') - self.target['android_arm64'] = Target('android_arm64') - self.target['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() - self.linker_scripts = set() - # 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 - # Name of the output. Used for setting .so file name for libcronet - self.libs = set() - self.stem = None - self.compile_multilib = None - self.aidl = dict() - self.plugins = set() - self.processor_class = None - self.sdk_version = None - - 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 not self.device_supported: - self._output_field(output, 'device_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') - 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, 'linker_scripts') - self._output_field(output, 'cppflags') - self._output_field(output, 'libs') - self._output_field(output, 'stem') - self._output_field(output, 'compile_multilib') - self._output_field(output, 'aidl') - self._output_field(output, 'plugins') - self._output_field(output, 'processor_class') - self._output_field(output, 'sdk_version') - if self.rtti: - self._output_field(output, 'rtti') - - target_out = [] - for arch, target in sorted(self.target.items()): - # _output_field calls getattr(self, arch). - setattr(self, arch, target) - self._output_field(target_out, arch) - - 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.target['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.target['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) - - def is_compiled(self): - return self.type not in ('cc_genrule', 'filegroup', 'java_genrule') - - def is_genrule(self): - return self.type == "cc_genrule" - - def has_input_files(self): - return len(self.srcs) > 0 or any([len(target.srcs) > 0 for target in self.target.values()]) - - def merge_attribute(self, key, source_module, allowed_archs, source_key = None): - """ - Merges the value of the attribute `source_key` for the `dep_module` with - the value of the attribute `key` for this module. If the value of the - `source_key` is equal to None. Then `key` is used for both modules. - - This merges the attribute for both non-arch and archs - specified in `allowed_archs`. - :param key: The attribute used for merging in the calling module. Also - used for `dep_module` if the `source_key` is None. - :param source_module: The module where data is propagated from. - :param allowed_archs: A list of archs to merge the attribute on. - :param source_key: if the attribute merged from the `dep_module` - is different from the `key` - """ - if not source_key: - source_key = key - self.__dict__[key].update(source_module.__dict__[source_key]) - for arch_name in source_module.target.keys(): - if arch_name in allowed_archs: - self.target[arch_name].__dict__[key].update( - source_module.target[arch_name].__dict__[source_key]) - -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.""" - module = re.sub(r'^//:?', '', label) - 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') - - protoc_gn_target_name = gn.get_target('//third_party/protobuf:protoc').name - protoc_module_name = label_to_module_name(protoc_gn_target_name) - tools = {protoc_module_name} - 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 %s)' % protoc_module_name] - 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('cc_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('cc_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('cc_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) - - # This function does not return header_module so setting apex_available attribute here. - header_module.apex_available.add(tethering_apex) - - 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_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) - -def create_gcc_preprocess_modules(blueprint, target): - # gcc_preprocess.py internally execute host gcc which is not allowed in genrule. - # So, this function create multiple modules and realize equivalent processing - # TODO: Consider to support gcc_preprocess.py in different way - # It's not great to have genrule and cc_object in the dependency from java_library - assert (len(target.sources) == 1) - source = list(target.sources)[0] - assert (Path(source).suffix == '.template') - stem = Path(source).stem - - bp_module_name = label_to_module_name(target.name) - - # Rename .template to .cc since cc_object does not accept .template file as srcs - rename_module = Module('genrule', bp_module_name + '_rename', target.name) - rename_module.srcs.add(gn_utils.label_to_path(source)) - rename_module.out.add(stem + '.cc') - rename_module.cmd = 'cp $(in) $(out)' - blueprint.add_module(rename_module) - - # Preprocess template file and generates java file - preprocess_module = Module('cc_object', bp_module_name + '_preprocess', target.name) - # -E: stop after preprocessing. - # -P: disable line markers, i.e. '#line 309' - preprocess_module.cflags.update(['-E', '-P', '-DANDROID']) - preprocess_module.srcs.add(':' + rename_module.name) - defines = ['-D' + target.args[i+1] for i, arg in enumerate(target.args) if arg == '--define'] - preprocess_module.cflags.update(defines) - # HACK: Specifying compile_multilib to build cc_object only once. - # Without this, soong complain to genrule that depends on cc_object when built for 64bit target. - # It seems this is because cc object is a module with per-architecture variants and genrule is a - # module with default variant. For 64bit target, cc_object is built multiple times for 32/64bit - # modes and genrule doesn't know which one to depend on. - preprocess_module.compile_multilib = 'first' - blueprint.add_module(preprocess_module) - - # Generates srcjar using soong_zip - module = Module('genrule', bp_module_name, target.name) - module.srcs.add(':' + preprocess_module.name) - module.out.add(stem + '.srcjar') - module.cmd = NEWLINE.join([ - f'cp $(in) $(genDir)/{stem}.java &&', - f'$(location soong_zip) -o $(out) -srcjar -f $(genDir)/{stem}.java' - ]) - module.tools.add('soong_zip') - blueprint.add_module(module) - return module - - -class BaseActionSanitizer(): - def __init__(self, target): - # Just to be on the safe side, create a deep-copy. - self.target = copy.deepcopy(target) - self.target.args = self._normalize_args() - - def get_name(self): - return label_to_module_name(self.target.name) - - def _normalize_args(self): - # Convert ['--param=value'] to ['--param', 'value'] for consistency. - # Escape quotations. - normalized_args = [] - for arg in self.target.args: - arg = arg.replace('"', r'\"') - if arg.startswith('-'): - normalized_args.extend(arg.split('=')) - else: - normalized_args.append(arg) - return normalized_args - - # There are three types of args: - # - flags (--flag) - # - value args (--arg value) - # - list args (--arg value1 --arg value2) - # value args have exactly one arg value pair and list args have one or more arg value pairs. - # Note that the set of list args contains the set of value args. - # This is because list and value args are identical when the list args has only one arg value pair - # Some functions provide special implementations for each type, while others - # work on all of them. - def _has_arg(self, arg): - return arg in self.target.args - - def _get_arg_indices(self, target_arg): - return [i for i, arg in enumerate(self.target.args) if arg == target_arg] - - # Whether an arg value pair appears once or more times - def _is_list_arg(self, arg): - indices = self._get_arg_indices(arg) - return len(indices) > 0 and all([not self.target.args[i + 1].startswith('--') for i in indices]) - - def _update_list_arg(self, arg, func, throw_if_absent = True): - if self._should_fail_silently(arg, throw_if_absent): - return - assert(self._is_list_arg(arg)) - indices = self._get_arg_indices(arg) - for i in indices: - self._set_arg_at(i + 1, func(self.target.args[i + 1])) - - # Whether an arg value pair appears exactly once - def _is_value_arg(self, arg): - return operator.countOf(self.target.args, arg) == 1 and self._is_list_arg(arg) - - def _get_value_arg(self, arg): - assert(self._is_value_arg(arg)) - i = self.target.args.index(arg) - return self.target.args[i + 1] - - # used to check whether a function call should cause an error when an arg is - # missing. - def _should_fail_silently(self, arg, throw_if_absent): - return not throw_if_absent and not self._has_arg(arg) - - def _set_value_arg(self, arg, value, throw_if_absent = True): - if self._should_fail_silently(arg, throw_if_absent): - return - assert(self._is_value_arg(arg)) - i = self.target.args.index(arg) - self.target.args[i + 1] = value - - def _update_value_arg(self, arg, func, throw_if_absent = True): - if self._should_fail_silently(arg, throw_if_absent): - return - self._set_value_arg(arg, func(self._get_value_arg(arg))) - - def _set_arg_at(self, position, value): - self.target.args[position] = value - - def _delete_value_arg(self, arg, throw_if_absent = True): - if self._should_fail_silently(arg, throw_if_absent): - return - assert(self._is_value_arg(arg)) - i = self.target.args.index(arg) - self.target.args.pop(i) - self.target.args.pop(i) - - def _append_arg(self, arg, value): - self.target.args.append(arg) - self.target.args.append(value) - - def _sanitize_filepath_with_location_tag(self, arg): - if arg.startswith('../../'): - arg = self._sanitize_filepath(arg) - arg = self._add_location_tag(arg) - return arg - - # wrap filename in location tag. - def _add_location_tag(self, filename): - return '$(location %s)' % filename - - # applies common directory transformation that *should* be universally applicable. - # TODO: verify if it actually *is* universally applicable. - def _sanitize_filepath(self, filepath): - # Careful, order matters! - # delete all leading ../ - filepath = re.sub('^(\.\./)+', '', filepath) - filepath = re.sub('^gen/jni_headers', '$(genDir)', filepath) - filepath = re.sub('^gen', '$(genDir)', filepath) - return filepath - - # Iterate through all the args and apply function - def _update_all_args(self, func): - self.target.args = [func(arg) for arg in self.target.args] - - def get_cmd(self): - arg_string = NEWLINE.join(self.target.args) - cmd = '$(location %s) %s' % ( - gn_utils.label_to_path(self.target.script), arg_string) - - if self.use_response_file: - # Pipe response file contents into script - cmd = 'echo \'%s\' |%s%s' % (self.target.response_file_contents, NEWLINE, cmd) - return cmd - - def get_outputs(self): - return self.target.outputs - - def get_srcs(self): - # gn treats inputs and sources for actions equally. - # soong only supports source files inside srcs, non-source files are added as - # tool_files dependency. - files = self.target.sources.union(self.target.inputs) - return {gn_utils.label_to_path(file) for file in files if is_supported_source_file(file)} - - def get_tool_files(self): - # gn treats inputs and sources for actions equally. - # soong only supports source files inside srcs, non-source files are added as - # tool_files dependency. - files = self.target.sources.union(self.target.inputs) - tool_files = {gn_utils.label_to_path(file) - for file in files if not is_supported_source_file(file)} - tool_files.add(gn_utils.label_to_path(self.target.script)) - return tool_files - - def _sanitize_args(self): - # Handle passing parameters via response file by piping them into the script - # and reading them from /dev/stdin. - - self.use_response_file = gn_utils.RESPONSE_FILE in self.target.args - if self.use_response_file: - # Replace {{response_file_contents}} with /dev/stdin - self.target.args = ['/dev/stdin' if it == gn_utils.RESPONSE_FILE else it - for it in self.target.args] - - def _sanitize_outputs(self): - pass - - def _sanitize_inputs(self): - pass - - def sanitize(self): - self._sanitize_args() - self._sanitize_outputs() - self._sanitize_inputs() - - # Whether this target generates header files - def is_header_generated(self): - return any(os.path.splitext(it)[1] == '.h' for it in self.target.outputs) - -class WriteBuildDateHeaderSanitizer(BaseActionSanitizer): - def _sanitize_args(self): - self._set_arg_at(0, '$(out)') - super()._sanitize_args() - -class WriteBuildFlagHeaderSanitizer(BaseActionSanitizer): - def _sanitize_args(self): - self._set_value_arg('--gen-dir', '.') - self._set_value_arg('--output', '$(out)') - super()._sanitize_args() - -class JniGeneratorSanitizer(BaseActionSanitizer): - def _add_location_tag_to_filepath(self, arg): - if not arg.endswith('.class'): - # --input_file supports both .class specifiers or source files as arguments. - # Only source files need to be wrapped inside a $(location <label>) tag. - arg = self._add_location_tag(arg) - return arg - - def _sanitize_args(self): - self._update_value_arg('--jar_file', self._sanitize_filepath, False) - self._update_value_arg('--jar_file', self._add_location_tag, False) - if self._has_arg('--jar_file'): - self._append_arg('--javap', '$$(find out/.path -name javap)') - self._update_value_arg('--output_dir', self._sanitize_filepath) - self._update_value_arg('--includes', self._sanitize_filepath, False) - self._delete_value_arg('--prev_output_dir', False) - self._update_list_arg('--input_file', self._sanitize_filepath) - self._update_list_arg('--input_file', self._add_location_tag_to_filepath) - super()._sanitize_args() - - def _sanitize_outputs(self): - # fix target.output directory to match #include statements. - self.target.outputs = {re.sub('^jni_headers/', '', out) for out in self.target.outputs} - super()._sanitize_outputs() - - def get_tool_files(self): - tool_files = super().get_tool_files() - # android_jar.classes should be part of the tools as it list implicit classes - # for the script to generate JNI headers. - tool_files.add("base/android/jni_generator/android_jar.classes") - return tool_files - -class JniRegistrationGeneratorSanitizer(BaseActionSanitizer): - def _sanitize_inputs(self): - self.target.inputs = [file for file in self.target.inputs if not file.startswith('//out/')] - - def _sanitize_args(self): - self._update_value_arg('--depfile', self._sanitize_filepath) - self._update_value_arg('--srcjar-path', self._sanitize_filepath) - self._update_value_arg('--header-path', self._sanitize_filepath) - self._set_value_arg('--sources-files', '$(genDir)/java.sources') - # update_jni_registration_module removes them from the srcs of the module - # It might be better to remove sources by '--sources-exclusions' - self._delete_value_arg('--sources-exclusions') - super()._sanitize_args() - - def get_cmd(self): - # jni_registration_generator.py doesn't work with python2 - cmd = "python3 " + super().get_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;", - 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") - return NEWLINE.join(commands) - -class JavaJniRegistrationGeneratorSanitizer(JniRegistrationGeneratorSanitizer): - def get_name(self): - return label_to_module_name(self.target.name) + "__java" - - def _sanitize_outputs(self): - self.target.outputs = [out for out in self.target.outputs if - out.endswith(".srcjar")] - super()._sanitize_outputs() - -class VersionSanitizer(BaseActionSanitizer): - def _sanitize_args(self): - self._set_value_arg('-o', '$(out)') - # args for the version.py contain file path without leading --arg key. So apply sanitize - # function for all the args. - self._update_all_args(self._sanitize_filepath_with_location_tag) - self._set_value_arg('-e', "'%s'" % self._get_value_arg('-e')) - super()._sanitize_args() - - def get_tool_files(self): - tool_files = super().get_tool_files() - # android_chrome_version.py is not specified in anywhere but version.py imports this file - tool_files.add('build/util/android_chrome_version.py') - return tool_files - -class JavaCppEnumSanitizer(BaseActionSanitizer): - def _sanitize_args(self): - self._update_all_args(self._sanitize_filepath_with_location_tag) - self._set_value_arg('--srcjar', '$(out)') - super()._sanitize_args() - -class MakeDafsaSanitizer(BaseActionSanitizer): - def is_header_generated(self): - # This script generates .cc files but they are #included by other sources - # (e.g. registry_controlled_domain.cc) - return True - -class JavaCppFeatureSanitizer(BaseActionSanitizer): - def _sanitize_args(self): - self._update_all_args(self._sanitize_filepath_with_location_tag) - self._set_value_arg('--srcjar', '$(out)') - super()._sanitize_args() - -class JavaCppStringSanitizer(BaseActionSanitizer): - def _sanitize_args(self): - self._update_all_args(self._sanitize_filepath_with_location_tag) - self._set_value_arg('--srcjar', '$(out)') - super()._sanitize_args() - -class WriteNativeLibrariesJavaSanitizer(BaseActionSanitizer): - def _sanitize_args(self): - self._set_value_arg('--output', '$(out)') - super()._sanitize_args() - -def get_action_sanitizer(target, type): - if target.script == "//build/write_buildflag_header.py": - return WriteBuildFlagHeaderSanitizer(target) - elif target.script == "//build/write_build_date_header.py": - return WriteBuildDateHeaderSanitizer(target) - elif target.script == '//base/android/jni_generator/jni_generator.py': - return JniGeneratorSanitizer(target) - elif target.script == '//base/android/jni_generator/jni_registration_generator.py': - if type == 'java_genrule': - return JavaJniRegistrationGeneratorSanitizer(target) - else: - return JniRegistrationGeneratorSanitizer(target) - elif target.script == "//build/util/version.py": - return VersionSanitizer(target) - elif target.script == "//build/android/gyp/java_cpp_enum.py": - return JavaCppEnumSanitizer(target) - elif target.script == "//net/tools/dafsa/make_dafsa.py": - return MakeDafsaSanitizer(target) - elif target.script == '//build/android/gyp/java_cpp_features.py': - return JavaCppFeatureSanitizer(target) - elif target.script == '//build/android/gyp/java_cpp_strings.py': - return JavaCppStringSanitizer(target) - elif target.script == '//build/android/gyp/write_native_libraries_java.py': - return WriteNativeLibrariesJavaSanitizer(target) - else: - # TODO: throw exception here once all script hacks have been converted. - return BaseActionSanitizer(target) - -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, 'cc_genrule') - -def create_action_module(blueprint, target, type): - sanitizer = get_action_sanitizer(target, type) - sanitizer.sanitize() - - module = Module(type, sanitizer.get_name(), target.name) - module.cmd = sanitizer.get_cmd() - module.out = sanitizer.get_outputs() - if sanitizer.is_header_generated(): - module.genrule_headers.add(module.name) - module.srcs = sanitizer.get_srcs() - module.tool_files = sanitizer.get_tool_files() - - blueprint.add_module(module) - return module - - - -def _get_cflags(cflags, defines): - cflags = {flag for flag in cflags if flag in cflag_allowlist} - # Consider proper allowlist or denylist if needed - cflags |= set("-D%s" % define.replace("\"", "\\\"") for define in defines) - return cflags - -def set_module_flags(module, cflags, defines): - module.cflags.update(_get_cflags(cflags, defines)) - # TODO: implement proper cflag parsing. - for flag in cflags: - if '-std=' in flag: - module.cpp_std = flag[len('-std='):] - if '-fexceptions' in flag: - module.cppflags.add('-fexceptions') - -def set_module_include_dirs(module, cflags, include_dirs): - for flag in cflags: - if '-isystem' in flag: - module.local_include_dirs.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. - module.local_include_dirs.update([gn_utils.label_to_path(d) - for d in include_dirs - if not re.match('^//out/.*', d)]) - -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) - - if target.type == 'executable': - if target.testonly: - module_type = 'cc_test' - else: - # Can be used for both host and device targets. - 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('cc_object', 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': - module = create_action_module(blueprint, target, 'cc_genrule') - 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.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")) - - # Add arch-specific properties - for arch_name, arch in target.arch.items(): - module.target[arch_name].srcs.update( - gn_utils.label_to_path(src) - for src in arch.sources - if is_supported_source_file(src) and not src.startswith("//out/test")) - - module.rtti = target.rtti - - if target.type in gn_utils.LINKER_UNIT_TYPES: - set_module_flags(module, target.cflags, target.defines) - set_module_include_dirs(module, target.cflags, target.include_dirs) - # TODO: set_module_xxx is confusing, apply similar function to module and target in better way. - for arch_name, arch in target.arch.items(): - set_module_flags(module.target[arch_name], arch.cflags, arch.defines) - # -Xclang -target-feature -Xclang +mte are used to enable MTE (Memory Tagging Extensions). - # Flags which does not start with '-' could not be in the cflags so enabling MTE by - # -march and -mcpu Feature Modifiers. MTE is only available on arm64. This is needed for - # building //base/allocator/partition_allocator:partition_alloc for arm64. - if '+mte' in arch.cflags and arch_name == 'android_arm64': - module.target[arch_name].cflags.add('-march=armv8-a+memtag') - set_module_include_dirs(module.target[arch_name], arch.cflags, arch.include_dirs) - - module.host_supported = target.host_supported() - module.device_supported = target.device_supported() - - if module.is_genrule(): - module.apex_available.add(tethering_apex) - - 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 - - if module.name == 'cronet_aml_components_cronet_android_cronet': - if target.output_name is None: - raise Error('Failed to get output_name for libcronet name') - # .so file name needs to match with CronetLibraryLoader.java (e.g. libcronet.109.0.5386.0.so) - # So setting the output name based on the output_name from the desc.json - module.stem = 'lib' + target.output_name - - # 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 dep_name in builtin_deps: - builtin_deps[dep_name](module) - continue - - dep_module = create_modules_from_target(blueprint, gn, dep_name) - - if dep_module is None: - continue - # 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.is_genrule() and dep_module.is_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() or module.is_genrule(): - 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 == 'cc_object': - module.merge_attribute('generated_headers', dep_module, target.arch.keys()) - if module.type != 'cc_object': - if dep_module.has_input_files(): - # Only add it as part of srcs if the dep_module has input files otherwise - # this would throw an error. - module.srcs.add(":" + dep_module.name) - module.merge_attribute('export_generated_headers', dep_module, - target.arch.keys(), 'generated_headers') - elif dep_module.type == 'cc_genrule': - module.merge_attribute('generated_headers', dep_module, [], 'genrule_headers') - module.merge_attribute('srcs', dep_module, [], 'genrule_srcs') - module.merge_attribute('shared_libs', dep_module, [], 'genrule_shared_libs') - module.merge_attribute('header_libs', dep_module, [], 'genrule_header_libs') - if module.type not in ["cc_object"]: - module.merge_attribute('export_generated_headers', dep_module, [], - 'genrule_headers') - 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)) - - for arch_name, arch in target.arch.items(): - for dep_name in arch.deps: - dep_module = create_modules_from_target(blueprint, gn, dep_name) - # Arch-specific dependencies currently only include cc_library_static. - # Revisit this approach once we need to support more target types. - if dep_module.type == 'cc_library_static': - module.target[arch_name].static_libs.add(dep_module.name) - elif dep_module.type == 'cc_genrule': - if dep_module.name.endswith(arch_name): - module.target[arch_name].generated_headers.update(dep_module.genrule_headers) - module.target[arch_name].srcs.update(dep_module.genrule_srcs) - module.target[arch_name].shared_libs.update(dep_module.genrule_shared_libs) - module.target[arch_name].header_libs.update(dep_module.genrule_header_libs) - if module.type not in ["cc_object"]: - module.target[arch_name].export_generated_headers.update( - dep_module.genrule_headers) - else: - raise Error('Unsupported arch-specific dependency %s of target %s with type %s' % - (dep_module.name, target.name, dep_module.type)) - for dep_name in arch.source_set_deps: - dep_module = create_modules_from_target(blueprint, gn, dep_name) - if dep_module.type == 'cc_object': - if module.type != 'cc_object': - # We only want to bubble up cc_objects for modules that are not cc_objects - # otherwise they'd be recompiled and that would cause multiple symbol redefinitions. - if dep_module.has_input_files(): - # Only add it as part of srcs if the dep_module has input files otherwise - # this would throw an error. - module.target[arch_name].srcs.add(":" + dep_module.name) - else: - raise Error('Unsupported arch-specific dependency %s of target %s with type %s' % - (dep_module.name, target.name, dep_module.type)) - return module - -def create_java_jni_preprocessor(blueprint): - bp_module_name = module_prefix + 'java_jni_annotation_preprocessor' - module = Module('java_plugin', bp_module_name, '//base/android/jni_generator:jni_processor') - module.srcs.update( - [ - "base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java", - # Avoids a circular dependency with base:base_java. This is okay because - # no target should ever expect to package an annotation processor. - "build/android/java/src/org/chromium/build/annotations/CheckDiscard.java", - "build/android/java/src/org/chromium/build/annotations/MainDex.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/NativeMethods.java", - "base/android/java/src/org/chromium/base/JniException.java", - ":cronet_aml_build_android_build_config_gen", - ]) - module.static_libs.update({ - "javapoet", - "guava", - "auto_service_annotations", - }) - module.processor_class = "org.chromium.jni_generator.JniProcessor" - blueprint.add_module(module) - 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]) - module.libs = { - "androidx.annotation_annotation", - "jsr305", - "androidx.core_core-nodeps", - "androidx.collection_collection", - "androidx.annotation_annotation-experimental-nodeps", - "android-support-multidex", - "framework-connectivity.stubs.module_lib", - "framework-connectivity-t.stubs.module_lib", - "framework-tethering.stubs.module_lib", - "framework-wifi.stubs.module_lib", - "framework-mediaprovider.stubs.module_lib", - } - module.aidl["include_dirs"] = {"frameworks/base/core/java/"} - module.aidl["local_include_dirs"] = {"base/android/java/src/"} - module.sdk_version = "module_current" - module.apex_available.add(tethering_apex) - # TODO: remove following workaround required to make this module visible to make (b/203203405) - module.apex_available.add("//apex_available:platform") - for dep in gn.java_actions: - target = gn.get_target(dep) - if target.script == '//build/android/gyp/gcc_preprocess.py': - module.srcs.add(':' + create_gcc_preprocess_modules(blueprint, target).name) - else: - module.srcs.add(':' + create_action_module(blueprint, target, 'java_genrule').name) - preprocessor_module = create_java_jni_preprocessor(blueprint) - module.plugins.add(preprocessor_module.name) - blueprint.add_module(module) - -def update_jni_registration_module(module, gn): - # 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.endswith('.java') and source not in deny_list]) - -def create_blueprint_for_targets(gn, 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 = [ - '-DGOOGLE_PROTOBUF_NO_RTTI', - '-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-null-pointer-subtraction', # Needed to libevent - '-Wno-deprecated-non-prototype', # needed for zlib - '-fvisibility=hidden', - '-Wno-ambiguous-reversed-operator', # needed for icui18n - '-Wno-unreachable-code-loop-increment', # needed for icui18n - '-O2', - '-fPIC', - ] - # Chromium builds do not add a dependency for headers found inside the - # sysroot, so they are added globally via defaults. - defaults.target['android'].header_libs = [ - 'media_ndk_headers', - 'jni_headers', - ] - defaults.target['host'].cflags = [ - # -DANDROID is added by default but target.defines contain -DANDROID if - # it's required. So adding -UANDROID to cancel default -DANDROID if it's - # not specified. - # Note: -DANDROID is not consistently applied across the chromium code - # base, so it is removed unconditionally for host targets. - '-UANDROID', - ] - defaults.stl = 'none' - defaults.min_sdk_version = 29 - defaults.apex_available.add(tethering_apex) - blueprint.add_module(defaults) - - for target in targets: - create_modules_from_target(blueprint, gn, target) - - create_java_module(blueprint, gn) - for module in blueprint.modules.values(): - if 'cronet_jni_registration' in module.name: - update_jni_registration_module(module, 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 "//*".' + - 'You can specify multiple --desc options for different target_cpu', - required=True, - action='append' - ) - 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) - - targets = args.targets or default_targets - gn = gn_utils.GnParser() - for desc_file in args.desc: - with open(desc_file) as f: - desc = json.load(f) - for target in targets: - gn.parse_gn_desc(desc, target) - blueprint = create_blueprint_for_targets(gn, 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 deleted file mode 100644 index 6cbbd67..0000000 --- a/tools/gn2bp/gn_utils.py +++ /dev/null
@@ -1,497 +0,0 @@ -# Copyright (C) 2022 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# 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' -LINKER_UNIT_TYPES = ('executable', 'shared_library', 'static_library', 'source_set') -JAVA_BANNED_SCRIPTS = [ - "//build/android/gyp/turbine.py", - "//build/android/gyp/compile_java.py", - "//build/android/gyp/filter_zip.py", - "//build/android/gyp/dex.py", - "//build/android/gyp/write_build_config.py", - "//build/android/gyp/create_r_java.py", - "//build/android/gyp/ijar.py", - "//build/android/gyp/create_r_java.py", - "//build/android/gyp/bytecode_processor.py", - "//build/android/gyp/prepare_resources.py", - "//build/android/gyp/aar.py", - "//build/android/gyp/zip.py", -] -# TODO(primiano): investigate these, they require further componentization. -ODR_VIOLATION_IGNORE_TARGETS = { - '//test/cts:perfetto_cts_deps', - '//:perfetto_integrationtests', -} -ARCH_REGEX = r'(android_x86_64|android_x86|android_arm|android_arm64|host)' -RESPONSE_FILE = '{{response_file_name}}' - -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 - -def _is_java_source(src): - return os.path.splitext(src)[1] == '.java' and not src.startswith("//out/test/gen/") - -def is_java_action(script, outputs): - return (script != "" and script not in JAVA_BANNED_SCRIPTS) and any( - [file.endswith(".srcjar") or file.endswith(".java") - for file in outputs]) - -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. - """ - class Arch(): - """Architecture-dependent properties - """ - def __init__(self): - self.sources = set() - self.cflags = set() - self.defines = set() - self.include_dirs = set() - self.deps = set() - self.transitive_static_libs_deps = set() - self.source_set_deps = set() - - - 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() - self.rtti = False - - # TODO: come up with a better way to only run this once. - # is_finalized tracks whether finalize() was called on this target. - self.is_finalized = False - self.arch = dict() - - # This is used to get the name/version of libcronet - self.output_name = None - - def host_supported(self): - return 'host' in self.arch - - def device_supported(self): - return any([name.startswith('android') for name in self.arch.keys()]) - - 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, arch): - 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, [])) - - for key_in_arch in ('cflags', 'defines', 'include_dirs', 'source_set_deps'): - self.arch[arch].__dict__[key_in_arch].update( - other.arch[arch].__dict__.get(key_in_arch, [])) - - def finalize(self): - """Move common properties out of arch-dependent subobjects to Target object. - - TODO: find a better name for this function. - """ - if self.is_finalized: - return - self.is_finalized = True - - # Target contains the intersection of arch-dependent properties - self.sources = set.intersection(*[arch.sources for arch in self.arch.values()]) - self.cflags = set.intersection(*[arch.cflags for arch in self.arch.values()]) - self.defines = set.intersection(*[arch.defines for arch in self.arch.values()]) - self.include_dirs = set.intersection(*[arch.include_dirs for arch in self.arch.values()]) - self.deps.update(set.intersection(*[arch.deps for arch in self.arch.values()])) - self.source_set_deps.update(set.intersection(*[arch.source_set_deps for arch in self.arch.values()])) - - # Deduplicate arch-dependent properties - for arch in self.arch.keys(): - self.arch[arch].sources -= self.sources - self.arch[arch].cflags -= self.cflags - self.arch[arch].defines -= self.defines - self.arch[arch].include_dirs -= self.include_dirs - self.arch[arch].deps -= self.deps - self.arch[arch].source_set_deps -= self.source_set_deps - - - def __init__(self): - self.all_targets = {} - self.linker_units = {} # Executables, shared or static libraries. - self.source_sets = {} - self.actions = {} - self.proto_libs = {} - self.java_sources = set() - self.java_actions = 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_group(self, type_, target_name): - # 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 type_ == 'group' and re.match('.*_java$', target_name) - - def _get_arch(self, toolchain): - if toolchain == '//build/toolchain/android:android_clang_x86': - return 'android_x86' - elif toolchain == '//build/toolchain/android:android_clang_x64': - return 'android_x86_64' - elif toolchain == '//build/toolchain/android:android_clang_arm': - return 'android_arm' - elif toolchain == '//build/toolchain/android:android_clang_arm64': - return 'android_arm64' - else: - return 'host' - - def get_target(self, gn_target_name): - """Returns a Target object from the fully qualified GN target name. - - get_target() requires that parse_gn_desc() has already been called. - """ - # Run this every time as parse_gn_desc can be called at any time. - for target in self.all_targets.values(): - target.finalize() - - return self.all_targets[label_without_toolchain(gn_target_name)] - - def parse_gn_desc(self, gn_desc, gn_target_name, is_java_target = False): - """Parses a gn desc tree and resolves all target dependencies. - - It bubbles up variables from source_set dependencies as described in the - class-level comments. - """ - # Use name without toolchain for targets to support targets built for - # multiple archs. - target_name = label_without_toolchain(gn_target_name) - desc = gn_desc[gn_target_name] - type_ = desc['type'] - arch = self._get_arch(desc['toolchain']) - - is_java_target = is_java_target or self._is_java_group(type_, target_name) - - # Action modules can differ depending on the target architecture, yet - # genrule's do not allow to overload cmd per target OS / arch. Create a - # separate action for every architecture. - # Cover both action and action_foreach - if type_.startswith('action') and not is_java_target: - # Don't meddle with the java actions name - target_name += '__' + arch - - target = self.all_targets.get(target_name) - if target is None: - target = GnParser.Target(target_name, type_) - self.all_targets[target_name] = target - - if arch not in target.arch: - target.arch[arch] = GnParser.Target.Arch() - else: - return target # Target already processed. - - target.testonly = desc.get('testonly', False) - - proto_target_type, proto_desc = self.get_proto_target_type(gn_desc, gn_target_name) - 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) - for gn_proto_deps_name in proto_desc.get('deps', []): - dep = self.parse_gn_desc(gn_desc, gn_proto_deps_name) - target.deps.add(dep.name) - target.arch[arch].sources.update(proto_desc.get('sources', [])) - assert (all(x.endswith('.proto') for x in target.arch[arch].sources)) - elif target.type == 'source_set': - self.source_sets[gn_target_name] = target - target.arch[arch].sources.update(desc.get('sources', [])) - elif target.type in LINKER_UNIT_TYPES: - self.linker_units[gn_target_name] = target - target.arch[arch].sources.update(desc.get('sources', [])) - elif (desc.get("script", "") in JAVA_BANNED_SCRIPTS - or self._is_java_group(target.type, target.name)): - # 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) - if target.type == "action": - # Convert java actions into java_group and keep the inputs for collection. - target.inputs.update(desc.get('inputs', [])) - target.type = 'java_group' - elif target.type in ['action', 'action_foreach']: - self.actions[gn_target_name] = target - target.inputs.update(desc.get('inputs', [])) - target.arch[arch].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 - - # 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.arch[arch].cflags.update(desc.get('cflags', []) + desc.get('cflags_cc', [])) - target.libs.update(desc.get('libs', [])) - target.ldflags.update(desc.get('ldflags', [])) - target.arch[arch].defines.update(desc.get('defines', [])) - target.arch[arch].include_dirs.update(desc.get('include_dirs', [])) - target.output_name = desc.get('output_name', None) - if "-frtti" in target.arch[arch].cflags: - target.rtti = True - - # Recurse in dependencies. - for gn_dep_name in desc.get('deps', []): - dep = self.parse_gn_desc(gn_desc, gn_dep_name, is_java_target) - if 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.arch[arch].source_set_deps.add(dep.name) - target.arch[arch].source_set_deps.update(dep.arch[arch].source_set_deps) - elif dep.type == 'group': - target.update(dep, arch) # Bubble up groups's cflags/ldflags etc. - elif dep.type in ['action', 'action_foreach', 'copy']: - if proto_target_type is None: - target.arch[arch].deps.add(dep.name) - elif dep.type in LINKER_UNIT_TYPES: - target.arch[arch].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 - - # Source set bubble up transitive source sets but can't be combined with this - # if they are combined then source sets will bubble up static libraries - # while we only want to have source sets bubble up only source sets. - if dep.type == 'static_library': - # Bubble up static_libs. Necessary, since soong does not propagate - # static_libs up the build tree. - target.arch[arch].transitive_static_libs_deps.add(dep.name) - - if arch in dep.arch: - target.arch[arch].transitive_static_libs_deps.update( - dep.arch[arch].transitive_static_libs_deps) - target.arch[arch].deps.update(target.arch[arch].transitive_static_libs_deps) - - # 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 target.name.endswith('__dex'): - if dep.name.endswith('__compile_java'): - log.debug('Adding java sources for %s', dep.name) - java_srcs = [src for src in dep.inputs if _is_java_source(src)] - self.java_sources.update(java_srcs) - if dep.type in ["action"] and target.type == "java_group": - # //base:base_java_aidl generates srcjar from .aidl files. But java_library in soong can - # directly have .aidl files in srcs. So adding .aidl files to the java_sources. - # TODO: Find a better way/place to do this. - if dep.name == '//base:base_java_aidl': - self.java_sources.update(dep.arch[arch].sources) - else: - self.java_actions.add(dep.name) - 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, gn_desc, gn_target_name): - """ 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 = gn_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 = gn_desc.get(gn_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 = 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 deleted file mode 100755 index a464604..0000000 --- a/tools/gn2bp/update_results.sh +++ /dev/null
@@ -1,16 +0,0 @@ -#!/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 - -BASEDIR=$(dirname "$0") -$BASEDIR/gen_android_bp --desc $BASEDIR/desc_x64.json --desc $BASEDIR/desc_x86.json \ ---desc $BASEDIR/desc_arm.json --desc $BASEDIR/desc_arm64.json --out $BASEDIR/Android.bp