diff options
93 files changed, 1979 insertions, 1025 deletions
diff --git a/Android.bp b/Android.bp index baa715e3bcac..cfdfeb3de0e0 100644 --- a/Android.bp +++ b/Android.bp @@ -687,7 +687,7 @@ java_library { filegroup { name: "framework-ike-shared-srcs", - visibility: ["//frameworks/opt/net/ike"], + visibility: ["//packages/modules/IPsec"], srcs: [ "core/java/android/annotation/StringDef.java", "core/java/android/net/annotations/PolicyDirection.java", @@ -1132,6 +1132,7 @@ metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.x "--hide MissingPermission --hide BroadcastBehavior " + "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " + + "--error NoSettingsProvider " + "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.* " + "--api-lint-ignore-prefix android.icu. " + "--api-lint-ignore-prefix java. " + diff --git a/ApiDocs.bp b/ApiDocs.bp index 60f56de73598..029699efe3b9 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -66,7 +66,7 @@ stubs_defaults { ":opt-telephony-srcs", ":opt-net-voip-srcs", ":art-module-public-api-stubs-source", - ":conscrypt.module.public.api.stubs.source", + ":conscrypt.module.public.api{.public.stubs.source}", ":android_icu4j_public_api_files", "test-mock/src/**/*.java", "test-runner/src/**/*.java", diff --git a/StubLibraries.bp b/StubLibraries.bp index 4a77463160f6..c80d1343cfb5 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -49,6 +49,7 @@ stubs_defaults { ":opt-net-voip-srcs", ":art-module-public-api-stubs-source", ":android_icu4j_public_api_files", + "**/package.html", ], libs: ["framework-internal-utils"], installable: false, @@ -65,7 +66,7 @@ stubs_defaults { name: "metalava-full-api-stubs-default", defaults: ["metalava-base-api-stubs-default"], srcs: [ - ":conscrypt.module.public.api.stubs.source", + ":conscrypt.module.public.api{.public.stubs.source}", ":framework-updatable-sources", ], sdk_version: "core_platform", diff --git a/apex/Android.bp b/apex/Android.bp index 3a63c80588ca..380b4c6cc0be 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -71,6 +71,15 @@ java_defaults { // stubs libraries. libs: ["framework-annotations-lib"], + // Framework modules are not generally shared libraries, i.e. they are not + // intended, and must not be allowed, to be used in a <uses-library> manifest + // entry. + shared_library: false, + + // Prevent dependencies that do not specify an sdk_version from accessing the + // implementation library by default and force them to use stubs instead. + default_to_stubs: true, + // Enable api lint. This will eventually become the default for java_sdk_library // but it cannot yet be turned on because some usages have not been cleaned up. // TODO(b/156126315) - Remove when no longer needed. diff --git a/apex/sdkextensions/Android.bp b/apex/sdkextensions/Android.bp deleted file mode 100644 index fdb078e00d92..000000000000 --- a/apex/sdkextensions/Android.bp +++ /dev/null @@ -1,84 +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_visibility: [":__subpackages__"], -} - -apex { - name: "com.android.sdkext", - defaults: [ "com.android.sdkext-defaults" ], - binaries: [ "derive_sdk" ], - prebuilts: [ "cur_sdkinfo" ], - manifest: "manifest.json", - min_sdk_version: "current", -} - -apex_defaults { - name: "com.android.sdkext-defaults", - updatable: true, - min_sdk_version: "R", - java_libs: [ "framework-sdkextensions" ], - prebuilts: [ - "derive_sdk.rc", - ], - key: "com.android.sdkext.key", - certificate: ":com.android.sdkext.certificate", -} - -sdk { - name: "sdkextensions-sdk", - java_sdk_libs: [ "framework-sdkextensions" ], -} - -apex_key { - name: "com.android.sdkext.key", - public_key: "com.android.sdkext.avbpubkey", - private_key: "com.android.sdkext.pem", -} - -android_app_certificate { - name: "com.android.sdkext.certificate", - certificate: "com.android.sdkext", -} - -python_binary_host { - name: "gen_sdkinfo", - srcs: [ - "sdk.proto", - "gen_sdkinfo.py", - ], - proto: { - canonical_path_from_root: false, - }, - version: { - py3: { - embedded_launcher: true, - }, - }, -} - -gensrcs { - name: "cur_sdkinfo_src", - srcs: [""], - tools: [ "gen_sdkinfo" ], - cmd: "$(location) -v 0 -o $(out)", -} - -prebuilt_etc { - name: "cur_sdkinfo", - src: ":cur_sdkinfo_src", - filename: "sdkinfo.binarypb", - installable: false, -} diff --git a/apex/sdkextensions/OWNERS b/apex/sdkextensions/OWNERS deleted file mode 100644 index a6e55228596b..000000000000 --- a/apex/sdkextensions/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -dariofreni@google.com -hansson@google.com diff --git a/apex/sdkextensions/TEST_MAPPING b/apex/sdkextensions/TEST_MAPPING deleted file mode 100644 index 3dc1b9fa5dd0..000000000000 --- a/apex/sdkextensions/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { - "name": "CtsSdkExtensionsTestCases" - }, - { - "name": "sdkextensions_e2e_tests" - } - ] -} diff --git a/apex/sdkextensions/com.android.sdkext.avbpubkey b/apex/sdkextensions/com.android.sdkext.avbpubkey Binary files differdeleted file mode 100644 index 8f47741ed3b8..000000000000 --- a/apex/sdkextensions/com.android.sdkext.avbpubkey +++ /dev/null diff --git a/apex/sdkextensions/com.android.sdkext.pem b/apex/sdkextensions/com.android.sdkext.pem deleted file mode 100644 index 816460183aa3..000000000000 --- a/apex/sdkextensions/com.android.sdkext.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKQIBAAKCAgEAr72pTSavrziDP54AtQZlRclDxJf9HXRZwFRbYx9hWZ4z7ZtO -pNBDPvPJCiAOVUsILgCQhBUolz2dyLob25Fd0PVp0n9ibIPEQYjTfHjOK40qb57N -LhEp2ceGiAfsywPSi0TH1PQ6JgbCe/RM4TefI/sj3gYJPka3ksMvylhMIgUVLgME -kYizhzwHqlLMspB858SioREZdGwcdZrMMIajGFU69Q9ZRDBzhPvxyKhYoObcOtk1 -uVaiE/fNoi3wKGJz2l2vhUuNrQW7MWlVMag+Qes4YACUTk9LZrOVFEJFjWc8xGUi -ABtfKGs5JgNr/sWnhvifLn8lJuf0/BJmjD+L5QwXYs2cS7gcZJtTM12J94r0Twgw -wF2lNmIxAE9sYqj5Rh3dIlTPE5vMUECmQEGjIBB/hzT65VxVqSjU/IlS506JTg3p -IOQtZ15cUzTBpda4jrvqcq6RNVvgBCu2bV5D8Z4z9FUlPyvD+Zq/6lcoJfLtznAs -G2463hyPAHTGBIcZ5p5bTuGxoAb6ivyqo4b9Qi4yYA6je9HJmuy8T3Mn5JROoeu9 -BH1K54r/mpT4TQPwuKUvRRtBAV2OPHjo+zp0Gd4Y6rxDYxEIdfEae7pQr/QExSPB -q/QCr9RhixR1mO373LHuja+MxdAxIxugb2HTS61PQo+PbYrhJMcVuxTwJOECAwEA -AQKCAgAH7ToRrMkH0ji5SdsmTx+KQkW4PFLCXVke/68PjX7KmAQnl3W4oVwnHr/W -oROEbVn1GTlre7jU+YaAY0SWZrwgjLE1OWGrG1ZizlUbrCdAd6GOX09J4KROml1L -DXB0x7tbZMLOrCVjSbLD/ITrM6MN8Gnxvbv0/yOQjxU8vzbP4gLOjHxMRCo001RV -Ll7lPvcjTQ84zJilU6sE8vJ6zdfVZSK/ou2X0cekG+kP7+fvefo8/UcbEPlGhUrV -IdVPPQGUu90K2hmN0FBdLi8Vik0klAN68Qu/bHwuKbNzsnmIoztucFFUR+fG3u84 -87aPS0L/J3+mjT2Tv6qhJANUGBmrK/h7MkelpKXlRTCITJLX9xP7hfSbJ4f6aLVq -ZYPPciGxSBbUDgAwvPtOlMDzccg7YsYyiBBO28wh8MN97rePmc0z6nGmjeXhcbCC -QktG50VYFCyqp5muKgqQmRfRjHFHLWs8GEqgxMeEL3U3HjYfCYr+6E8Sr5OnOBeH -3buCi1+zgnNYCvbamgY/OJmW7f9h5O31hxmTplc2E1ZuxUGQZthabt1rN3bmNkyf -KUmPwnIYkDkWBSV5lzyQExfS3/EVvj0EnHhx8faamimNrGo8xCcfnLT3c0WEFVmo -yIyVRX3EpXJFM2JkeJ21/IEZXTzHSoNxk12CBG8i8lLSflWSMQKCAQEA2ZqVnOuV -SZfLCUYUUh8Hvhc5zONstfq7ma1Zsttsdaj9t68nLRiBDvLOGnMjDkYZzoSd4fyl -oy+YqWGBqcqa5kg1NOCH0I46p9d8RcWAfDnB4sqbLgWh70qsvni6igRijmsMDvkA -U9HeEdPaLCjQ4UXw7GQvN5rRxuRt+OSqV3tV/Pk9JYyYjz7faC8dmbKDrWHHuOvm -/9y6Xy+L5IgftykNlUeddSCIoMOAadM7BiRjsrHnOYBQ8xBcn0OYafpIswItrgVi -IrsPJaBFidx8QYK4MVibyka6U0cm28OocDSPtSk/4jrnCEEhLjFUnWwuMXuBGlrd -W7wP/muoJqb1VwKCAQEAzsAT90kkOCvAcrfGRE3KkUjwWAsQyP8u2+27JIQPqrpW -GfWAzJXFt80TSp0Zf/Lrq3/SQ9n4AaL4K9dcMoreedoQN9C9JI7zPtZAWNrJVUcV -dq2gZjBQ78+oK7uQgvFNWxga5D+Nh+Y+9Tp537fc5HIh0Y13PgsxxPk2OnZJTvLX -HM5H7Aua9ssmqChsrKihuUsDSPozfBz+H7FNHEdKMqVLqJJSK6m0uMxuLovdVfka -5S7iBMjEGZc46Iz3ckE0pdOiQLooNqfEQqFe5Uou/KZxxKI1NW25rEEBTVyQWt+2 -BNUCfKP7noZ45u5sUY3eJrgI7BrPEDbNS81WYaLchwKCAQA8Q4mHyd6wYO+EA/qA -u8NDK9+AFMP4qhXme5HJ7Obetwx9IG7zGEQ1xZy6yoQ84cEn5qZq/bNJvFbFIhHs -2gWIHRtPJ5e1dI5eCVmLYSUyQjSmAIJ1fm3YfY/VuE3BB3HcC11tkBw9GnQr78YO -UMd4fAw7C4vgFGpgcMbcFUfvrmKkCsqaaZOeqETq75F9DWlWTSwo1HxHA/RBhENz -6RcPfLkcTJcY5wevrjUUGcHQ86cAyDBHRngkuLVODkRZpU0Y9lN8TFVfVPre6sIX -ag6nffJRCD8tB+V2RtBGMKunV4ctHt1oY/Oz34W260aJynoIjjG1ANEpJK4xQdNx -0O9FAoIBAQCz2AGGKemHswdEwveEkuaSWpA3Bekj7lYkmTchHH9EU7JyAkx3qhDD -QXB2hxGXawf1tsqAmypQwiJ+gGeCz6mW9UkGRF1DX9XX4yc2I5rew2a4RXAxc/Xz -pP70i8O5I43Wn7FEusOyY2aAis1Y/eb4EQ+56QTAw5wXa3DwidRbCIJ2XDnT6oRy -CWUnAYMG7ek/9TB2Wq5OWCn2B5S79IdmZsLZb+5qbMT3u1xcwO1Xy8jJc27IGpv6 -ZsDqCTV1/aJ+XQnWpBg28tiV3Sle6pjUzTRJh5AhWcEZRbKMSOiJI/CBY4k2Qq6t -xuuEdgFjL7T+mTepqehUglcyiPuLEtAhAoIBAQDDQ5pTFOlunfYzm+CIvvImAgy7 -vrEabJYABATytAbXRMMbrKoEdU2ApEDyEW7PgysDnYLAZ+icObnJlBTYvNdlWFly -XiviGVfpjFWDT9U/gUwFQu2lfEjoiivoGS92USHUy4UMVHiiznnm20VLLkgd3xna -HUNSDdHIEgzOTmDsKJwMfA9zGckx23JJimPR5ekv6vr6QllYtECs4lTC1gVQAp2f -5daxHRbkmO6gw1RgQADLkAnYz3aI1jNuHm5VyAZGt/d3JCtZ3Wwwejll8uJ4J09G -oEtqyY9RVeHK50bLO4lyAXFiE+J6qqXjsGC20cpxeZYW5llMY/dhA6WV4YXV ------END RSA PRIVATE KEY----- diff --git a/apex/sdkextensions/com.android.sdkext.pk8 b/apex/sdkextensions/com.android.sdkext.pk8 Binary files differdeleted file mode 100644 index ccc0bf438cd1..000000000000 --- a/apex/sdkextensions/com.android.sdkext.pk8 +++ /dev/null diff --git a/apex/sdkextensions/com.android.sdkext.x509.pem b/apex/sdkextensions/com.android.sdkext.x509.pem deleted file mode 100644 index 45d2ade354d4..000000000000 --- a/apex/sdkextensions/com.android.sdkext.x509.pem +++ /dev/null @@ -1,35 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGIzCCBAugAwIBAgIUXuDL7QvzQh7S6rihWz2KRvCFVT0wDQYJKoZIhvcNAQEL -BQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH -DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy -b2lkMRswGQYDVQQDDBJjb20uYW5kcm9pZC5zZGtleHQxIjAgBgkqhkiG9w0BCQEW -E2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMTkxMjAyMTQyNDM0WhgPNDc1NzEwMjgx -NDI0MzRaMIGfMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG -A1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwH -QW5kcm9pZDEbMBkGA1UEAwwSY29tLmFuZHJvaWQuc2RrZXh0MSIwIAYJKoZIhvcN -AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAxFvZZ6ES1oqAu1K74/ZxnC3SOhHnLISLBgJEe7DqtdpuNFAwvdVO -RL/HULhDbjYlOhpU2x3SavDIZZ2lRfiS9Q+M25WftxTRHVjBcpgwbV77TVxPKlAa -tVN2lUVOY+s4QAVMNIXjC4kCKK/pCQtacH715EtdV47fWdg/Nx4iP/Aord8k3KGI -9iI2ZOUjaugTRxu5lKRNDrv0bw5rEzyYmDyMud+kR/iS3/5oog57wPE0ffAkZXWE -p3L2Cejre3ekCizsvVh6EmH6ForKLtL6f0z5Zir1f4R9+YcENspTlJR3pDhg7y3I -uTQT/iDCtV0l+g2PjGZPEeAQHND3+kDQR7Sno/WC1Nhws6vcu1MdrC+kIh1ewx4y -8moy/yqb5M98PJDzTSi/AOTB/OiqLXo/T8rjLBmirs9y3fTT6gJ6qXxOWgt8dle9 -7TBfa84Xi8uVY61c+A+YI0nLal7QDPsP3RPv5sJSQ9x9YnweVfD9Q0EOi52sSNu+ -QuN/kcUrMgPgha20VhfH/CkkPDyIp6aZyHHM69MIl+cYEm8vPa5uy3dosuRomT0f -I4HOBjULDIuj+rIi+Rg3qHvmpuejwZXI/FBNWIhLEUG3ytgksjMaBoYAYflGdrcj -BQexuF3EO+j4uo7JGjNcaT7wRoCH9gt29VHckDg2qz6VWXrlpmME4UkCAwEAAaNT -MFEwHQYDVR0OBBYEFISN2nmUHllgPZMZ62U7mU3ZxzlXMB8GA1UdIwQYMBaAFISN -2nmUHllgPZMZ62U7mU3ZxzlXMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggIBAFHIwyBNIVyHXUsDUdcjxfojXQsF/BCL9ehE3pgdkvDfQanaIREWn0nc -oCFDFkYMRqaXOGC5TKq4OCjXOLsdfODt8HQ3F9J1B0ghQ5tfOdw7xDugNAszqP/Q -h7kpvqLTycjrqOeZ5KjxEEYtP/KlUmALgOKcTcSH+XhWyxhjF4j24T9F2yJRr3/A -r1NGU/djH953bHKC8OpJ2teUpDLA4TxVp/EhslH2eVigF80c/w74QPLEWkD9zv/4 -YeRg/R5N83zHs99NtlWMIeHfK6fUbzMyaSZtvm+jK20tkByQb/OQRed+drk25MtL -68IRvxqri367qRScdpTZbu0ByLO4X8gFdubRUWr+tcO4pZX+DJRVriExbOkU2xhS -Vtslq23V/hwTuUNm1CXjR70mPS13BTmHrIQDqLoIw/WTQlGh+vxnlAFRIHM3KB2c -OdzUBu+NcB4aZEd0KKtct600A0DKPr1MQPb5jDq9wEtPSQYwMF0nRFNnXltbrXMd -4hhwnhKr74fVMUmb+7eQP56XE/Nk4D+npMO54vv1pav+DI2/nxCND9BOLBweY38p -Tvd2RjesMok0zXuVXiCIu4GEpwo7WkSnv25xrb0Ey2M8QWnGNnCcX7Kv6ip3RdWy -HiN0G8RJrs/yNEVSDRx8ZhtwTpXVPQxbARbmhNF4/fnolElkmrMP ------END CERTIFICATE----- diff --git a/apex/sdkextensions/derive_sdk/Android.bp b/apex/sdkextensions/derive_sdk/Android.bp deleted file mode 100644 index 41eae09b1351..000000000000 --- a/apex/sdkextensions/derive_sdk/Android.bp +++ /dev/null @@ -1,55 +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. - -cc_defaults { - name: "derive_sdk-defaults", - srcs: [ - "derive_sdk.cpp", - "sdk.proto", - ], - proto: { - type: "lite", - static: true, - }, - min_sdk_version: "current", - shared_libs: ["liblog"], - // static c++/libbase for smaller size - stl: "c++_static", - static_libs: ["libbase"], -} - -cc_binary { - name: "derive_sdk", - defaults: [ "derive_sdk-defaults" ], - apex_available: [ "com.android.sdkext" ], - visibility: [ "//frameworks/base/apex/sdkextensions" ] -} - -// Work around testing using a 64-bit test suite on 32-bit test device by -// using a prefer32 version of derive_sdk in testing. -cc_binary { - name: "derive_sdk_prefer32", - defaults: [ "derive_sdk-defaults" ], - compile_multilib: "prefer32", - stem: "derive_sdk", - apex_available: [ "test_com.android.sdkext" ], - visibility: [ "//frameworks/base/apex/sdkextensions/testing" ], - installable: false, -} - -prebuilt_etc { - name: "derive_sdk.rc", - src: "derive_sdk.rc", - installable: false, -} diff --git a/apex/sdkextensions/derive_sdk/derive_sdk.cpp b/apex/sdkextensions/derive_sdk/derive_sdk.cpp deleted file mode 100644 index 900193a6bd0d..000000000000 --- a/apex/sdkextensions/derive_sdk/derive_sdk.cpp +++ /dev/null @@ -1,79 +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. - */ - -#define LOG_TAG "derive_sdk" - -#include <algorithm> -#include <dirent.h> -#include <iostream> -#include <sys/stat.h> -#include <vector> - -#include <android-base/file.h> -#include <android-base/logging.h> -#include <android-base/properties.h> - -#include "frameworks/base/apex/sdkextensions/derive_sdk/sdk.pb.h" - -using com::android::sdkext::proto::SdkVersion; - -int main(int, char**) { - std::unique_ptr<DIR, decltype(&closedir)> apex(opendir("/apex"), closedir); - if (!apex) { - LOG(ERROR) << "Could not read /apex"; - return EXIT_FAILURE; - } - struct dirent* de; - std::vector<std::string> paths; - while ((de = readdir(apex.get()))) { - std::string name = de->d_name; - if (name[0] == '.' || name.find('@') != std::string::npos) { - // Skip <name>@<ver> dirs, as they are bind-mounted to <name> - continue; - } - std::string path = "/apex/" + name + "/etc/sdkinfo.binarypb"; - struct stat statbuf; - if (stat(path.c_str(), &statbuf) == 0) { - paths.push_back(path); - } - } - - std::vector<int> versions; - for (const auto& path : paths) { - std::string contents; - if (!android::base::ReadFileToString(path, &contents, true)) { - LOG(ERROR) << "failed to read " << path; - continue; - } - SdkVersion sdk_version; - if (!sdk_version.ParseFromString(contents)) { - LOG(ERROR) << "failed to parse " << path; - continue; - } - LOG(INFO) << "Read version " << sdk_version.version() << " from " << path; - versions.push_back(sdk_version.version()); - } - auto itr = std::min_element(versions.begin(), versions.end()); - std::string prop_value = itr == versions.end() ? "0" : std::to_string(*itr); - - if (!android::base::SetProperty("build.version.extensions.r", prop_value)) { - LOG(ERROR) << "failed to set sdk_info prop"; - return EXIT_FAILURE; - } - - LOG(INFO) << "R extension version is " << prop_value; - return EXIT_SUCCESS; -} diff --git a/apex/sdkextensions/derive_sdk/derive_sdk.rc b/apex/sdkextensions/derive_sdk/derive_sdk.rc deleted file mode 100644 index 18f021ccadff..000000000000 --- a/apex/sdkextensions/derive_sdk/derive_sdk.rc +++ /dev/null @@ -1,5 +0,0 @@ -service derive_sdk /apex/com.android.sdkext/bin/derive_sdk - user nobody - group nobody - oneshot - disabled diff --git a/apex/sdkextensions/derive_sdk/sdk.proto b/apex/sdkextensions/derive_sdk/sdk.proto deleted file mode 100644 index d15b93552ff4..000000000000 --- a/apex/sdkextensions/derive_sdk/sdk.proto +++ /dev/null @@ -1,25 +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. - */ - -syntax = "proto3"; -package com.android.sdkext.proto; - -option java_outer_classname = "SdkProto"; -option optimize_for = LITE_RUNTIME; - -message SdkVersion { - int32 version = 1; -} diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp deleted file mode 100644 index b8aad7d8204f..000000000000 --- a/apex/sdkextensions/framework/Android.bp +++ /dev/null @@ -1,49 +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_visibility: [ ":__pkg__" ] -} - -filegroup { - name: "framework-sdkextensions-sources", - srcs: [ - "java/**/*.java", - ], - path: "java", - visibility: [ "//frameworks/base" ] // For the "global" stubs. -} - -java_sdk_library { - name: "framework-sdkextensions", - srcs: [ ":framework-sdkextensions-sources" ], - defaults: ["framework-module-defaults"], - - // TODO(b/155480189) - Remove naming_scheme once references have been resolved. - // Temporary java_sdk_library component naming scheme to use to ease the transition from separate - // modules to java_sdk_library. - naming_scheme: "framework-modules", - - permitted_packages: [ "android.os.ext" ], - installable: true, - visibility: [ - "//frameworks/base/apex/sdkextensions", - "//frameworks/base/apex/sdkextensions/testing", - ], - hostdex: true, // for hiddenapi check - apex_available: [ - "com.android.sdkext", - "test_com.android.sdkext", - ], -} diff --git a/apex/sdkextensions/framework/api/current.txt b/apex/sdkextensions/framework/api/current.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/sdkextensions/framework/api/current.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/sdkextensions/framework/api/module-lib-current.txt b/apex/sdkextensions/framework/api/module-lib-current.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/sdkextensions/framework/api/module-lib-current.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/sdkextensions/framework/api/module-lib-removed.txt b/apex/sdkextensions/framework/api/module-lib-removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/sdkextensions/framework/api/module-lib-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/sdkextensions/framework/api/removed.txt b/apex/sdkextensions/framework/api/removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/sdkextensions/framework/api/removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/sdkextensions/framework/api/system-current.txt b/apex/sdkextensions/framework/api/system-current.txt deleted file mode 100644 index bbff4c5ae6f4..000000000000 --- a/apex/sdkextensions/framework/api/system-current.txt +++ /dev/null @@ -1,9 +0,0 @@ -// Signature format: 2.0 -package android.os.ext { - - public class SdkExtensions { - method public static int getExtensionVersion(int); - } - -} - diff --git a/apex/sdkextensions/framework/api/system-removed.txt b/apex/sdkextensions/framework/api/system-removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/sdkextensions/framework/api/system-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java deleted file mode 100644 index c268ff4291e4..000000000000 --- a/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.ext; - -import android.annotation.IntDef; -import android.annotation.SystemApi; -import android.os.Build.VERSION_CODES; -import android.os.SystemProperties; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Methods for interacting with the extension SDK. - * - * This class provides information about the extension SDK version present - * on this device. Use the {@link #getExtensionVersion(int) getExtension} to - * query for the extension version for the given SDK version. - - * @hide - */ -@SystemApi -public class SdkExtensions { - - private static final int R_EXTENSION_INT; - static { - R_EXTENSION_INT = SystemProperties.getInt("build.version.extensions.r", 0); - } - - /** - * Values suitable as parameters for {@link #getExtensionVersion(int)}. - * @hide - */ - @IntDef(value = { VERSION_CODES.R }) - @Retention(RetentionPolicy.SOURCE) - public @interface SdkVersion {} - - private SdkExtensions() { } - - /** - * Return the version of the extension to the given SDK. - * - * @param sdk the SDK version to get the extension version of. - * @see SdkVersion - * @throws IllegalArgumentException if sdk is not an sdk version with extensions - */ - public static int getExtensionVersion(@SdkVersion int sdk) { - if (sdk < VERSION_CODES.R) { - throw new IllegalArgumentException(String.valueOf(sdk) + " does not have extensions"); - } - - if (sdk == VERSION_CODES.R) { - return R_EXTENSION_INT; - } - return 0; - } - -} diff --git a/apex/sdkextensions/framework/java/android/os/ext/package.html b/apex/sdkextensions/framework/java/android/os/ext/package.html deleted file mode 100644 index 34c1697c01fd..000000000000 --- a/apex/sdkextensions/framework/java/android/os/ext/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<HTML> -<BODY> -Provides APIs to interface with the SDK extensions. -</BODY> -</HTML> diff --git a/apex/sdkextensions/gen_sdkinfo.py b/apex/sdkextensions/gen_sdkinfo.py deleted file mode 100644 index 5af478ba7fe6..000000000000 --- a/apex/sdkextensions/gen_sdkinfo.py +++ /dev/null @@ -1,19 +0,0 @@ -import sdk_pb2 -import sys - -if __name__ == '__main__': - argv = sys.argv[1:] - if not len(argv) == 4 or sorted([argv[0], argv[2]]) != ['-o', '-v']: - print('usage: gen_sdkinfo -v <version> -o <output-file>') - sys.exit(1) - - for i in range(len(argv)): - if sys.argv[i] == '-o': - filename = sys.argv[i+1] - if sys.argv[i] == '-v': - version = int(sys.argv[i+1]) - - proto = sdk_pb2.SdkVersion() - proto.version = version - with open(filename, 'wb') as f: - f.write(proto.SerializeToString()) diff --git a/apex/sdkextensions/manifest.json b/apex/sdkextensions/manifest.json deleted file mode 100644 index 048f5c4f177b..000000000000 --- a/apex/sdkextensions/manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.sdkext", - "version": 1 -} diff --git a/apex/sdkextensions/testing/Android.bp b/apex/sdkextensions/testing/Android.bp deleted file mode 100644 index f2f5b321fafe..000000000000 --- a/apex/sdkextensions/testing/Android.bp +++ /dev/null @@ -1,46 +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. - -apex_test { - name: "test_com.android.sdkext", - visibility: [ "//system/apex/tests" ], - defaults: ["com.android.sdkext-defaults"], - manifest: "test_manifest.json", - prebuilts: [ "sdkinfo_45" ], - file_contexts: ":com.android.sdkext-file_contexts", - installable: false, // Should never be installed on the systemimage - multilib: { - prefer32: { - binaries: ["derive_sdk_prefer32"], - }, - }, - // The automated test infra ends up building this apex for 64+32-bit and - // then installs it on a 32-bit-only device. Work around this weirdness - // by preferring 32-bit. - compile_multilib: "prefer32", -} - -genrule { - name: "sdkinfo_45_src", - out: [ "sdkinfo.binarypb" ], - tools: [ "gen_sdkinfo" ], - cmd: "$(location) -v 45 -o $(out)", -} - -prebuilt_etc { - name: "sdkinfo_45", - src: ":sdkinfo_45_src", - filename: "sdkinfo.binarypb", - installable: false, -} diff --git a/apex/sdkextensions/testing/test_manifest.json b/apex/sdkextensions/testing/test_manifest.json deleted file mode 100644 index 1b4a2b0c6e60..000000000000 --- a/apex/sdkextensions/testing/test_manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.sdkext", - "version": 2147483647 -} diff --git a/api/system-current.txt b/api/system-current.txt index 4a1bf0d803a6..26153caebfce 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6572,6 +6572,7 @@ package android.provider { field public static final String NAMESPACE_APP_COMPAT = "app_compat"; field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service"; field public static final String NAMESPACE_AUTOFILL = "autofill"; + field public static final String NAMESPACE_BLUETOOTH = "bluetooth"; field public static final String NAMESPACE_CONNECTIVITY = "connectivity"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; field public static final String NAMESPACE_DEX_BOOT = "dex_boot"; diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt index 306b8afaadae..ffde094e8813 100644 --- a/api/system-lint-baseline.txt +++ b/api/system-lint-baseline.txt @@ -144,6 +144,13 @@ MutableBareField: android.net.wifi.WifiConfiguration#carrierId: NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0: + + + +NoSettingsProvider: android.provider.Settings.Global#TETHER_OFFLOAD_DISABLED: + New setting keys are not allowed. (Field: TETHER_OFFLOAD_DISABLED) +NoSettingsProvider: android.provider.Settings.Global#TETHER_SUPPORTED: + New setting keys are not allowed. (Field: TETHER_SUPPORTED) diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt index 46f3aeba85bd..47d87c501938 100644 --- a/api/test-lint-baseline.txt +++ b/api/test-lint-baseline.txt @@ -2298,6 +2298,75 @@ NoClone: android.service.autofill.augmented.AugmentedAutofillService#dump(java.i NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0: NoClone: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.FileDescriptor) parameter #0: + + + +NoSettingsProvider: android.provider.Settings.Global#AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES: + New setting keys are not allowed. (Field: AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES) +NoSettingsProvider: android.provider.Settings.Global#AUTOMATIC_POWER_SAVE_MODE: + New setting keys are not allowed. (Field: AUTOMATIC_POWER_SAVE_MODE) +NoSettingsProvider: android.provider.Settings.Global#BATTERY_SAVER_CONSTANTS: + New setting keys are not allowed. (Field: BATTERY_SAVER_CONSTANTS) +NoSettingsProvider: android.provider.Settings.Global#DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD: + New setting keys are not allowed. (Field: DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD) +NoSettingsProvider: android.provider.Settings.Global#DYNAMIC_POWER_SAVINGS_ENABLED: + New setting keys are not allowed. (Field: DYNAMIC_POWER_SAVINGS_ENABLED) +NoSettingsProvider: android.provider.Settings.Global#HIDDEN_API_BLACKLIST_EXEMPTIONS: + New setting keys are not allowed. (Field: HIDDEN_API_BLACKLIST_EXEMPTIONS) +NoSettingsProvider: android.provider.Settings.Global#LOCATION_GLOBAL_KILL_SWITCH: + New setting keys are not allowed. (Field: LOCATION_GLOBAL_KILL_SWITCH) +NoSettingsProvider: android.provider.Settings.Global#LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST: + New setting keys are not allowed. (Field: LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST) +NoSettingsProvider: android.provider.Settings.Global#LOW_POWER_MODE: + New setting keys are not allowed. (Field: LOW_POWER_MODE) +NoSettingsProvider: android.provider.Settings.Global#LOW_POWER_MODE_STICKY: + New setting keys are not allowed. (Field: LOW_POWER_MODE_STICKY) +NoSettingsProvider: android.provider.Settings.Global#NOTIFICATION_BUBBLES: + New setting keys are not allowed. (Field: NOTIFICATION_BUBBLES) +NoSettingsProvider: android.provider.Settings.Global#OVERLAY_DISPLAY_DEVICES: + New setting keys are not allowed. (Field: OVERLAY_DISPLAY_DEVICES) +NoSettingsProvider: android.provider.Settings.Global#TETHER_OFFLOAD_DISABLED: + New setting keys are not allowed. (Field: TETHER_OFFLOAD_DISABLED) +NoSettingsProvider: android.provider.Settings.Global#USE_OPEN_WIFI_PACKAGE: + New setting keys are not allowed. (Field: USE_OPEN_WIFI_PACKAGE) +NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED: + New setting keys are not allowed. (Field: ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED) +NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE: + New setting keys are not allowed. (Field: ACCESSIBILITY_SHORTCUT_TARGET_SERVICE) +NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_FEATURE_FIELD_CLASSIFICATION: + New setting keys are not allowed. (Field: AUTOFILL_FEATURE_FIELD_CLASSIFICATION) +NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_SERVICE: + New setting keys are not allowed. (Field: AUTOFILL_SERVICE) +NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT: + New setting keys are not allowed. (Field: AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT) +NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE: + New setting keys are not allowed. (Field: AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE) +NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE: + New setting keys are not allowed. (Field: AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE) +NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_USER_DATA_MAX_VALUE_LENGTH: + New setting keys are not allowed. (Field: AUTOFILL_USER_DATA_MAX_VALUE_LENGTH) +NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_USER_DATA_MIN_VALUE_LENGTH: + New setting keys are not allowed. (Field: AUTOFILL_USER_DATA_MIN_VALUE_LENGTH) +NoSettingsProvider: android.provider.Settings.Secure#CONTENT_CAPTURE_ENABLED: + New setting keys are not allowed. (Field: CONTENT_CAPTURE_ENABLED) +NoSettingsProvider: android.provider.Settings.Secure#DISABLED_PRINT_SERVICES: + New setting keys are not allowed. (Field: DISABLED_PRINT_SERVICES) +NoSettingsProvider: android.provider.Settings.Secure#DOZE_ALWAYS_ON: + New setting keys are not allowed. (Field: DOZE_ALWAYS_ON) +NoSettingsProvider: android.provider.Settings.Secure#ENABLED_VR_LISTENERS: + New setting keys are not allowed. (Field: ENABLED_VR_LISTENERS) +NoSettingsProvider: android.provider.Settings.Secure#LOCATION_ACCESS_CHECK_DELAY_MILLIS: + New setting keys are not allowed. (Field: LOCATION_ACCESS_CHECK_DELAY_MILLIS) +NoSettingsProvider: android.provider.Settings.Secure#LOCATION_ACCESS_CHECK_INTERVAL_MILLIS: + New setting keys are not allowed. (Field: LOCATION_ACCESS_CHECK_INTERVAL_MILLIS) +NoSettingsProvider: android.provider.Settings.Secure#NOTIFICATION_BADGING: + New setting keys are not allowed. (Field: NOTIFICATION_BADGING) +NoSettingsProvider: android.provider.Settings.Secure#SYNC_PARENT_SOUNDS: + New setting keys are not allowed. (Field: SYNC_PARENT_SOUNDS) +NoSettingsProvider: android.provider.Settings.Secure#USER_SETUP_COMPLETE: + New setting keys are not allowed. (Field: USER_SETUP_COMPLETE) +NoSettingsProvider: android.provider.Settings.Secure#VOICE_INTERACTION_SERVICE: + New setting keys are not allowed. (Field: VOICE_INTERACTION_SERVICE) diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java index b669d775b3c1..647f63025cf7 100644 --- a/core/java/android/app/AlarmManager.java +++ b/core/java/android/app/AlarmManager.java @@ -37,7 +37,6 @@ import android.util.proto.ProtoOutputStream; import libcore.timezone.ZoneInfoDb; -import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -998,12 +997,7 @@ public class AlarmManager { // Reject this timezone if it isn't an Olson zone we recognize. if (mTargetSdkVersion >= Build.VERSION_CODES.M) { - boolean hasTimeZone = false; - try { - hasTimeZone = ZoneInfoDb.getInstance().hasTimeZone(timeZone); - } catch (IOException ignored) { - } - + boolean hasTimeZone = ZoneInfoDb.getInstance().hasTimeZone(timeZone); if (!hasTimeZone) { throw new IllegalArgumentException("Timezone: " + timeZone + " is not an Olson ID"); } diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java index 407ff04dc4a3..c8ca618e5969 100644 --- a/core/java/android/net/Ikev2VpnProfile.java +++ b/core/java/android/net/Ikev2VpnProfile.java @@ -25,6 +25,8 @@ import static com.android.internal.util.Preconditions.checkStringNotEmpty; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; +import android.content.pm.PackageManager; import android.os.Process; import android.security.Credentials; import android.security.KeyStore; @@ -647,6 +649,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * @param serverAddr the server that the VPN should connect to * @param identity the identity string to be used for IKEv2 authentication */ + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Builder(@NonNull String serverAddr, @NonNull String identity) { checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "serverAddr"); checkNotNull(identity, MISSING_PARAM_MSG_TMPL, "identity"); @@ -680,6 +683,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * unrecognized format */ @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Builder setAuthUsernamePassword( @NonNull String user, @NonNull String pass, @@ -715,6 +719,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * unrecognized format */ @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Builder setAuthDigitalSignature( @NonNull X509Certificate userCert, @NonNull PrivateKey key, @@ -745,6 +750,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * @return this {@link Builder} object to facilitate chaining of method calls */ @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Builder setAuthPsk(@NonNull byte[] psk) { checkNotNull(psk, MISSING_PARAM_MSG_TMPL, "psk"); @@ -768,6 +774,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * @return this {@link Builder} object to facilitate chaining of method calls */ @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Builder setBypassable(boolean isBypassable) { mIsBypassable = isBypassable; return this; @@ -782,6 +789,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * @return this {@link Builder} object to facilitate chaining of method calls */ @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Builder setProxy(@Nullable ProxyInfo proxy) { mProxyInfo = proxy; return this; @@ -798,6 +806,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * @throws IllegalArgumentException if the value is not at least the minimum IPv6 MTU (1280) */ @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Builder setMaxMtu(int mtu) { // IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6 // networks, the VPN must provide a link fulfilling the stricter of the two conditions @@ -825,6 +834,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * @see NetworkCapabilities#NET_CAPABILITY_NOT_METERED */ @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Builder setMetered(boolean isMetered) { mIsMetered = isMetered; return this; @@ -852,6 +862,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * @see IpSecAlgorithm */ @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Builder setAllowedAlgorithms(@NonNull List<String> algorithmNames) { checkNotNull(algorithmNames, MISSING_PARAM_MSG_TMPL, "algorithmNames"); validateAllowedAlgorithms(algorithmNames); @@ -870,6 +881,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * @hide */ @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Builder restrictToTestNetworks() { mIsRestrictedToTestNetworks = true; return this; @@ -881,6 +893,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { * @throws IllegalArgumentException if any of the required keys or values were invalid */ @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) public Ikev2VpnProfile build() { return new Ikev2VpnProfile( mType, diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 57d5d03a6cf2..0fbffbac5d04 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -679,13 +679,14 @@ public final class NetworkCapabilities implements Parcelable { */ public void restrictCapabilitesForTestNetwork(int creatorUid) { final long originalCapabilities = mNetworkCapabilities; + final long originalTransportTypes = mTransportTypes; final NetworkSpecifier originalSpecifier = mNetworkSpecifier; final int originalSignalStrength = mSignalStrength; final int originalOwnerUid = getOwnerUid(); final int[] originalAdministratorUids = getAdministratorUids(); clearAll(); - // Reset the transports to only contain TRANSPORT_TEST. - mTransportTypes = (1 << TRANSPORT_TEST); + mTransportTypes = (originalTransportTypes & TEST_NETWORKS_ALLOWED_TRANSPORTS) + | (1 << TRANSPORT_TEST); mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES; mNetworkSpecifier = originalSpecifier; mSignalStrength = originalSignalStrength; @@ -787,6 +788,13 @@ public final class NetworkCapabilities implements Parcelable { }; /** + * Allowed transports on a test network, in addition to TRANSPORT_TEST. + */ + private static final int TEST_NETWORKS_ALLOWED_TRANSPORTS = 1 << TRANSPORT_TEST + // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces + | 1 << TRANSPORT_ETHERNET; + + /** * Adds the given transport type to this {@code NetworkCapability} instance. * Multiple transports may be applied. Note that when searching * for a network to satisfy a request, any listed in the request will satisfy the request. diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index b7fb280efdc4..34e48eb44f32 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,8 +16,6 @@ package android.net; -import static android.os.Process.CLAT_UID; - import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1047,73 +1045,54 @@ public final class NetworkStats implements Parcelable { } /** - * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. + * Calculate and apply adjustments to captured statistics for 464xlat traffic. * - * <p>This mutates both base and stacked traffic stats, to account respectively for - * double-counted traffic and IPv4/IPv6 header size difference. + * <p>This mutates stacked traffic stats, to account for IPv4/IPv6 header size difference. * - * <p>For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 - * packet on the stacked interface, and once as translated to an IPv6 packet on the - * base interface. For correct stats accounting on the base interface, if using xt_qtaguid, - * every rx 464xlat packet needs to be subtracted from the root UID on the base interface - * (http://b/12249687, http:/b/33681750), and every tx 464xlat packet which was counted onto - * clat uid should be ignored. + * <p>UID stats, which are only accounted on the stacked interface, need to be increased + * by 20 bytes/packet to account for translation overhead. * - * As for eBPF, the per uid stats is collected by different hook, the rx packets on base - * interface will not be counted. Thus, the adjustment on root uid is not needed. However, the - * tx traffic counted in the same way xt_qtaguid does, so the traffic on clat uid still - * needs to be ignored. + * <p>The potential additional overhead of 8 bytes/packet for ip fragments is ignored. + * + * <p>Interface stats need to sum traffic on both stacked and base interface because: + * - eBPF offloaded packets appear only on the stacked interface + * - Non-offloaded ingress packets appear only on the stacked interface + * (due to iptables raw PREROUTING drop rules) + * - Non-offloaded egress packets appear only on the stacked interface + * (due to ignoring traffic from clat daemon by uid match) + * (and of course the 20 bytes/packet overhead needs to be applied to stacked interface stats) * * <p>This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only * {@code ConcurrentHashMap} * @param baseTraffic Traffic on the base interfaces. Will be mutated. * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. - * @param useBpfStats True if eBPF is in use. * @hide */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, Map<String, String> stackedIfaces, boolean useBpfStats) { - // Total 464xlat traffic to subtract from uid 0 on all base interfaces. - // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. - final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); - + NetworkStats stackedTraffic, Map<String, String> stackedIfaces) { // For recycling Entry entry = null; - Entry adjust = new NetworkStats.Entry(IFACE_ALL, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); - for (int i = 0; i < stackedTraffic.size; i++) { entry = stackedTraffic.getValues(i, entry); - if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { - continue; - } - final String baseIface = stackedIfaces.get(entry.iface); - if (baseIface == null) { - continue; - } - // Subtract xt_qtaguid 464lat rx traffic seen for the root UID on the current base - // interface. As for eBPF, the per uid stats is collected by different hook, the rx - // packets on base interface will not be counted. - adjust.iface = baseIface; - if (!useBpfStats) { - adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets = -entry.rxPackets; - } - adjustments.combineValues(adjust); + if (entry == null) continue; + if (entry.iface == null) continue; + if (!entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) continue; // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes // difference for all packets (http://b/12249687, http:/b/33681750). + // + // Note: this doesn't account for LRO/GRO/GSO/TSO (ie. >mtu) traffic correctly, nor + // does it correctly account for the 8 extra bytes in the IPv6 fragmentation header. + // + // While the ebpf code path does try to simulate proper post segmentation packet + // counts, we have nothing of the sort of xt_qtaguid stats. entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; stackedTraffic.setValues(i, entry); } - - // Traffic on clat uid is v6 tx traffic that is already counted with app uid on the stacked - // v4 interface, so it needs to be removed to avoid double-counting. - baseTraffic.removeUids(new int[] {CLAT_UID}); - baseTraffic.combineAllValues(adjustments); } /** @@ -1125,8 +1104,8 @@ public final class NetworkStats implements Parcelable { * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. * @hide */ - public void apply464xlatAdjustments(Map<String, String> stackedIfaces, boolean useBpfStats) { - apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats); + public void apply464xlatAdjustments(Map<String, String> stackedIfaces) { + apply464xlatAdjustments(this, this, stackedIfaces); } /** diff --git a/core/java/android/os/ParcelableHolder.java b/core/java/android/os/ParcelableHolder.java new file mode 100644 index 000000000000..c37a2ff1112c --- /dev/null +++ b/core/java/android/os/ParcelableHolder.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2020 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.os; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.util.MathUtils; + +/** + * Parcelable containing the other Parcelable object. + * @hide + */ +public final class ParcelableHolder implements Parcelable { + /** + * This is set by {@link #setParcelable}. + * {@link #mParcelable} and {@link #mParcel} are mutually exclusive + * if {@link ParcelableHolder} contains value, otherwise, both are null. + */ + private Parcelable mParcelable; + /** + * This is set by {@link #readFromParcel}. + * {@link #mParcelable} and {@link #mParcel} are mutually exclusive + * if {@link ParcelableHolder} contains value, otherwise, both are null. + */ + private Parcel mParcel; + private boolean mIsStable = false; + + public ParcelableHolder(boolean isStable) { + mIsStable = isStable; + } + + private ParcelableHolder() { + + } + + /** + * {@link ParcelableHolder}'s stability is determined by the parcelable + * which contains this ParcelableHolder. + * For more detail refer to {@link Parcelable#isStable}. + */ + @Override + public boolean isStable() { + return mIsStable; + } + + @NonNull + public static final Parcelable.Creator<ParcelableHolder> CREATOR = + new Parcelable.Creator<ParcelableHolder>() { + @NonNull + @Override + public ParcelableHolder createFromParcel(@NonNull Parcel parcel) { + ParcelableHolder parcelable = new ParcelableHolder(); + parcelable.readFromParcel(parcel); + return parcelable; + } + + @NonNull + @Override + public ParcelableHolder[] newArray(int size) { + return new ParcelableHolder[size]; + } + }; + + + /** + * Write a parcelable into ParcelableHolder, the previous parcelable will be removed. + * @return {@code false} if the parcelable's stability is more unstable ParcelableHolder. + */ + public synchronized boolean setParcelable(@Nullable Parcelable p) { + if (p != null && this.isStable() && !p.isStable()) { + return false; + } + mParcelable = p; + if (mParcel != null) { + mParcel.recycle(); + mParcel = null; + } + return true; + } + + /** + * @return the parcelable that was written by {@link #setParcelable} or {@link #readFromParcel}, + * or {@code null} if the parcelable has not been written, or T is different from + * the type written by (@link #setParcelable}. + */ + @Nullable + public synchronized <T extends Parcelable> T getParcelable(@NonNull Class<T> clazz) { + if (mParcel == null) { + if (!clazz.isInstance(mParcelable)) { + return null; + } + return (T) mParcelable; + } + + mParcel.setDataPosition(0); + + T parcelable = mParcel.readParcelable(clazz.getClassLoader()); + if (!clazz.isInstance(parcelable)) { + return null; + } + mParcelable = parcelable; + + mParcel.recycle(); + mParcel = null; + return parcelable; + } + + /** + * Read ParcelableHolder from a parcel. + */ + public synchronized void readFromParcel(@NonNull Parcel parcel) { + this.mIsStable = parcel.readBoolean(); + + mParcelable = null; + + if (mParcel == null) { + mParcel = Parcel.obtain(); + } + mParcel.setDataPosition(0); + mParcel.setDataSize(0); + + int dataSize = parcel.readInt(); + if (dataSize < 0) { + throw new IllegalArgumentException("dataSize from parcel is negative"); + } + int dataStartPos = parcel.dataPosition(); + + mParcel.appendFrom(parcel, dataStartPos, dataSize); + parcel.setDataPosition(MathUtils.addOrThrow(dataStartPos, dataSize)); + } + + @Override + public synchronized void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeBoolean(this.mIsStable); + + if (mParcel != null) { + parcel.writeInt(mParcel.dataSize()); + parcel.appendFrom(mParcel, 0, mParcel.dataSize()); + return; + } + + int sizePos = parcel.dataPosition(); + parcel.writeInt(0); + int dataStartPos = parcel.dataPosition(); + parcel.writeParcelable(mParcelable, 0); + int dataSize = parcel.dataPosition() - dataStartPos; + + parcel.setDataPosition(sizePos); + parcel.writeInt(dataSize); + parcel.setDataPosition(MathUtils.addOrThrow(parcel.dataPosition(), dataSize)); + } + + @Override + public synchronized int describeContents() { + if (mParcel != null) { + return mParcel.hasFileDescriptors() ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0; + } + if (mParcelable != null) { + return mParcelable.describeContents(); + } + return 0; + } +} diff --git a/core/java/android/os/RegistrantList.java b/core/java/android/os/RegistrantList.java index 53e0ae442deb..b36734bcd199 100644 --- a/core/java/android/os/RegistrantList.java +++ b/core/java/android/os/RegistrantList.java @@ -66,6 +66,10 @@ public class RegistrantList } } + public synchronized void removeAll() { + registrants.clear(); + } + @UnsupportedAppUsage public synchronized int size() diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index c837b9346173..5e1b22399d57 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -110,6 +110,14 @@ public final class DeviceConfig { public static final String NAMESPACE_AUTOFILL = "autofill"; /** + * Namespace for all Bluetooth related features. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_BLUETOOTH = "bluetooth"; + + /** * Namespace for all networking connectivity related features. * * @hide diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java index 248e321df467..8e8409d15143 100644 --- a/core/java/android/text/format/Time.java +++ b/core/java/android/text/format/Time.java @@ -21,7 +21,6 @@ import android.util.TimeFormatException; import libcore.timezone.ZoneInfoDb; import libcore.util.ZoneInfo; -import java.io.IOException; import java.util.Locale; import java.util.TimeZone; @@ -1106,19 +1105,14 @@ public class Time { } private static ZoneInfo lookupZoneInfo(String timezoneId) { - try { - ZoneInfo zoneInfo = ZoneInfoDb.getInstance().makeTimeZone(timezoneId); - if (zoneInfo == null) { - zoneInfo = ZoneInfoDb.getInstance().makeTimeZone("GMT"); - } - if (zoneInfo == null) { - throw new AssertionError("GMT not found: \"" + timezoneId + "\""); - } - return zoneInfo; - } catch (IOException e) { - // This should not ever be thrown. - throw new AssertionError("Error loading timezone: \"" + timezoneId + "\"", e); + ZoneInfo zoneInfo = ZoneInfoDb.getInstance().makeTimeZone(timezoneId); + if (zoneInfo == null) { + zoneInfo = ZoneInfoDb.getInstance().makeTimeZone("GMT"); + } + if (zoneInfo == null) { + throw new AssertionError("GMT not found: \"" + timezoneId + "\""); } + return zoneInfo; } public void switchTimeZone(String timezone) { diff --git a/core/java/android/view/textclassifier/OWNERS b/core/java/android/view/textclassifier/OWNERS index 893a083398fa..be4fbaa6d06a 100644 --- a/core/java/android/view/textclassifier/OWNERS +++ b/core/java/android/view/textclassifier/OWNERS @@ -7,4 +7,8 @@ jalt@google.com joannechung@google.com svetoslavganov@google.com eugeniom@google.com -samsellem@google.com
\ No newline at end of file +samsellem@google.com +adamhe@google.com +augale@google.com +lpeter@google.com +tymtsai@google.com
\ No newline at end of file diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 741a65e45c3d..2e152123c94c 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -367,11 +367,17 @@ public class ZygoteInit { null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/); hidlManager.addDependency(hidlBase); + SharedLibraryInfo androidTestBase = new SharedLibraryInfo( + "/system/framework/android.test.base.jar", null /*packageName*/, + null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN, + null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/); + ApplicationLoaders.getDefault().createAndCacheNonBootclasspathSystemClassLoaders( new SharedLibraryInfo[]{ // ordered dependencies first hidlBase, hidlManager, + androidTestBase, }); } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 9bc4adca1402..27415c58f367 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -231,7 +231,10 @@ cc_library_shared { "system/media/private/camera/include", ], - header_libs: ["bionic_libc_platform_headers"], + header_libs: [ + "bionic_libc_platform_headers", + "dnsproxyd_protocol_headers", + ], static_libs: [ "libasync_safe", diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index ba7fe7ff8739..03b9793ccba8 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -27,12 +27,13 @@ #include <netinet/ip.h> #include <netinet/udp.h> +#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS #include <android_runtime/AndroidRuntime.h> #include <cutils/properties.h> -#include <utils/misc.h> -#include <utils/Log.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedLocalRef.h> +#include <utils/Log.h> +#include <utils/misc.h> #include "NetdClient.h" #include "core_jni_helpers.h" diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index d723ecc13dd0..eb8d26e7bf71 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -475,7 +475,11 @@ static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jclass clazz, j if (fd < 0) return NULL; fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); if (fd < 0) return NULL; - return jniCreateFileDescriptor(env, fd); + jobject jifd = jniCreateFileDescriptor(env, fd); + if (jifd == NULL) { + close(fd); + } + return jifd; } return NULL; } diff --git a/core/jni/android_os_SharedMemory.cpp b/core/jni/android_os_SharedMemory.cpp index c33405def25e..a812c35036f3 100644 --- a/core/jni/android_os_SharedMemory.cpp +++ b/core/jni/android_os_SharedMemory.cpp @@ -69,7 +69,11 @@ jobject SharedMemory_nCreate(JNIEnv* env, jobject, jstring jname, jint size) { return nullptr; } - return jniCreateFileDescriptor(env, fd); + jobject jifd = jniCreateFileDescriptor(env, fd); + if (jifd == nullptr) { + close(fd); + } + return jifd; } jint SharedMemory_nGetSize(JNIEnv* env, jobject, jobject fileDescriptor) { diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index b2aef78a79af..48a764e7c404 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -483,11 +483,8 @@ static void nativeSetMetadata(JNIEnv* env, jclass clazz, jlong transactionObj, auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); - std::vector<uint8_t> byteData(parcel->dataSize()); - memcpy(byteData.data(), parcel->data(), parcel->dataSize()); - SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject); - transaction->setMetadata(ctrl, id, std::move(byteData)); + transaction->setMetadata(ctrl, id, *parcel); } static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 1a2dfce88fd0..2fb281cce522 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4584,12 +4584,12 @@ <!-- @SystemApi Allows to access all app shortcuts. @hide --> <permission android:name="android.permission.ACCESS_SHORTCUTS" - android:protectionLevel="signature|textClassifier" /> + android:protectionLevel="signature|appPredictor" /> <!-- @SystemApi Allows unlimited calls to shortcut mutation APIs. @hide --> <permission android:name="android.permission.UNLIMITED_SHORTCUTS_API_CALLS" - android:protectionLevel="signature|textClassifier" /> + android:protectionLevel="signature|appPredictor" /> <!-- @SystemApi Allows an application to read the runtime profiles of other apps. @hide <p>Not for use by third-party applications. --> diff --git a/data/keyboards/Vendor_0f0d_Product_00c1.kl b/data/keyboards/Vendor_0f0d_Product_00c1.kl new file mode 100644 index 000000000000..c74512a3a4b0 --- /dev/null +++ b/data/keyboards/Vendor_0f0d_Product_00c1.kl @@ -0,0 +1,55 @@ +# Copyright (C) 2020 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. + +# Device name: HORI CO.,LTD. HORIPAD S +# HORIPAD for Nintendo Switch, USB game controller +# https://hori.co.uk/horipad-for-nintendo-switch/ + +# Button labeled as "Y" but should really produce keycode "X" +key 0x130 BUTTON_X +# Button labeled as "B" but should really produce keycode "A" +key 0x131 BUTTON_A +# Button labeled as "A" but should really produce keycode "B" +key 0x132 BUTTON_B +# Button labeled as "X" but should really product keycode "Y" +key 0x133 BUTTON_Y + +key 0x134 BUTTON_L1 +key 0x135 BUTTON_R1 +key 0x136 BUTTON_L2 +key 0x137 BUTTON_R2 + +# Minus +key 0x138 BUTTON_SELECT +# Plus +key 0x139 BUTTON_START + +# Analog stick buttons +key 0x13a BUTTON_THUMBL +key 0x13b BUTTON_THUMBR + +# Home +key 0x13c HOME +# Capture +key 0x13d BUTTON_MODE + +# Left analog stick +axis 0x00 X +axis 0x01 Y +# Right analog stick +axis 0x02 Z +axis 0x05 RZ +# D-pad +axis 0x10 HAT_X +axis 0x11 HAT_Y diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 89d3cc4f5083..16f2917f8df8 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -20,6 +20,7 @@ cc_library_shared { ], shared_libs: [ + "libbinder", "libcutils", "liblog", "libutils", diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index abf083789c23..5c2ef15cbd1e 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -257,19 +257,24 @@ void PointerController::unfade(Transition transition) { void PointerController::setPresentation(Presentation presentation) { AutoMutex _l(mLock); - if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) { - mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources, - &mLocked.animationResources, mLocked.viewport.displayId); + if (mLocked.presentation == presentation) { + return; } - if (mLocked.presentation != presentation) { - mLocked.presentation = presentation; - mLocked.presentationChanged = true; + mLocked.presentation = presentation; + mLocked.presentationChanged = true; - if (presentation != PRESENTATION_SPOT) { - fadeOutAndReleaseAllSpotsLocked(); - } + if (!mLocked.viewport.isValid()) { + return; + } + if (presentation == PRESENTATION_POINTER) { + if (mLocked.additionalMouseResources.empty()) { + mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources, + &mLocked.animationResources, + mLocked.viewport.displayId); + } + fadeOutAndReleaseAllSpotsLocked(); updatePointerLocked(); } } @@ -291,6 +296,9 @@ void PointerController::setSpots(const PointerCoords* spotCoords, #endif AutoMutex _l(mLock); + if (!mLocked.viewport.isValid()) { + return; + } std::vector<Spot*> newSpots; std::map<int32_t, std::vector<Spot*>>::const_iterator iter = @@ -337,6 +345,9 @@ void PointerController::clearSpots() { #endif AutoMutex _l(mLock); + if (!mLocked.viewport.isValid()) { + return; + } fadeOutAndReleaseAllSpotsLocked(); } @@ -758,6 +769,10 @@ void PointerController::fadeOutAndReleaseAllSpotsLocked() { } void PointerController::loadResourcesLocked() REQUIRES(mLock) { + if (!mLocked.viewport.isValid()) { + return; + } + mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId); mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId); diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index 52305b8244a6..ebc622bae302 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -100,6 +100,7 @@ public: virtual int32_t getDisplayId() const; virtual void fade(Transition transition); virtual void unfade(Transition transition); + virtual void setDisplayViewport(const DisplayViewport& viewport); virtual void setPresentation(Presentation presentation); virtual void setSpots(const PointerCoords* spotCoords, @@ -108,7 +109,6 @@ public: void updatePointerIcon(int32_t iconId); void setCustomPointerIcon(const SpriteIcon& icon); - void setDisplayViewport(const DisplayViewport& viewport); void setInactivityTimeout(InactivityTimeout inactivityTimeout); void reloadPointerResources(); diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp index c1868d3a94d6..fd386e9f7a8a 100644 --- a/libs/input/SpriteController.cpp +++ b/libs/input/SpriteController.cpp @@ -245,7 +245,8 @@ void SpriteController::doUpdateSprites() { if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER - | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID))))) { + | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID + | DIRTY_ICON_STYLE))))) { needApplyTransaction = true; if (wantSurfaceVisibleAndDrawn @@ -274,6 +275,21 @@ void SpriteController::doUpdateSprites() { update.state.transformationMatrix.dtdy); } + if (wantSurfaceVisibleAndDrawn + && (becomingVisible + || (update.state.dirty & (DIRTY_HOTSPOT | DIRTY_ICON_STYLE)))) { + Parcel p; + p.writeInt32(update.state.icon.style); + p.writeFloat(update.state.icon.hotSpotX); + p.writeFloat(update.state.icon.hotSpotY); + + // Pass cursor metadata in the sprite surface so that when Android is running as a + // client OS (e.g. ARC++) the host OS can get the requested cursor metadata and + // update mouse cursor in the host OS. + t.setMetadata( + update.state.surfaceControl, METADATA_MOUSE_CURSOR, p); + } + int32_t surfaceLayer = mOverlayLayer + update.state.layer; if (wantSurfaceVisibleAndDrawn && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) { @@ -397,9 +413,14 @@ void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) { } else { dirty = DIRTY_BITMAP; } + + if (mLocked.state.icon.style != icon.style) { + mLocked.state.icon.style = icon.style; + dirty |= DIRTY_ICON_STYLE; + } } else if (mLocked.state.icon.isValid()) { mLocked.state.icon.bitmap.reset(); - dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; + dirty = DIRTY_BITMAP | DIRTY_HOTSPOT | DIRTY_ICON_STYLE; } else { return; // setting to invalid icon and already invalid so nothing to do } diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h index 5b216f50d113..79a904f5fe65 100644 --- a/libs/input/SpriteController.h +++ b/libs/input/SpriteController.h @@ -55,11 +55,12 @@ struct SpriteTransformationMatrix { * Icon that a sprite displays, including its hotspot. */ struct SpriteIcon { - inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { } - inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) : - bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { } + inline SpriteIcon() : style(0), hotSpotX(0), hotSpotY(0) { } + inline SpriteIcon(const SkBitmap& bitmap, int32_t style, float hotSpotX, float hotSpotY) : + bitmap(bitmap), style(style), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { } SkBitmap bitmap; + int32_t style; float hotSpotX; float hotSpotY; @@ -69,11 +70,12 @@ struct SpriteIcon { bitmap.readPixels(bitmapCopy.info(), bitmapCopy.getPixels(), bitmapCopy.rowBytes(), 0, 0); } - return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY); + return SpriteIcon(bitmapCopy, style, hotSpotX, hotSpotY); } inline void reset() { bitmap.reset(); + style = 0; hotSpotX = 0; hotSpotY = 0; } @@ -149,15 +151,15 @@ public: SpriteController(const sp<Looper>& looper, int32_t overlayLayer); /* Creates a new sprite, initially invisible. */ - sp<Sprite> createSprite(); + virtual sp<Sprite> createSprite(); /* Opens or closes a transaction to perform a batch of sprite updates as part of * a single operation such as setPosition and setAlpha. It is not necessary to * open a transaction when updating a single property. * Calls to openTransaction() nest and must be matched by an equal number * of calls to closeTransaction(). */ - void openTransaction(); - void closeTransaction(); + virtual void openTransaction(); + virtual void closeTransaction(); private: enum { @@ -174,6 +176,7 @@ private: DIRTY_VISIBILITY = 1 << 5, DIRTY_HOTSPOT = 1 << 6, DIRTY_DISPLAY_ID = 1 << 7, + DIRTY_ICON_STYLE = 1 << 8, }; /* Describes the state of a sprite. diff --git a/libs/input/TEST_MAPPING b/libs/input/TEST_MAPPING new file mode 100644 index 000000000000..fe74c62d4ec1 --- /dev/null +++ b/libs/input/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "libinputservice_test" + } + ] +} diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp new file mode 100644 index 000000000000..e83b2a78d180 --- /dev/null +++ b/libs/input/tests/Android.bp @@ -0,0 +1,45 @@ +// 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. + +cc_test { + name: "libinputservice_test", + srcs: [ + "PointerController_test.cpp", + ], + shared_libs: [ + "libinputservice", + "libgui", + "libhwui", + "libutils", + ], + static_libs: [ + "libgmock", + "libgtest", + ], + header_libs: [ + "libbase_headers", + "libinputflinger_headers", + ], + include_dirs: [ + "frameworks/base/libs", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + test_suites: [ + "general-tests", + ], +} diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp new file mode 100644 index 000000000000..a15742671dc7 --- /dev/null +++ b/libs/input/tests/PointerController_test.cpp @@ -0,0 +1,262 @@ +/* + * 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. + */ + +#include "mocks/MockSprite.h" +#include "mocks/MockSpriteController.h" + +#include <input/PointerController.h> +#include <input/SpriteController.h> + +#include <atomic> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <thread> + +namespace android { + +enum TestCursorType { + CURSOR_TYPE_DEFAULT = 0, + CURSOR_TYPE_HOVER, + CURSOR_TYPE_TOUCH, + CURSOR_TYPE_ANCHOR, + CURSOR_TYPE_ADDITIONAL, + CURSOR_TYPE_ADDITIONAL_ANIM, + CURSOR_TYPE_CUSTOM = -1, +}; + +using ::testing::AllOf; +using ::testing::Field; +using ::testing::Mock; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::Test; + +std::pair<float, float> getHotSpotCoordinatesForType(int32_t type) { + return std::make_pair(type * 10, type * 10 + 5); +} + +class MockPointerControllerPolicyInterface : public PointerControllerPolicyInterface { +public: + virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) override; + virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) override; + virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, + std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) override; + virtual int32_t getDefaultPointerIconId() override; + virtual int32_t getCustomPointerIconId() override; + + bool allResourcesAreLoaded(); + bool noResourcesAreLoaded(); + +private: + void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType); + + bool pointerIconLoaded{false}; + bool pointerResourcesLoaded{false}; + bool additionalMouseResourcesLoaded{false}; +}; + +void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) { + loadPointerIconForType(icon, CURSOR_TYPE_DEFAULT); + pointerIconLoaded = true; +} + +void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources* outResources, + int32_t) { + loadPointerIconForType(&outResources->spotHover, CURSOR_TYPE_HOVER); + loadPointerIconForType(&outResources->spotTouch, CURSOR_TYPE_TOUCH); + loadPointerIconForType(&outResources->spotAnchor, CURSOR_TYPE_ANCHOR); + pointerResourcesLoaded = true; +} + +void MockPointerControllerPolicyInterface::loadAdditionalMouseResources( + std::map<int32_t, SpriteIcon>* outResources, + std::map<int32_t, PointerAnimation>* outAnimationResources, + int32_t) { + SpriteIcon icon; + PointerAnimation anim; + + // CURSOR_TYPE_ADDITIONAL doesn't have animation resource. + int32_t cursorType = CURSOR_TYPE_ADDITIONAL; + loadPointerIconForType(&icon, cursorType); + (*outResources)[cursorType] = icon; + + // CURSOR_TYPE_ADDITIONAL_ANIM has animation resource. + cursorType = CURSOR_TYPE_ADDITIONAL_ANIM; + loadPointerIconForType(&icon, cursorType); + anim.animationFrames.push_back(icon); + anim.durationPerFrame = 10; + (*outResources)[cursorType] = icon; + (*outAnimationResources)[cursorType] = anim; + + additionalMouseResourcesLoaded = true; +} + +int32_t MockPointerControllerPolicyInterface::getDefaultPointerIconId() { + return CURSOR_TYPE_DEFAULT; +} + +int32_t MockPointerControllerPolicyInterface::getCustomPointerIconId() { + return CURSOR_TYPE_CUSTOM; +} + +bool MockPointerControllerPolicyInterface::allResourcesAreLoaded() { + return pointerIconLoaded && pointerResourcesLoaded && additionalMouseResourcesLoaded; +} + +bool MockPointerControllerPolicyInterface::noResourcesAreLoaded() { + return !(pointerIconLoaded || pointerResourcesLoaded || additionalMouseResourcesLoaded); +} + +void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* icon, int32_t type) { + icon->style = type; + std::pair<float, float> hotSpot = getHotSpotCoordinatesForType(type); + icon->hotSpotX = hotSpot.first; + icon->hotSpotY = hotSpot.second; +} +class PointerControllerTest : public Test { +protected: + PointerControllerTest(); + ~PointerControllerTest(); + + void ensureDisplayViewportIsSet(); + + sp<MockSprite> mPointerSprite; + sp<MockPointerControllerPolicyInterface> mPolicy; + sp<MockSpriteController> mSpriteController; + sp<PointerController> mPointerController; + +private: + void loopThread(); + + std::atomic<bool> mRunning = true; + class MyLooper : public Looper { + public: + MyLooper() : Looper(false) {} + ~MyLooper() = default; + }; + sp<MyLooper> mLooper; + std::thread mThread; +}; + +PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<MockSprite>), + mLooper(new MyLooper), mThread(&PointerControllerTest::loopThread, this) { + + mSpriteController = new NiceMock<MockSpriteController>(mLooper); + mPolicy = new MockPointerControllerPolicyInterface(); + + EXPECT_CALL(*mSpriteController, createSprite()) + .WillOnce(Return(mPointerSprite)); + + mPointerController = new PointerController(mPolicy, mLooper, mSpriteController); +} + +PointerControllerTest::~PointerControllerTest() { + mRunning.store(false, std::memory_order_relaxed); + mThread.join(); +} + +void PointerControllerTest::ensureDisplayViewportIsSet() { + DisplayViewport viewport; + viewport.displayId = ADISPLAY_ID_DEFAULT; + viewport.logicalRight = 1600; + viewport.logicalBottom = 1200; + viewport.physicalRight = 800; + viewport.physicalBottom = 600; + viewport.deviceWidth = 400; + viewport.deviceHeight = 300; + mPointerController->setDisplayViewport(viewport); + + // The first call to setDisplayViewport should trigger the loading of the necessary resources. + EXPECT_TRUE(mPolicy->allResourcesAreLoaded()); +} + +void PointerControllerTest::loopThread() { + Looper::setForThread(mLooper); + + while (mRunning.load(std::memory_order_relaxed)) { + mLooper->pollOnce(100); + } +} + +TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) { + ensureDisplayViewportIsSet(); + mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); + + std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT); + EXPECT_CALL(*mPointerSprite, setVisible(true)); + EXPECT_CALL(*mPointerSprite, setAlpha(1.0f)); + EXPECT_CALL(*mPointerSprite, setIcon( + AllOf( + Field(&SpriteIcon::style, CURSOR_TYPE_DEFAULT), + Field(&SpriteIcon::hotSpotX, hotspot.first), + Field(&SpriteIcon::hotSpotY, hotspot.second)))); + mPointerController->reloadPointerResources(); +} + +TEST_F(PointerControllerTest, updatePointerIcon) { + ensureDisplayViewportIsSet(); + mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); + + int32_t type = CURSOR_TYPE_ADDITIONAL; + std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type); + EXPECT_CALL(*mPointerSprite, setVisible(true)); + EXPECT_CALL(*mPointerSprite, setAlpha(1.0f)); + EXPECT_CALL(*mPointerSprite, setIcon( + AllOf( + Field(&SpriteIcon::style, type), + Field(&SpriteIcon::hotSpotX, hotspot.first), + Field(&SpriteIcon::hotSpotY, hotspot.second)))); + mPointerController->updatePointerIcon(type); +} + +TEST_F(PointerControllerTest, setCustomPointerIcon) { + ensureDisplayViewportIsSet(); + mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); + + int32_t style = CURSOR_TYPE_CUSTOM; + float hotSpotX = 15; + float hotSpotY = 20; + + SpriteIcon icon; + icon.style = style; + icon.hotSpotX = hotSpotX; + icon.hotSpotY = hotSpotY; + + EXPECT_CALL(*mPointerSprite, setVisible(true)); + EXPECT_CALL(*mPointerSprite, setAlpha(1.0f)); + EXPECT_CALL(*mPointerSprite, setIcon( + AllOf( + Field(&SpriteIcon::style, style), + Field(&SpriteIcon::hotSpotX, hotSpotX), + Field(&SpriteIcon::hotSpotY, hotSpotY)))); + mPointerController->setCustomPointerIcon(icon); +} + +TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) { + mPointerController->setPresentation(PointerController::PRESENTATION_POINTER); + mPointerController->setSpots(nullptr, nullptr, BitSet32(), -1); + mPointerController->clearSpots(); + mPointerController->setPosition(1.0f, 1.0f); + mPointerController->move(1.0f, 1.0f); + mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); + mPointerController->fade(PointerController::TRANSITION_IMMEDIATE); + + EXPECT_TRUE(mPolicy->noResourcesAreLoaded()); + + ensureDisplayViewportIsSet(); +} + +} // namespace android diff --git a/libs/input/tests/mocks/MockSprite.h b/libs/input/tests/mocks/MockSprite.h new file mode 100644 index 000000000000..013b79c3a3bf --- /dev/null +++ b/libs/input/tests/mocks/MockSprite.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef _MOCK_SPRITE_H +#define _MOCK_SPRITE_H + +#include <input/SpriteController.h> + +#include <gmock/gmock.h> + +namespace android { + +class MockSprite : public Sprite { +public: + virtual ~MockSprite() = default; + + MOCK_METHOD(void, setIcon, (const SpriteIcon& icon), (override)); + MOCK_METHOD(void, setVisible, (bool), (override)); + MOCK_METHOD(void, setPosition, (float, float), (override)); + MOCK_METHOD(void, setLayer, (int32_t), (override)); + MOCK_METHOD(void, setAlpha, (float), (override)); + MOCK_METHOD(void, setTransformationMatrix, (const SpriteTransformationMatrix&), (override)); + MOCK_METHOD(void, setDisplayId, (int32_t), (override)); +}; + +} // namespace android + +#endif // _MOCK_SPRITE_H diff --git a/apex/sdkextensions/sdk.proto b/libs/input/tests/mocks/MockSpriteController.h index d15b93552ff4..a034f66c9abf 100644 --- a/apex/sdkextensions/sdk.proto +++ b/libs/input/tests/mocks/MockSpriteController.h @@ -14,12 +14,26 @@ * limitations under the License. */ -syntax = "proto3"; -package com.android.sdkext.proto; +#ifndef _MOCK_SPRITE_CONTROLLER_H +#define _MOCK_SPRITE_CONTROLLER_H -option java_outer_classname = "SdkProto"; -option optimize_for = LITE_RUNTIME; +#include "MockSprite.h" -message SdkVersion { - int32 version = 1; -} +#include <input/SpriteController.h> + +namespace android { + +class MockSpriteController : public SpriteController { + +public: + MockSpriteController(sp<Looper> looper) : SpriteController(looper, 0) {} + ~MockSpriteController() {} + + MOCK_METHOD(sp<Sprite>, createSprite, (), (override)); + MOCK_METHOD(void, openTransaction, (), (override)); + MOCK_METHOD(void, closeTransaction, (), (override)); +}; + +} // namespace android + +#endif // _MOCK_SPRITE_CONTROLLER_H diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index c8cf7f503468..304f81b4e77f 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -43,7 +43,7 @@ twickham@google.com winsonc@google.com #Android Auto -stenning@google.com +hseog@google.com #Android TV rgl@google.com diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index eb72b81fb766..33c2b5828dac 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -33,7 +33,7 @@ java_defaults { "net-utils-framework-common", ], libs: [ - "framework-tethering", + "framework-tethering.impl", "unsupportedappusage", ], plugins: ["java_api_finder"], @@ -96,7 +96,7 @@ java_defaults { "res", ], libs: [ - "framework-tethering", + "framework-tethering.impl", ], jarjar_rules: "jarjar-rules.txt", optimize: { diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index 79a178297aa5..408725c8658b 100644 --- a/packages/Tethering/common/TetheringLib/Android.bp +++ b/packages/Tethering/common/TetheringLib/Android.bp @@ -13,31 +13,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -java_library { +java_sdk_library { name: "framework-tethering", - sdk_version: "module_current", + defaults: ["framework-module-defaults"], srcs: [ ":framework-tethering-srcs", ], + + // TODO(b/155480189) - Remove naming_scheme once references have been resolved. + // Temporary java_sdk_library component naming scheme to use to ease the transition from separate + // modules to java_sdk_library. + naming_scheme: "framework-modules", + jarjar_rules: "jarjar-rules.txt", installable: true, - libs: [ - "framework-annotations-lib", - ], - hostdex: true, // for hiddenapi check visibility: ["//frameworks/base/packages/Tethering:__subpackages__"], + stubs_library_visibility: ["//visibility:public"], apex_available: ["com.android.tethering"], permitted_packages: ["android.net"], } -stubs_defaults { - name: "framework-tethering-stubs-defaults", - srcs: [":framework-tethering-srcs"], - dist: { dest: "framework-tethering.txt" }, -} - filegroup { name: "framework-tethering-srcs", srcs: [ @@ -55,56 +52,3 @@ filegroup { ], path: "src" } - -droidstubs { - name: "framework-tethering-stubs-srcs-publicapi", - defaults: [ - "framework-module-stubs-defaults-publicapi", - "framework-tethering-stubs-defaults", - ], -} - -droidstubs { - name: "framework-tethering-stubs-srcs-systemapi", - defaults: [ - "framework-module-stubs-defaults-systemapi", - "framework-tethering-stubs-defaults", - ], -} - -droidstubs { - name: "framework-tethering-api-module_libs_api", - defaults: [ - "framework-module-api-defaults-module_libs_api", - "framework-tethering-stubs-defaults", - ], -} - -droidstubs { - name: "framework-tethering-stubs-srcs-module_libs_api", - defaults: [ - "framework-module-stubs-defaults-module_libs_api", - "framework-tethering-stubs-defaults", - ], -} - -java_library { - name: "framework-tethering-stubs-publicapi", - srcs: [":framework-tethering-stubs-srcs-publicapi"], - defaults: ["framework-module-stubs-lib-defaults-publicapi"], - dist: { dest: "framework-tethering.jar" }, -} - -java_library { - name: "framework-tethering-stubs-systemapi", - srcs: [":framework-tethering-stubs-srcs-systemapi"], - defaults: ["framework-module-stubs-lib-defaults-systemapi"], - dist: { dest: "framework-tethering.jar" }, -} - -java_library { - name: "framework-tethering-stubs-module_libs_api", - srcs: [":framework-tethering-stubs-srcs-module_libs_api"], - defaults: ["framework-module-stubs-lib-defaults-module_libs_api"], - dist: { dest: "framework-tethering.jar" }, -} diff --git a/packages/Tethering/common/TetheringLib/api/module-lib-lint-baseline.txt b/packages/Tethering/common/TetheringLib/api/module-lib-lint-baseline.txt new file mode 100644 index 000000000000..af7ad52c0782 --- /dev/null +++ b/packages/Tethering/common/TetheringLib/api/module-lib-lint-baseline.txt @@ -0,0 +1,39 @@ +// Baseline format: 1.0 +ActionValue: android.net.TetheringConstants#EXTRA_ADD_TETHER_TYPE: + Inconsistent extra value; expected `android.net.extra.ADD_TETHER_TYPE`, was `extraAddTetherType` +ActionValue: android.net.TetheringConstants#EXTRA_PROVISION_CALLBACK: + Inconsistent extra value; expected `android.net.extra.PROVISION_CALLBACK`, was `extraProvisionCallback` +ActionValue: android.net.TetheringConstants#EXTRA_REM_TETHER_TYPE: + Inconsistent extra value; expected `android.net.extra.REM_TETHER_TYPE`, was `extraRemTetherType` +ActionValue: android.net.TetheringConstants#EXTRA_RUN_PROVISION: + Inconsistent extra value; expected `android.net.extra.RUN_PROVISION`, was `extraRunProvision` +ActionValue: android.net.TetheringConstants#EXTRA_SET_ALARM: + Inconsistent extra value; expected `android.net.extra.SET_ALARM`, was `extraSetAlarm` +ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED: + Inconsistent action value; expected `android.net.action.TETHER_STATE_CHANGED`, was `android.net.conn.TETHER_STATE_CHANGED` +ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER: + Inconsistent extra value; expected `android.net.extra.ACTIVE_TETHER`, was `tetherArray` +ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER: + Inconsistent extra value; expected `android.net.extra.AVAILABLE_TETHER`, was `availableArray` +ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER: + Inconsistent extra value; expected `android.net.extra.ERRORED_TETHER`, was `erroredArray` + + +CallbackInterface: android.net.TetheringManager.StartTetheringCallback: + Callbacks must be abstract class instead of interface to enable extension in future API levels: StartTetheringCallback +CallbackInterface: android.net.TetheringManager.TetheringEventCallback: + Callbacks must be abstract class instead of interface to enable extension in future API levels: TetheringEventCallback + + +ManagerConstructor: android.net.TetheringManager#TetheringManager(android.content.Context, java.util.function.Supplier<android.os.IBinder>): + Managers must always be obtained from Context; no direct constructors + + +MissingGetterMatchingBuilder: android.net.TetheringManager.TetheringRequest.Builder#setShouldShowEntitlementUi(boolean): + android.net.TetheringManager.TetheringRequest does not declare a `shouldShowEntitlementUi()` method matching method android.net.TetheringManager.TetheringRequest.Builder.setShouldShowEntitlementUi(boolean) +MissingGetterMatchingBuilder: android.net.TetheringManager.TetheringRequest.Builder#setStaticIpv4Addresses(android.net.LinkAddress, android.net.LinkAddress): + android.net.TetheringManager.TetheringRequest does not declare a `getStaticIpv4Addresses()` method matching method android.net.TetheringManager.TetheringRequest.Builder.setStaticIpv4Addresses(android.net.LinkAddress,android.net.LinkAddress) + + +StaticFinalBuilder: android.net.TetheringManager.TetheringRequest.Builder: + Builder must be final: android.net.TetheringManager.TetheringRequest.Builder diff --git a/packages/Tethering/common/TetheringLib/api/system-lint-baseline.txt b/packages/Tethering/common/TetheringLib/api/system-lint-baseline.txt new file mode 100644 index 000000000000..f8d291ca2a79 --- /dev/null +++ b/packages/Tethering/common/TetheringLib/api/system-lint-baseline.txt @@ -0,0 +1,25 @@ +// Baseline format: 1.0 +ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED: + Inconsistent action value; expected `android.net.action.TETHER_STATE_CHANGED`, was `android.net.conn.TETHER_STATE_CHANGED` +ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER: + Inconsistent extra value; expected `android.net.extra.ACTIVE_TETHER`, was `tetherArray` +ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER: + Inconsistent extra value; expected `android.net.extra.AVAILABLE_TETHER`, was `availableArray` +ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER: + Inconsistent extra value; expected `android.net.extra.ERRORED_TETHER`, was `erroredArray` + + +CallbackInterface: android.net.TetheringManager.StartTetheringCallback: + Callbacks must be abstract class instead of interface to enable extension in future API levels: StartTetheringCallback +CallbackInterface: android.net.TetheringManager.TetheringEventCallback: + Callbacks must be abstract class instead of interface to enable extension in future API levels: TetheringEventCallback + + +MissingGetterMatchingBuilder: android.net.TetheringManager.TetheringRequest.Builder#setShouldShowEntitlementUi(boolean): + android.net.TetheringManager.TetheringRequest does not declare a `shouldShowEntitlementUi()` method matching method android.net.TetheringManager.TetheringRequest.Builder.setShouldShowEntitlementUi(boolean) +MissingGetterMatchingBuilder: android.net.TetheringManager.TetheringRequest.Builder#setStaticIpv4Addresses(android.net.LinkAddress, android.net.LinkAddress): + android.net.TetheringManager.TetheringRequest does not declare a `getStaticIpv4Addresses()` method matching method android.net.TetheringManager.TetheringRequest.Builder.setStaticIpv4Addresses(android.net.LinkAddress,android.net.LinkAddress) + + +StaticFinalBuilder: android.net.TetheringManager.TetheringRequest.Builder: + Builder must be final: android.net.TetheringManager.TetheringRequest.Builder diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 659d344acfcd..f08429bb0696 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -16,14 +16,13 @@ package android.net.ip; -import static android.net.InetAddresses.parseNumericAddress; import static android.net.RouteInfo.RTN_UNICAST; import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; -import static android.net.util.NetworkConstants.FF; import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; import static android.net.util.NetworkConstants.asByte; +import static android.net.util.PrefixUtils.asIpPrefix; import static android.net.util.TetheringMessageBase.BASE_IPSERVER; import static android.system.OsConstants.RT_SCOPE_UNIVERSE; @@ -66,11 +65,11 @@ import androidx.annotation.Nullable; import com.android.internal.util.MessageUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.networkstack.tethering.PrivateAddressCoordinator; import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; -import java.net.InetAddress; import java.net.NetworkInterface; import java.net.UnknownHostException; import java.util.ArrayList; @@ -108,27 +107,8 @@ public class IpServer extends StateMachine { private static final byte DOUG_ADAMS = (byte) 42; - private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129"; - private static final int USB_PREFIX_LENGTH = 24; - private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1"; - private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24; - private static final String WIFI_P2P_IFACE_ADDR = "192.168.49.1"; - private static final int WIFI_P2P_IFACE_PREFIX_LENGTH = 24; - private static final String ETHERNET_IFACE_ADDR = "192.168.50.1"; - private static final int ETHERNET_IFACE_PREFIX_LENGTH = 24; - - // TODO: remove this constant after introducing PrivateAddressCoordinator. - private static final List<IpPrefix> NCM_PREFIXES = Collections.unmodifiableList( - Arrays.asList( - new IpPrefix("192.168.42.0/24"), - new IpPrefix("192.168.51.0/24"), - new IpPrefix("192.168.52.0/24"), - new IpPrefix("192.168.53.0/24") - )); - // TODO: have PanService use some visible version of this constant - private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1"; - private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; + private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1/24"; // TODO: have this configurable private static final int DHCP_LEASE_TIME_SECS = 3600; @@ -167,6 +147,14 @@ public class IpServer extends StateMachine { * Notify that the DHCP leases changed in one of the IpServers. */ public void dhcpLeasesChanged() { } + + /** + * Request Tethering change. + * + * @param tetheringType the downstream type of this IpServer. + * @param enabled enable or disable tethering. + */ + public void requestEnableTethering(int tetheringType, boolean enabled) { } } /** Capture IpServer dependencies, for injection. */ @@ -196,6 +184,7 @@ public class IpServer extends StateMachine { return 0; } } + /** Create a DhcpServer instance to be used by IpServer. */ public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params, DhcpServerCallbacks cb); @@ -225,16 +214,20 @@ public class IpServer extends StateMachine { public static final int CMD_NEIGHBOR_EVENT = BASE_IPSERVER + 11; // request from DHCP server that it wants to have a new prefix public static final int CMD_NEW_PREFIX_REQUEST = BASE_IPSERVER + 12; + // request from PrivateAddressCoordinator to restart tethering. + public static final int CMD_NOTIFY_PREFIX_CONFLICT = BASE_IPSERVER + 13; private final State mInitialState; private final State mLocalHotspotState; private final State mTetheredState; private final State mUnavailableState; + private final State mWaitingForRestartState; private final SharedLog mLog; private final INetd mNetd; private final Callback mCallback; private final InterfaceController mInterfaceCtrl; + private final PrivateAddressCoordinator mPrivateAddressCoordinator; private final String mIfaceName; private final int mInterfaceType; @@ -261,7 +254,6 @@ public class IpServer extends StateMachine { private int mDhcpServerStartIndex = 0; private IDhcpServer mDhcpServer; private RaParams mLastRaParams; - private LinkAddress mIpv4Address; private LinkAddress mStaticIpv4ServerAddr; private LinkAddress mStaticIpv4ClientAddr; @@ -316,12 +308,14 @@ public class IpServer extends StateMachine { private final IpNeighborMonitor mIpNeighborMonitor; + private LinkAddress mIpv4Address; + // TODO: Add a dependency object to pass the data members or variables from the tethering // object. It helps to reduce the arguments of the constructor. public IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, INetd netd, Callback callback, boolean usingLegacyDhcp, boolean usingBpfOffload, - Dependencies deps) { + PrivateAddressCoordinator addressCoordinator, Dependencies deps) { super(ifaceName, looper); mLog = log.forSubComponent(ifaceName); mNetd = netd; @@ -332,6 +326,7 @@ public class IpServer extends StateMachine { mLinkProperties = new LinkProperties(); mUsingLegacyDhcp = usingLegacyDhcp; mUsingBpfOffload = usingBpfOffload; + mPrivateAddressCoordinator = addressCoordinator; mDeps = deps; resetLinkProperties(); mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; @@ -352,9 +347,11 @@ public class IpServer extends StateMachine { mLocalHotspotState = new LocalHotspotState(); mTetheredState = new TetheredState(); mUnavailableState = new UnavailableState(); + mWaitingForRestartState = new WaitingForRestartState(); addState(mInitialState); addState(mLocalHotspotState); addState(mTetheredState); + addState(mWaitingForRestartState, mTetheredState); addState(mUnavailableState); setInitialState(mInitialState); @@ -387,6 +384,11 @@ public class IpServer extends StateMachine { return new LinkProperties(mLinkProperties); } + /** The address which IpServer is using. */ + public LinkAddress getAddress() { + return mIpv4Address; + } + /** * Get the latest list of DHCP leases that was reported. Must be called on the IpServer looper * thread. @@ -617,6 +619,7 @@ public class IpServer extends StateMachine { // NOTE: All of configureIPv4() will be refactored out of existence // into calls to InterfaceController, shared with startIPv4(). mInterfaceCtrl.clearIPv4Address(); + mPrivateAddressCoordinator.releaseDownstream(this); mIpv4Address = null; mStaticIpv4ServerAddr = null; mStaticIpv4ClientAddr = null; @@ -625,43 +628,24 @@ public class IpServer extends StateMachine { private boolean configureIPv4(boolean enabled) { if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); - // TODO: Replace this hard-coded information with dynamically selected - // config passed down to us by a higher layer IP-coordinating element. - final Inet4Address srvAddr; - int prefixLen = 0; - try { - if (mStaticIpv4ServerAddr != null) { - srvAddr = (Inet4Address) mStaticIpv4ServerAddr.getAddress(); - prefixLen = mStaticIpv4ServerAddr.getPrefixLength(); - } else if (mInterfaceType == TetheringManager.TETHERING_USB - || mInterfaceType == TetheringManager.TETHERING_NCM) { - srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR); - prefixLen = USB_PREFIX_LENGTH; - } else if (mInterfaceType == TetheringManager.TETHERING_WIFI) { - srvAddr = (Inet4Address) parseNumericAddress(getRandomWifiIPv4Address()); - prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH; - } else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) { - srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR); - prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH; - } else if (mInterfaceType == TetheringManager.TETHERING_ETHERNET) { - // TODO: randomize address for tethering too, similarly to wifi - srvAddr = (Inet4Address) parseNumericAddress(ETHERNET_IFACE_ADDR); - prefixLen = ETHERNET_IFACE_PREFIX_LENGTH; - } else { - // BT configures the interface elsewhere: only start DHCP. - // TODO: make all tethering types behave the same way, and delete the bluetooth - // code that calls into NetworkManagementService directly. - srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR); - mIpv4Address = new LinkAddress(srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); - return configureDhcp(enabled, mIpv4Address, null /* clientAddress */); - } - mIpv4Address = new LinkAddress(srvAddr, prefixLen); - } catch (IllegalArgumentException e) { - mLog.e("Error selecting ipv4 address", e); - if (!enabled) stopDhcp(); + if (enabled) { + mIpv4Address = requestIpv4Address(); + } + + if (mIpv4Address == null) { + mLog.e("No available ipv4 address"); return false; } + if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) { + // BT configures the interface elsewhere: only start DHCP. + // TODO: make all tethering types behave the same way, and delete the bluetooth + // code that calls into NetworkManagementService directly. + return configureDhcp(enabled, mIpv4Address, null /* clientAddress */); + } + + final IpPrefix ipv4Prefix = asIpPrefix(mIpv4Address); + final Boolean setIfaceUp; if (mInterfaceType == TetheringManager.TETHERING_WIFI || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) { @@ -688,21 +672,14 @@ public class IpServer extends StateMachine { return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); } - private Inet4Address getRandomIPv4Address(@NonNull final byte[] rawAddr) { - final byte[] ipv4Addr = rawAddr; - ipv4Addr[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF); - try { - return (Inet4Address) InetAddress.getByAddress(ipv4Addr); - } catch (UnknownHostException e) { - mLog.e("Failed to construct Inet4Address from raw IPv4 addr"); - return null; + private LinkAddress requestIpv4Address() { + if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr; + + if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) { + return new LinkAddress(BLUETOOTH_IFACE_ADDR); } - } - private String getRandomWifiIPv4Address() { - final Inet4Address ipv4Addr = - getRandomIPv4Address(parseNumericAddress(WIFI_HOST_IFACE_ADDR).getAddress()); - return ipv4Addr != null ? ipv4Addr.getHostAddress() : WIFI_HOST_IFACE_ADDR; + return mPrivateAddressCoordinator.requestDownstreamAddress(this); } private boolean startIPv6() { @@ -978,19 +955,6 @@ public class IpServer extends StateMachine { } } - // TODO: call PrivateAddressCoordinator.requestDownstreamAddress instead of this temporary - // logic. - private Inet4Address requestDownstreamAddress(@NonNull final IpPrefix currentPrefix) { - final int oldIndex = NCM_PREFIXES.indexOf(currentPrefix); - if (oldIndex == -1) { - mLog.e("current prefix isn't supported for NCM link: " + currentPrefix); - return null; - } - - final IpPrefix newPrefix = NCM_PREFIXES.get((oldIndex + 1) % NCM_PREFIXES.size()); - return getRandomIPv4Address(newPrefix.getRawAddress()); - } - private void handleNewPrefixRequest(@NonNull final IpPrefix currentPrefix) { if (!currentPrefix.contains(mIpv4Address.getAddress()) || currentPrefix.getPrefixLength() != mIpv4Address.getPrefixLength()) { @@ -999,12 +963,12 @@ public class IpServer extends StateMachine { } final LinkAddress deprecatedLinkAddress = mIpv4Address; - final Inet4Address srvAddr = requestDownstreamAddress(currentPrefix); - if (srvAddr == null) { + mIpv4Address = requestIpv4Address(); + if (mIpv4Address == null) { mLog.e("Fail to request a new downstream prefix"); return; } - mIpv4Address = new LinkAddress(srvAddr, currentPrefix.getPrefixLength()); + final Inet4Address srvAddr = (Inet4Address) mIpv4Address.getAddress(); // Add new IPv4 address on the interface. if (!mInterfaceCtrl.addAddress(srvAddr, currentPrefix.getPrefixLength())) { @@ -1162,7 +1126,7 @@ public class IpServer extends StateMachine { } try { - NetdUtils.tetherInterface(mNetd, mIfaceName, PrefixUtils.asIpPrefix(mIpv4Address)); + NetdUtils.tetherInterface(mNetd, mIfaceName, asIpPrefix(mIpv4Address)); } catch (RemoteException | ServiceSpecificException | IllegalStateException e) { mLog.e("Error Tethering", e); mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; @@ -1222,6 +1186,11 @@ public class IpServer extends StateMachine { case CMD_NEW_PREFIX_REQUEST: handleNewPrefixRequest((IpPrefix) message.obj); break; + case CMD_NOTIFY_PREFIX_CONFLICT: + mLog.i("restart tethering: " + mInterfaceType); + mCallback.requestEnableTethering(mInterfaceType, false /* enabled */); + transitionTo(mWaitingForRestartState); + break; default: return false; } @@ -1403,6 +1372,28 @@ public class IpServer extends StateMachine { } } + class WaitingForRestartState extends State { + @Override + public boolean processMessage(Message message) { + logMessage(this, message.what); + switch (message.what) { + case CMD_TETHER_UNREQUESTED: + transitionTo(mInitialState); + mLog.i("Untethered (unrequested) and restarting " + mIfaceName); + mCallback.requestEnableTethering(mInterfaceType, true /* enabled */); + break; + case CMD_INTERFACE_DOWN: + transitionTo(mUnavailableState); + mLog.i("Untethered (interface down) and restarting" + mIfaceName); + mCallback.requestEnableTethering(mInterfaceType, true /* enabled */); + break; + default: + return false; + } + return true; + } + } + // Accumulate routes representing "prefixes to be assigned to the local // interface", for subsequent modification of local_network routing. private static ArrayList<RouteInfo> getLocalRoutesFor( diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java new file mode 100644 index 000000000000..160a166b632b --- /dev/null +++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2020 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.content.Context; +import android.net.ConnectivityManager; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.Network; +import android.net.ip.IpServer; +import android.net.util.PrefixUtils; +import android.util.ArrayMap; +import android.util.ArraySet; + +import androidx.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +/** + * This class coordinate IP addresses conflict problem. + * + * Tethering downstream IP addresses may conflict with network assigned addresses. This + * coordinator is responsible for recording all of network assigned addresses and dispatched + * free address to downstream interfaces. + * + * This class is not thread-safe and should be accessed on the same tethering internal thread. + * @hide + */ +public class PrivateAddressCoordinator { + public static final int PREFIX_LENGTH = 24; + + private static final int MAX_UBYTE = 256; + private static final int BYTE_MASK = 0xff; + // reserved for bluetooth tethering. + private static final int BLUETOOTH_RESERVED = 44; + private static final byte DEFAULT_ID = (byte) 42; + + // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream + // address may be requested before coordinator get current upstream notification. To ensure + // coordinator do not select conflict downstream prefix, mUpstreamPrefixMap would not be cleared + // when tethering is down. Instead coordinator would remove all depcreted upstreams from + // mUpstreamPrefixMap when tethering is starting. See #maybeRemoveDeprectedUpstreams(). + private final ArrayMap<Network, List<IpPrefix>> mUpstreamPrefixMap; + private final ArraySet<IpServer> mDownstreams; + // IANA has reserved the following three blocks of the IP address space for private intranets: + // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 + // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers. + private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16"; + private final IpPrefix mTetheringPrefix; + private final ConnectivityManager mConnectivityMgr; + + public PrivateAddressCoordinator(Context context) { + mDownstreams = new ArraySet<>(); + mUpstreamPrefixMap = new ArrayMap<>(); + mTetheringPrefix = new IpPrefix(DEFAULT_TETHERING_PREFIX); + mConnectivityMgr = (ConnectivityManager) context.getSystemService( + Context.CONNECTIVITY_SERVICE); + } + + /** + * Record a new upstream IpPrefix which may conflict with tethering downstreams. + * The downstreams will be notified if a conflict is found. + */ + public void updateUpstreamPrefix(final Network network, final LinkProperties lp) { + final ArrayList<IpPrefix> ipv4Prefixes = getIpv4Prefixes(lp.getAllLinkAddresses()); + if (ipv4Prefixes.isEmpty()) { + removeUpstreamPrefix(network); + return; + } + + mUpstreamPrefixMap.put(network, ipv4Prefixes); + handleMaybePrefixConflict(ipv4Prefixes); + } + + private ArrayList<IpPrefix> getIpv4Prefixes(final List<LinkAddress> linkAddresses) { + final ArrayList<IpPrefix> list = new ArrayList<>(); + for (LinkAddress address : linkAddresses) { + if (!address.isIpv4()) continue; + + list.add(PrefixUtils.asIpPrefix(address)); + } + + return list; + } + + private void handleMaybePrefixConflict(final List<IpPrefix> prefixes) { + for (IpServer downstream : mDownstreams) { + final IpPrefix target = getDownstreamPrefix(downstream); + if (target == null) continue; + + for (IpPrefix source : prefixes) { + if (isConflictPrefix(source, target)) { + downstream.sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + break; + } + } + } + } + + /** Remove IpPrefix records corresponding to input network. */ + public void removeUpstreamPrefix(final Network network) { + mUpstreamPrefixMap.remove(network); + } + + private void maybeRemoveDeprectedUpstreams() { + if (!mDownstreams.isEmpty() || mUpstreamPrefixMap.isEmpty()) return; + + final ArrayList<Network> toBeRemoved = new ArrayList<>(); + List<Network> allNetworks = Arrays.asList(mConnectivityMgr.getAllNetworks()); + for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { + final Network network = mUpstreamPrefixMap.keyAt(i); + if (!allNetworks.contains(network)) toBeRemoved.add(network); + } + + mUpstreamPrefixMap.removeAll(toBeRemoved); + } + + /** + * Pick a random available address and mark its prefix as in use for the provided IpServer, + * returns null if there is no available address. + */ + @Nullable + public LinkAddress requestDownstreamAddress(final IpServer ipServer) { + maybeRemoveDeprectedUpstreams(); + + // Address would be 192.168.[subAddress]/24. + final byte[] bytes = mTetheringPrefix.getRawAddress(); + final int subAddress = getRandomSubAddr(); + final int subNet = (subAddress >> 8) & BYTE_MASK; + bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff); + for (int i = 0; i < MAX_UBYTE; i++) { + final int newSubNet = (subNet + i) & BYTE_MASK; + if (newSubNet == BLUETOOTH_RESERVED) continue; + + bytes[2] = (byte) newSubNet; + final InetAddress addr; + try { + addr = InetAddress.getByAddress(bytes); + } catch (UnknownHostException e) { + throw new IllegalStateException("Invalid address, shouldn't happen.", e); + } + + final IpPrefix prefix = new IpPrefix(addr, PREFIX_LENGTH); + // Check whether this prefix is in use. + if (isDownstreamPrefixInUse(prefix)) continue; + // Check whether this prefix is conflict with any current upstream network. + if (isConflictWithUpstream(prefix)) continue; + + mDownstreams.add(ipServer); + return new LinkAddress(addr, PREFIX_LENGTH); + } + + // No available address. + return null; + } + + /** Get random sub address value. Return value is in 0 ~ 0xffff. */ + @VisibleForTesting + public int getRandomSubAddr() { + return ((new Random()).nextInt()) & 0xffff; // subNet is in 0 ~ 0xffff. + } + + private byte getSanitizedAddressSuffix(final int source, byte... excluded) { + final byte subId = (byte) (source & BYTE_MASK); + for (byte value : excluded) { + if (subId == value) return DEFAULT_ID; + } + + return subId; + } + + /** Release downstream record for IpServer. */ + public void releaseDownstream(final IpServer ipServer) { + mDownstreams.remove(ipServer); + } + + /** Clear current upstream prefixes records. */ + public void clearUpstreamPrefixes() { + mUpstreamPrefixMap.clear(); + } + + private boolean isConflictWithUpstream(final IpPrefix source) { + for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { + final List<IpPrefix> list = mUpstreamPrefixMap.valueAt(i); + for (IpPrefix target : list) { + if (isConflictPrefix(source, target)) return true; + } + } + return false; + } + + private boolean isConflictPrefix(final IpPrefix prefix1, final IpPrefix prefix2) { + if (prefix2.getPrefixLength() < prefix1.getPrefixLength()) { + return prefix2.contains(prefix1.getAddress()); + } + + return prefix1.contains(prefix2.getAddress()); + } + + private boolean isDownstreamPrefixInUse(final IpPrefix source) { + // This class always generates downstream prefixes with the same prefix length, so + // prefixes cannot be contained in each other. They can only be equal to each other. + for (IpServer downstream : mDownstreams) { + final IpPrefix prefix = getDownstreamPrefix(downstream); + if (source.equals(prefix)) return true; + } + return false; + } + + private IpPrefix getDownstreamPrefix(final IpServer downstream) { + final LinkAddress address = downstream.getAddress(); + if (address == null) return null; + + return PrefixUtils.asIpPrefix(address); + } + + void dump(final IndentingPrintWriter pw) { + pw.decreaseIndent(); + pw.println("mUpstreamPrefixMap:"); + pw.increaseIndent(); + for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { + pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i)); + } + pw.decreaseIndent(); + pw.println("mDownstreams:"); + pw.increaseIndent(); + for (IpServer ipServer : mDownstreams) { + pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress()); + } + pw.decreaseIndent(); + } +} diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java index 3ce3b4506c3f..6eb10129efd5 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -207,6 +207,7 @@ public class Tethering { new SparseArray<>(); // used to synchronize public access to members + // TODO(b/153621704): remove mPublicSync to make Tethering lock free private final Object mPublicSync; private final Context mContext; private final ArrayMap<String, TetherState> mTetherStates; @@ -231,6 +232,7 @@ public class Tethering { private final TetheringThreadExecutor mExecutor; private final TetheringNotificationUpdater mNotificationUpdater; private final UserManager mUserManager; + private final PrivateAddressCoordinator mPrivateAddressCoordinator; private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID; // All the usage of mTetheringEventCallback should run in the same thread. private ITetheringEventCallback mTetheringEventCallback = null; @@ -314,6 +316,7 @@ public class Tethering { mExecutor = new TetheringThreadExecutor(mHandler); mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor); mNetdCallback = new NetdCallback(); + mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext); // Load tethering configuration. updateConfiguration(); @@ -1616,6 +1619,14 @@ public class Tethering { } } + private void addUpstreamPrefixes(final UpstreamNetworkState ns) { + mPrivateAddressCoordinator.updateUpstreamPrefix(ns.network, ns.linkProperties); + } + + private void removeUpstreamPrefixes(final UpstreamNetworkState ns) { + mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network); + } + @VisibleForTesting void handleUpstreamNetworkMonitorCallback(int arg1, Object o) { if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) { @@ -1624,6 +1635,14 @@ public class Tethering { } final UpstreamNetworkState ns = (UpstreamNetworkState) o; + switch (arg1) { + case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES: + addUpstreamPrefixes(ns); + break; + case UpstreamNetworkMonitor.EVENT_ON_LOST: + removeUpstreamPrefixes(ns); + break; + } if (ns == null || !pertainsToCurrentUpstream(ns)) { // TODO: In future, this is where upstream evaluation and selection @@ -2190,6 +2209,11 @@ public class Tethering { mOffloadController.dump(pw); pw.decreaseIndent(); + pw.println("Private address coordinator:"); + pw.increaseIndent(); + mPrivateAddressCoordinator.dump(pw); + pw.decreaseIndent(); + pw.println("Log:"); pw.increaseIndent(); if (argsContain(args, "--short")) { @@ -2231,6 +2255,11 @@ public class Tethering { public void dhcpLeasesChanged() { updateConnectedClients(null /* wifiClients */); } + + @Override + public void requestEnableTethering(int tetheringType, boolean enabled) { + enableTetheringInternal(tetheringType, enabled, null); + } }; } @@ -2314,7 +2343,8 @@ public class Tethering { final TetherState tetherState = new TetherState( new IpServer(iface, mLooper, interfaceType, mLog, mNetd, makeControlCallback(), mConfig.enableLegacyDhcpServer, - mConfig.enableBpfOffload, mDeps.getIpServerDependencies())); + mConfig.enableBpfOffload, mPrivateAddressCoordinator, + mDeps.getIpServerDependencies())); mTetherStates.put(iface, tetherState); tetherState.ipServer.start(); } diff --git a/packages/Tethering/tests/integration/Android.bp b/packages/Tethering/tests/integration/Android.bp index 3305ed084481..ed69b7d63cb4 100644 --- a/packages/Tethering/tests/integration/Android.bp +++ b/packages/Tethering/tests/integration/Android.bp @@ -63,7 +63,6 @@ android_test { // NetworkStackTests. android_test { name: "TetheringCoverageTests", - certificate: "platform", platform_apis: true, test_suites: ["device-tests", "mts"], test_config: "AndroidTest_Coverage.xml", diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index 4bac9da9c3d2..2fb7e607d0af 100644 --- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -76,7 +76,7 @@ import java.util.concurrent.TimeoutException; public class EthernetTetheringTest { private static final String TAG = EthernetTetheringTest.class.getSimpleName(); - private static final int TIMEOUT_MS = 1000; + private static final int TIMEOUT_MS = 5000; private static final int PACKET_READ_TIMEOUT_MS = 100; private static final int DHCP_DISCOVER_ATTEMPTS = 10; private static final byte[] DHCP_REQUESTED_PARAMS = new byte[] { @@ -338,7 +338,8 @@ public class EthernetTetheringTest { private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception { return enableEthernetTethering(iface, - new TetheringRequest.Builder(TETHERING_ETHERNET).build()); + new TetheringRequest.Builder(TETHERING_ETHERNET) + .setExemptFromEntitlementCheck(true).build()); } private int getMTU(TestNetworkInterface iface) throws SocketException { @@ -508,7 +509,8 @@ public class EthernetTetheringTest { LinkAddress localAddr = local == null ? null : new LinkAddress(local); LinkAddress clientAddr = client == null ? null : new LinkAddress(client); return new TetheringRequest.Builder(TETHERING_ETHERNET) - .setStaticIpv4Addresses(localAddr, clientAddr).build(); + .setStaticIpv4Addresses(localAddr, clientAddr) + .setExemptFromEntitlementCheck(true).build(); } private void assertInvalidStaticIpv4Request(String iface, String local, String client) diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp index 9b7d68309fbf..15727689a406 100644 --- a/packages/Tethering/tests/unit/Android.bp +++ b/packages/Tethering/tests/unit/Android.bp @@ -29,7 +29,7 @@ java_library { sdk_version: "core_platform", libs: [ "framework-minus-apex", - "framework-tethering", + "framework-tethering.impl", ], visibility: ["//cts/tests/tests/tethering"], } @@ -59,7 +59,7 @@ java_defaults { "ext", "framework-minus-apex", "framework-res", - "framework-tethering", + "framework-tethering.impl", ], jni_libs: [ // For mockito extended @@ -82,7 +82,7 @@ android_library { android_test { name: "TetheringTests", - certificate: "platform", + platform_apis: true, test_suites: [ "device-tests", "mts", diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 307ebf17d229..0cda29a32f59 100644 --- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -78,6 +78,7 @@ import android.net.ip.IpNeighborMonitor.NeighborEventConsumer; import android.net.ip.RouterAdvertisementDaemon.RaParams; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; +import android.net.util.PrefixUtils; import android.net.util.SharedLog; import android.os.RemoteException; import android.os.test.TestLooper; @@ -86,6 +87,8 @@ import android.text.TextUtils; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.networkstack.tethering.PrivateAddressCoordinator; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -109,7 +112,7 @@ public class IpServerTest { private static final String UPSTREAM_IFACE2 = "upstream1"; private static final int UPSTREAM_IFINDEX = 101; private static final int UPSTREAM_IFINDEX2 = 102; - private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1"; + private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1"; private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; private static final int DHCP_LEASE_TIME_SECS = 3600; private static final boolean DEFAULT_USING_BPF_OFFLOAD = true; @@ -119,6 +122,9 @@ public class IpServerTest { private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000; + private final LinkAddress mTestAddress = new LinkAddress("192.168.42.5/24"); + private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24"); + @Mock private INetd mNetd; @Mock private IpServer.Callback mCallback; @Mock private SharedLog mSharedLog; @@ -126,6 +132,7 @@ public class IpServerTest { @Mock private RouterAdvertisementDaemon mRaDaemon; @Mock private IpNeighborMonitor mIpNeighborMonitor; @Mock private IpServer.Dependencies mDependencies; + @Mock private PrivateAddressCoordinator mAddressCoordinator; @Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor; @@ -173,7 +180,7 @@ public class IpServerTest { mIpServer = new IpServer( IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, - mCallback, usingLegacyDhcp, usingBpfOffload, mDependencies); + mCallback, usingLegacyDhcp, usingBpfOffload, mAddressCoordinator, mDependencies); mIpServer.start(); mNeighborEventConsumer = neighborCaptor.getValue(); @@ -200,12 +207,14 @@ public class IpServerTest { lp.setInterfaceName(upstreamIface); dispatchTetherConnectionChanged(upstreamIface, lp, 0); } - reset(mNetd, mCallback); + reset(mNetd, mCallback, mAddressCoordinator); + when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); } @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); + when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); } @Test @@ -214,7 +223,7 @@ public class IpServerTest { .thenReturn(mIpNeighborMonitor); mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog, mNetd, mCallback, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD, - mDependencies); + mAddressCoordinator, mDependencies); mIpServer.start(); mLooper.dispatchAll(); verify(mCallback).updateInterfaceState( @@ -277,16 +286,17 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, null); dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED); - InOrder inOrder = inOrder(mNetd, mCallback); + InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME); inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); + inOrder.verify(mAddressCoordinator).releaseDownstream(any()); inOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNetd, mCallback); + verifyNoMoreInteractions(mNetd, mCallback, mAddressCoordinator); } @Test @@ -294,7 +304,8 @@ public class IpServerTest { initStateMachine(TETHERING_USB); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); - InOrder inOrder = inOrder(mCallback, mNetd); + InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); @@ -306,7 +317,7 @@ public class IpServerTest { inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), mLinkPropertiesCaptor.capture()); assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue()); - verifyNoMoreInteractions(mNetd, mCallback); + verifyNoMoreInteractions(mNetd, mCallback, mAddressCoordinator); } @Test @@ -314,7 +325,8 @@ public class IpServerTest { initStateMachine(TETHERING_WIFI_P2P); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); - InOrder inOrder = inOrder(mCallback, mNetd); + InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); @@ -326,7 +338,7 @@ public class IpServerTest { inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), mLinkPropertiesCaptor.capture()); assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue()); - verifyNoMoreInteractions(mNetd, mCallback); + verifyNoMoreInteractions(mNetd, mCallback, mAddressCoordinator); } @Test @@ -392,18 +404,19 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED); - InOrder inOrder = inOrder(mNetd, mCallback); + InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator); inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME); inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); + inOrder.verify(mAddressCoordinator).releaseDownstream(any()); inOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNetd, mCallback); + verifyNoMoreInteractions(mNetd, mCallback, mAddressCoordinator); } @Test @@ -483,7 +496,7 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE); - assertDhcpStarted(new IpPrefix("192.168.43.0/24")); + assertDhcpStarted(PrefixUtils.asIpPrefix(mTestAddress)); } @Test @@ -491,7 +504,7 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE); - assertDhcpStarted(new IpPrefix("192.168.44.0/24")); + assertDhcpStarted(mBluetoothPrefix); } @Test @@ -499,7 +512,7 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_WIFI_P2P, UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE); - assertDhcpStarted(new IpPrefix("192.168.49.0/24")); + assertDhcpStarted(PrefixUtils.asIpPrefix(mTestAddress)); } @Test @@ -524,21 +537,27 @@ public class IpServerTest { eventCallbacks = dhcpEventCbsCaptor.getValue(); assertDhcpStarted(new IpPrefix("192.168.42.0/24")); - // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals - // onNewPrefixRequest callback. - eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24")); - mLooper.dispatchAll(); - final ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class); - InOrder inOrder = inOrder(mNetd, mCallback); - inOrder.verify(mCallback).updateInterfaceState( - mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR); - inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); + InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); 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), any(), any()); + inOrder.verify(mCallback).updateInterfaceState( + mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR); + inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); + verifyNoMoreInteractions(mCallback, mAddressCoordinator); + + // 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())).thenReturn(newAddress); + eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24")); + mLooper.dispatchAll(); + + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); verifyNoMoreInteractions(mCallback); diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java new file mode 100644 index 000000000000..93efd49a6d69 --- /dev/null +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2020 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 org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.InetAddresses; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.Network; +import android.net.ip.IpServer; +import android.net.util.NetworkConstants; +import android.net.util.PrefixUtils; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public final class PrivateAddressCoordinatorTest { + private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0"; + private static final String TEST_WIFI_IFNAME = "test_wlan0"; + + @Mock private IpServer mHotspotIpServer; + @Mock private IpServer mUsbIpServer; + @Mock private IpServer mEthernetIpServer; + @Mock private Context mContext; + @Mock private ConnectivityManager mConnectivityMgr; + + private PrivateAddressCoordinator mPrivateAddressCoordinator; + private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24"); + private final Network mWifiNetwork = new Network(1); + private final Network mMobileNetwork = new Network(2); + private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork}; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityMgr); + when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks); + mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext)); + } + + @Test + public void testDownstreamPrefixRequest() throws Exception { + LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer); + final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); + assertNotEquals(hotspotPrefix, mBluetoothPrefix); + + address = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer); + final IpPrefix testDupRequest = PrefixUtils.asIpPrefix(address); + assertNotEquals(hotspotPrefix, testDupRequest); + assertNotEquals(mBluetoothPrefix, testDupRequest); + mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); + + address = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer); + final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address); + assertNotEquals(usbPrefix, mBluetoothPrefix); + assertNotEquals(usbPrefix, hotspotPrefix); + mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); + } + + @Test + public void testRequestDownstreamAddress() throws Exception { + LinkAddress expectedAddress = new LinkAddress("192.168.43.42/24"); + int fakeSubAddr = 0x2b00; + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + LinkAddress actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer); + assertEquals(actualAddress, expectedAddress); + mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); + + fakeSubAddr = 0x2b01; + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer); + assertEquals(actualAddress, expectedAddress); + mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); + + fakeSubAddr = 0x2bff; + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer); + assertEquals(actualAddress, expectedAddress); + mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); + + expectedAddress = new LinkAddress("192.168.43.5/24"); + fakeSubAddr = 0x2b05; + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer); + assertEquals(actualAddress, expectedAddress); + mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); + } + + @Test + public void testReserveBluetoothPrefix() throws Exception { + final int fakeSubAddr = 0x2c05; + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer); + final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); + assertNotEquals("Should not get reserved prefix: ", mBluetoothPrefix, hotspotPrefix); + mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); + } + + @Test + public void testNoConflictDownstreamPrefix() throws Exception { + final int fakeHotspotSubAddr = 0x2b05; + final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); + LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer); + final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); + assertEquals("Wrong wifi perfix: ", predefinedPrefix, hotspotPrefix); + when(mHotspotIpServer.getAddress()).thenReturn(address); + + address = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer); + final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address); + assertNotEquals(predefinedPrefix, usbPrefix); + + mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); + mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); + address = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer); + final IpPrefix allowUseFreePrefix = PrefixUtils.asIpPrefix(address); + assertEquals("Fail to reselect available perfix: ", predefinedPrefix, allowUseFreePrefix); + } + + private LinkProperties buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6, + boolean isMobile) { + final String testIface; + final String testIpv4Address; + if (isMobile) { + testIface = TEST_MOBILE_IFNAME; + testIpv4Address = "10.0.0.1"; + } else { + testIface = TEST_WIFI_IFNAME; + testIpv4Address = "192.168.43.5"; + } + + final LinkProperties prop = new LinkProperties(); + prop.setInterfaceName(testIface); + + if (withIPv4) { + prop.addLinkAddress( + new LinkAddress(InetAddresses.parseNumericAddress(testIpv4Address), + NetworkConstants.IPV4_ADDR_BITS)); + } + + if (withIPv6) { + prop.addLinkAddress( + new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"), + NetworkConstants.RFC7421_PREFIX_LENGTH)); + } + return prop; + } + + @Test + public void testNoConflictUpstreamPrefix() throws Exception { + final int fakeHotspotSubId = 43; + final int fakeHotspotSubAddr = 0x2b05; + final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); + // Force always get subAddress "43.5" for conflict testing. + when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); + // 1. Enable hotspot with prefix 192.168.43.0/24 + final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer); + final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr); + assertEquals("Wrong wifi perfix: ", predefinedPrefix, hotspotPrefix); + when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr); + // 2. Update v6 only mobile network, hotspot prefix should not be removed. + List<String> testConflicts; + final LinkProperties v6OnlyMobileProp = buildUpstreamLinkProperties(false, true, true); + mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v6OnlyMobileProp); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + mPrivateAddressCoordinator.removeUpstreamPrefix(mMobileNetwork); + // 3. Update v4 only mobile network, hotspot prefix should not be removed. + final LinkProperties v4OnlyMobileProp = buildUpstreamLinkProperties(true, false, true); + mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4OnlyMobileProp); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + // 4. Update v4v6 mobile network, hotspot prefix should not be removed. + final LinkProperties v4v6MobileProp = buildUpstreamLinkProperties(true, true, true); + mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4v6MobileProp); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + // 5. Update v6 only wifi network, hotspot prefix should not be removed. + final LinkProperties v6OnlyWifiProp = buildUpstreamLinkProperties(false, true, false); + mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v6OnlyWifiProp); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); + // 6. Update v4 only wifi network, it conflict with hotspot prefix. + final LinkProperties v4OnlyWifiProp = buildUpstreamLinkProperties(true, false, false); + mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp); + verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + reset(mHotspotIpServer); + // 7. Restart hotspot again and its prefix is different previous. + mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); + final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer); + final IpPrefix hotspotPrefix2 = PrefixUtils.asIpPrefix(hotspotAddr2); + assertNotEquals(hotspotPrefix, hotspotPrefix2); + when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2); + mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + // 7. Usb tethering can be enabled and its prefix is different with conflict one. + final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer); + final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(usbAddr); + assertNotEquals(predefinedPrefix, usbPrefix); + assertNotEquals(hotspotPrefix2, usbPrefix); + when(mUsbIpServer.getAddress()).thenReturn(usbAddr); + // 8. Disable wifi upstream, then wifi's prefix can be selected again. + mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); + final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress( + mEthernetIpServer); + final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr); + assertEquals(predefinedPrefix, ethPrefix); + } +} diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 7734a3c61eaf..5fffaaedd8de 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -32,6 +32,7 @@ import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; @@ -84,6 +85,7 @@ import android.content.res.Resources; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; import android.net.EthernetManager; +import android.net.EthernetManager.TetheredInterfaceCallback; import android.net.EthernetManager.TetheredInterfaceRequest; import android.net.IIntResultListener; import android.net.INetd; @@ -169,9 +171,11 @@ public class TetheringTest { private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0"; private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0"; private static final String TEST_USB_IFNAME = "test_rndis0"; - private static final String TEST_WLAN_IFNAME = "test_wlan0"; + private static final String TEST_WIFI_IFNAME = "test_wlan0"; + private static final String TEST_WLAN_IFNAME = "test_wlan1"; private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0"; private static final String TEST_NCM_IFNAME = "test_ncm0"; + private static final String TEST_ETH_IFNAME = "test_eth0"; private static final String TETHERING_NAME = "Tethering"; private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; @@ -279,10 +283,11 @@ public class TetheringTest { || ifName.equals(TEST_WLAN_IFNAME) || ifName.equals(TEST_MOBILE_IFNAME) || ifName.equals(TEST_P2P_IFNAME) - || ifName.equals(TEST_NCM_IFNAME)); + || ifName.equals(TEST_NCM_IFNAME) + || ifName.equals(TEST_ETH_IFNAME)); final String[] ifaces = new String[] { TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME, - TEST_NCM_IFNAME}; + TEST_NCM_IFNAME, TEST_ETH_IFNAME}; return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET, MacAddress.ALL_ZEROS_ADDRESS); } @@ -490,7 +495,7 @@ public class TetheringTest { when(mNetd.interfaceGetList()) .thenReturn(new String[] { TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME, - TEST_NCM_IFNAME}); + TEST_NCM_IFNAME, TEST_ETH_IFNAME}); when(mResources.getString(R.string.config_wifi_tether_enable)).thenReturn(""); mInterfaceConfiguration = new InterfaceConfigurationParcel(); mInterfaceConfiguration.flags = new String[0]; @@ -1836,6 +1841,109 @@ public class TetheringTest { mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); sendConfigurationChanged(); } + + private static UpstreamNetworkState buildV4WifiUpstreamState(final String ipv4Address, + final int prefixLength, final Network network) { + final LinkProperties prop = new LinkProperties(); + prop.setInterfaceName(TEST_WIFI_IFNAME); + + prop.addLinkAddress( + new LinkAddress(InetAddresses.parseNumericAddress(ipv4Address), + prefixLength)); + + final NetworkCapabilities capabilities = new NetworkCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + return new UpstreamNetworkState(prop, capabilities, network); + } + + @Test + public void testHandleIpConflict() throws Exception { + final Network wifiNetwork = new Network(200); + final Network[] allNetworks = { wifiNetwork }; + when(mCm.getAllNetworks()).thenReturn(allNetworks); + UpstreamNetworkState upstreamNetwork = null; + runUsbTethering(upstreamNetwork); + final ArgumentCaptor<InterfaceConfigurationParcel> ifaceConfigCaptor = + ArgumentCaptor.forClass(InterfaceConfigurationParcel.class); + verify(mNetd).interfaceSetCfg(ifaceConfigCaptor.capture()); + final String ipv4Address = ifaceConfigCaptor.getValue().ipv4Addr; + verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( + any(), any()); + reset(mNetd, mUsbManager); + upstreamNetwork = buildV4WifiUpstreamState(ipv4Address, 30, wifiNetwork); + mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage( + Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK, + UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, + 0, + upstreamNetwork); + mLooper.dispatchAll(); + // verify trun off usb tethering + verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); + mTethering.interfaceRemoved(TEST_USB_IFNAME); + mLooper.dispatchAll(); + // verify restart usb tethering + verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_RNDIS); + } + + @Test + public void testNoAddressAvailable() throws Exception { + final Network wifiNetwork = new Network(200); + final Network[] allNetworks = { wifiNetwork }; + when(mCm.getAllNetworks()).thenReturn(allNetworks); + final String upstreamAddress = "192.168.0.100"; + runUsbTethering(null); + verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( + any(), any()); + reset(mUsbManager); + final TetheredInterfaceRequest mockRequest = mock(TetheredInterfaceRequest.class); + when(mEm.requestTetheredInterface(any(), any())).thenReturn(mockRequest); + final ArgumentCaptor<TetheredInterfaceCallback> callbackCaptor = + ArgumentCaptor.forClass(TetheredInterfaceCallback.class); + mTethering.startTethering(createTetheringRequestParcel(TETHERING_ETHERNET), null); + mLooper.dispatchAll(); + verify(mEm).requestTetheredInterface(any(), callbackCaptor.capture()); + TetheredInterfaceCallback ethCallback = callbackCaptor.getValue(); + ethCallback.onAvailable(TEST_ETH_IFNAME); + mLooper.dispatchAll(); + reset(mUsbManager, mEm); + + final UpstreamNetworkState upstreamNetwork = buildV4WifiUpstreamState( + upstreamAddress, 16, wifiNetwork); + mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage( + Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK, + UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, + 0, + upstreamNetwork); + mLooper.dispatchAll(); + // verify trun off usb tethering + verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); + // verify trun off ethernet tethering + verify(mockRequest).release(); + mTethering.interfaceRemoved(TEST_USB_IFNAME); + ethCallback.onUnavailable(); + mLooper.dispatchAll(); + // verify restart usb tethering + verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_RNDIS); + // verify restart ethernet tethering + verify(mEm).requestTetheredInterface(any(), callbackCaptor.capture()); + ethCallback = callbackCaptor.getValue(); + ethCallback.onAvailable(TEST_ETH_IFNAME); + + reset(mUsbManager, mEm); + when(mNetd.interfaceGetList()) + .thenReturn(new String[] { + TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME, + TEST_NCM_IFNAME, TEST_ETH_IFNAME}); + + mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true); + sendUsbBroadcast(true, true, true, TETHERING_USB); + mLooper.dispatchAll(); + assertContains(Arrays.asList(mTethering.getTetherableIfaces()), TEST_USB_IFNAME); + assertContains(Arrays.asList(mTethering.getTetherableIfaces()), TEST_ETH_IFNAME); + assertEquals(TETHER_ERROR_IFACE_CFG_ERROR, mTethering.getLastTetherError(TEST_USB_IFNAME)); + assertEquals(TETHER_ERROR_IFACE_CFG_ERROR, mTethering.getLastTetherError(TEST_ETH_IFNAME)); + } + // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface. } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6e026ab7fe2c..4b66cea88ed0 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -8183,6 +8183,11 @@ public class ConnectivityService extends IConnectivityManager.Stub + "creators"); } + // Instead of passing the data stall directly to the ConnectivityDiagnostics handler, treat + // this as a Data Stall received directly from NetworkMonitor. This requires wrapping the + // Data Stall information as a DataStallReportParcelable and passing to + // #notifyDataStallSuspected. This ensures that unknown Data Stall detection methods are + // still passed to ConnectivityDiagnostics (with new detection methods masked). final DataStallReportParcelable p = new DataStallReportParcelable(); p.timestampMillis = timestampMillis; p.detectionMethod = detectionMethod; diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index 34d0bed9a802..3091a7178377 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -198,6 +198,9 @@ public class Nat464Xlat extends BaseNetworkObserver { if (mPrefixDiscoveryRunning && !isPrefixDiscoveryNeeded()) { stopPrefixDiscovery(); } + if (!mPrefixDiscoveryRunning) { + setPrefix64(mNat64PrefixInUse); + } } /** @@ -221,6 +224,10 @@ public class Nat464Xlat extends BaseNetworkObserver { mIface = null; mBaseIface = null; + if (!mPrefixDiscoveryRunning) { + setPrefix64(null); + } + if (isPrefixDiscoveryNeeded()) { if (!mPrefixDiscoveryRunning) { startPrefixDiscovery(); @@ -308,6 +315,16 @@ public class Nat464Xlat extends BaseNetworkObserver { return requiresClat(mNetwork) && mNat64PrefixFromRa == null; } + private void setPrefix64(IpPrefix prefix) { + final String prefixString = (prefix != null) ? prefix.toString() : ""; + try { + mDnsResolver.setPrefix64(getNetId(), prefixString); + } catch (RemoteException | ServiceSpecificException e) { + Slog.e(TAG, "Error setting NAT64 prefix on netId " + getNetId() + " to " + + prefix + ": " + e); + } + } + private void maybeHandleNat64PrefixChange() { final IpPrefix newPrefix = selectNat64Prefix(); if (!Objects.equals(mNat64PrefixInUse, newPrefix)) { diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 730da28ba8a2..0cda7ca30414 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -2867,6 +2867,23 @@ public class Vpn { return Credentials.PLATFORM_VPN + mUserHandle + "_" + packageName; } + @VisibleForTesting + void validateRequiredFeatures(VpnProfile profile) { + switch (profile.type) { + case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: + case VpnProfile.TYPE_IKEV2_IPSEC_PSK: + case VpnProfile.TYPE_IKEV2_IPSEC_RSA: + if (!mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_IPSEC_TUNNELS)) { + throw new UnsupportedOperationException( + "Ikev2VpnProfile(s) requires PackageManager.FEATURE_IPSEC_TUNNELS"); + } + break; + default: + return; + } + } + /** * Stores an app-provisioned VPN profile and returns whether the app is already prepared. * @@ -2883,6 +2900,7 @@ public class Vpn { verifyCallingUidAndPackage(packageName); enforceNotRestrictedUser(); + validateRequiredFeatures(profile); if (profile.isRestrictedToTestNetworks) { mContext.enforceCallingPermission(Manifest.permission.MANAGE_TEST_NETWORKS, diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 3dac106418c5..86ad0b308676 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -152,12 +152,10 @@ public class NetworkStatsFactory { /** * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. - * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map, boolean) + * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) */ - public void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, boolean useBpfStats) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces, - useBpfStats); + public void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic) { + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces); } public NetworkStatsFactory() { @@ -380,7 +378,7 @@ public class NetworkStatsFactory { // network, the overhead is their fault. // No locking here: apply464xlatAdjustments behaves fine with an add-only // ConcurrentHashMap. - delta.apply464xlatAdjustments(mStackedIfaces, mUseBpfStats); + delta.apply464xlatAdjustments(mStackedIfaces); // Migrate data usage over a VPN to the TUN network. for (VpnInfo info : vpnArray) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 5d1cc2a5c24a..ba538e1cd826 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1306,21 +1306,39 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // Traffic occurring on stacked interfaces is usually clatd. - // UID stats are always counted on the stacked interface and never - // on the base interface, because the packets on the base interface - // do not actually match application sockets until they are translated. // - // Interface stats are more complicated. Packets subject to BPF offload - // never appear on the base interface and only appear on the stacked - // interface, so to ensure those packets increment interface stats, interface - // stats from stacked interfaces must be collected. + // UID stats are always counted on the stacked interface and never on the base + // interface, because the packets on the base interface do not actually match + // application sockets (they're not IPv4) and thus the app uid is not known. + // For receive this is obvious: packets must be translated from IPv6 to IPv4 + // before the application socket can be found. + // For transmit: either they go through the clat daemon which by virtue of going + // through userspace strips the original socket association during the IPv4 to + // IPv6 translation process, or they are offloaded by eBPF, which doesn't: + // However, on an ebpf device the accounting is done in cgroup ebpf hooks, + // which don't trigger again post ebpf translation. + // (as such stats accounted to the clat uid are ignored) + // + // Interface stats are more complicated. + // + // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus + // *all* statistics are collected by iptables on the stacked v4-* interface. + // + // Additionally for ingress all packets bound for the clat IPv6 address are dropped + // in ip6tables raw prerouting and thus even non-offloaded packets are only + // accounted for on the stacked interface. + // + // For egress, packets subject to eBPF offload never appear on the base interface + // and only appear on the stacked interface. Thus to ensure packets increment + // interface stats, we must collate data from stacked interfaces. For xt_qtaguid + // (or non eBPF offloaded) TX they would appear on both, however egress interface + // accounting is explicitly bypassed for traffic from the clat uid. + // final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); if (stackedIface != null) { - if (mUseBpfTrafficStats) { - findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); - } + findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); if (isMobile) { mobileIfaces.add(stackedIface); @@ -1859,14 +1877,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot, - mUseBpfTrafficStats); + mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); uidSnapshot.combineAllValues(tetherSnapshot); // get a stale copy of uid stats snapshot provided by providers. final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID); providerStats.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats, mUseBpfTrafficStats); + mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats); uidSnapshot.combineAllValues(providerStats); uidSnapshot.combineAllValues(mUidOperations); diff --git a/services/core/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp index aef0b25503c8..c9459994a658 100644 --- a/services/core/jni/com_android_server_SerialService.cpp +++ b/services/core/jni/com_android_server_SerialService.cpp @@ -48,6 +48,7 @@ static jobject android_server_SerialService_open(JNIEnv *env, jobject /* thiz */ jobject fileDescriptor = jniCreateFileDescriptor(env, fd); if (fileDescriptor == NULL) { + close(fd); return NULL; } return env->NewObject(gParcelFileDescriptorOffsets.mClass, diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp index ff1ec04cb23e..72dce4dca0da 100644 --- a/services/core/jni/com_android_server_UsbDeviceManager.cpp +++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp @@ -19,6 +19,7 @@ #include "jni.h" #include <nativehelper/JNIHelp.h> +#include <nativehelper/ScopedUtfChars.h> #include "android_runtime/AndroidRuntime.h" #include "android_runtime/Log.h" #include "MtpDescriptors.h" @@ -88,6 +89,7 @@ static jobject android_server_UsbDeviceManager_openAccessory(JNIEnv *env, jobjec } jobject fileDescriptor = jniCreateFileDescriptor(env, fd); if (fileDescriptor == NULL) { + close(fd); return NULL; } return env->NewObject(gParcelFileDescriptorOffsets.mClass, @@ -120,35 +122,30 @@ static jint android_server_UsbDeviceManager_getAudioMode(JNIEnv* /* env */, jobj } static jobject android_server_UsbDeviceManager_openControl(JNIEnv *env, jobject /* thiz */, jstring jFunction) { - const char *function = env->GetStringUTFChars(jFunction, NULL); + ScopedUtfChars function(env, jFunction); bool ptp = false; int fd = -1; - if (!strcmp(function, "ptp")) { + if (!strcmp(function.c_str(), "ptp")) { ptp = true; } - if (!strcmp(function, "mtp") || ptp) { + if (!strcmp(function.c_str(), "mtp") || ptp) { fd = TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP0 : FFS_MTP_EP0, O_RDWR)); if (fd < 0) { - ALOGE("could not open control for %s %s", function, strerror(errno)); - goto error; + ALOGE("could not open control for %s %s", function.c_str(), strerror(errno)); + return NULL; } if (!writeDescriptors(fd, ptp)) { - goto error; + close(fd); + return NULL; } } - if (function != NULL) { - env->ReleaseStringUTFChars(jFunction, function); - } - return jniCreateFileDescriptor(env, fd); -error: - if (fd != -1) { + jobject jifd = jniCreateFileDescriptor(env, fd); + if (jifd == NULL) { + // OutOfMemoryError will be pending. close(fd); } - if (function != NULL) { - env->ReleaseStringUTFChars(jFunction, function); - } - return NULL; + return jifd; } static const JNINativeMethod method_table[] = { diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp index 24f2014afa30..a40bcd0d7c07 100644 --- a/services/core/jni/com_android_server_UsbHostManager.cpp +++ b/services/core/jni/com_android_server_UsbHostManager.cpp @@ -134,6 +134,7 @@ static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* jobject fileDescriptor = jniCreateFileDescriptor(env, newFD); if (fileDescriptor == NULL) { + close(newFD); return NULL; } return env->NewObject(gParcelFileDescriptorOffsets.mClass, diff --git a/services/core/jni/com_android_server_UsbMidiDevice.cpp b/services/core/jni/com_android_server_UsbMidiDevice.cpp index 79d935fe610c..8ac2c4f37ecd 100644 --- a/services/core/jni/com_android_server_UsbMidiDevice.cpp +++ b/services/core/jni/com_android_server_UsbMidiDevice.cpp @@ -20,6 +20,7 @@ #include "jni.h" #include <nativehelper/JNIHelp.h> +#include <nativehelper/ScopedLocalRef.h> #include "android_runtime/AndroidRuntime.h" #include "android_runtime/Log.h" @@ -99,24 +100,45 @@ android_server_UsbMidiDevice_open(JNIEnv *env, jobject thiz, jint card, jint dev int fd = open(path, O_RDWR); if (fd < 0) { ALOGE("open failed on %s for index %d", path, i); - return NULL; + goto release_fds; } - - jobject fileDescriptor = jniCreateFileDescriptor(env, fd); - env->SetObjectArrayElement(fds, i, fileDescriptor); - env->DeleteLocalRef(fileDescriptor); + ScopedLocalRef<jobject> jifd(env, jniCreateFileDescriptor(env, fd)); + if (jifd.get() == NULL) { + goto release_fds; + } + env->SetObjectArrayElement(fds, i, jifd.get()); } // create a pipe to use for unblocking our input thread - int pipeFD[2]; - pipe(pipeFD); - jobject fileDescriptor = jniCreateFileDescriptor(env, pipeFD[0]); - env->SetObjectArrayElement(fds, subdevice_count, fileDescriptor); - env->DeleteLocalRef(fileDescriptor); - // store our end of the pipe in mPipeFD - env->SetIntField(thiz, sPipeFDField, pipeFD[1]); + { + int pipeFD[2]; + if (pipe(pipeFD) == -1) { + ALOGE("pipe() failed, errno = %d", errno); + goto release_fds; + } + ScopedLocalRef<jobject> jifd(env, jniCreateFileDescriptor(env, pipeFD[0])); + if (jifd.get() == NULL) { + close(pipeFD[0]); + close(pipeFD[1]); + goto release_fds; + } + env->SetObjectArrayElement(fds, subdevice_count, jifd.get()); + // store our end of the pipe in mPipeFD + env->SetIntField(thiz, sPipeFDField, pipeFD[1]); + } return fds; + +release_fds: + for (int i = 0; i < subdevice_count + 1; ++i) { + ScopedLocalRef<jobject> jifd(env, env->GetObjectArrayElement(fds, i)); + if (jifd.get() == NULL) { + break; + } + int fd = jniGetFDFromFileDescriptor(env, jifd.get()); + close(fd); + } + return NULL; } static void diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index d331d1f58b2d..89bcb7fc667a 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -166,6 +166,7 @@ static void loadSystemIconAsSpriteWithPointerIcon(JNIEnv* env, jobject contextOb outPointerIcon->bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(), bitmapCopy->rowBytes(), 0, 0); } + outSpriteIcon->style = outPointerIcon->style; outSpriteIcon->hotSpotX = outPointerIcon->hotSpotX; outSpriteIcon->hotSpotY = outPointerIcon->hotSpotY; } @@ -318,7 +319,6 @@ private: void updateInactivityTimeoutLocked(); void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags); void ensureSpriteControllerLocked(); - const DisplayViewport* findDisplayViewportLocked(int32_t displayId); int32_t getPointerDisplayId(); void updatePointerDisplayLocked(); static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName); @@ -396,16 +396,6 @@ bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const c return false; } -const DisplayViewport* NativeInputManager::findDisplayViewportLocked(int32_t displayId) - REQUIRES(mLock) { - for (const DisplayViewport& v : mLocked.viewports) { - if (v.displayId == displayId) { - return &v; - } - } - return nullptr; -} - void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray) { std::vector<DisplayViewport> viewports; @@ -554,6 +544,8 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon outConfig->setDisplayViewports(mLocked.viewports); + outConfig->defaultPointerDisplayId = mLocked.pointerDisplayId; + outConfig->disabledDevices = mLocked.disabledInputDevices; } // release lock } @@ -571,8 +563,6 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32 updateInactivityTimeoutLocked(); } - updatePointerDisplayLocked(); - return controller; } @@ -587,23 +577,6 @@ int32_t NativeInputManager::getPointerDisplayId() { return pointerDisplayId; } -void NativeInputManager::updatePointerDisplayLocked() REQUIRES(mLock) { - ATRACE_CALL(); - - sp<PointerController> controller = mLocked.pointerController.promote(); - if (controller != nullptr) { - const DisplayViewport* viewport = findDisplayViewportLocked(mLocked.pointerDisplayId); - if (viewport == nullptr) { - ALOGW("Can't find pointer display viewport, fallback to default display."); - viewport = findDisplayViewportLocked(ADISPLAY_ID_DEFAULT); - } - - if (viewport != nullptr) { - controller->setDisplayViewport(*viewport); - } - } -} - void NativeInputManager::ensureSpriteControllerLocked() REQUIRES(mLock) { if (mLocked.spriteController == nullptr) { JNIEnv* env = jniEnv(); @@ -1252,7 +1225,8 @@ void NativeInputManager::loadPointerIcon(SpriteIcon* icon, int32_t displayId) { status_t status = android_view_PointerIcon_load(env, pointerIconObj.get(), displayContext.get(), &pointerIcon); if (!status && !pointerIcon.isNullIcon()) { - *icon = SpriteIcon(pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY); + *icon = SpriteIcon( + pointerIcon.bitmap, pointerIcon.style, pointerIcon.hotSpotX, pointerIcon.hotSpotY); } else { *icon = SpriteIcon(); } @@ -1293,10 +1267,12 @@ void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIc milliseconds_to_nanoseconds(pointerIcon.durationPerFrame); animationData.animationFrames.reserve(numFrames); animationData.animationFrames.push_back(SpriteIcon( - pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY)); + pointerIcon.bitmap, pointerIcon.style, + pointerIcon.hotSpotX, pointerIcon.hotSpotY)); for (size_t i = 0; i < numFrames - 1; ++i) { animationData.animationFrames.push_back(SpriteIcon( - pointerIcon.bitmapFrames[i], pointerIcon.hotSpotX, pointerIcon.hotSpotY)); + pointerIcon.bitmapFrames[i], pointerIcon.style, + pointerIcon.hotSpotX, pointerIcon.hotSpotY)); } } } @@ -1732,6 +1708,7 @@ static void nativeSetCustomPointerIcon(JNIEnv* env, jclass /* clazz */, pointerIcon.bitmap.readPixels(spriteInfo, spriteIcon.bitmap.getPixels(), spriteIcon.bitmap.rowBytes(), 0, 0); } + spriteIcon.style = pointerIcon.style; spriteIcon.hotSpotX = pointerIcon.hotSpotX; spriteIcon.hotSpotY = pointerIcon.hotSpotY; im->setCustomPointerIcon(spriteIcon); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 0167a3b0aebe..23b1512081da 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -165,6 +165,8 @@ import com.android.server.wm.ActivityTaskManagerService; import com.android.server.wm.WindowManagerGlobalLock; import com.android.server.wm.WindowManagerService; +import libcore.timezone.ZoneInfoDb; + import dalvik.system.VMRuntime; import java.io.File; @@ -395,8 +397,9 @@ public final class SystemServer { // Default the timezone property to GMT if not set. // String timezoneProperty = SystemProperties.get("persist.sys.timezone"); - if (timezoneProperty == null || timezoneProperty.isEmpty()) { - Slog.w(TAG, "Timezone not set; setting to GMT."); + if (!isValidTimeZoneId(timezoneProperty)) { + Slog.w(TAG, "persist.sys.timezone is not valid (" + timezoneProperty + + "); setting to GMT."); SystemProperties.set("persist.sys.timezone", "GMT"); } @@ -564,6 +567,12 @@ public final class SystemServer { throw new RuntimeException("Main thread loop unexpectedly exited"); } + private static boolean isValidTimeZoneId(String timezoneProperty) { + return timezoneProperty != null + && !timezoneProperty.isEmpty() + && ZoneInfoDb.getInstance().hasTimeZone(timezoneProperty); + } + private boolean isFirstBootOrUpgrade() { return mPackageManagerService.isFirstBoot() || mPackageManagerService.isDeviceUpgrading(); } diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index 9ec3f61ba6a7..6840e8eed318 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -430,7 +430,6 @@ public class MmTelFeature extends ImsFeature { /** * @param listener A {@link Listener} used when the MmTelFeature receives an incoming call and * notifies the framework. - * @hide */ private void setListener(IImsMmTelListener listener) { synchronized (mLock) { @@ -442,6 +441,16 @@ public class MmTelFeature extends ImsFeature { } /** + * @return the listener associated with this MmTelFeature. May be null if it has not been set + * by the framework yet. + */ + private IImsMmTelListener getListener() { + synchronized (mLock) { + return mListener; + } + } + + /** * The current capability status that this MmTelFeature has defined is available. This * configuration will be used by the platform to figure out which capabilities are CURRENTLY * available to be used. @@ -489,15 +498,14 @@ public class MmTelFeature extends ImsFeature { throw new IllegalArgumentException("ImsCallSessionImplBase and Bundle can not be " + "null."); } - synchronized (mLock) { - if (mListener == null) { - throw new IllegalStateException("Session is not available."); - } - try { - mListener.onIncomingCall(c.getServiceImpl(), extras); - } catch (RemoteException e) { - throw new RuntimeException(e); - } + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + try { + listener.onIncomingCall(c.getServiceImpl(), extras); + } catch (RemoteException e) { + throw new RuntimeException(e); } } @@ -516,15 +524,14 @@ public class MmTelFeature extends ImsFeature { throw new IllegalArgumentException("ImsCallProfile and ImsReasonInfo must not be " + "null."); } - synchronized (mLock) { - if (mListener == null) { - throw new IllegalStateException("Session is not available."); - } - try { - mListener.onRejectedCall(callProfile, reason); - } catch (RemoteException e) { - throw new RuntimeException(e); - } + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + try { + listener.onRejectedCall(callProfile, reason); + } catch (RemoteException e) { + throw new RuntimeException(e); } } @@ -533,15 +540,14 @@ public class MmTelFeature extends ImsFeature { * @hide */ public final void notifyIncomingCallSession(IImsCallSession c, Bundle extras) { - synchronized (mLock) { - if (mListener == null) { - throw new IllegalStateException("Session is not available."); - } - try { - mListener.onIncomingCall(c, extras); - } catch (RemoteException e) { - throw new RuntimeException(e); - } + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + try { + listener.onIncomingCall(c, extras); + } catch (RemoteException e) { + throw new RuntimeException(e); } } @@ -552,15 +558,14 @@ public class MmTelFeature extends ImsFeature { */ @SystemApi @TestApi public final void notifyVoiceMessageCountUpdate(int count) { - synchronized (mLock) { - if (mListener == null) { - throw new IllegalStateException("Session is not available."); - } - try { - mListener.onVoiceMessageCountUpdate(count); - } catch (RemoteException e) { - throw new RuntimeException(e); - } + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + try { + listener.onVoiceMessageCountUpdate(count); + } catch (RemoteException e) { + throw new RuntimeException(e); } } diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java index 442ac5605e90..0b13800bc5c9 100644 --- a/tests/net/java/android/net/IpMemoryStoreTest.java +++ b/tests/net/java/android/net/IpMemoryStoreTest.java @@ -105,7 +105,7 @@ public class IpMemoryStoreTest { private static NetworkAttributes buildTestNetworkAttributes(String hint, int mtu) { return new NetworkAttributes.Builder() - .setGroupHint(hint) + .setCluster(hint) .setMtu(mtu) .build(); } diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index 98f705f45e98..735fa7cf3751 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -909,8 +909,8 @@ public class NetworkStatsTest { 13805 /* txPackets */, 0 /* operations */); - // Traffic measured for the root uid on the base interface if eBPF is in use. - final NetworkStats.Entry ebpfRootUidEntry = new NetworkStats.Entry( + // Traffic measured for the root uid on the base interface. + final NetworkStats.Entry rootUidEntry = new NetworkStats.Entry( baseIface, rootUid, SET_DEFAULT, TAG_NONE, 163577 /* rxBytes */, 187 /* rxPackets */, @@ -918,17 +918,6 @@ public class NetworkStatsTest { 97 /* txPackets */, 0 /* operations */); - // Traffic measured for the root uid on the base interface if xt_qtaguid is in use. - // Incorrectly includes appEntry's bytes and packets, plus IPv4-IPv6 translation - // overhead (20 bytes per packet), in rx direction. - final NetworkStats.Entry xtRootUidEntry = new NetworkStats.Entry( - baseIface, rootUid, SET_DEFAULT, TAG_NONE, - 31113087 /* rxBytes */, - 22588 /* rxPackets */, - 17607 /* txBytes */, - 97 /* txPackets */, - 0 /* operations */); - final NetworkStats.Entry otherEntry = new NetworkStats.Entry( otherIface, appUid, SET_DEFAULT, TAG_NONE, 2600 /* rxBytes */, @@ -937,21 +926,14 @@ public class NetworkStatsTest { 3 /* txPackets */, 0 /* operations */); - final NetworkStats statsXt = new NetworkStats(TEST_START, 3) - .insertEntry(appEntry) - .insertEntry(xtRootUidEntry) - .insertEntry(otherEntry); - - final NetworkStats statsEbpf = new NetworkStats(TEST_START, 3) + final NetworkStats stats = new NetworkStats(TEST_START, 3) .insertEntry(appEntry) - .insertEntry(ebpfRootUidEntry) + .insertEntry(rootUidEntry) .insertEntry(otherEntry); - statsXt.apply464xlatAdjustments(stackedIface, false); - statsEbpf.apply464xlatAdjustments(stackedIface, true); + stats.apply464xlatAdjustments(stackedIface); - assertEquals(3, statsXt.size()); - assertEquals(3, statsEbpf.size()); + assertEquals(3, stats.size()); final NetworkStats.Entry expectedAppUid = new NetworkStats.Entry( v4Iface, appUid, SET_DEFAULT, TAG_NONE, 30949510, @@ -966,12 +948,9 @@ public class NetworkStatsTest { 17607, 97, 0); - assertEquals(expectedAppUid, statsXt.getValues(0, null)); - assertEquals(expectedRootUid, statsXt.getValues(1, null)); - assertEquals(otherEntry, statsXt.getValues(2, null)); - assertEquals(expectedAppUid, statsEbpf.getValues(0, null)); - assertEquals(expectedRootUid, statsEbpf.getValues(1, null)); - assertEquals(otherEntry, statsEbpf.getValues(2, null)); + assertEquals(expectedAppUid, stats.getValues(0, null)); + assertEquals(expectedRootUid, stats.getValues(1, null)); + assertEquals(otherEntry, stats.getValues(2, null)); } @Test @@ -996,7 +975,7 @@ public class NetworkStatsTest { .insertEntry(secondEntry); // Empty map: no adjustment - stats.apply464xlatAdjustments(new ArrayMap<>(), false); + stats.apply464xlatAdjustments(new ArrayMap<>()); assertEquals(2, stats.size()); assertEquals(firstEntry, stats.getValues(0, null)); diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java index 1a3ea6096c82..02f5286506a8 100644 --- a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java +++ b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java @@ -54,7 +54,7 @@ public class ParcelableTests { builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9")); builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000); - builder.setGroupHint("groupHint"); + builder.setCluster("groupHint"); builder.setDnsAddresses(Arrays.asList( InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"), InetAddress.getByName("6.7.8.9"))); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 065ddd3f1d65..ea4982ed7c7d 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -6322,6 +6322,7 @@ public class ConnectivityServiceTest { int netId = network.getNetId(); callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString()); + inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString()); inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId); callback.assertNoCallback(); assertEquals(pref64FromRa, mCm.getLinkProperties(network).getNat64Prefix()); @@ -6331,6 +6332,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(lp); expectNat64PrefixChange(callback, mCellNetworkAgent, null); inOrder.verify(mMockNetd).clatdStop(iface); + inOrder.verify(mMockDnsResolver).setPrefix64(netId, ""); inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId); // If the RA prefix appears while DNS discovery is in progress, discovery is stopped and @@ -6340,6 +6342,7 @@ public class ConnectivityServiceTest { expectNat64PrefixChange(callback, mCellNetworkAgent, pref64FromRa); inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString()); inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId); + inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString()); // Withdraw the RA prefix so we can test the case where an RA prefix appears after DNS // discovery has succeeded. @@ -6347,6 +6350,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(lp); expectNat64PrefixChange(callback, mCellNetworkAgent, null); inOrder.verify(mMockNetd).clatdStop(iface); + inOrder.verify(mMockDnsResolver).setPrefix64(netId, ""); inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId); mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */, @@ -6363,6 +6367,7 @@ public class ConnectivityServiceTest { inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString()); inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId); inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId); + inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString()); // If the RA is later withdrawn, nothing happens again. lp.setNat64Prefix(null); @@ -6372,6 +6377,7 @@ public class ConnectivityServiceTest { inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString()); inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId); inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId); + inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString()); // If the RA prefix changes, clatd is restarted and prefix discovery is stopped. lp.setNat64Prefix(pref64FromRa); @@ -6385,6 +6391,7 @@ public class ConnectivityServiceTest { pref64FromDnsStr, 96); inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString()); + inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString()); inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId); // If the RA prefix changes, clatd is restarted and prefix discovery is not started. @@ -6392,7 +6399,9 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(lp); expectNat64PrefixChange(callback, mCellNetworkAgent, newPref64FromRa); inOrder.verify(mMockNetd).clatdStop(iface); + inOrder.verify(mMockDnsResolver).setPrefix64(netId, ""); inOrder.verify(mMockNetd).clatdStart(iface, newPref64FromRa.toString()); + inOrder.verify(mMockDnsResolver).setPrefix64(netId, newPref64FromRa.toString()); inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId); inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId); @@ -6405,11 +6414,45 @@ public class ConnectivityServiceTest { inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString()); inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId); inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId); + inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString()); // The transition between no prefix and DNS prefix is tested in testStackedLinkProperties. + // 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); + mCellNetworkAgent.sendLinkProperties(lp); + expectNat64PrefixChange(callback, mCellNetworkAgent, null); + inOrder.verify(mMockNetd).clatdStop(iface); + inOrder.verify(mMockDnsResolver).setPrefix64(netId, ""); + inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId); + mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */, + pref64FromDnsStr, 96); + expectNat64PrefixChange(callback, mCellNetworkAgent, pref64FromDns); + inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString()); + inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any()); + + lp.setNat64Prefix(pref64FromDns); + mCellNetworkAgent.sendLinkProperties(lp); callback.assertNoCallback(); + inOrder.verify(mMockNetd, never()).clatdStop(iface); + inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString()); + inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId); + inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId); + inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString()); + + // When tearing down a network, clat state is only updated after CALLBACK_LOST is fired, but + // before CONNECTIVITY_ACTION is sent. Wait for CONNECTIVITY_ACTION before verifying that + // clat has been stopped, or the test will be flaky. + ConditionVariable cv = registerConnectivityBroadcast(1); mCellNetworkAgent.disconnect(); + callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); + waitFor(cv); + + inOrder.verify(mMockNetd).clatdStop(iface); + inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId); + inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString()); + mCm.unregisterNetworkCallback(callback); } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index f8d8a56b57c0..4ccf79a0cb37 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -199,6 +199,8 @@ public class VpnTest { when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent)) .thenReturn(Resources.getSystem().getString( R.string.config_customVpnAlwaysOnDisconnectedDialogComponent)); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)) + .thenReturn(true); when(mSystemServices.isCallerSystem()).thenReturn(true); // Used by {@link Notification.Builder} @@ -731,6 +733,20 @@ public class VpnTest { } @Test + public void testProvisionVpnProfileNoIpsecTunnels() throws Exception { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)) + .thenReturn(false); + final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN); + + try { + checkProvisionVpnProfile( + vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN); + fail("Expected exception due to missing feature"); + } catch (UnsupportedOperationException expected) { + } + } + + @Test public void testProvisionVpnProfilePreconsented() throws Exception { final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN); diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java index 4473492d7972..e4996d981fac 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java @@ -446,7 +446,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest { assertStatsEntry(stats, "v4-wlan0", 1000, SET_DEFAULT, 0x0, 30812L, 2310L); assertStatsEntry(stats, "v4-wlan0", 10102, SET_DEFAULT, 0x0, 10022L, 3330L); assertStatsEntry(stats, "v4-wlan0", 10060, SET_DEFAULT, 0x0, 9532772L, 254112L); - assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 15229L, 0L); + assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 0L, 0L); assertStatsEntry(stats, "wlan0", 1000, SET_DEFAULT, 0x0, 6126L, 2013L); assertStatsEntry(stats, "wlan0", 10013, SET_DEFAULT, 0x0, 0L, 144L); assertStatsEntry(stats, "wlan0", 10018, SET_DEFAULT, 0x0, 5980263L, 167667L); @@ -468,9 +468,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest { long appRxBytesAfter = 439237478L; assertEquals("App traffic should be ~100MB", 110553449, appRxBytesAfter - appRxBytesBefore); - long rootRxBytesBefore = 1394011L; - long rootRxBytesAfter = 1398634L; - assertEquals("UID 0 traffic should be ~0", 4623, rootRxBytesAfter - rootRxBytesBefore); + long rootRxBytes = 330187296L; mFactory.noteStackedIface("v4-wlan0", "wlan0"); NetworkStats stats; @@ -478,12 +476,12 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest { // Stats snapshot before the download stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_before); assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesBefore, 5199872L); - assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesBefore, 0L); + assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytes, 0L); // Stats snapshot after the download stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_after); assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L); - assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 0L); + assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytes, 0L); } /** diff --git a/tests/net/res/raw/xt_qtaguid_with_clat b/tests/net/res/raw/xt_qtaguid_with_clat index 6cd7499545be..f04b32f08332 100644 --- a/tests/net/res/raw/xt_qtaguid_with_clat +++ b/tests/net/res/raw/xt_qtaguid_with_clat @@ -7,7 +7,7 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe 7 v4-wlan0 0x0 10060 1 1448660 1041 31192 753 1448660 1041 0 0 0 0 31192 753 0 0 0 0 8 v4-wlan0 0x0 10102 0 9702 16 2870 23 9702 16 0 0 0 0 2870 23 0 0 0 0 9 v4-wlan0 0x0 10102 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -10 wlan0 0x0 0 0 11058671 7892 0 0 11043898 7811 13117 61 1656 20 0 0 0 0 0 0 +10 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 wlan0 0x0 1000 0 6126 13 2013 16 5934 11 192 2 0 0 1821 14 192 2 0 0 13 wlan0 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 @@ -41,5 +41,3 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe 41 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 lo 0x0 0 0 1288 16 1288 16 0 0 532 8 756 8 0 0 532 8 756 8 43 lo 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -44 wlan0 0x0 1029 0 0 0 312046 5113 0 0 0 0 0 0 306544 5046 3230 38 2272 29 -45 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after index 9f86153a33cf..12d98ca29f57 100644 --- a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after +++ b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after @@ -9,7 +9,7 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe 9 v4-wlan0 0x0 10057 1 728 7 392 7 0 0 728 7 0 0 0 0 392 7 0 0 10 v4-wlan0 0x0 10106 0 2232 18 2232 18 0 0 2232 18 0 0 0 0 2232 18 0 0 11 v4-wlan0 0x0 10106 1 432952718 314238 5442288 121260 432950238 314218 2480 20 0 0 5433900 121029 8388 231 0 0 -12 wlan0 0x0 0 0 440746376 329772 0 0 439660007 315369 232001 1276 854368 13127 0 0 0 0 0 0 +12 wlan0 0x0 0 0 330187296 250652 0 0 329106990 236273 226202 1255 854104 13124 0 0 0 0 0 0 13 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 wlan0 0x0 1000 0 77113 272 56151 575 77113 272 0 0 0 0 19191 190 36960 385 0 0 15 wlan0 0x0 1000 1 20227 80 8356 72 18539 74 1688 6 0 0 7562 66 794 6 0 0 diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_simple b/tests/net/res/raw/xt_qtaguid_with_clat_simple index b37fae6d2a3d..a1d6d411bad8 100644 --- a/tests/net/res/raw/xt_qtaguid_with_clat_simple +++ b/tests/net/res/raw/xt_qtaguid_with_clat_simple @@ -1,5 +1,4 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets 2 v4-wlan0 0x0 10060 0 42600 213 4100 41 42600 213 0 0 0 0 4100 41 0 0 0 0 3 v4-wlan0 0x0 10060 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -4 wlan0 0x0 0 0 46860 213 0 0 46860 213 0 0 0 0 0 0 0 0 0 0 -5 wlan0 0x0 1029 0 0 0 4920 41 0 0 0 0 0 0 4920 41 0 0 0 0 +4 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 |